This is a personal project for my portfolio and also to show
family pictures to my friends and family online. I do have an account
with flickr and picasa but I just love having my own personal gallery.
I'm going to add functionality in the future to allow the gallery to
read feeds from those photo services.
You just basically create a folder and place all your pictures in
there and then point the Photo Gallery config.php file to read this
folder and voila! Instant photo gallery :) a drop down navigation
is provided, similar to nautilus and Windows 7 explorer style. Images
are preloaded using javascript and thumbnails are generated on the fly.
It uses the built in GD library for generating thumbnails and can be
configured to use a different script with a different library if needed.
The gallery uses PHP SPL Directory Iterators and it also uses lightview
for displaying images and a slideshow. It uses ajax when switching between
pages.
Click here to see a demo of my PHP Photo Gallery.
config.php
<?php
define ('APP_PATH', realpath(dirname(__FILE__)) );
define ('APP_URL', "http://hbalagtas.0fees.net");
define ('THUMBNAIL_SCRIPT', "thumbnailgd.php");
define ('VIEW_SCRIPT', "view.php");
define ('THUMBNAIL_PATH', APP_PATH.'/thumbnails/');
#define ('THUMBNAIL_PATH', '/tmp/');
define ('THUMBNAIL_WIDTH', 150);
define ('THUMBNAIL_HEIGHT', 100);
define ('LOCAL_GALLERY_PATH', APP_PATH.'/');
define ('GALLERY_ROOT', 'PhotoGallery');
define('IMAGE_PER_PAGE', 8);
define('ALBUM_TITLE', "Bing's Photo Gallery");
myfunctions.php
<?php
/**
* Functions that I use in the gallery
*
* @author Herbert Balagtas
*
*/
include_once ('config.php');
/**
* Get the files and directories from a given path, returns them as
* an array, ust list($dir, $files) = getDirElements($path)
* @param string $localpath
* @return array $dir, $files
*/
function getDirElements($localpath){
try{
$localpath = stripslashes($localpath);
$dirIterator = new DirectoryIterator("$localpath");
} catch (UnexpectedValueException $u){
header("Location: .");
}
foreach ($dirIterator as $node){
if ( $node->isFile() && isImage($node->getFilename()) ) {
$files[] = $node->getFilename();
}
if ( $node->isDir() && !$node->isDot()) {
$dirs[] = $node->getFilename();
}
}
@sort($dirs);
@sort($files);
return array($dirs, $files);
}
/**
* checks if a filename has an image extensions
*
* @param string $file
* @return boolean
*/
function isImage($file){
if (eregi ("(.)+\\.(jp(e){0,1}g$|png$|jpeg$|gif$)", $file))
return true;
else
return false;
}
/**
* Drop down navigation from path
*
* @param string $dir
* @return string
*/
function jumpnav($dir){
$localpath = LOCAL_GALLERY_PATH;
$patharray = explode('/',$dir);
$jumpdir = array();
foreach ($patharray as $pathmember){
$localpath .= $pathmember . '/';
$jumpdir[] = $pathmember;
$prevpath = implode('/',$jumpdir);
$dh = new DirectoryIterator($localpath);
$jumpurl = '';
$options = '';
$dir_array = array();
foreach($dh as $item){
if ($item->isDir() && !$item->isDot() ){
$dir_array[] = $item->getFilename();
}
}
sort($dir_array);
foreach($dir_array as $item){
#if ($item->isDir() && !$item->isDot() ){
#$jumpurl = implode('/',$jumpdir) . '/' . $item->getFilename();
$jumpurl = implode('/',$jumpdir) . '/' . $item;
$selected = '';
$indicator = '';
if (preg_match('/'.escape_string_for_regex($jumpurl).'$/', $dir) ||
preg_match('/'.escape_string_for_regex($jumpurl).'\//', $dir)
)
{
$selected = 'selected="selected"';
$indicator = '>>';
}
$jumpurl = encode_string($jumpurl);
#$options .= '<option value="?path='.$jumpurl.'" '. $selected .'>'.$indicator.$item->getFilename().'</option>' . "\n";
$options .= '<option value="?path='.$jumpurl.'" '. $selected .'>'.$indicator.$item.'</option>' . "\n";
#}
}
if ( $options !== "" ) {
$dropdata .= '<form name="form'.$ctr.'" style="margin:0;padding:0;display:inline;">' . "\n";
$dropdata .= '<select name="fieldname" id="subpath" onChange="openDir( this.form )">' . "\n";
if ( $ctr == $subdircnt ) {
$options = '<option value="?path='.urlencode($prevpath).'" label="" width="50">Main Folder</option>' . $options;
}
$dropdata .= $options;
$dropdata .= '</select>' . "\n";
$dropdata .= '</form>' . "\n";
} // end if $options
}
$dropdata = '<div class="gallery_nav">Gallery Navigation: '. $dropdata . '</div>';
return $dropdata;
}
/**
* Escapes string to be used in a regular expression function
* @param string $str
* @return string
*/
function escape_string_for_regex($str)
{
//All regex special chars (according to arkani at iol dot pt below):
$patterns = array('/\//', '/\^/', '/\./', '/\$/', '/\|/', '/\(/', '/\)/', '/\[/', '/\]/', '/\*/', '/\+/', '/\?/', '/\{/', '/\}/', '/\,/', '/\ /');
$replace = array('\/', '\^', '\.', '\$', '\|', '\(', '\)', '\[', '\]', '\*', '\+', '\?', '\{', '\}', '\,', '\\ ');
return preg_replace($patterns,$replace, $str);
}
/**
* quickly resizes and image
*/
// FROM PHP.NET
function fastimagecopyresampled (&$dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h, $quality = 2) {
// Plug-and-Play fastimagecopyresampled function replaces much slower imagecopyresampled.
// Just include this function and change all "imagecopyresampled" references to "fastimagecopyresampled".
// Typically from 30 to 60 times faster when reducing high resolution images down to thumbnail size using the default quality setting.
// Author: Tim Eckel - Date: 09/07/07 - Version: 1.1 - Project: FreeRingers.net - Freely distributable - These comments must remain.
//
// Optional "quality" parameter (defaults is 3). Fractional values are allowed, for example 1.5. Must be greater than zero.
// Between 0 and 1 = Fast, but mosaic results, closer to 0 increases the mosaic effect.
// 1 = Up to 350 times faster. Poor results, looks very similar to imagecopyresized.
// 2 = Up to 95 times faster. Images appear a little sharp, some prefer this over a quality of 3.
// 3 = Up to 60 times faster. Will give high quality smooth results very close to imagecopyresampled, just faster.
// 4 = Up to 25 times faster. Almost identical to imagecopyresampled for most images.
// 5 = No speedup. Just uses imagecopyresampled, no advantage over imagecopyresampled.
if (empty($src_image) || empty($dst_image) || $quality <= 0) { return false; }
if ($quality < 5 && (($dst_w * $quality) < $src_w || ($dst_h * $quality) < $src_h)) {
$temp = imagecreatetruecolor ($dst_w * $quality + 1, $dst_h * $quality + 1);
imagecopyresized ($temp, $src_image, 0, 0, $src_x, $src_y, $dst_w * $quality + 1, $dst_h * $quality + 1, $src_w, $src_h);
imagecopyresampled ($dst_image, $temp, $dst_x, $dst_y, 0, 0, $dst_w, $dst_h, $dst_w * $quality, $dst_h * $quality);
imagedestroy ($temp);
} else imagecopyresampled ($dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h);
return true;
}
/**
* Open Image
* @param unknown_type $file
* @return unknown_type
*/
function open_image ($file) {
// Get extension
$extension = strrchr($file, '.');
$extension = strtolower($extension);
switch($extension) {
case '.jpg':
case '.jpeg':
$im = @imagecreatefromjpeg($file);
break;
case '.gif':
$im = @imagecreatefromgif($file);
break;
case '.png':
$im = @imagecreatefrompng($file);
break;
// ... etc
default:
$im = false;
break;
}
return $im;
}
function implode_dir($array){
foreach ($array as $a){
$b .= $a . (substr($a, -1) == '/'?'':'/');
}
$b = substr($b, 0, -1);
return $b;
}
/**
* Encodes a string to be used as a url parameter
* @param unknown_type $str
*/
function encode_string($str){
$str = htmlentities($str, ENT_QUOTES);
$str = urlencode($str);
return $str;
}
/**
* Decode a string passed from a url
* @param String $str
*/
function decode_string($str){
$str = html_entity_decode($str, ENT_QUOTES);
$str = stripslashes(urldecode($str));
return $str;
}
phpgallery.php
<?php
/**
* PHP Gallery
*
* Uses GD to create a gallery from a directory structure
*
* @author Herbert Balagtas
*
*/
error_reporting(0);
include('../cache_start.php');
#define ( 'APP_PATH', realpath ( dirname ( __FILE__ ) ) );
include_once ('config.php');
include_once ('myfunctions.php');
$time_start = microtime_float ();
// if no path is passed to the script use default path
if (! empty ( $_GET ['path'] ) && isset ( $_GET ['path'] ) && ! preg_match ( '/(^\/|\.\.\/)/', decode_string ( $_GET ['path'] ) )) {
$path = decode_string ( $_GET ['path'] );
$localpath = implode_dir ( array (LOCAL_GALLERY_PATH, $path ) );
} else {
$localpath = implode_dir ( array (LOCAL_GALLERY_PATH, GALLERY_ROOT ) );
$path = GALLERY_ROOT;
}
list ( $dirs, $files ) = getDirElements ( $localpath );
$navigation = jumpnav ( $path );
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>Photo Gallery DEMO - Herbert Balagtas - Online Portfolio</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" type="text/css" href="gallery.css" />
<script type='text/javascript' src='js/prototype.js'></script>
<script type='text/javascript' src='js/scriptaculous/scriptaculous.js'></script>
<script type='text/javascript' src='js/scriptaculous/effects.js'></script>
<script type='text/javascript' src='lightview/js/lightview.js'></script>
<link rel="stylesheet" type="text/css"
href="lightview/css/lightview.css" />
<script type="text/javascript">
<!--
<?php
// Load the first page thumbnails
if (! empty ( $files )) {
$imgctr = 0;
echo 'document.observe("dom:loaded", function() {' . "\n";
echo '$$(\'#page1 img[src="file.png"]\').invoke(\'onmouseover\');' . "\n";
echo '});' . "\n";
}
?>
// Shows and hides pages
function togglePage(pagectr){
$$('.page').invoke('hide');
//$$(pagectr).invoke('hide');
//$$(pagectr).invoke('show');
//alert('test');
$$(pagectr + ' img[src="file.png"]').invoke('onmouseover');
}
// checks to see if the crawler is running
function protoUpdater(){
var crawler_running = 'no';
new Ajax.PeriodicalUpdater('result', 'crawlerprogress.php',
{
method: 'get',
frequency: 3,
decay: 2,
onSuccess: function(transport) {
if ( transport.responseText.match(/Crawler\ is\ idle/) ){
// do nothing
} else {
crawler_running = 'yes';
}
if (crawler_running == 'yes' && transport.responseText.match(/Crawler\ is\ idle/) ){
location.reload(true);
crawler_running = 'no';
}
}
});
}
// used by the drop down navigation
function openDir( form ) {
var newIndex = form.fieldname.selectedIndex;
cururl = form.fieldname.options[ newIndex ].value;
window.location.assign( cururl );
}
// preloads and shows an image
function showThumb(ImageID, ThumbUrl){
imgDir = getImgDirectory(document.getElementById(ImageID).src);
if (document.getElementById(ImageID).src == imgDir + 'file.png' ){
var img = document.createElement('img');
img.onload = function (evt) {
document.getElementById(ImageID).src=this.src;
}
document.getElementById(ImageID).src= imgDir + 'ajax-loader.gif';
img.src = ThumbUrl;
}
return false;
}
/*********************************************
Name : getImgDirectory
Parameters : Image source path
Return : Image source Directory
Author : Jean-Michel Garnier
***********************************************/
function getImgDirectory(source) {
return source.substring(0, source.lastIndexOf('/') + 1);
}
//-->
</script>
</head>
<body>
<h1><?php
echo ALBUM_TITLE;
?></h1>
<a href="../">Home</a>
<hr />
<?php
echo $navigation;
?>
<br />
<?php
$gallery = '';
$totalpage = 0;
$pages = '';
$gallery .= '<div id="gallery">';
if (! empty ( $files )) {
$imgpp = 10;
$imgtotal = count ( $files );
$gallery .= 'Album: ' . $path;
$gallery .= ' :: Total files: ' . $imgtotal . "<br /> \n";
$totalpage = ceil ( $imgtotal / IMAGE_PER_PAGE );
$imgonpage = 0;
$imgctr = 0;
$pagectr = 1;
$ctr = 0;
$idx = 0;
foreach ( $files as $file ) {
if ($imgonpage == 0) {
$gallery .= '<div class="page" id="page' . $pagectr . '" ' . ($pagectr > 1 ? 'style="display:none;"' : '') . '>' . "\n";
$gallery .= '<a name="page' . $pagectr . '" />';
}
$id = crc32 ( $file );
$gallery .= '<div class="thumbnail">' . "\n";
$gallery .= '<a href="' . VIEW_SCRIPT . '?filename=' . encode_string ( $file ) . '&path=' . encode_string ( $path ) . '&height=800" class="lightview" rel="gallery[myset400]" title="' . $file . ' :: :: slideshow: true" id="link' . $id . '">' . "\n";
$imgsrc = THUMBNAIL_SCRIPT . '?filename=' . encode_string ( $file ) . '&path=' . encode_string ( $path );
$ctr ++;
if ($ctr <= IMAGE_PER_PAGE) {
$gallery .= '<img id="' . $id . '" src="' . $imgsrc . '" border="0" alt="'.$file.'"/>' . "\n";
#$gallery .= '<img id="'.$id.'" src="file.png" border="0" onmouseover="showThumb(\''.$id.'\',\''.$imgsrc.'\');"/>' . "\n";
} else {
$gallery .= '<img id="' . $id . '" src="file.png" border="0" onmouseover="showThumb(\'' . $id . '\',\'' . $imgsrc . '\');"/>' . "\n";
}
$gallery .= '</a>' . "\n";
$gallery .= '<br />' . $file;
$gallery .= '</div>' . "\n";
$imgonpage ++;
$imgctr ++;
if ($imgonpage >= IMAGE_PER_PAGE || $imgctr >= $imgtotal) {
$gallery .= '<br clear="all" />';
$gallery .= 'Page ' . $pagectr;
$gallery .= '</div>' . "\n";
$pager [] = '<a href="#page' . ($pagectr) . '" class="pageno" onclick="togglePage(\'#page' . $pagectr . '\');$(\'page' . $pagectr . '\').appear({ duration: 1.5, from: 0, to: 1 });">' . $pagectr . '</a>' . "\n";
if (count ( $pager ) >= 20 || $imgctr >= $imgtotal) {
$multipage [] = $pager;
$pager = array ();
}
$pagectr ++;
$imgonpage = 0;
}
}
} else {
$gallery .= 'No files found in: ' . $path;
$gallery .= '<br clear="all" />';
if (! empty ( $dirs )) {
foreach ( $dirs as $dir ) {
$pathsrc = urlencode ( $path . '/' . $dir );
$gallery .= '<a href="?path=' . $pathsrc . '" class="folder">' . $dir . '</a>';
}
} else {
$gallery .= 'No sub album for this album.';
}
}
$gallery .= '</div>';
if ($totalpage > 1) {
#$pages .= '<br />';
#$pages .= '<br clear="all" />' . "\n";
#$pages .= '<hr />' . "\n";
$pages .= '<div id="pager">' . "\n";
foreach ( $multipage as $mp ) {
$pages .= implode ( '', $mp );
$pages .= '<br clear="all"/>';
}
$pages .= '</div>';
}
echo $pages;
echo '<br clear="all"/>';
echo $gallery;
echo '<br clear="all"/>';
echo '<br clear="all"/>';
echo $pages;
echo '<br clear="all"/>';
echo $navigation;
$time_end = microtime_float ();
$time = $time_end - $time_start;
echo '<br clear="all" />';
echo '<hr />';
echo "Script Execution time $time seconds\n";
?>
</body>
</html>
<?php include('../cache_end.php'); ?>