Custom Content Management with PHP

October 12, 2007

 Custom Content Management with PHP
by Thomas Perl

It is well known that you can create powerful Web pages with PHP. Often, the question arises: How are these pages made? This tutorial wants to give you some hints on how to make your Web site appear more managed from both inside and outside. These are my own approaches to Web development; I hope you find them useful. Take these things as ideas rather than good practice.


Copyright notice: All reader-contributed material on freshmeat.net is the property and responsibility of its author; for reprint rights, please contact the author directly.

About the hints

Each hint in this tutorial can be implemented by itself without the others, but sometimes, it’s more useful if you combine them. It depends on you to decide which hint is good for your site.

Clean directory structure

Are you tired of calling a subpage of your site http://www.example.com/index.php?page=news&id=45? You could have a stylish URI in the form of http://www.example.com/news/45/. This gives better-sounding addresses, and your visitors may more easily remember your URIs. All you need is the Apache Web server or a browser in which this .htaccess file will be processed in the same way:

RewriteEngine  on
RewriteBase    /news/
RewriteRule    ^.*$    handler.php

These three lines instruct Apache to rewrite all URIs from the base directory /news/ matching the rule ^.*$ to the handler.php script.

Place this file in your newly-created /news/ directory, then create a handler.php file, which will handle all the requests beneath the /news/ tree. In other words, all URLs you request within that directory will be handled by handler.php. To get an array of “parameters” that are passed to handler.php, you can use this function:

function get_url_params( $base_url)
{
  $request = substr( $_SERVER['REQUEST_URI'], strlen( $base_url));

  if( substr( $request, -1) == '/')
    $request = substr( $request, 0, -1);

  return explode( '/', $request);
}

Use it in handler.php like the following:

get_url_params( '/news/');

You will receive an array with the parameters, which you can process as you wish. You could improve the get_url_params() function by adding code for processing a ? (and everything behind it) in the request URI.

I use this technique to get some fancy URI mapping of my Web site. It’s not any harder than using a single index.php which handles all requests, and the benefits are clearly visible. You will be able to make URLs on your Web page that don’t have to change, which is exactly what Cool URIs don’t change tells you is good practice. (This document got me into making this URI mapping system for my Web site; it’s really worth reading.)

Creating a template framework

You can use templates for outputting both static and dynamic content. You will want to create a directory in which you put the templates. You should secure this directory using this .htaccess file:

allow from none
deny from all

This will instruct Apache to deny all access to the template files directly. Access using template functions is still granted, because they’re not directly accessed.

You will now want to write a template function. Here’s what I currently use for my site:

function template_create( $template_name, $mapping = NULL)
{
  $template_data = file_get_contents( $_SERVER['DOCUMENT_ROOT'] .
    '/templates/' . $template_name . '.template');

  if( NULL != $mapping)
    return str_replace( $mapping['from'], $mapping['to'], $template_data);
  else
    return $template_data;
}

This means I have my templates in the /templates/ directory of my document root and that the files have the extension *.template (which isn’t necessary; you could name the extension of your templates as you like). If you include the $mapping parameter, this should be an array with two elements: $mapping['from'] and $mapping['to']. All occurrences of the “from” element will be replaced with the “to” element. Both elements can also be arrays, which results in all elements in the “from” array being replaced with the corresponding elements in the “to” array. Here is an example of how you could use this:

$time = time();
$text = 'This is a Test';

$mymap = array(
  'from' => array( '%%TIME%%', '%%TEXT%%'),
  'to' => array( $time, $text)
);

template_create( 'my_document', $mymap);

Where the file /templates/my_document.template could look like this:

<p>Hello. The time is %%TIME%% and here is some text:</p>
<p>%%TEXT%%</p>

You should now have seen how easy it is to create templates for pages and how to fill them with dynamic content. This is especially useful if you want to create templates for displaying dynamic data from databases and such. You can surely improve this by creating a function which reads one row from a database table and fills a mapping variable with data from that row, returning a valid mapping for the template_create() function.

Using templates for a unique layout

This is a short and easy one. Let’s say you want to create a unique layout for a page, but you don’t want to include the full code in every file or script you write. Use the templates hint above to create template functionality and include it in every subpage. Then, use it like the following (assuming header.template and footer.template include all the code for the beginning and the ending of the page):

template_create( 'header');

// place content output here

template_create( 'footer');

Yes, that’s all!

Make database access abstract

Here’s some more code for your include directory. After some time, it’s easier to make queries in this fashion than to make a mysql_query everywhere you need some data from the database. It also gives more sense to the code and makes it more readable because you just see the function call with the important parameters.

function database_get_single_element( $table_name, $key, $value);
function database_select_multiple_elements( $table_name, $from, $to,
   $order = NULL, $how = 'ASC', $key = NULL, $value = NULL);
function database_get_random_element( $table_name, $key = NULL, $value = NULL);
function database_get_column_sum( $table_name, $column, $key = NULL, $value = NULL);
function database_get_next_element( $query);
function database_count_elements( $table_name, $key = NULL, $value = NULL);

The database_get_single_element() function will select and mysql_fetch_assoc one row of the table named by $table_name. There will also be a WHERE part, and the $key field in the table must have the $value value.

The database_select_multiple_elements() will return a mysql_query of the same things. $from and $to are for the LIMIT part of the query. The data can then be fetched with database_get_next_element(), which is exactly the same as mysql_fetch_assoc, but has a more informative name.

database_get_random_element() will use the ORDER BY RAND() LIMIT 1 SQL query words to select some random element from the table.

Finally, database_count_elements() counts the number of rows of the results. This is good for counting how many elements another query will return.

These are just some hints of what I mean by database abstraction. I’m sure that you’ll probably need other functions which better suit your needs, and you might not need all the functions I’ve shown. Let me tell you from experience that it will get a lot easier when you start using these functions instead of simple queries. And if you have some very complicated queries, make a function for each of them. If your database layout changes or if you use another database instead of MySQL (which is certainly possible in PHP), you do not have to change all queries, but simply fire up your editor on the database include files and change all queries there.

Entry Filed under: php articles. .

Leave a Comment

Required

Required, hidden

Some HTML allowed:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <pre> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Trackback this post  |  Subscribe to the comments via RSS Feed


Calendar

October 2007
M T W T F S S
    Nov »
1234567
891011121314
15161718192021
22232425262728
293031  

Most Recent Posts