<?php if( !defined('is_running' ) ){ define('is_running',true); define('gpdebug',false); define('gp_cookie_cmd',false); //define('gp_dev_combine',false); //prevents cache and 304 header when set to true require_once('common.php'); \gp\tool::EntryPoint(1,'image.php',false); new gp_resized(); } class gp_resized{ public $img; public $height; public $width; public static $index = false; private static $index_checksum = false; private static $last_index = '9'; /** * Check the path of the img, return full path of image if the requested image is found * */ function __construct(){ global $dataDir; if( !isset($_GET['w']) || !isset($_GET['h']) || !isset($_GET['img']) ){ self::Send404(); //dies } $img = $_GET['img']; $height = $_GET['h']; $width = $_GET['w']; if( !is_numeric($height) || !is_numeric($width) ){ self::Send404(); //dies } $width = (int)$width; $height = (int)$height; $img = \gp\tool\Files::NoNull($img); //check file path if( strpos($img,'./') !== false || strpos($img,'%2f') !== false || strpos($img,'%2F') !== false ){ return false; } //make sure the index is set gp_resized::SetIndex(); $index = \gp\tool::ArrayKey($_GET['i'], (array)self::$index ); if( !$index ){ self::Send404(); //dies } //if the image has been renamed, redirect to the new name $index_img = self::$index[$index]; if( $index_img != $img ){ $path = \gp\tool::GetDir('/include/image.php',false).'?i='.$index.'&w='.$width.'&h='.$height.'&img='.rawurlencode($index_img); \gp\tool::Redirect($path); } $info = self::ImageInfo($img,$width,$height); $folder = $dataDir.'/data/_resized/'.$info['index']; $full_path = $folder.'/'.$info['name']; //if it exists return true if( file_exists($full_path) ){ header('Cache-Control: public, max-age=5184000');//60 days //attempt to send 304 $stats = lstat($full_path); if( $stats ){ \gp\tool::Send304( \gp\tool::GenEtag( $stats['mtime'], $stats['size'] ) ); } header('Content-Transfer-Encoding: binary'); header('Content-Type: '.$info['ctype']); readfile($full_path); die(); } //redirect to next largest image if available $usage = self::GetUsage($info['index']); foreach($usage as $size => $data){ if( !$data['uses'] ){ continue; } list($use_width,$use_height) = explode('x',$size); if( ($use_width >= $width && $use_height > $height) || ($use_width > $width && $use_height >= $height) ){ $path = \gp\tool::GetDir('/include/image.php',false).'?i='.$index.'&w='.$use_width.'&h='.$use_height.'&img='.rawurlencode($img); \gp\tool::Redirect($path); //dies } } //redirect to full size image $original = \gp\tool::GetDir('/data/_uploaded'.$img,false); \gp\tool::Redirect($original); //dies } /** * Send a 404 Not Found header to the client */ static function Send404(){ \gp\tool::status_header(404,'404 Not Found'); die(); } /** * Return information about a resized image * - path * - extension * - ctype * */ static function ImageInfo($img,$width,$height){ global $dataDir; $info = array(); $part_name = basename($img); $parts = explode('.',$part_name); if( count($parts) == 0 ){ return false; } $info['extension'] = array_pop($parts); $part_name = implode('.',$parts); switch(strtolower($info['extension'])){ case 'gif': $info['ctype'] = 'image/gif'; break; case 'png': $info['ctype'] = 'image/png'; break; case 'jpeg': case 'jpg': $info['ctype'] = 'image/jpg'; break; default: return false; } //check to see if the reduced image exists $info['name'] = $width.'x'.$height.'.'.$info['extension']; $info['index'] = array_search($img,(array)self::$index); return $info; } /** * Get a new folder * */ static function NewFolder(){ global $dataDir; $new_index = gp_resized::NewIndex(); return $dataDir.'/data/_resized/'.$new_index; } /** * Get the next index * */ static function NewIndex(){ $next_numeric = base_convert(self::$last_index,36,10)+1; do{ $index = array(); $this_numeric = $next_numeric; do{ $index[] = base_convert( substr($this_numeric,-2),10,36); $this_numeric = floor($this_numeric/100); }while($this_numeric >= 1); $index = implode('/',array_reverse($index)); $next_numeric++; }while( is_numeric($index) || isset(self::$index[$index]) ); self::$last_index = $index; return $index; } /** * Get the image index information * */ static function SetIndex(){ global $dataDir; //prevent setting twice if( self::$index !== false ){ return; } $index_file = $dataDir.'/data/_site/image_index.php'; self::$index = \gp\tool\Files::Get($index_file,'image_index'); if( self::$index ){ self::$index_checksum = self::checksum(self::$index); if( isset(\gp\tool\Files::$last_meta['last_index']) ){ self::$last_index = \gp\tool\Files::$last_meta['last_index']; }elseif( isset(\gp\tool\Files::$last_stats['last_index']) ){ //pre 4.3.6 self::$last_index = \gp\tool\Files::$last_stats['last_index']; } } } /** * Save the image index information if the checksum has changed * */ static function SaveIndex(){ global $dataDir; if( self::$index_checksum === self::checksum(self::$index) ){ return true; } $meta = array('last_index'=>self::$last_index); $index_file = $dataDir.'/data/_site/image_index.php'; return \gp\tool\Files::SaveData($index_file,'image_index',(array)self::$index,'meta_data',$meta); } /** * Generate a checksum for the $array * */ static function checksum($array){ return md5(serialize($array) ); } /** * Get usage information about a image * */ static function GetUsage($index){ return \gp\tool\Files::Get('_resized/'.$index.'/data','usage'); } /** * Get usage information about a image * */ static function SaveUsage($index,$data){ global $dataDir; $data_file = $dataDir.'/data/_resized/'.$index.'/data.php'; return \gp\tool\Files::SaveData($data_file,'usage',$data); } /** * Return the folder path used for resized images of $img * */ static function Folder($img){ global $dataDir; $name = basename($img); return $dataDir.'/data/_resized'.\gp\tool::DirName($img).'/'.gp_resized::EncodePath($name); } /** * Encode a path component * */ static function EncodePath($path){ $encoded = base64_encode($path); $encoded = rtrim($encoded, '='); return strtr($encoded, '+/=', '-_.'); } /** * Dencode a path component * */ static function DecodePath($encoded){ $encoded = strtr($encoded, '-_.', '+/='); return base64_decode($encoded); } }