<?php
/* ---------------------------------------------------------------------------
ImgBrowz0r, a simple PHP5 Gallery class
Version 0.2.2, September 26th, 2008
http://61924.wepwnyou.net/projects/imgbrowz0r.html
Copyright (c) 2008 Frank Smit
License: http://www.gzip.org/zlib/zlib_license.html
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
--------------------------------------------------------------------------- */
define('IMGBROWZ0R_VERSION', '0.2.2');
class imgbrowz0r
{
public $cur_category, $cur_category_name;
private $cur_category_encoded, $config, $display=false;
static public $supported_image_types = array(1 => 'gif', 2 => 'jpg', 3 => 'png');
// The constructor
public function __construct($config)
{
// First check if GD is enabled
if (!extension_loaded('gd') && !function_exists('gd_info'))
exit('<a href="http://www.php.net/manual/en/book.image.php">GD</a> is not enabled!');
// Set configuration
$this->config = array(
// Gallery settings - Note that 'basefile' and 'gallery_dir' are required
'basefile' => isset($config['basefile']) ? $config['basefile'] : exit('You have to set a basefile!'),
'gallery_dir' => isset($config['gallery_dir']) ? $config['gallery_dir'] : exit('You have to set a path to your gallery folder!'),
'thumbs_per_page' => isset($config['thumbs_per_page']) ? $config['thumbs_per_page'] : 12,
'max_thumb_row' => isset($config['max_thumb_row']) ? $config['max_thumb_row'] : 4,
// Thumbnail settings
'max_thumb_width' => isset($config['max_thumb_width']) ? $config['max_thumb_width'] : 200,
'max_thumb_height' => isset($config['max_thumb_height']) ? $config['max_thumb_height'] : 200,
'no_thumb_image' => isset($config['no_thumb_image']) ? $config['no_thumb_image'] : 'no-thumbnail.png',
// Template settings
'category_template' => isset($config['category_template']) ? $config['category_template'] : '<a class="thumb" href="%URL%" title="%NAME%"><img src="%THUMB%" alt="%NAME%" /></a><div class="title">%NAME%</div><div class="date">%CREATION_TIME%</div>',
'thumb_template' => isset($config['thumb_template']) ? $config['thumb_template'] : '<a class="thumb" href="%URL%" title="%NAME%"><img src="%THUMB%" alt="%NAME%" /></a><div class="date">%UPLOAD_TIME%</div>',
// Time settings
'time_format' => isset($config['time_format']) ? $config['time_format'] : 'd-m-Y H:i:s',
'time_zone' => isset($config['time_zone']) ? $config['time_zone'] : 0
);
// Set vars
$this->cur_category = isset($_GET['c']) ? ereg_replace('[^A-Za-z0-9,_ -()]','', self::base64_url_decode($_GET['c'])) : false;
$this->cur_category_encoded = $this->cur_category !== false ? ereg_replace('[^A-Za-z0-9,_ -()]','', $_GET['c']) : false;
$this->cur_category_name = $this->cur_category !== false ? $this->get_cat_name($this->cur_category) : false;
}
public function display()
{
if ($this->display === false)
{
$output = '';
if ($this->cur_category !== false)
$output .= $this->view_images();
else
$output .= $this->view_categories();
echo '<div id="imgbrowz0r">'."\n\n".$output."\n\n".'</div>';
$this->display = true;
}
}
// Fetch categories
private function view_categories()
{
$output = '';
$total_count = 0;
$page_links = '';
$categories = array();
$temp_categories = glob($this->config['gallery_dir'].'*', GLOB_ONLYDIR);
// Check if there are categories
if (count($temp_categories) < 1)
return '<p class="info">There are currently no categories in this gallery.</p>';
// Gather info
foreach ($temp_categories as $category)
{
$total_count += $category_images = count(array_merge(glob($category.'/*.jpg'), glob($category.'/*.png'), glob($category.'/*.gif')));
if ($category_images > 0)
{
$category_thumbs = array_merge(glob($category.'/thumbs/*.jpg'), glob($category.'/thumbs/*.png'), glob($category.'/thumbs/*.gif'));
$category_thumbs_count = count($category_thumbs);
$this_category_name = $this->get_cat_name($category);
$categories[] = array(
'thumb' => !empty($category_thumbs_count) ? $category_thumbs[mt_rand(0, $category_thumbs_count-1)] : $this->config['no_thumb_image'],
'name' => $this_category_name,
'url' => $this->config['basefile'].'?c='.self::base64_url_encode(basename($category)),
'creation_time' => filectime($category)
);
}
}
// Check if there are images
if ($total_count === 0)
return '<p class="info">There are currently no categories in this gallery.</p>';
// Sorting
if (($category_count = count($categories)) > 0)
{
foreach($categories as $res) $sortAux[] = $res['creation_time'];
array_multisort($sortAux, SORT_DESC, $categories);
}
// Gallery info
$output .= "\n\t".'<p class="info">'.($category_count == 1 ? 'There is '.$category_count.' category' : 'There are '.$category_count.' categories').' in this gallery and a total of '.$total_count.' images.</p>'."\n";
// Pagination
$page_count = ceil($category_count / $this->config['thumbs_per_page']);
$start_img = isset($_GET['p']) && intval($_GET['p']) <= $page_count ? (intval($_GET['p'])-1) * $this->config['thumbs_per_page'] : 0;
$end_img = ($start_img+$this->config['thumbs_per_page']) <= $category_count ? $start_img+$this->config['thumbs_per_page'] : $category_count;
for($p=1;$p <= $page_count;$p++)
{
if (isset($_GET['p']) && $p == intval($_GET['p']) || ($start_img == '0' && $p == 1))
$page_links .= '<a href="'.$this->config['basefile'].'?p='.$p.'"><strong>'.$p.'</strong></a>'.($p != $page_count ? ' · ' : '');
else
$page_links .= '<a href="'.$this->config['basefile'].'?p='.$p.'">'.$p.'</a>'.($p != $page_count ? ' · ' : '');
}
if ($page_count > 1)
$output .= "\n\t".'<p class="pagination">Pages: '.$page_links.'</p>'."\n";
$output .= "\n\t".'<table>'."\n\t\t".'<tr>';
$row_count = 1;
for($x=$start_img;$x < $end_img;$x++)
{
$output .= "\n\t\t\t".'<td>'."\n\t\t\t\t".'<div id="cat-'.$x.'">'.strtr($this->config['category_template'], array('%THUMB%' => $categories[$x]['thumb'], '%NAME%' => $categories[$x]['name'], '%URL%' => $categories[$x]['url'], '%CREATION_TIME%' => $this->format_time($categories[$x]['creation_time']))).'</div>'."\n\t\t\t".'</td>';
if ($row_count == $this->config['max_thumb_row'] && ($x+1) < $end_img)
{
$output .= "\n\t\t".'</tr>'."\n\t\t".'<tr>';
$row_count = 0;
}
$row_count++;
}
$output .= "\n\t\t".'</tr>'."\n\t".'</table>'."\n";
// Pagination
if ($page_count > 1)
$output .= "\n\t".'<p class="pagination">Pages: '.$page_links.'</p>'."\n";
return '<div id="categories">'.$output.'</div>';
}
// Fetch images
private function view_images()
{
$output = NULL;
$page_links = NULL;
$cur_category_path = $this->config['gallery_dir'].$this->cur_category;
// Check if category exists
if (!is_dir($cur_category_path))
return '<p class="info">Category does not exist. Click <a href="'.$this->config['basefile'].'">here</a> to go back to the category overview.</p>';
$opendir = opendir($cur_category_path);
while (false !== ($image = readdir($opendir)))
{
// get file extension
$file_extension = self::get_ext($cur_category_path.'/'.$image);
// Check if file is an supported image type
if (!in_array($file_extension, self::$supported_image_types))
continue;
$images[] = array(
'thumb' => $cur_category_path.'/thumbs/thumb_'.$image,
'name' => $image,
'url' => $cur_category_path.'/'.$image,
'upload_time' => filectime($cur_category_path.'/'.$image)
);
}
// Check if there are images in the current category
if (($image_count = count($images)) < 1)
return '<p class="info">There are currently no images in this category. Click <a href="'.$this->config['basefile'].'">here</a> to go back to the category overview.</p>';
// Sorting
foreach($images as $res) $sortAux[] = $res['upload_time'];
array_multisort($sortAux, SORT_DESC, $images);
// Category info
$output .= "\n\t".'<p class="info">You are viewing <strong>'.$this->cur_category_name.'</strong>, <a href="'.$this->config['basefile'].'">click here</a> to go back. There are '.$image_count.' images in this category.</p>'."\n";
// Pagination
$page_count = ceil($image_count / $this->config['thumbs_per_page']);
$start_img = isset($_GET['p']) && intval($_GET['p']) <= $page_count ? (intval($_GET['p'])-1) * $this->config['thumbs_per_page'] : 0;
$end_img = ($start_img+$this->config['thumbs_per_page']) <= $image_count ? $start_img+$this->config['thumbs_per_page'] : $image_count;
for($p=1;$p <= $page_count;$p++)
{
if (isset($_GET['p']) && $p == intval($_GET['p']) || ($start_img == '0' && $p == 1))
$page_links .= '<a href="'.$this->config['basefile'].'?c='.$this->cur_category_encoded.'&p='.$p.'"><strong>'.$p.'</strong></a>'.($p != $page_count ? ' · ' : '');
else
$page_links .= '<a href="'.$this->config['basefile'].'?c='.$this->cur_category_encoded.'&p='.$p.'">'.$p.'</a>'.($p != $page_count ? ' · ' : '');
}
if ($page_count > 1)
$output .= "\n\t".'<p class="pagination">Pages: '.$page_links.'</p>'."\n";
$output .= "\n\t".'<table>'."\n\t\t".'<tr>';
// Build image table
$row_count = 1;
for($x=$start_img;$x < $end_img;$x++)
{
// Make thumbnail if there isn't one
if (!file_exists($images[$x]['thumb']))
$this->make_thumb($cur_category_path, $images[$x]['name']);
$output .= "\n\t\t\t".'<td>'."\n\t\t\t\t".'<div id="img-'.$x.'">'.str_replace(array('%THUMB%', '%NAME%', '%URL%', '%UPLOAD_TIME%'), array($images[$x]['thumb'], $images[$x]['name'], $images[$x]['url'], $this->format_time($images[$x]['upload_time'])), $this->config['thumb_template']).'</div>'."\n\t\t\t".'</td>';
if ($row_count == $this->config['max_thumb_row'] && ($x+1) < $end_img)
{
$output .= "\n\t\t".'</tr>'."\n\t\t".'<tr>';
$row_count = 0;
}
$row_count++;
}
$output .= "\n\t\t".'</tr>'."\n\t".'</table>'."\n";
// Pagination
if ($page_count > 1)
$output .= "\n\t".'<p class="pagination">Pages: '.$page_links.'</p>'."\n";
return '<div id="images">'.$output.'</div>';
}
// Get name of category, patch provided by Serge Timakov
private function get_cat_name($category)
{
$category = basename($category);
$category_name_file = $this->config['gallery_dir'].$category.'/.name';
if (file_exists($category_name_file))
return htmlspecialchars(file_get_contents($category_name_file), ENT_QUOTES, 'UTF-8');
else
return $category;
}
// Checks and prepares the source image and makes a thumbnail of it
private function make_thumb($image_folder, $image_name)
{
$no_resize = false;
//Check if thumb dir exists
if (!is_dir($image_folder.'/thumbs'))
mkdir($image_folder.'/thumbs', 0777);
// Get image information
$image_info = self::get_image_info($image_folder.'/'.$image_name);
// Check if file is an supported image type
if (!in_array($image_info['extension'], self::$supported_image_types))
return false;
// Open the image so we can make a thumbnail
if ($image_info['type'] == 3)
$image = imagecreatefrompng($image_folder.'/'.$image_name);
else if ($image_info['type'] == 2)
$image = imagecreatefromjpeg($image_folder.'/'.$image_name);
else if ($image_info['type'] == 1)
$image = imagecreatefromgif($image_folder.'/'.$image_name);
else
return false;
// Calculate new width and height
if ($image_info['height'] > $image_info['width'])
{
$thumb_width = floor($image_info['width'] * ($this->config['max_thumb_height'] / $image_info['height']));
$thumb_height = $this->config['max_thumb_height'];
}
else if ($image_info['width'] > $image_info['height'])
{
$thumb_width = $this->config['max_thumb_width'];
$thumb_height = floor($image_info['height'] * ($this->config['max_thumb_width'] / $image_info['width']));
}
else if ($image_info['width'] == $image_info['height'] && $image_info['width'] > $this->config['max_thumb_width'])
{
$thumb_width = $this->config['max_thumb_width'];
$thumb_height = $this->config['max_thumb_height'];
}
else
{
$thumb_width = $image_info['width'];
$thumb_height = $image_info['height'];
$no_resize = true;
}
// Copy image into new one
if ($no_resize === false)
{
$thumbnail = imagecreatetruecolor($thumb_width, $thumb_height);
// Preserve transparency in PNG and GIF images
if ($image_info['type'] === 3)
{
imagealphablending($thumbnail, false);
imagesavealpha($thumbnail, true);
}
else if ($image_info['type'] === 1 && ($transparent_index = imagecolortransparent($image)) >= 0)
{
imagepalettecopy($image, $thumbnail);
imagefill($thumbnail, 0, 0, $transparent_index);
imagecolortransparent($thumbnail, $transparent_index);
imagetruecolortopalette($thumbnail, true, 256);
}
imagecopyresampled($thumbnail, $image, 0, 0, 0, 0, $thumb_width, $thumb_height, $image_info['width'], $image_info['height']);
}
else
$thumbnail = $image;
// Save the thumbnail, but first check what kind of file it is
if ($image_info['type'] == 3)
imagepng($thumbnail, $image_folder.'/thumbs/thumb_'.$image_name);
else if ($image_info['type'] == 2)
imagejpeg($thumbnail, $image_folder.'/thumbs/thumb_'.$image_name, 85);
else if ($image_info['type'] == 1)
imagegif($thumbnail, $image_folder.'/thumbs/thumb_'.$image_name);
// Destroy
imagedestroy($thumbnail);
}
// Format unixtimestamp to a human readable date
private function format_time($timestamp)
{
return gmdate($this->config['time_format'], ($timestamp + $this->config['time_zone'] * 3600));
}
// A url safe base64 en/de- code
static private function base64_url_encode($input)
{
return strtr(base64_encode($input), '+/=', '-_,');
}
static private function base64_url_decode($input)
{
return base64_decode(strtr($input, '-_,', '+/='));
}
// Get info from image
static private function get_image_info($filepath)
{
$getimagesize = getimagesize($filepath);
return array('width' => $getimagesize[0], 'height' => $getimagesize[1], 'type' => $getimagesize[2], 'extension' => self::get_ext($filepath));
}
// Get extension from image
static private function get_ext($filepath)
{
$explode = explode('.', $filepath);
return $explode[count($explode)-1];
}
}
?>