Intermediate Code Reuse: Using and Including Files


After awhile, you will discover the need to start reusing functions you have written in different scripts or projects. For one or two simple functions, cutting and pasting them between your various PHP scripts will not present a big problem. However, as the number of routines grows or the complexity of a particular group of routines increases, you will want to keep them in a single placetypically in a file, which we will call a code libraryand then find some other way to use that library from within various scripts.

Organizing Code into Files

One of the first steps toward reusing your code is to decide how to factor it and to choose what to put into separate files. There are no hard and fast rules here, but we will offer some suggestions and things to consider when choosing how to organize your code.

Group Common Functionality

You will see as we write functions for particular areas of functionality that we tend to group these together and put them into separate code files. A good example of this would be the set of functions and objects (introduced in Chapter 4, "Object-Oriented Programming") used to manage users that visit your web site.

You might also have a set of routines that is for the generation of various pieces of user interface in your project. Therefore, if you have particularly complicated routines for the generation of menu bars and core web page elements, you might find yourself grouping these.

The size that a collection of routines needs to be before you split it into a separate file is a personal judgment. For example, if you only have three user management functions, and another two or three functions to manage a closely related feature called sessions, you might choose to group that complete set into one file. However, you will have a difficult time convincing people that grouping your product shipping functions along with your code to customize the user interface of your web pages is a good idea.

If in doubt, do not be afraid to have separate code files with only a few things in them. (Some included files might only have a few constants.) While some might argue that there are performance implications to consider, we will more often err on the side of code maintainability, readability, and (hopefully) stability. You should only start to worry about performance if you find yourself with dozens of separate files. In this case, the criteria for choosing how to split up functionality is a little too fine (or your web application is extremely large).

Make Consistent Interfaces

Many people do not notice that much of the code being written as they use a set of functions, constants, or routines with similar functionality is quite similar. Many database routines want a handle to the database connection as the first parameter, just as many file routines want the name of the file to modify as the first parameter. If we were to write a set of routines to operate on circles as follows

 <?php   // circle is (x, y) + radius   function compute_circle_area($x, $y, $radius)   {     return ($radius * $radius * pi());   }   function circle_move_location(&$y, &$x, $deltax, $deltay)   {     $x += $deltax;     $y += $deltay;   }   function compute_circumference_of_circle($radius)   {     return array("Circumference" => 2 * $radius * pi());   } ?> 

not only do the functions in the previous set of routines have dissimilar names, but their function signatures (set of parameters and how they return values) are inconsistent. Users who are accustomed to passing in the center point of a circle as (x, y) in the first function will be frustrated or not notice that the second function wants these in reverse order.

By giving these functions consistent names, parameter orders, and obvious ways of returning values, you considerably reduce the frustration and the bugs in your code.

 <?php   //   // all routines in this file assume a circle is passed in as   // an array with:   //   "X" => x coord   "Y" => y coord  "Radius" => circle radius   //   function circles_compute_area($circle)   {     return $circle["Radius"] * $circle["Radius"] * pi();   }   function circles_compute_circumference($circle)   {     return 2 * $circle["Radius"] * pi();   }   // $circle is passed in BY REFERENCE and modified!!!   function circles_move_circle(&$circle, $deltax, $deltay)   {     $circle["X"] += $deltax;     $circle["Y"] += $deltay;   } ?> 

We will try to do something similar for constants. If we were to have some file locations we wanted to represent as string constants, we might choose to organize them with the following names and style:

 <?php   define('FILE_ERRORLOG', '../logs/errors.log');   define('FILE_ACCESSLOG', '../logs/access.log');   define('FILE_PURCHASELOG', '../logs/purchases.log'); ?> 

Choosing Filenames and Locations

Once you have your code organized into a separate code file, you need to choose a name and location. As we will see next in our discussion of the include and require directives, you are free to choose any filename, as long as you are careful to notice where the files will be placed.

There is nothing that prevents us from giving our subroutine library script files the .php extension (for example, circlefuncs.php), but this can be a bit misleading. First of all, it does not convey that this is supposed to be a library of code designed for use from within other PHP scripts. Second, there is nothing that prevents somebody from trying to run it as a PHP script in the browser, where it might not do what is expected.

Therefore, we will choose filenames ending in a different extension. Names such as .inc or .lib often prove good choices (although both are sometimes seen on other platforms). We will stick with the former throughout this book.

Using the extension .inc does have one disadvantagemost web servers do not know this extension is filled with PHP script. Thus, if the user attempts to open the .inc file, he will see a full listing of your source code, which is a serious security problem. If we were to put our previous circle functions in an .inc file and then try to browse them in a browser, we might see something akin to Figure 3-1.

Figure 3-1. Looking at .inc files in a web browser.


We will use two mechanisms to prevent this from happening. First, we will make sure that our web server does not permit people to browse or load files that it does not want them to in the directories that make up the document directory tree. (We will show you how to do this in Chapter 16, "Securing Your Web Applications: Planning and Code Security.") We will then configure our browser to let people browse for .php files and .html files but not .inc files.

The second way we will prevent this problem is to not put library code within the document tree. We can easily put files in another directory and either explicitly refer to that directory in our code or tell PHP to generally look there.

For example, if we had configured our web server to place the browsable documents for our web site in

 D:\WebApplications\WWW 

on a server running Microsoft Internet Information Server (IIS), or in

 /home/httpd/www 

on a Unix (Linux, FreeBSD, Solaris, and so on) server running the Apache Foundation's httpd, we might choose to put our library files in

 D:\WebApplications\Lib 

or

 /home/httpd/lib 

These directories cannot be accessed by the end user, so we do not have to worry about them trying to see files.

APPLICATIONS ON COMMERCIALLY HOSTED PHP SERVERS

Not all users will be writing web applications on their own servers or even servers to which they will have administrator-level access privileges. Many web applications are hosted by Internet Service Providers (ISPs) that merely give you a virtual web site capable of running PHP on a server being shared with many other users and web applications.

On these, you are not guaranteed the ability to create a lib/ subdirectory that is outside of your document root, and you are not certain that your .inc files cannot be viewed by other users.

For such systems, an acceptable workaround is to use .php as your file extension and add the following code to the top of the file:

 <?php $selfparts = split('/', $_SERVER['PHP_SELF']); $file = ereg_replace('\\\\', '/', __FILE__); $fileparts = split('/', $file); if ($selfparts[count($selfparts) - 1]     == $fileparts[count($fileparts) - 1]) {   echo "Do not call this file directly.";   exit; } // otherwise, continue with our library as normal. ?> 

We will see explanations for this code as we work our way through the bookwe have given it to you now so that you can start to put library files up on a publicly hosted server without worrying about their security.

For the curious, the preceding code basically looks at the name of the script that our server was asked to execute versus the name of the file in which the code resides (with any backslashes converted to forward slashes with Windows). We only want to see these library files called from within other scripts, so watch out for any error messages emitted from the codethis means the script has been incorrectly used.


Including Your Library Files in Script

PHP provides a couple of key ways to include files within your script.

Include and Require

The include and require constructs are the ones you will encounter the most. They are used as follows:

 <?php   // you could use include here instead of require   require('user_management.inc');   $userlist = userman_list_all_users(); ?> 

The key difference between these two features is that require prints an error when it cannot find the file, whereas include prints a warning. Thus

 <?php   include('i_dont_exist.inc');   require('i_dont_exist.inc'); ?> 

generates a number of warnings for the include (and then continues processing the script). Then it produces a fatal error for the require and immediately stops processing the script.

Throughout this book, when we want to use a code library in our scripts, we want to be sure it exists and can be used. Therefore, you will not see us using include very often.

Where Include and Require Look for Files

When you use one of the keywords to include a file within your scripts, you can either specify an explicit path or let PHP look for one in one of the places it knows to look.

You can specify an explicit path by entering the full or relative path to the file to be included:

 require('/home/httpd/lib/frontend/table_gen.inc'); require('../../lib/datafuncs.inc'); require('D:\WebApps\Libs\data\connections.inc'); require('..\..\..\lib\happycode\happylibs\happyutils.inc'); 

If you do not specify an explicit path, PHP looks in the current directory for the file to be included, followed by the directories listed in the include_path setting (a separated list of directories to search) in the php.ini file. Under Unix, the separation character is the colon character (:), whereas Windows machines use a semicolon character (;). Examples of this setting on a Unix system might be as follows:

 include_path=".:/usr/local/lib/php:/home/httpd/globalincs" 

Under Microsoft Windows, this setting might look as follows:

 include_path=".;C:\PHP\include;D:\WebApps\Libs" 

Do not forget to restart your web server after changing this setting. (See Appendix A, "Installation/Configuration" for more information.)

What Include and Require Do

Regardless of the extension used in the files included via include and require, PHP scans these files as it loads them. Anything that is not wrapped in script markers will be sent to the output stream, while anything within script markers is processed as normal PHP script. Listing 3-1 and Listing 3-2 show us a simple PHP script and a simple file for inclusion. The output of these listings is shown in Figure 3-2.

Listing 3-1. Source for printmessage.inc
 <p align='center'>   <b> <?php  echo $message; ?>   </b> </p> 

Figure 3-2. Output of running message.php.


Listing 3-2. Source for message.php
 <html> <head>   <title>Sample</title> </head> <body> <?php   $message = "Well, Howdy Pardner!";   require('printmessage.inc'); ?> </body> </html> 

We see from the code in the two files that PHP begins by working its way through message.php. When PHP sees the required directive, it includes the contents of printmessage.inc, which is then processed. The HTML in the latter file is sent to the output stream, and the PHP code is executed as it is encountered. When the included file is fully processed, PHP resumes its work on the primary script file.

Another interesting fact in the included file is that script variables are visible and available to use (hence its use of the $message variable).

One last note on how included files function in PHP: Just as all functions have a return value in PHP (if none is declared, it is just NULL), so do all scripts. If your script includes a return statement in it, PHP returns that to the caller. For included scripts, you can have them return a value to the caller, which is then given as the return value to the require or include construct. Thus, the following script (using the name getpi.inc)

 <?php    return pi(); ?> 

could be included from another script as follows:

 <?php   $value_of_pi = include('getpi.inc');   echo "PI has the value: $value_of_pi<br/>\n"; ?> 

Since most of our files for inclusion are not going to be executing much code, we will use this feature sparingly throughout the book.

File Inclusion and Function Scoping

We must now look at how moving functions from your scripts into included files affects the scoping rules and their ability to be called. If your function is in another file, and the contents of that file have not yet been included in the contents of the current script via the include or require language features, then the function call is invalid.

 <?php   //   // this won't work, because it's in the    // salutations_and_greetings.inc file, which hasn't been    // included yet.   //   print_salutation_message();   require('salutations_and_greetings.inc'); ?> 

The previous example produces the following output:

 Fatal error: Call to undefined function print_salutation_message() in c:\Inetpub\wwwroot\phpwebapps\src\chapter03\examples.php on line 303 

Reorganize the previous code along the following lines, and all is well:

 <?php   require('salutations_and_greetings.inc');   print_salutation_message(); ?> 

To get around this, it is a good idea to include other files at the top of your script.

When Sharing Becomes Problematic

All this sharing of code is bound to make us feel warm and fuzzy on the inside as many of our organizational troubles are solved, but, in some cases, it can become a problem for us. Imagine we were writing a web site for an engineering firm that had the ability to do some engineering calculations and manipulations for the user in addition to some charting and graphing of plans.

We could imagine that our web application scripts would make reference to some file called engineeringfuncs.inc in addition to graphicsfuncs.inc. However, the authors of these two files were also big fans of code sharing, and they decided that they would use circlefuncs.inc within their scripts. This would lead us to a situation similar to the one shown in Figure 3-3.

Figure 3-3. Library files including other library files.


Imagine that our script begins with the following:

 <?php   //   // we need some engineering and graphics helpers.   //   require('engineeringfuncs.inc');   require('graphicsfuncs.inc'); ?> 

If both of these files had the following line near the top

 require('circlefuncs.inc'); 

we would see the following when we loaded our script:

 Fatal error: Cannot redeclare circles_compute_area()    (previously declared in   /home/httpd/www/phpwasrc/chapter03/circlefuncs.inc:3) in   /home/httpd/www/phpwasrc/chapter03/circlefuncs.inc on   line 12 

We could spend some time trying to make sure that our files included none of these duplicate references, but we would end up creating far more work for ourselves than we would really like. What we would like is a way to tell PHP to include files once and recognize that it has done so later on.

Fortunately, PHP has the language constructs require_once and include_once. These behave just like their _once-less cousins, except that they will remember if they have loaded a particular file. This prevents any problems with function or constant redefinitions.

If we change our engineeringfuncs.inc and graphicsfuncs.inc to use

 require_once('circlefuncs.inc'); 

we will be set. We will commonly use this method of file inclusion throughout this book.

Using Inclusion for Page Templating

One of the things many web application authors notice is that most of the pages they are producing look extremely similar. Cutting and pasting the code for the page for every new type of script in their application proves tedious and also creates enormous amounts of work for them when they decide it is time for a "new look" for the web site.

Fortunately, file inclusion can be of some assistance here. If we factor out the common content that comes before and after the new content of each page, we could imagine creating pages as seen in code Listings 3-3, 3-4, and 3-5.

Listing 3-3. template_top.inc
 <html> <head>     <title><?php echo $page_title; ?></title> </head> <body>   <p align='right'>     <img src='/books/3/445/1/html/2/pic.jpg' border='0' alt=''/>   </p> 

Listing 3-4. template_bottom.inc
 <br/> <hr size='1'/> <p align='center'>   <font size='1'> Copyright (c) 2004-2005 Happy Happy Clown Inc.  All Rights Ignored.</font> </body> </html> 

Listing 3-5. welcomepage.php
 <?php   $page_title = "Welcome to our Template Test !!!";   require('template_top.inc'); ?>   <p align='center'>     This is the sample body for our page.  It sure     is nice not having to worry about any stuff like     the page title, core HTML tags, and other tedious     goop with which we don't want to deal ...   </p> <?php   require('template_bottom.inc'); ?> 

As shown in the three listings, we set up a variable with our page title and then include the top portion of the page content. Then we can do whatever we want to generate the main contents of the page before we include some standard information at the bottom of our page.

If we knew we were going to do this for every script in our web application, we could take advantage of two settings available to us in php.ini auto_prepend_file and auto_append_file. These let us specify files for inclusion both before and after each executing script, and would save us from writing the two require statements earlier.

As we will see throughout this book, there are many other uses for PHP scripts that do not involve output, and we will often use these in our web applications. Because of this, we will avoid using the auto_prepend_file and auto_append_file settings and suggest other solutions for the sharing of user interface generation.




Core Web Application Development With PHP And MYSQL
Core Web Application Development with PHP and MySQL
ISBN: 0131867164
EAN: 2147483647
Year: 2005
Pages: 255

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net