Chapter 11. A Universal Class for Connections and a Proxy Pattern for Security

It is art that makes life, makes interest, makes importance... and I know of no substitute whatever for the force and beauty of its process.

Substitute “damn” every time you’re inclined to write “very”; your editor will delete it and the writing will be just as it should be.

The work of science is to substitute facts for appearances, and demonstrations for impressions.

In Chapter 2, you saw one example of how PHP allows interfaces to store constants that can be used by classes that implement the interface. One set of constants that can be stored in the interface is that required for connecting to a MySQL database. The routine using the PHP mysqli extension provides some variations for connection, but all variations need the host, username, password, and database information. Once the routine is set in a class, it should be available for general reuse whenever a program requires a MySQL connection. Figure 11-1 shows the class diagram for this arrangement.

The connection information is independent of the client because the concrete information is stored in constants in the interface. The UniversalConnect class uses the Scope Resolution Operator to access the data stored in the constants in the interface.

All IConnectInfo interface implementations access the connection values using the Scope Resolution Operator. In the context of the way in which the values are passed from the interface to an implementing class and employed, assigning variables a private static status has the speed advantage of a static variable and the encapsulation of a private visibility:

<?php
include_once('IConnectInfo.php');

class UniversalConnect implements IConnectInfo
{
    private static $server=IConnectInfo::HOST;
    private static $currentDB= IConnectInfo::DBNAME;
    private static $user= IConnectInfo::UNAME;
    private static $pass= IConnectInfo::PW;
    private static $hookup;

    public function doConnect()
    {
        self::$hookup=mysqli_connect(self::$server, self::$user, self::$pass,
                      self::$currentDB);
        if(self::$hookup)
        {
            //Remove slashes in following line for debugging
            //echo "Successful connection to MySQL:";
        }
        elseif (mysqli_connect_error(self::$hookup))
        {
            echo('Here is why it failed: '  . mysqli_connect_error());
        }
        return self::$hookup;
    }
}
?>

In addition to assigning the connection variables static status, the mysqli variable ($hookup) is static as well in the UniversalConnect class. This enables it to be used in a larger static context when requested by a client class.

Perhaps the biggest advantage of using static variables is the capacity to use their values without having to instantiate the UniversalConnect class every time a different part of the program must create a new connection. For example, data entry requires a new connection every time new data are entered in a table through an online HTML form. That means a new instantiation with every data entry. Using static variables avoids constant reinstantiation.

One of the Structural category design patterns is the Proxy. The Gang of Four specify four types of Proxy patterns:

The Proxy patterns have two primary participants: a proxy subject and a real subject. Clients submit requests through the Subject interface to the Proxy, but access to the RealSubject is possible only if a request first goes through the Proxy. Figure 11-2 shows the class diagram of the Proxy design pattern.

Both the Proxy and RealSubject participants implement the Subject interface, but the Proxy implements it in the role of a gatekeeper or an encryption module. If the request is cleared by the Proxy, the Proxy then calls the RealSubject to provide the user with the content of the request.

To create a Proxy for a login that requires registration, this program first sets up a table with username and password fields—and nothing else. This is a simple example that can be expanded, but the focus will be on the Proxy design pattern. The following PHP script creates the table that stores the user information:

<?php
include_once('UniversalConnect.php');
class CreateTable
{
    private $tableMaster;
    private $hookup;

    public function __construct()
    {
        $this->tableMaster="proxyLog";
        $this->hookup=UniversalConnect::doConnect();

        $drop = "DROP TABLE IF EXISTS $this->tableMaster";

        if($this->hookup->query($drop) === true)
        {
            printf("Old table %s has been dropped.<br/>",$this->tableMaster);
        }

        $sql = "CREATE TABLE $this->tableMaster (uname NVARCHAR(15),
                pw NVARCHAR(120)";

        if($this->hookup->query($sql) === true)
        {
            echo "Table $this->tableMaster has been created successfully.<br/>";
        }
        $this->hookup->close();
    }
}
$worker=new CreateTable();
?>

The class is pretty standard for creating a table storing a username and password. The number of characters provided for the password, NVARCHAR (120), reflects the capacity to use hashed passwords up to 120 characters. To enter data, the following PHP accepts data sent from an HTML form:

<?php
include_once('UniversalConnect.php');
class HashRegister
{
    public function __construct()
    {
        $this->tableMaster="proxyLog";
        $this->hookup=UniversalConnect::doConnect();
        $username=$this->hookup->real_escape_string(trim($_POST['uname']));
        $pwNow=$this->hookup->real_escape_string(trim($_POST['pw']));

        $sql = "INSERT INTO $this->tableMaster (uname,pw) VALUES ('$username',
                md5('$pwNow'))";

        if($this->hookup->query($sql))
        {
            echo "Registration completed:";
        }

        elseif ( ($result = $this->hookup->query($sql))===false )
        {
              printf("Invalid query: %s <br/> Whole query: %s <br/>",
                  $this->hookup->error, $sql);
          exit();
        }
        $this->hookup->close();
    }
}
$worker=new HashRegister();
?>

The MD5 function returns the hash as a 32-character hexadecimal number. The md5() function represents an older but simpler hash function used only for purposes of illustration of where encryption might take place on setting up a registration password that would later be used with a Proxy login.

The following HTML5 script is used for registration—adding a username and password:

<!DOCTYPE HTML>
<html>
<head>
<link rel="stylesheet" href="proxy.css">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Username/Password Registration</title>
</head>
<body>
<header>Registration</header>
<section>
  <article id="entry">
    <form action="HashRegister.php" method="post">
      Username: (15 Characters Max-No spaces)<br/>
      <input type="text" name="uname" maxlength="15">
      <br/>
      Password: (10 Characters Max-No spaces)<br/>
      <input type="password" name="pw" maxlength="10">
      <br/>
      <input type="submit" value="Register">
    </form>
  </article>
</section>
</body>
</html>

Finally, a CSS file, used by some of the other files, is straightforward:

@charset "UTF-8";
/* CSS Document */
/*EFECCA,046380,002F2F */

body {
    margin-left:20px;
    font-family:Verdana, Geneva, sans-serif;
    background-color:#EFECCA;
}
header {
    font-family: "Arial Black", Gadget, sans-serif;
    font-size:24px;
    color:#002F2F;
}
#entry {
    font-size:11;
    color:#046380;
}
.subhead
{
    font-size:16px;
    font-family:Verdana, Geneva, sans-serif;
}

Figure 11-3 shows what the user sees during the registration process. (The HTML files are all separated for the sake of clarity in understanding the different elements that go into the setup and execution of the login into a site using a Proxy design pattern. The login registration and login itself could easily be included in a single HTML5 page with multiple forms; one for registration and one for login.)

Once a user has registered, a small “confirmation” message displays a completion message, as shown in Figure 11-4.

The confirmation message is short and could have been embedded in HTML code with an option to now log in, but as noted, everything has been modularized for better clarity.

In the two PHP files that use the UniversalConnect class to link to the MySQL database, we’re able to do so using a single line, which avoids a good deal of code smog:

$this->hookup=UniversalConnect::doConnect();

To prepare for testing the Proxy pattern implementation, “register” several users with passwords. The next section that builds the proxy login application uses the proxyLog table to check to see if the username and password are available and correct. So before continuing, add some usernames and passwords to the proxyLog table with the Registration.html and InsertData class.

In looking at the participants in the Proxy file diagram in Figure 11-5, the names of the classes (and their files) closely follows the participant names in the design pattern.

The Proxy class calls the MySQL database to make sure that the username and password are matches, and if they are, the request is passed to the RealSubject class. So while the IConnectInfo interface and the UniversalConnect class are not part of the design pattern, they play an important component of the gatekeeper role.

The user places the login information into a form in the HTML file. As soon as the user enters the data and clicks the Submit button, the information is sent to the Client:

<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Proxy Login</title>
<link rel="stylesheet" href="proxy.css">
</head>
<body>
<header>Login</header>
<section>
  <article id="entry">
    <form action="Client.php" method="post">
      Username: <br/>
      <input type="text" name="uname" >
      <br/>
      Password: <br/>
      <input type="password" name="pw" maxlength="10">
      <br/>
      <input type="submit" value="Login">
    </form>
  </article>
</section>
</body>
</html>

In the initial development, the HTML form sent the data directly to the Proxy class, but on reconsideration, the Client is a good place to encapsulate the password and username. It also trims and filters the data from the HTML form. The Client uses a private method with type hinting to pass the data from the HTML form to the login method in the Proxy class:

<?php
include_once("Proxy.php");
class Client
{
    private $proxy;
    private $un;
    private $pw;

    public function __construct()
    {
        $this->tableMaster="proxyLog";
        $this->hookup=UniversalConnect::doConnect();
        $this->un=$this->hookup->real_escape_string(trim($_POST['uname']));
        $this->pw=$this->hookup->real_escape_string(trim($_POST['pw']));
        $this->getIface($this->proxy=new Proxy());
    }

    private function getIface(ISubject $proxy)
    {
            $proxy->login($this->un,$this->pw);
    }
}
$worker=new Client();
?>

Because the username and password are unwrapped into a private variable and dispatched to the Proxy class in a private method (getIface), they are effectively encapsulated before being compared for validity in the Proxy class.

When passed to the Proxy class, the data sent from the HTML form via the Client must be compared to stored data in a MySQL table. Because the Proxy and RealSubject classes share a common interface, each must implement the ISubject interface:

<?php
interface ISubject
{
    function request();
}
?>

The single method, request, can be implemented in many different ways. For the Proxy, it is a way to pass on the original request to the RealSubject class if the username and password are validated. In other words, the Proxy determines whether the RealSubject method, request, is to be called at all.

In designing the Proxy, little was done other than informing the user that the password and username are invalid. Other available options are to return the user to the login page or the registration page:

<?php
include_once("ISubject.php");
include_once('RealSubject.php');
include_once('UniversalConnect.php');
class Proxy implements ISubject
{
    private $tableMaster;
    private $hookup;
    private $logGood;
    private $realSubject;

    public function login($uNow,$pNow)
    {
        //Filtered from Client; hash the password
        $uname=$uNow;
        $pw=md5($pNow);
        $this->logGood=false;
        //Choose table and connect
        $this->tableMaster="proxyLog";
        $this->hookup=UniversalConnect::doConnect();

        //Create MySQL statement
        $sql = "SELECT pw FROM $this->tableMaster WHERE uname='$uname'";

        if($result=$this->hookup->query($sql))
        {
            $row=$result->fetch_array(MYSQLI_ASSOC);
            if($row['pw']==$pw)
            {
                $this->logGood=true;
            }
        $result->close();
        }
        elseif ( ($result = $this->hookup->query($sql))===false )
        {
              printf("Failed: %s <br/>", $this->hookup->error);
              exit();
        }
        $this->hookup->close();

        if($this->logGood)
        {
            $this->request();
        }
        else
        {
            echo "Username and/or Password not on record.";
        }
    }
    public function request()
    {
        $this->realSubject=new RealSubject();
        $this->realSubject->request();
    }
}

?>

Most of the work is done by the login method. It receives the password and username, hashes the password with the md5() function, opens the database, and queries the table. If it finds a matching pair (username and password), it sets the $logGood variable to true. It then summons the request method if $logGood is true; otherwise, it simply leaves a message.

The Proxy request method calls the RealSubject request method. In the case of the Proxy pattern, the surrogate for the real subject (the target of the request) is the Proxy class, and so its job is to run interference for the real subject, not to duplicate the request method of the real subject.

The “star” of the Proxy design pattern is the proxy participant. However, what the user wants is whatever is in the real subject, and so the only thing important to the user is the real subject. The good news is that it can be virtually anything. For this example, it is a page with some OOP and design pattern pointers:

<?php
include_once('ISubject.php');

class RealSubject implements ISubject
{
    public function request()
    {
    $practice=<<<REQUEST
    <!DOCTYPE html>
    <html>
        <head>
        <meta charset="UTF-8">
        <link rel='stylesheet' type='text/css' href='proxy.css' />
        </head>
        <body>
        <header>PHP Tip Sheet:<br>
          <span class='subhead'>For OOP Developers</span></header>
        <ol>
              <li>Program to the interface and not the implementation.</li>
              <li>Encapsulate your objects.</li>
              <li>Favor composition over class inheritance.</li>
              <li>A class should only have a single responsibility.</li>
            </ol>
        </body>
    </html>
REQUEST;
echo $practice;
    }
}
?>

Its only method is one required when implementing the ISubject interface—request. The request method simply generates some HTML to display an ordered list. It could be anything, and as for its position in the pattern, it’s the caboose and has no backward impact.

From the user’s perspective, all of the classes and code are transparent. Figure 11-6 shows what the user first sees at login in the HTML5 page.

The login sends the request to the Client class, which takes the login data from the HTML5 form and forwards the request to the Proxy through the Proxy login method. Of course, the user never sees any of this. All she sees is the RealSubject output, as shown in Figure 11-7.

Of course, the contents of the RealSubject class is all the user wanted to see in the first place, and she has no idea that the initial request had to successfully go through the Client and Proxy classes.

If the request does not work out because the incorrect username and/or password was entered or the user has not registered, some alternative message must be sent. In this case, a simple message like that in Figure 11-8 informs the user that the entered materials could not be found.

Typically, a message to the user would suggest registration or taking more care in logging in. Further, it would most likely link to a page where the user has the option to register or try logging in again. However, this example has been kept to a minimum for the sake of clarity. Once you’re comfortable with using the Proxy design pattern implemented as a protection proxy, you can make the necessary modifications to create a seamless registration and login. After all, the purpose of any website is to make access easy for the users, and the proxy simply ensures that the users with the correct privileges can use it.

The Proxy pattern by itself, especially as illustrated in this chapter’s example, is certainly not enough for real-world site security. It is even less secure if a financial transaction may be involved. However, if a Proxy module hands off a request to a high security module, it maintains the Proxy design pattern. In fact, you can think of the proxy participant in the pattern to be a place where a true high security operation takes place before the user goes to the real subject. In this example, the md5() function shows where a password hash can be generated, but MD5 is not a very high security encryption. You can add far more security for your site. For example, in a credit card financial processing context, the proxy would send the request to a credit card processing company’s module to take care of the financial matters, and if the return from the processing module indicates that the transaction is successful, it would pass on the request to the real subject, which itself would then make the product or service available to the user.

However, under no circumstance should you think that the Proxy design pattern, with PHP or any other programming language, is a high security design. Instead, it stands as a general model for security with the details of that security handled by a different module within or outside of the Proxy. Figure 11-9 illustrates the Proxy role in real-world high security.

As far as the user is concerned, all requests go directly to the real subject. The proxy module can be a simple password check, or it can be used to call a high security module to process sensitive materials.