PHP TIPS AND TRICKS - Using Classes and OOP in PHP 4

This tutorial is designed for the intermediate to advanced-level PHP programmer.

(For more about Zend Technologies, please visit www.zend.com)

Introduction

This tutorial teaches you how to write and use classes, to make your PHP code more flexible and easier to manage.

The tutorial guides you through the construction of a simple, security-related class that performs some basic security functions for a web site: checking user logons. The class implements security features that answer some needs for a number of current security models and could be easily implemented at most dynamic Web sites. Note that this class does not provide a full security solution.

The example presented in this tutorial addresses a rudimentary yet effective form of web hacking: manually modifying the URL in the browser window. Among the many ways to hack, this is one of the easiest, but still a difficult one to defend against. Someone with the wrong intentions can potentially change prices or gain access to areas of the site where they aren't authorized; either by modifying the query string after the URL, or by saving the HTML somewhere and modifying hidden variables in the code. Prevention of this type of hacking is particularly important in straight-line applications. A straight-line application is one where pages must be filled out and followed in order, such as e-commerce order forms, registration, and private areas such as web mail.

The tutorial example protects against a hacker's modifying a URL query string by creating a class that uses resources that are built into PHP. The first tutorial function presented uses the PHP getenv ( ) function for retrieving the values of HTTP Headers. The specific header retrieved is HTTP_REFERER, which stores the full path to the referring page. The tutorial example checks that the header has the expected value for each page, to ensure that visitors aren't tampering with them.

The class built in this tutorial is modular: it has a number of functions, each of which performs a short, specific piece of work. One function has been described already in the preceding paragraph. A second function displays a "bad reference" page to a visitor having a bad referral page and adds the visitor's IP to a "bad referral page" file. A third function checks if a visitor's IP is already in the "bad referral page" file, and how many times is it there. A fourth function checks if there is a current session, and so on. An example of a function that changes a class variable is given, as is a constructor function.

The main point of the tutorial, as said above, is to give a basic understanding of how to build classes as the basis of your coding. This modular approach assists you in writing better-planned, more elegant code that can be re-used by your other PHP applications. This tutorial shows that classes can be very flexible. Classes enable programmers to accomplish complicated tasks very easily, and are portable across many applications.

Although the class of this tutorial is useful as it stands, it is merely an introduction, and by no means uses the full capabilities of the class structure. For example, classes can access and manipulate databases, and can be extended in your scripts for special purposes beyond what they were intended for.

Classes were originally designed to be used in large, complex applications. However, they can still play an important role in your web applications, especially if you plan to reuse your code. Put in that extra preparation and work to make a tight class that performs common, complex tasks for your application, and it pays off in the time you save later.

Goals of the Tutorial

In this tutorial you can learn the following:

  • What a class is, and what it is good for.
  • Defining a class.
  • Defining and using functions inside the class.
  • Defining and using variables inside the class.
  • Defining and using constructors inside the class.
  • Creating a complete and useful class.
  • Implementing an instance of a class.
  • Using ( invoking ) in your application the routines that are defined within a class.
  • Changing the setting of a class variable
  • Using the following PHP functions:
  • Using the following PHP operators:
  • Using the following PHP variable:
    • PHPSESSID
  • Using the following server variables:
    • HTTP_REFERER
    • REMOTE_ADDR

Background Information

What is a class?

A class is a collection of related variables and functions ( also called "attributes" and "methods" ) . The variables and functions work together to describe and change the data associated with an object ( or class ) . An object can be just about anything you use in your code. For example, it can describe a certain chunk of data, or it can be used to perform an action such as interacting with a server's mail system.

A good class is a well-designed system. It takes into account all the relevant factors available, so that you can request any particular attribute at any time, and get all the relevant information. Good classes are like a subset of powerful commands that do all of their work behind the scenes.

As an example of how a class could be used, think of an airline reservation system. The system performs functions such as handling flights, scheduling flight crew, and properly booking each flight. Each function is part of the class. As a passenger, you don't see the functions, but you can access attributes: flight number, departure and arrival time, ticket price, and whether there are any window seats. "Calling" one function, such as reserving a space on a flight, affects various attributes of the class: the passenger's frequent flyer information, the number of meals required for the flight, and whether the flight is fully booked.

After making a "class" such as this, you could use another copy of it having the same structure, for describing the reservation system of some other airline. There's no need to rewrite a new reservation system: you just reuse ( make a copy of ) the existing system. This is precisely how classes in programming work. They create generalized functions that can be used for different applications. To make use of a particular class' functions in your application, you merely have your application declare an instance ( "make a new copy" ) of that class.

In some ways, you already use classes in your PHP programming. When you create a file handle by opening a file, you are creating an object. When you receive an SQL result set, you are receiving an object and using its attributes ( by getting numrows, for example ) . Think about how those actions fit into this framework, and you can see how classes make your programming simpler, more portable, and more elegant.

Preliminary Tips and Prerequisites

Be organized. Keep your PHP application code in *.php files. Keep your class code in separate *.inc files that can be included as needed in your various applications.

The sample code has been written with an eye to good programming style. Classes are by nature modular, and so are the functions of the class presented in this tutorial. Each function is short, and performs one or two specific, related items of work.

As applications get more complicated, classes help you simplify your code and avoid clashes of variables and functions. Classes can provide consistency in naming your functions the same as another developer's. Classes compartmentalize their variables and functions in neat packages that don't interfere with functions or variables of the same name in other classes, or even in other instances ( or "copies" ) of the same class.

Classes are a handy way to speed development time. Using a robust class helps make code portable, which means you don't have to rewrite code for your most common tasks.

How it Works

Each step shows accompanying code. In the code, the PHP elements are found within the "< ? php" "? >" marks.

Defining the class

This segment of code defines the class by giving it a name. Note that all the code for this class must be located within the class' pair of braces: "{" and "}".

Code Flow

  • Define the class by giving it a name ( Security ) .

class Security {

...

}

Tips

You can name a class anything you want except for PHP keywords.

Verifying the Referral Link

Code Flow

  • Declare the class function verifyReferer.
  • Accept the input $ ref, which is the previous web page the visitor should have viewed.
  • Retrieve the actual referrer to the web page ( HTTP_REFERER ) by reading the header sent with the request for the page.
  • If the previous referral page does not have the expected value, run the printbadRef function ( defined in a later segment of the class' code ) .

class Security {

...

function

verifyReferer ( $ ref ) {

$ headerref = getenv ( "HTTP_REFERER" ) ;

if (

$ headerref==$ ref ) {

return

true;

} else {

$ this - > printbadRef ( ) ;

}

}

...

}

HTTP_REFERER might legitimately contain more information than what is in $ ref, so that the strings won't be the same even though the visitor is not a hacker. This point is handled in the Complete Code section of the tutorial. Here, for the sake of clarity, only the minimum code needed for security is shown.

Tips

A function belonging to a class is declared/defined exactly the same way as a function in normal code. The difference between them is that a function belonging to a class can be invoked ( called ) only on an instance of that class.

Within the class itself, "$ this - > "is a substitute for "this object", that is, the instance of the class on which the function was called. This allows the functions in an object to access the same object's variables and other functions.

Consequently, calling a class' function within the class itself is done by using the syntax $ this - > printbadRef ( ) ;

Note that one function of a class ( verifyReferer ) can call a second function ( printbadRef ) of the same class before the second function is declared or defined. This is true for regular functions in PHP4 as well, but may seem unusual to people who come from PHP3.

Infrastructure for Handling Bad Referral Link

Code Flow

  • Declare the class function printbadRef.
  • Display a web page, presumably with an error message, to the visitor ( with the bad referral page ) .
  • Retrieve the visitor's IP address ( REMOTE_ADDR ) by reading the header sent with the request for the page.
  • Enable the program to track repeat offenders by adding the visitor's IP address to the file badips.txt.

class Security {

...

function

printbadRef {

include (

"badref.html" ) ;

$ myfile = fopen ( "badips.txt","a" ) ;

fputs ( $ myfile,getenv ( "REMOTE_ADDR" ) ."\\n" ) ;

fclose ( $ myfile ) ;

exit;

}

...

}

Tips

Note the modular approach. The function verifyReferer checks for a bad referral link. If there is a bad referral link, the function printbadRef shows the visitor an error message and stores the visitor's IP address. Later on, another function ( verifyIP ) checks to see if the visitor is a repeat offender. Each function is small and specific.

Checking the Referral Link

The class called Security has been created, so use it in your PHP application. Just declare a new instance of the class and you can invoke its functions. In this example, your application allows visitors to access a web page only if they were referred from page1.phtml.

Code Flow

  • Define a new instance of the Security class.
  • Allow visitors to access web page only if they were referred from page1.phtml.

$ sec = new Security;

$ sec - > verifyReferer ( "http://www.here.com/page1.phtml" ) ;

Tips

To invoke a new instance of a class in your application, use the PHP new operator and the following syntax:

$ sec = new Security;

In the above line, the class is Security and the new instance is sec.

Class instances are placed in normal PHP variables, just like numbers or strings. This makes it easy to address the instance you want without affecting other instances of that class. You can have many different instances of the same class, or of several classes, active at the same time. Obviously, no two class instances, even of two different classes, can have the same name.

To invoke a function of an instance of a class in your application's code, use the following syntax:

$ sec - > verifyReferer ( ) ;

This is the same syntax as was used above for invoking a class function in the class itself:

$ this - > printbadRef ( ) ;

That is, a class function must be referred to as "object - > function." This syntax is a means for getting the function you want, since "$ object1 - > function" and "$ object2 - > function" might be two totally different functions.

Alternatively, you can call a function ( a method ) using the syntax Class::function ( $ vars ) , thereby leaving the "$ this" variable unset. Here, "$ vars" are the function's parameters.

Adding Detection of Repeat Offenders

This segment of code adds another function, verifyIP, which determines whether the visitor has tried to enter from an illegal location in the past. A repeat offender is shown an error message instead of the web page, even if this time the referral page is correct.

This is a somewhat drastic reaction to take against a one-time offender who has decided to be a good citizen now, or to someone who simply made a mistake. The Complete Code section of this tutorial takes a modified and more moderate approach, but it also takes more code. In this section of the tutorial, only the essential ( and "drastic reaction" ) parts of the code are presented.

Code Flow

  • Declare the function verifyIP.
  • Retrieve the visitor's IP address ( REMOTE_ADDR ) by reading the header sent with the request for the page.
  • If file badips.txt has already been written to, read the file into $ myfile as an array.
  • Check to see if the visitor's IP is recorded in the file ( each element has to be chopped to remove the trailing newline ) .
  • If the visitor is a repeat offender, redirect to printbadRef.

class Security {

...

function

verifyIP ( ) {

$ IP = getenv ( "REMOTE_ADDR" ) ;

if (

file_exists ( "badips.txt" ) ) {

$ myfile = file ( "badips.txt" ) ;

}

for (

$ index=0; $ index <count ( $ myfile ) ; $ index ) {

if (

$ IP == chop ( $ myfile[$ index] ) ) {

$ this - > printbadRef ( ) ;

}

}

}

...

}

Tips

A variable, such as $ IP, that is defined within a function of a class, exists within the scope of that function. This behavior is similar to that of normal functions.

Checking the Referral Link and Repeat Offenders

This is a slight expansion of the application code given above. Here, in addition to checking visitors for a correct referral link ( using verifyReferer ) , you also check for repeat offenders ( using verifyIP ) to keep out offensive IPs. Code Flow

  • Define a new instance of the Security class.
  • Allow the visitor to access this page only if they were referred from page1.phtml.
  • Check if the visitor is a repeat offender.

$ sec = new Security;

$ sec - > verifyReferer ( "http://www.here.com/page1.phtml" ) ;

$ sec - > verifyIP ( ) ;

Tips

Be very careful before implementing an IP checker like this - you don't want to punish visitors who got to the page by accident ( an old bookmark, for example ) , or visitors who by chance receive the same IP later on through their ISP. You may want either to handpick IPs you know are causing problems, or to timestamp them and not let them get to your pages for a defined period of time.

Session Function

You can add another function that takes advantage of the session features in PHP4. This function allows visitors to continue only if their session is current. In some applications it's important not to restrict visitors where they can go next in the site, yet allow them to click around only if their session is current. This is useful in a web-mail application, both for protecting visitors who may leave their screen for a time, and for preventing someone else from trying to click around after the session has expired. Code Flow

  • Declare the function verifySession.
  • Check if there is a current session active by checking for the PHP default session cookie $ PHPSESSID.
  • If there's no session active, show the visitor the bad reference page.

class Security {

...

function

verifySession ( ) {

if ( !isset (

$ PHPSESSID ) ) {

$ this - > printbadRef ( ) ;

}

}

...

}

Tips

The function verifySession can be used onlyif you have started or registered a session before invoking the function. In addition, you have to tweak the code if you modify the name of the session ( using session_name ) .

Putting All the Security Functions Together

Finally, a catchall function verifySecurity fits right in. This function calls all the other security functions of this class, making an extra-secure connection. Visitors who fail even one test do not see the web page.

Code Flow

  • Declare the function verifySecurity.
  • Check if the visitor was referred from the expected page.
  • Check if there is an open session.
  • Check if the visitor is a repeat offender.

class Security {

...

function

verifySecurity ( $ expectedpage ) {

$ this - > verifyReferer ( $ expectedpage ) ;

$ this - > verifySession ( ) ;

$ this - > verifyIP ( ) ;

}

...

}

Tips

Note how the code for verifySecurity passes the parameter containing the correct referring link ( $ expectedpage ) straight through to verifyReferer.

Constructors

Another feature of classes are constructors. A constructor is a function that is run on the class when a new instance of the class is created. A constructor can set default values and build attributes. A good use for a constructor in the class Security would be allowing web architects to set their own badref.html page. Doing so enables you to set different pages for different areas of your site, instead of a one-size-fits-all approach.

To create a constructor that executes without intervention when the class is created, name the function the same name as the class. In the example given below, every time a new instance of the class Security is made, the constructor function Security automatically runs and sets the default value for $ badref.

Code Flow

  • Declare the class variable $ badref.
  • Declare the constructor Security.
  • Set the default value for the variable $ badref.

class Security {

...

var

$ badref;

function

Security {

$ this - > badref = "badref.html";

}

...

}

Tips

All of the variables used by a class must be declared before any of the class' functions, including constructors.

When the class variable $ badref is referenced within the class code, the syntax used is

$ this - > badref

Likewise, when the class variable $ badref is referenced within the application code ( where the instance sec of the class has been declared ) , the syntax used is

$ sec - > badref

That is, badref does not appear by itself and there is no $ in front of badref. This is because you always address a variable of an object as "$ object - > varname," and a class is an object. The full identifier of a variable is "object - > varname," plus the "$ " before a variable name. In the case here, the variable name is not badref, but object - > badref. This is because badref is a property of an object ( a variable of the class Security ) ; badref is not a free variable.

Note that "$ object - > varname" is not at all the same as "$ object - > $ varname." The latter expression means: replace $ varname by its content, and let "object - > content of $ varname" be the name of the required variable.

In addition to constructors, C classes can have "destructors", that is, functions that are executed when an instance of the class is destroyed. PHP4 currently does not support destructors. However, PHP4 does automatically free the memory used by various items ( such as variables, strings, arrays, and objects ) when there are no longer any references to them. See the article Reference Counting, by Andi Gutmans.

Changing the Bad Reference Destination Page

The function set_badref<