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.
In design patterns, interfaces allow developers to create loosely bound objects and classes, but in this case, the interface is used to store data—MySQL connection data. So, far from being an abstract structure for organizing operations, this interface has concrete data the classes that implement the interface can use.
<?php //Filename: IConnectInfo.php interface IConnectInfo { const HOST ="localhost"; const UNAME ="phpWorker"; const PW ="easyWay"; const DBNAME = "dpPatt"; public function doConnect(); } ?>
This interface is easily isolated and changed to include any host
you want. By using mysqli
, the four
elements are available for it to employ to make a connection to the
desired database. By substituting an interface for a set of values
defined in a class, less time is consumed in development because a
simple yet necessary part of the program has been set aside and can be
implemented by any number of programs.
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.
The client in this case is any program that needs a
connection to MySQL. In a typical application, the client would simply
be any concrete class that requires a MySQL connection. Other than an
include_once()
operation to access
the UniversalConnect
class, the
connection routine takes only a single line:
<?php include_once('UniversalConnect.php'); class ConnectClient { private $hookup; public function __construct() { //One line for entire connection operation $this->hookup=UniversalConnect::doConnect(); } } $worker=new ConnectClient(); ?>
By having a simple connection operation set up through a single
class and interface, development time can be cut considerably. Changes
are easy because all of the information is stored in constants. To
change a host, user, password, or database name requires only a change
to the value of the constants in the interface. Nothing has to be done
either to the UniversalConnect
class
or the program that uses the UniversalConnect
class.
One of the Structural category design patterns is the Proxy. The Gang of Four specify four types of Proxy patterns:
When a proxy object is in one address space and the real object is in another, the proxy is remote. Besides using a remote proxy as a firewall, the remote proxy can be used for online games where the same object is needed in different places at the same time.
A virtual proxy may cache information about a real subject so that access to the real subject can be postponed. Sometimes high security logins use a virtual proxy for the login before the real object handles the login data.
The protection proxy keeps the request away from the real subject until the request is verified by the protection proxy. The real subject is the target of the request, such as access to database information. Many protection proxies have different levels of access, depending on the user’s login information; instead of having a single real subject, the real subject may be multiple and restricted.
When the program requires something more than what GoF call a “bare pointer,” the Proxy can act as a smart reference (or smart pointer) that performs additional actions when an object is referenced. For instance, data from a database may be first loaded by the Proxy participant acting as a smart reference.
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.