More Books
PHP 5 Unleashed
PHP 5 Unleashed
Table of Contents
Copyright
Lead Author
Contributing Authors
Acknowledgments
We Want to Hear from You!
Reader Services
Introduction
Organization of the Book
Part I. Working with PHP for General Web Development
Chapter 1. Basic PHP Development
How PHP Scripts Work
Basic PHP Syntax
Basic PHP Data Types
Variable Manipulation
Control Structures
User-Defined Functions
Dynamic Variables and Functions
Multiple File PHP Scripts
References
Strings in PHP
Comparing Strings
Advanced String Comparison
Search and Replacement
Formatting Strings
Strings and Locales
Formatting Date and Time Values
Summary
Chapter 2. Arrays
Basic Arrays
Implementing Arrays
More Array Materials
Chapter 3. Regular Expressions
The Basics of Regular Expressions
Limitations of the Basic Syntax
POSIX Regular Expressions
Perl-Compatible Regular Expressions (PCRE)
PCRE Modifiers
A Few Final Words
Chapter 4. Working with Forms in PHP
HTML Forms 101
Working with Form Submissions in PHP
Summary
Chapter 5. Advanced Form Techniques
Data Manipulation and Conversion
Form Data Integrity
Form Processing
Summary
Chapter 6. Persistent Data Using Sessions and Cookies
HTTP Cookies
PHP Sessions
Advanced Sessions
Summary
Chapter 7. Using Templates
The What and Why of Templates
The Smarty Template Engine
Summary
Part II. Advanced Web Development
Chapter 8. PEAR
What Is PEAR?
Getting and Installing PEAR
Using the PEAR Package Manager
Using the PEAR Website
Using PEAR Packages in Applications
Summary
Reference
Chapter 9. XSLT and Other XML Concerns
Relating XML to HTML
Using XSLT to Describe HTML Output Using XML Input
PHP4 and XSLT Using the DOM XML Module
PHP4 and XSLT Using the XSLT Module
PHP5 and XSLT
Accessing XML Data Using SimpleXML
Generating XML Documents Using PHP
Summary
References
Chapter 10. Debugging and Optimizations
Debugging Your PHP Scripts
Optimizing Your PHP Scripts
Summary
Chapter 11. User Authentication
Authenticating Users in PHP
Securing PHP Code
Summary
Chapter 12. Data Encryption
Shared Secret Versus Public Key
Shared Secret Algorithms
Public Key Cryptography
Using Public Keys in PHP
Summary
Chapter 13. Object-Oriented Programming in PHP
Why Objects?
Creating Basic Classes
Advanced Classes
Special Methods
Class Autoloading
Object Serialization
Exceptions
Iterators
Summary
Chapter 14. Error Handling
The PHP Error-Handling Model
What to Do About Errors
The Default Error Handler
Error Suppression
Custom Error Handlers
Causing Errors
Putting It All Together
Summary
Chapter 15. Working with HTML/XHTML Using Tidy
Introduction
Basic Tidy Usage
Tidy Configuration Options
Using the Tidy Parser
Applications of Tidy
Summary
Chapter 16. Writing Email in PHP
The MIME Protocol
Implementing MIME Email in PHP
Summary
Part III. Building Applications in PHP
Chapter 17. Using PHP for Console Scripting
Core CLI Differences
Working with PHP CLI
CLI Tools and Extensions
Summary
Chapter 18. SOAP and PHP
What Are Web Services?
Installation
Creating Web Services
Consuming Web Services
Looking for Web Services
Summary
Chapter 19. Building WAP-Enabled Websites
What Is WAP?
System Requirements
Introduction to WML
Serving WAP Content
Sample Applications
Summary
Part IV. I/O, System Calls, and PHP
Chapter 20. Working with the File System
Working with Files in PHP
File Permissions
File Access Support Functions
Summary
Chapter 21. Network I/O
DNS/Reverse DNS Lookups
Socket Programming
Network Helper Functions
Summary
Chapter 22. Accessing the Underlying OS from PHP
Introduction
Unix-Specific OS Functionality
Platform-Independent System Functions
A Brief Note About Security
Summary
Part V. Working with Data in PHP
Chapter 23. Introduction to Databases
Using the MySQL Client
Basic MySQL Usage
Summary
Chapter 24. Using MySQL with PHP
Performing Queries from PHP
A MySQLi Session Handler
What Is a Custom Session Handler?
Summary
Chapter 25. Using SQLite with PHP
What Makes SQLite Unique?
Basic SQLite Functionality
Working with PHP UDFs in SQLite
Odds and Ends
Summary
Chapter 26. PHP's dba Functions
Preparations and Settings
Creating a File-Based Database
Writing Data
Reading Data
Sample Application
Conclusion
Part VI. Graphical Output with PHP
Chapter 27. Working with Images
Basic Image Creation Using GD
Using the PHP/GD Drawing Functions
Working with Colors and Brushes
Using Fonts and Printing Strings
General Image Manipulation
Other Graphics Functions
Summary
Chapter 28. Printable Document Generation
A Note Regarding the Examples in This Chapter
Generating Dynamic RTF Documents
Generating Dynamic PDF Documents
Related Resources
Part VII. Appendixes
Appendix A. Installing PHP5 and MySQL
Installing PHP5
Installing MySQL and PHP Modules
Installing PEAR
Appendix B. HTTP Reference
What Is HTTP?
PHP Programming Libraries for HTTP Work
Understanding an HTTP Transaction
HTTP Client Methods
What Comes Back: Server Response Codes
HTTP Headers
Encoding
Identifying Clients and Servers
The "Referer"
Fetching Content from an HTTP Source
Media Types
Cookies: Preserving State and a Tasty Treat
Security and Authorization
Client-Side Caching of HTTP Content
Appendix C. Migrating Applications from PHP4 to PHP5
Configuration
Object-Oriented Programming (OOP)
New Behavior of Functions
Further Reading
Appendix D. Good Programming Techniques and Performance Issues
Common Style Mistakes
Common Security Concerns
Style and SecurityLogging
Summary
Appendix E. Resources and Mailing Lists
Relevant Websites
Mailing Lists and Newsgroups
Index
SYMBOL
A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
P
Q
R
S
T
U
V
W
X
Y
Z

The What and Why of Templates

In PHP, the most common method of separating presentation and application logic is through the use of templates. A template is (in general) an HTML document that contains special markers and/or control structures. In fact, PHP was originally designed to be a simple macro language that functioned much like a template engine.

Separating Common Elements from Code

As PHP grew more popular, it was quickly adopted by Web developers across the world because it was very easy to learn. This ease of development made PHP one of the best languages for rapid application development and prototyping. Unfortunately, the same capabilities that make PHP such an excellent language for prototyping quickly also make it very easy to create unmanageable code. Developers soon realize that as websites become larger, making their websites more modular becomes very important. The most common solution to this problem is to separate the website into common elements that can be included via a PHP include statement. For instance, in most cases, you can separate any given website into three separate elements: a header, a footer, and the actual content. Listing 7.1 shows how to separate your average Web page into three segments:

Listing 7.1. Your Typical Segmented Web Page

segments.php

<?php
   function display_head($title="Your typical web page") {
   ?>
   <HTML>
   <HEAD><TITLE><?=$title?></TITLE></HEAD>
   <BODY>
   <TABLE CELLPADDING=0 CELLSPACING=0 BORDER=0>
   <TR>
   <TD>
      <TABLE CELLPADDING=0 CELLSPACING=0 BORDER=0>
      <TR><TD><A href="products.php">products</a></td></tr>
      <TR><TD><A href="contact.php">contact</a></td></tr>
      <TR><TD><A href="about.php">about Us</A></TD></TR>
      </TABLE>
   </TD>
   <TD>
   <?php } // end of display_head() function

   function display_foot() {
   ?>
   </TD>
   </TR>
   </TABLE>
   </BODY>
   </HTML>
   <?php } // end of display_foot() function
?>

index.php

<?php include('segments.php');
      display_head();
?>
Welcome to my web site.
<?php display_foot(); ?>

Looking at Listing 7.1, you can see that such a way of doing things already provides a major benefit over the classical approach. Separating the common elementsthe header and footerinto their own functions simplifies the maintenance of the entire site drastically. With a system such as this, to do something trivial, only one file has to be modified, such as adding a link to the menu of the website, and it will be changed throughout the entire site. For most smaller websites that have only one or two developers (both of whom are familiar with PHP) a system such as this would work just fine.

Unfortunately, any site that has one group of people working on the actual layout of the website and another working on the PHP scripts will not be much better off using this system. Although it does reduce the amount of redundancy in a website, it still requires that PHP code be embedded directly into HTML documents for things to work properly.

A (Quick) Template System Example

For situations in which there is a real need for the separation of presentation and application logic, a true template system is required. Although later in the chapter I'll be talking about a professional template system, Smarty, written in PHP, it won't do you much good unless you know the basic idea of how it works in the first place. To assist you in understanding how a template system works, I've written my own simple template system I call QuickTemplate. By examining how this template system works, you'll not only get an idea of how all template systems work, but perhaps learn a little about writing some pretty complex PHP code properly.

Before I discuss the QuickTemplate script itself (it's actually a class) let's first take a look at what we want to accomplish. To separate HTML code from PHP code entirely, we'll need to somehow earmark certain points in the document where PHP code is responsible for filling in the spaces. When it comes to the QuickTemplate class, template markers are identified by enclosing a string (capital AZ only) between two percent (%) characters. For instance, you could define the same HTML document as in Listing 7.1 fairly easily (see Listing 7.2):

Listing 7.2. A QuickTemplate Template File
<HTML>
<HEAD><TITLE>%TITLE%</TITLE></HEAD>
<BODY>
<TABLE CELLPADDING=0 CELLSPACING=0 BORDER=0>
<TR>
<TD>%LEFTNAV%</TD>
<TD>%CONTENT%</TD>
</TR>
</TABLE>
</BODY>
</HTML>

As you can see, the HTML code in Listing 7.2 is completely free of any PHP code. It can be manipulated using any WYSIWYG (what you see is what you get) HTML editor without problems, yet it still offers the same amount of control over dynamic content as the similar segmentation method found in Listing 7.1. In this case, I have taken the liberty of separating the navigational links into a separate file shown in Listing 7.3:

Listing 7.3. The Content for the Navigational HTML
<TABLE CELLPADDING=0 CELLSPACING=0 BORDER=0>
      <TR><TD><A href="products.php">products</a></td></tr>
      <TR><TD><A href="contact.php">contact</a></td></tr>
      <TR><TD><A href="about.php">about Us</A></TD></TR>
</TABLE>

In practice, each of these two listings should be saved into its own separate file (I'll assume they are called index.thtml and links.html, respectively, for reasons you'll understand later). Now that you have defined your templates, put them to use with the QuickTemplate class.

As with every template system I discuss in this chapter, the QuickTemplate class uses complex arrays. In the case of the QuickTemplate class, the following array is typical for the template I've described in Listings 7.2 and 7.3:

Listing 7.4. A Typical QuickTemplate Array
<?php

$temp_data = array('main' => array('file' =>
                                         'index.thtml'),
                   'leftnav' => array('file' =>
                                         'link.html'),
                   'content' => array('content' =>
                                         'This is the content: %DYNAMIC%'),
                   'title' => array('content' =>
                                         'Your typical template web site'),
                   'dynamic' => array('content' =>
                                         'This is some more content')
                   );
?>

As you can see, this multidimensional associative array first contains a number of keys that (with the exception of the main key) reflect the template markers found in Listing 7.2. The values of each of these keys is another array containing a single associative element. The key (either file or content) is associated with a value (either a filename or a string) representing the data that should replace the template marker. In Listing 7.2 I defined a template marker by the name of %CONTENT%. This marker will be replaced by the value of the content key in the $temp_data array. Because the value of this key is an array with a content key, the string "This is the content: %DYNAMIC%" is used. However, before the %CONTENT% template marker is replaced, the string it is being replaced with is also parsed. Following is a summary of what happens:

  1. %CONTENT% is replaced with the value of the content key.

  2. %DYNAMIC% inside of the content key is replaced with the value of the dynamic key.

The end result of this process is that for every instance of the %CONTENT% marker you will find the string: "This is the content: This is some more content".

This process occurs for every template marker within your template document until there are no more markers to replace. If for whatever reason a marker exists that does not exist within the QuickTemplate array (Listing 7.4) an error message is generated that is stored as an HTML comment in place of that template marker.

Now that you have an idea of how the QuickTemplate system behaves, let's take a look at the actual code that makes the system work. Depending on how confused you were by my explanation of how a template marker is processed, you may or may not think this code is too complex for you. However, I encourage everyone to keep readingthe reality of the situation is that the entire class is only 40 lines of code!

For reference, let's lay out the entire class in Listing 7.5:

Listing 7.5. The QuickTemplate Class
<?php
    class quick_template {

        private $t_def;

        public function parse_template($subset = 'main') {

            $noparse = false;
            $content = "";
            $temp_file = $this->t_def[$subset]['file'];

            if(isset($temp_file)) {

                if(strlen($temp_file) > 6) {
                    substr($temp_file, strlen($temp_file)-6);
                }

                if(strcasecmp($ext, ".thtml") != 0) {
                    $noparse = true;
                }

                if(!$fr) {
                    $content = "<!-- Error loading '$temp_file' //-->";
                } else {
                    $content = fread($fr, filesize($temp_file));
                }

                @fclose($fr);

            } else {

                if(isset($this->t_def[$subset]['content'])) {
                    $content = $this->t_def[$subset]['content'];
                } else {
                    $content = "<!-- Content for '$subset' not defined //-->";
                }

            }

            if(!$noparse) {

                $content=preg_replace("/\%([A-Z]*)\%/e",
                "quick_template::parse_template(strtolower('$1'))",
                $content);
            }

            return $content;

        }

        function __construct($temp='') {

            if(is_array($temp)) $this->t_def = $temp;

        }
    }
?>

As you can see, this class contains only (ignoring the trivial constructor) a single functionparse_template(). Let's start there.

The QuickTemplate class functions through the use of recursion (as I suspect most template engines do). It is this recursive property that allows a template system to replace template markers within the content of other template markers so quickly and easily.

NOTE

Not sure what recursion is? Basically, a recursive function is a function that calls itself from within its own code. This is illustrated in the following function, which determines the greatest common divisor between two numbers:

<?php
     function gcd($a, $b) {
          return ($b > 0) ? gcd($b, $a % $b) : $a;
     }
?>

This is just one (very nice) example of how recursion can be quite useful.


Looking at the function definition for parse_template(), you can see that a single optional parameter $subset is allowed with a default value of main. This parameter is never meant to be used by the developer using the QuickTemplate class. Rather, it is used to define the array key that is currently being processed by the engine. Because the engine has to start processing somewhere, this key was chosen by me as the starting point for all template parsing.

When parsing begins, the initial step is to do some simple initialization of three variables: $content, $noparse, and $temp_file. The first variable, $content, will store the output generated by parsing the template for the particular segment being parsed. The $noparse variable is a Boolean used to determine whether the value of the current template marker should be parsed further by the engine. This is to allow us to have both template HTML files (which must be parsed) and pure HTML files (which don't have to be parsed). Although it would be easier to not bother with such a feature, it is done for efficiency reasons to stop unnecessary parsing. The second variable, $temp_file, is simply the file key of the current subset. This value should represent the filename to be parsed by the engine, if it's available. If the file key is not provided, an attempt is made to look for a content key before generating an error. As such, the next line of code in the function is a check to see if $temp_file is actually defined by using the isset() function. If the variable is defined, the file is then read into a variable from the file system using PHP's file system functions. If the $temp_file variable is not defined, the content key is checked to see whether there is a string instead of a full file to parse. If this key does not exist, an error is generated.

So far, we have dealt only with initialization and error checking. The real work in the parse_template() function is yet to come. Surprisingly, this "real work" is limited to the use of a single PHP function: preg_replace() using the /e mode. Recalling from Chapter 3, "Regular Expressions," the preg_replace() function matches strings using regular expressions, which are then replaced with other strings. In this case, you have asked preg_replace() to extract all instances of capitalized strings between % characters and call the parse_template() function recursively. The return value from this function call is then used to replace the string that was originally extracted.

The result of this function is the very heart of the entire QuickTemplate engine. By using the preg_replace() function, you recursively ensure that every single template marker meeting the requirements of the regular expression is replaced. The result of this replacement is stored into $content, which is then returned either to the initial script that created the instance of QuickTemplate or to another copy of the parse_template function that recursively called it.

That's pretty much the whole QuickTemplate class! Although it seems too simplistic, it works quite well. To wrap up the discussion, Listing 7.6 shows it in action:

Listing 7.6. Using the QuickTemplate Class
<?php

    include('quicktemplate.php');          // Class definition

    $temp_data = array('main' => array('file' =>
                                           'index.thtml'),
                       'leftnav' => array('file' =>
                                           'link.html'),
                       'content' => array('content' =>
                                           'This is the content: %DYNAMIC%'),
                       'title' => array('content' =>
                                           'Your typical template web site'),
                       'dynamic' => array('content' =>
                                            'This is some more content')
                       );

    $engine = new quick_template($temp_data);
    echo $engine->parse_template();
?>

When this code is executed using the templates defined in Listings 7.2 and 7.3, the following is the output of this script:

<HTML>
<HEAD><TITLE>Your typical template web site</TITLE></HEAD>
<BODY>
<TABLE CELLPADDING=0 CELLSPACING=0 BORDER=0>
<TR>
<TD><TABLE CELLPADDING=0 CELLSPACING=0 BORDER=0>
<TR>
<TD><A href="/">about Us</A></TD>
</TR>
<TR>
<TD><A href="/products.php">products</a></td>
</TR>
<TR>
<TD><A href="/contact.php">contact</a></td>
</TR>
</TABLE>
</TD>
<TD>
This is the content: This is some more content
</TD>
</TR>
</TABLE>
</BODY>
</HTML>

Hopefully, you can appreciate the amount of work that goes into even a simple template engine. To make matters worse, the QuickTemplate engine doesn't support really useful features such as control structures. However, unlike using include statements to segment your websites, the QuickTemplate class does a good job of ensuring the complete separation between presentation HTML code and the application logic that controls it.

Of course, this separation does not come without a price. At this point, you probably realize that writing (or using someone else's) template engine is sure to make your Web pages less intuitive. Hence, you should understand what the QuickTemplate class does (even if you don't completely understand how it does it) before proceeding further. If using QuickTemplate has confused you, you probably aren't ready for a system such as Smarty, which follows this section, because it is much more advanced and can be slightly confusing. Rather, if you are having difficulty with anything up to this point, you should review what we have covered thus far in discussing the QuickTemplate class before moving further in this chapter.