PHP by example, Part 2

Delving deeper into Webzine authoring and delivery

As a language for building dynamic Web pages, PHP offers a simplified method for constructing complex and powerful Web-related programs. Step by step, Erik demonstrates the fundamental principles of PHP in an original real-world Web site example. In Part 2 of this series, he shows you how the delivery module presents a menu of stories to the reader, and how the authoring module permits authors to submit stories to a Webzine.

Erik Zoltan (erik@zoltan.org), Senior Information Specialist, EDS

Erik Zoltan has been writing code professionally since 1990. He's a full-time telecommuter living in Leominster, Massachusetts. You can e-mail him at erik@zoltan.org or view his home page at www.zoltan.org. Erik drives a 1996 Saturn painted in Vincent Van Gogh's The Starry Night.



02 January 2001

If you're new to PHP, you might be pleasantly surprised by how easy it is in practice. My intention is for you to come away with a good feel for what it's like to work in PHP; after that, you'll be able to decide whether or not it's right for you.

Introduction

In Part 1 of this article, I covered the delivery portion of a simple PHP Webzine application. Although it's only about 3K of code, it packs a lot of functionality. You got a chance to try out the application and begin looking under the hood. I explained how the application displays category menus to users, and presents stories upon selection. I also gave a feel for how PHP applications work and how they accept parameters from the calling page.

Here in Part 2, you'll see how the delivery module presents a menu of stories to the reader, and then take a quick look at the authoring module, which permits authors to submit a story to the Webzine.


Menu of stories

To illustrate, a topic menu file (TradeShow.txt) containing just three stories might look like the following:

Great New Products This Year^/images/proddemo.jpg^Thursday's product demo ...
12^Opening Event Well Attended^/images/opnfoto.jpg^Ticket sales to the ...
5^Trade Show Opens^/images/tradelogo.gif^The Fourth Annual Trade Show ...

The menu driver takes this information and presents a story overview to the reader. It works like this:

  • First, the driver copies the appropriate number of entries from the topic menu file into an array $stories . Using the above example, $stories[0] contains the first line (story number 33), $stories[1] contains story number 12, and $stories[2] contains story number 5. You also need to count the number of elements in the array and use a variable $numstories to contain the result.
  • Next, the driver presents the information to the user as follows:
for ($i=0; $i<$numstories; $i++) {
   $storyinfo = split("\^", $stories[$i]);
   $storynum = $storyinfo[0];   // Story number (e.g. 33)
   $storydesc = $storyinfo[1];  // Story Title (e.g. "Great New Products This Year").
   $storyimg = $storyinfo[2];   // Image URL (e.g. "/images/proddemo.jpg").
   $dtext = $storyinfo[3];      // Story Synopsis (longer text description).
   $url = "<a href=\"index.php3?topic=$topic&story=$storynum\">$storydesc</a><br>";
   if ($i<10) {
      $url = "<h2>" . $url . "</h2>";
      if ($storyimg != "") {
         $url = "<p><img align=" . ($i%2==1 ? "right" : "left")
              . " src=\"$storyimg\"></p>\n"
              . $url;
      }
      $url = "<hr>" . $url;
   } else {
      $url = "<h3>" . $url . "</h3>";
   }
   echo("$url\n");
   echo("<p>$dtext</p>\n");
}

The split function copies the contents of the story information from a string into an array. Note that the caret becomes "escaped" by placing a backslash in front of it. The program transfers the array nodes into more descriptive variable names, making the code easier to follow. Then, construction of the URL occurs. The if/else structure handles the first 10 stories differently from the rest. The first 10 have a dividing line, use the H2 tag, and include a photo if available. The rest use the H3 tag, with no dividing line and no photo. This process highlights the newest stories, and maintains older ones for those readers who want them. Note the right-alignment of the odd-numbered images and the left-alignment of the even-numbered images.

To wind up this example, the resulting HTML source for theTradeShow.txt file above might appear as follows:

<hr><p><img align=left src="/images/proddemo.jpg"></p>
<h2><a href="index.php3?topic=TradeShow&story=33">Great New Products This Year</a><br></h2>
<p>Thursday's product demo included a couple of exciting new 
surprises from competing firms in the industry.</p>
<hr><p><img align=right src="/images/opnfoto.jpg"></p>
<h2><a href="index.php3?topic=TradeShow&story=12">Opening Event Well Attended</a><br></h2>
<p>Ticket sales to the Trade Show opening event were 
up 15% from last year's show.</p>
<hr><p><img align=left src="/images/tradelogo.gif"></p>
<h2><a href="index.php3?topic=TradeShow&story=5">Trade Show Opens</a><br></h2>
<p>The Fourth Annual Trade Show opened 10/11/2000 to an enthusiastic reception 
from attendees.</p>

Authoring page "author.php3"

I won't go into nearly the same level of detail about the authoring page because it is longer and I've already discussed many of the underlying concepts.

As a simple illustration of what a PHP function looks like, look at the complain function from the authoring module. It's a very simple function that serves as a good introduction.

// Informs the user of an input problem.
   function complain($problem) {
      global $status;
      if ($status != "") $status = $status . "<br>\n";
      $status = $status . $problem;
   }

You can invoke this function from anywhere in the code. For example, complain("The URL is too long."); takes the global variable $status and adds the new complaint to the end, preceded by a line break unless $status is currently empty.

Prepend

The prepend function is one of the most important in the authoring module. It adds a new entry to the first line in a file. Here, I use it to add the author's new submission to the beginning of the topic menu file.

// Add a new line to the start of an existing file.
   function prepend($file,$string) {
      // TO DO - use database to make this algorithm more scaleable.
      //         Current limit is 100 stories.
      if (file_exists($file)) {
         $filetext = file($file);
         $lines = count($filetext);
      } else {
         $lines = 0;
      }
      if ($lines > 100) $lines = 100;
      $handle = fopen($file,"w");
      fputs ($handle, "$string\n");
      for ($i=0; $i<$lines; $i++)
         fputs ($handle, $filetext[$i]);
      fclose ($handle);
   }

If the file exists, the entire text goes into the $filetext array. The lines are then counted. If the file doesn't exist, it's treated as having zero lines. One hundred lines is the limit of the length (actually 101 because of the first line added before counting starts). The file opens, the program writes the current string first, and then writes the remaining (up to 100) lines to the file. Anything after those additional 100 lines just drops off the end.

This function relies on several important file-handling functions that are built into PHP. The following table describes what each function does.

FunctionDescription
file_exists(string)Uses the string as a filename, and returns true if the file currently exists.
file(string)Using the string as a filename, returns the text of the file in an array where each line is a separate array element. Note that the line termination character(s) will be at the end of each line in the array.
count(array)Returns the number of elements in the array.
fopen(string, mode)The string is a filename, and the mode is a string such as "w" to write or "r" to read. The file will be opened, and a handle will be returned.
fputs(handle, string)Writes a string to the specified output file. You must specify a file handle, you can't specify a filename in string form.
fclose(handle)Closes the file, terminating output.

Save

      $entry = "$storynum^$storytitle^$storyimg^$synopsis";

$storynum$storytitle$storyimg$synopsis

      prepend("Main.txt",$entry);
      $topicfile = "$subject.txt";
      prepend($topicfile,$entry);

The value of the $entry variable prepends onto the main story menu file and the subject-specific story menu file. So, if the variable $subject equals "Politics", it prepends onto "Politics.txt".

      // Selective Security!  Convert most HTML tags to text.
      $storytext = eregi_replace("<", "<", $storytext);
      $storytext = eregi_replace("<b>", "<b>", $storytext);
      $storytext = eregi_replace("<i>", "<i>", $storytext);

There are a lot of search-and-replace statements that apply to the story text; you'll see just a few of them above. Replacing the < symbol with the HTML symbol < will prevent the author from entering any risky HTML tags into the document. However, since we want to give the author some formatting capabilities, we then replace <b> with <b>, <i> with <i>, and so on. The eregi_replace function is case-insensitive. You can use ereg_replace (same name without the "i") for case-sensitive replacement.

Initializations, setup

The program invokes the following code first when running author.php3:

if ($submit == "Submit") {
      $status = "";
      if (!isset($storyimg)) $storyimg = "$subject.gif";
      validate("Subject",$subject,1);
      validate("Story Title",$storytitle,10);
      validate("Synopsis",$synopsis,50);
      validate("Story Text",$storytext,300);
      if ($status == "") {
         $status = "complete";
         save();
      }
   }

If the user clicks the submit button to invoke the form (as opposed to the "Preview Image" button which is also a submit button), the input is validated. The validate function checks each field to make sure it is not null, and that it is not too short. (A maximum-length feature would be a good enhancement to add here.) If there's a problem, the complain function (shown earlier) updates the global variable $status. If everything is okay, the program invokes the save function to save the author's input.


Why you should use PHP

This article is intended to give you a feel for what it's like to program in PHP, especially since many developers still haven't fully committed to a Web scripting language. I've only discussed the features of PHP necessary to create this specific application, so these aren't just theoretical features that you're unlikely to use in practice.

PHP is an attractive choice for Web application development for many reasons. Here are a few that come to mind based on this example:

  • The integration of PHP and HTML together into a single source document makes it easy to add PHP to existing Web pages. It also means you can prototype an idea in HTML and add PHP to it later.
  • PHP programs are easy to understand because their structure inevitably mirrors the structure of the Web pages they produce. For the same reason, it's also pretty easy to design in PHP.
  • As you can see from this application, the file-handling and string-handling functions were designed with ease-of-use in mind. This is apparently a general design philosophy behind PHP -- it doesn't conform to someone's theoretical model of a programming language; it's easy to use in practice.
  • PHP is very approachable. It's easy to learn, and easy to get started writing great Web apps. You don't face a big learning curve. Once you know the basics, all you need is a manual and you're ready to hit the ground running.
  • PHP is also great with databases, but that's another article.

I hope you're excited about using PHP. Feel free to use and customize the source code contained herein.

Resources

  • Part 1 of this series gets you started.
  • PHP.net is the official home page of the PHP language. Here you can download the latest version of PHP for free, and check out what's going on in the development of PHP. There is a FAQ, a manual, and numerous other resources.
  • PHPbuilder.com is geared toward developers, containing numerous articles and code samples, job postings, and links to PHP resources.
  • Webmonkey's PHP Section contains a number of articles on PHP starting out at the introductory level.

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Web development on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Web development
ArticleID=11468
ArticleTitle=PHP by example, Part 2
publish-date=01022001