You've seen them all over the web--image galleries for your viewing pleasure! You've looked for decent image gallery software, but none of them seem to suit your needs, while others have a lot of extra features you don't need. And while you've seen some others that are just what you're looking for, you can't easily integrate them into your website. To solve this problem, I wrote my own photo gallery script and I'm going to share it with you in this article.
The first script I used for my photo gallery was created by Paul Oliver. He used procedural code in order to create a gallery, but his gallery only dealt with one directory. This meant that if you had 50 events you needed galleries for, you couldn't use one script, but had to use 50 different ones, or know a good bit about php in order to make it work.

Paul's flat system worked for a while. But as we develop sites, we need the ability to add more photos into different events, even different categories. Paul's script wasn't very flexible so I couldn't use it for that purpose. Using his concepts, however, I was able to create a simple Photo Gallery that would work as we needed.

Initial Setup

To start things off, we need an active working directory. We'll name this directory "gallery". All the files and directories mentioned in this article will be in that directory. Once we've got that set up, we need to create a few folders. We are going to have an "images" folder (duh! right?), and within that a "root photos" folder. We'll name this folder "photos". You may be wondering why we need a root photos folder? We need it because we may merge our site's images folder with the one where we host our image gallery photos. If that is the case, this directory will make that move very simple. Within the "images" folder we'll need a folder to hold small icons for categories and events. This directory will be called "icons".

 

We now have our working directory, along with the image and photo directories. Now we need directories for categories, events and thumbnails. With this in mind, inside of our "photo" directory we will create a directory called "Events", and within that one we'll create one called "My_Gallery_Example" and within that we'll create yet another directory called "thumbs". Now that we've created all of the directories we need, let's create the default documents. We will be using two documents (this is a very small script!!); one will be our script resource page ("class.photogallery.php") and the other will be the main page that users will visit in order to browse the gallery ("photos.php"). With everything set up, here's an overview of how things should appear:

/gallery/
|
+- images
|  |
|  +- icons
|  |
|  +- photos
|     |
|     +- Events
|        |
|        +- My_Gallery_Example
|           |
|           +- thumbs
|
+- photos.php
|
+- class.photogallery.php

NOTE: Directories are listed in blue and files are listed in red.

 

About The Script

One thing you may notice is that we named the php file that will do the brunt of the work "class.photogallery.php". That's because this is an object-oriented script. I chose this method because it reduced the overhead with the gallery. Don't worry--there's nothing too crazy in there, but I'll explain all of what is going on with the code as I go along.

Let's start things off with the easy part--the HTML.

[ Next ]

 

The HTML Layout
To set things up we need to decide which format we're using, whether to use CSS or not and how to display our images. I chose to use CSS mixed with a table. The layout is CSS, and the table is used to display the gallery. Obviously you can choose to use what you wish, but I used a table for a simple reason: it's simple and effective. Plus, it's more universal, so anyone can adapt it to their pages.

Here's what I have currently for my HTML code:

Code For: photos.php


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> PHP Image Gallery </TITLE>
<META NAME="Generator" CONTENT="EditPlus">
<META NAME="Author" CONTENT="Brett Patterson">
<META NAME="Keywords" CONTENT="PHP Image Gallery PHPBuilder Builder">
<META NAME="Description" CONTENT="A simple PHP Builder Article overviewing an Image Gallery">
<link type="text/css" rel="stylesheet" href="phpbstyle.css">
</HEAD>

<BODY>
<div id="wrap">
  <div id="header">
    <img src="http://phpbuilder.com/images/new-logo.gif">
    <span class="tag">Image Gallery for PHP Builder</span>
  </div>
  <div id="main">
    <p>
      <table>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #999;">&lt;!-- This is where our main stuff will go --></span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/table>
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/p>
&nbsp;&nbsp;&lt;/div>
&nbsp;&nbsp;&lt;div id="clear">&lt;/div>
&lt;/div>
&lt;/BODY>
&lt;/HTML>

Things you'll notice
At this point I'm sure you are familiar with this sort of code. What you may have noticed is that I referenced a CSS document called "phpbstyle.css" in the head. This stylesheet contains all the information needed to display the page and links properly. The code is simple:


Code For: phpbstyle.css


body{
  text-align: center;
  padding: 0;
  margin: 0;
}

body img{
  border: 0;
  padding: 0;
  margin: 0;
}

body a,
body a:link,
body a:visted{
  text-decoration: none;
  cursor: default;
  color: #090;
}

body a:hover,
body a:active{
  color: #abd;
  font-variant: small-caps;
}

#wrap{
  width: 750px;
  margin: 10px auto;
  padding: 0;
  border: 2px groove #ccc;
}

#header{
  width: 750px;
  height: 56px;
  background: url('http://phpbuilder.com/images/background.gif') top left repeat;
  padding: 0;
  margin: 0;
  border-bottom: 2px groove #ccc;
}

#header img{
  float: left;
  margin: 0;
  padding: 0;
  height: 56px;
  width: 300px;
}

#header .tag{
  float: right;
  width: auto;
  margin: 32px 5px 0 0;
  padding: 0;
  font-weight: bold;
  color: #fff;
  font-size: 14px;
}

#main{
  width: 740px;
  margin: 5px 5px;
  padding: 0;
  float: left;
  text-align: left;
}

#main table{
  width: 740px;
  border: 1px solid #ccc;
  float: left;
}

#main table tr,
#main table td,
#main table th{
  width: auto;
  border: 1px solid #ccc;
  color: #000;
}

#footer{
  width: 750px;
  margin: 0;
  padding: 0;
  float: left;
  border-top: 2px groove #ccc;
}

#footer .text{
  width: 740px;
  margin: 0 5px;
  padding: 0;
  float: left;
}

#clear{
  content: "";
  width: 750px;
  height: 0px;
  clear: both;
}


A Page is Born
Copy the code into a new document and save it in the same place as the other files, and name it "phpbstyle.css". If you view it in your browser, you should have an idea of what it will look like. Now we'll add some PHP to our HTML!!

Making photos.php a PHP Page
We're all set with the appearance of the page (for the most part) but we still need to make it work. We know that we need to have the "class.photogallery.php" script included or it won't work, so let's do that at the very top of the page. Add the line to require that class above the HTML code:
Code:
<?php   require_once('class.photogallery.php'); ?> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <HTML>
What About the Images?
We're stepping closer to getting a working gallery. At this point we just need to make a new object from our class (discussed on the next page) and then send the URL information to it, so we use the following php code:
Code:
<?php   $pix = new PhotoGallery();   $pix->get_items($_GET['cat'], $_GET['evt'], $_GET['pic']); ?>
Some Issues
This works great if there is always a value for each $_GET variable. Since most people will come to the gallery and not follow a specific link to a photo, we need to compensate for that potential problem. To do so, we check to see if the $_GET variable is set, and if it is, we set it to its original value; if not, we set it to an empty string:

Code:


$_GET['cat'] = (!isset($_GET['cat']))?'':$_GET['cat'];
$_GET['evt'] = (!isset($_GET['evt']))?'':$_GET['evt'];
$_GET['pic'] = (!isset($_GET['pic']))?'':$_GET['pic'];

The ternary operator usage here is for ease of use. It works like this:

Code:


$var = ($expression)?$true:$false;

The value of "$var" will be set to either the value of "$true" or "$false" depending upon whether the value of "$expression" is true or false. It could also be written as:

Code:


if($expression === TRUE){ $var = $true; }

else{ $var = $false }

We've checked our $_GET variables and made sure that they are set (either to an empty string, or their real value) and we need to take those lines and put them just above our object instantiation line:

Code:


<?php
  $_GET['cat'] = (!isset($_GET['cat']))?'':$_GET['cat'];
  $_GET['evt'] = (!isset($_GET['evt']))?'':$_GET['evt'];
  $_GET['pic'] = (!isset($_GET['pic']))?'':$_GET['pic'];

  $pix = new PhotoGallery();
  $pix->get_items($_GET['cat'], $_GET['evt'], $_GET['pic']);
?>

The code that now lies between the <table> tags should look like the following:

Code:


<table>
  <?php
    $_GET['cat'] = (!isset($_GET['cat']))?'':$_GET['cat'];
    $_GET['evt'] = (!isset($_GET['evt']))?'':$_GET['evt'];
    $_GET['pic'] = (!isset($_GET['pic']))?'':$_GET['pic'];

    $pix = new PhotoGallery();
    $pix->get_items($_GET['cat'], $_GET['evt'], $_GET['pic']);
  ?>
</table>

The entire "photos.php" should look like:

Code For: photos.php


<?php
require_once('class.photogallery.php');
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> PHP Image Gallery </TITLE>
<META NAME="Generator" CONTENT="EditPlus">
<META NAME="Author" CONTENT="Brett Patterson">
<META NAME="Keywords" CONTENT="PHP Image Gallery PHPBuilder Builder">
<META NAME="Description" CONTENT="A simple PHP Builder Article overviewing an Image Gallery">
<link type="text/css" rel="stylesheet" href="phpbstyle.css">
</HEAD>

<BODY>
<div id="wrap">
  <div id="header">
    <img src="images/site/phpb_logo.gif">
    <span class="tag">Image Gallery for PHP Builder</span>
  </div>
  <div id="main">
    <p>
      <table>
        <?php
        // Set defaults for the $_GET array
        $_GET['cat'] = (!isset($_GET['cat']))?'':$_GET['cat'];
        $_GET['evt'] = (!isset($_GET['evt']))?'':$_GET['evt'];
        $_GET['pic'] = (!isset($_GET['pic']))?'':$_GET['pic'];

        $pix = new PhotoGallery();
        $pix->get_items($_GET['cat'], $_GET['evt'], $_GET['pic']);
        ?>
      </table>
    </p>
  </div>
  <div id="clear"></div>
</div>
</BODY>
</HTML>

Let's get our class working so we can view some photos!!

Into the Class
Thus far we've got a pretty solid base to stand on. We have a layout, and we have checked to make sure that the $_GET items that are passed to the class are proper (i.e. either set or an empty string). We've also set the name of our class and its first function. The name of our class will be "PhotoGallery". We already know this because it's what we put in our "photos.php" script. Let's start off with a standard class declaration:

Code For: class.photogallery.php


<?php

class PhotoGallery
{
}

?>

Here we define our class. We have our first function (that we know of) called "get_items()" which has all the $_GET variables sent to it. You can think of the function get_items as the stepping stone for the rest of the class. Everything will always start there. In the class, we define the function as we normally would:

Code:


<?php

class PhotoGallery
{
  function get_items($cat='', $evt='', $pic='')
  {
  }
}

?>

We've got our function in the PhotoGallery class. Before we move any further, we need to set some things ready. We need to define some variables that will be used throughout the class. If we define a variable inside a function, then it is local to that function, and you can't use it outside of the function (unless you globalize it). So instead, we're going to make our own global class variables that can be used anywhere in the class at any point in time. Let's think about what information we need, and what we need to store:

    * Root Photo Directory
    * Root Icon Directory
    * Array of all our files
    * Any output we have
    * Any error messages
    * Whether we want to run in Debug Mode
    * Number of photos (columns) across before we start a new row

Simple enough. We just need to declare these variables, and they are easily declared as like so:

Code:


<?php

class PhotoGallery
{
  ###############
  ## Varaibles ##
  ###############
  var $_rt = 'images/photos/'; // Where the base "root" of our photos are
  var $ico = 'images/icons/'; // Where our icons will be held
  var $lst = array(); // Will hold our list of files (or directories)
  var $out = ''; // What will be outputted/displayed to the user
  var $err = ''; // Holds errors that are encountered along the way
  var $dbg = FALSE; // Defines whether debug mode is "on" (TRUE) or "off" (FALSE)
  var $cols = 5; // How many columns there will be across

  ###############
  ## Functions ##
  ###############
  function get_items($cat, $evt, $pic)
  {
  }
}

?>

We have some class global variables and we can reference them and their values at any point in time anywhere in the class. We do this by using the following syntax:

Code:


$this->variable

If I wanted to echo the root photo directory ($_rt) I would do so in this way:

$this->_rt
The "$this->" operator defines that the variable has a global scope from within the current class. This is just a part of Object Oriented Programming. Any time you reference any of the variables listed under the Variables heading at the top, it needs to have "$this->" in place of the normal "$".
So the fun part over--let's get into this "get_items" function. Basically, we want to loop through a directory and return all the files or directories there are to choose from. If each of the three variables are empty, then we want to loop through the root photo directory to get the categories. If the $cat variable is populated, then we want to loop through that directory to get each event. If both the $cat and $evt variables are populated, then we need to loop through to find all the images to display. And finally if all three variables are populated, then we need to retrieve the picture that is specified and display that.
It sounds like a lot, but once the first one is done, it's just repititious. Here's the code used to loop through a directory:

Code:


// Display all categories to choose from
$path = $this->_rt;
$d = @dir($path);
if(!$d){
  // If we can't open the directory, let's tell the user
  // something is wrong.
  $this->throw_error('Fatal Error', 'The directory
[ <i><span style="color: #999;">'.$path.'</span></i> ]
could not be opened.  Please check the path and try again.',
$php_errormsg, $this->dbg);
}
else{
  while(FALSE !== ($f = $d->read())){
    // While we are reading documents from within the directory
    if($f != '.' && $f != '..'){
      // If the currently read file is not "this directory" or "Up One Level"
      if(is_dir($path.$f)){
        // Since we're dealing with categories, we only want directories
        // since the directory name will be categories
        $this->lst[] = $f;
      }
    }
  }
  $this->gen_crumbs();
  $this->gen_page();
}

There are a couple of things you may notice: we added a few new functions, and we put a list of all directories into the "lst" global class variable. We are using the "dir" object to read a directory for its contents. All of the loops are the same with two minor differences. In the thumbnail loop (when $cat & $evt are populated) we look for files (not directories), and in the display pic loop (when all three variables are populated) we just want a loop for a reference point, so we don't need to generate the thumbnails. Since they're all so close in code, I'll give them to you.

They are housed with a few IF() ELSE() statements to find out whether we need to look for directories or images. It's pretty easy to understand, and I've documented it as well:
Code For: get_items()


function get_items($cat = '', $evt = '', $pic = ''){
  // Gets all of our items in our folder
  if($pic == ''){
    if($evt == ''){
      if($cat == ''){
        // Display all categories to choose from
        $path = $this->_rt;
        $d = @dir($path);
        if(!$d){
          // If we can't open the directory, let's tell the user
          // something is wrong.
          $this->throw_error('Fatal Error', 'The directory
[ <i><span style="color: #999;">'.$path.'</span></i> ]
could not be opened.  Please check the path and try again.',
$php_errormsg, $this->dbg);
        }
        else{
          while(FALSE !== ($f = $d->read())){
            // While we are reading documents from within the directory
            if($f != '.' && $f != '..'){
              // If the currently read file is not "this directory" or "Up One Level"
              if(is_dir($path.$f)){
                // Since we're dealing with categories, we only want directories
                // since the directory name will be categories
                $this->lst[] = $f;
              }
            }
          }
          $this->gen_crumbs();
          $this->gen_page();
        }
      }
      else{
        // Display all events to choose from
        $path = $this->_rt.$cat.'/';
        $d = @dir($path);
        if(!$d){
          $this->throw_error('Fatal Error', 'The directory
[<i><span style="color: #999;">'.$path.'</span></i> ]
could not be opened.  Please check the path and try again.',
$php_errormsg, $this->dbg);
        }
        else{
          while(FALSE !== ($f = $d->read())){
            if($f != '.' && $f != '..'){
              if(is_dir($path.$f)){
                $this->lst[] = $f;
              }
            }
          }
          $this->gen_crumbs($cat);
          $this->gen_page($cat);
        }
      }
    }
    else{
      // Display all thumbs to choose from
      $path = $this->_rt.$cat.'/'.$evt.'/';
      $d = @dir($path);
      if(!$d){
        $this->throw_error('Fatal Error', 'The directory
[ <i><span style="color: #999;">'.$path.'</span></i> ]
could not be opened.  Please check the path and try again.',
$php_errormsg, $this->dbg);
      }
      else{
        while(FALSE !== ($f = $d->read())){
          if($f != '.' && $f != '..' && !is_dir($path.$f)){
            if($this->check_img($path.$f)===TRUE){
              $this->lst[] = $f;
            }
          }
        }
        $this->gen_crumbs($cat, $evt);
        $this->gen_thumbs($cat, $evt);
      }
    }
  }
  else{
    // Generate a list of files within the directory
    $path = $this->_rt.$cat.'/'.$evt.'/';
    $d = @dir($path);
    while(FALSE !== ($f = $d->read())){
      if($f != '.' && $f != '..' && !is_dir($path.$f)){
        // This time, we're only getting all the image files from within our path.
        // This is to help us create the "next" and "previous" links.
        if($this->check_img($path.$f)===TRUE){
          $this->lst[] = $f;
        }
      }
    }
    $this->gen_crumbs($cat, $evt, $pic);
    // Get the proper image to display
    $this->gen_pic($cat, $evt, $pic);
  }
}

Now we can move on to all the other functions we need!! Be sure to come back next week for the rest of this tutorial!