Posted By

LuckyShot on 05/29/10


Tagged

php image thumb


Versions (?)

TimThumb


 / Published in: PHP
 

URL: http://timthumb.googlecode.com/svn/trunk/timthumb.php

TimThumb script created by Tim McDaniels and Darren Hoyt with tweaks by Ben Gillbanks (revision 81)

  1. <?php
  2. /*
  3.   TimThumb script created by Tim McDaniels and Darren Hoyt with tweaks by Ben Gillbanks
  4.   http://code.google.com/p/timthumb/
  5.  
  6.   MIT License: http://www.opensource.org/licenses/mit-license.php
  7.  
  8.   Paramters
  9.   ---------
  10.   w: width
  11.   h: height
  12.   zc: zoom crop (0 or 1)
  13.   q: quality (default is 75 and max is 100)
  14.  
  15.   HTML example: <img src="/scripts/timthumb.php?src=/images/whatever.jpg&w=150&h=200&zc=1" alt="" />
  16. */
  17.  
  18. /*
  19. $sizeLimits = array(
  20.   "100x100",
  21.   "150x150",
  22. );
  23.  
  24. error_reporting(E_ALL);
  25. ini_set("display_errors", 1);
  26. */
  27.  
  28. // check to see if GD function exist
  29. if(!function_exists('imagecreatetruecolor')) {
  30. displayError('GD Library Error: imagecreatetruecolor does not exist - please contact your webhost and ask them to install the GD library');
  31. }
  32.  
  33. define ('CACHE_SIZE', 250); // number of files to store before clearing cache
  34. define ('CACHE_CLEAR', 5); // maximum number of files to delete on each cache clear
  35. define ('VERSION', '1.14'); // version number (to force a cache refresh)
  36. define ('DIRECTORY_CACHE', './cache'); // cache directory
  37. define ('DIRECTORY_TEMP', './temp'); // temp directory
  38.  
  39. if (function_exists('imagefilter') && defined('IMG_FILTER_NEGATE')) {
  40. $imageFilters = array(
  41. "1" => array(IMG_FILTER_NEGATE, 0),
  42. "2" => array(IMG_FILTER_GRAYSCALE, 0),
  43. "3" => array(IMG_FILTER_BRIGHTNESS, 1),
  44. "4" => array(IMG_FILTER_CONTRAST, 1),
  45. "5" => array(IMG_FILTER_COLORIZE, 4),
  46. "6" => array(IMG_FILTER_EDGEDETECT, 0),
  47. "7" => array(IMG_FILTER_EMBOSS, 0),
  48. "8" => array(IMG_FILTER_GAUSSIAN_BLUR, 0),
  49. "9" => array(IMG_FILTER_SELECTIVE_BLUR, 0),
  50. "10" => array(IMG_FILTER_MEAN_REMOVAL, 0),
  51. "11" => array(IMG_FILTER_SMOOTH, 0),
  52. );
  53. }
  54.  
  55. // sort out image source
  56. $src = get_request("src", "");
  57. if($src == '' || strlen($src) <= 3) {
  58. displayError ('no image specified');
  59. }
  60.  
  61. // clean params before use
  62. $src = cleanSource($src);
  63. // last modified time (for caching)
  64. $lastModified = filemtime($src);
  65.  
  66. // get properties
  67. $new_width = preg_replace("/[^0-9]+/", '', get_request('w', 0));
  68. $new_height = preg_replace("/[^0-9]+/", '', get_request('h', 0));
  69. $zoom_crop = preg_replace("/[^0-9]+/", '', get_request('zc', 1));
  70. $quality = preg_replace("/[^0-9]+/", '', get_request('q', 80));
  71. $filters = get_request('f', '');
  72. $sharpen = get_request('s', 0);
  73.  
  74. if ($new_width == 0 && $new_height == 0) {
  75. $new_width = 100;
  76. $new_height = 100;
  77. }
  78.  
  79. // get mime type of src
  80. $mime_type = mime_type($src);
  81.  
  82. // check to see if this image is in the cache already
  83. check_cache ($mime_type);
  84.  
  85. // if not in cache then clear some space and generate a new file
  86. cleanCache();
  87.  
  88. ini_set('memory_limit', '50M');
  89.  
  90. // make sure that the src is gif/jpg/png
  91. if(!valid_src_mime_type($mime_type)) {
  92. displayError('Invalid src mime type: ' . $mime_type);
  93. }
  94.  
  95. if(strlen($src) && file_exists($src)) {
  96.  
  97. // open the existing image
  98. $image = open_image($mime_type, $src);
  99. if($image === false) {
  100. displayError('Unable to open image : ' . $src);
  101. }
  102.  
  103. // Get original width and height
  104. $width = imagesx($image);
  105. $height = imagesy($image);
  106.  
  107. // generate new w/h if not provided
  108. if( $new_width && !$new_height ) {
  109.  
  110. $new_height = $height * ( $new_width / $width );
  111.  
  112. } elseif($new_height && !$new_width) {
  113.  
  114. $new_width = $width * ( $new_height / $height );
  115.  
  116. } elseif(!$new_width && !$new_height) {
  117.  
  118. $new_width = $width;
  119. $new_height = $height;
  120.  
  121. }
  122.  
  123. // create a new true color image
  124. $canvas = imagecreatetruecolor( $new_width, $new_height );
  125. imagealphablending($canvas, false);
  126. // Create a new transparent color for image
  127. $color = imagecolorallocatealpha($canvas, 0, 0, 0, 127);
  128. // Completely fill the background of the new image with allocated color.
  129. imagefill($canvas, 0, 0, $color);
  130. // Restore transparency blending
  131. imagesavealpha($canvas, true);
  132.  
  133. if( $zoom_crop ) {
  134.  
  135. $src_x = $src_y = 0;
  136. $src_w = $width;
  137. $src_h = $height;
  138.  
  139. $cmp_x = $width / $new_width;
  140. $cmp_y = $height / $new_height;
  141.  
  142. // calculate x or y coordinate and width or height of source
  143.  
  144. if ( $cmp_x > $cmp_y ) {
  145.  
  146. $src_w = round( ( $width / $cmp_x * $cmp_y ) );
  147. $src_x = round( ( $width - ( $width / $cmp_x * $cmp_y ) ) / 2 );
  148.  
  149. } elseif ( $cmp_y > $cmp_x ) {
  150.  
  151. $src_h = round( ( $height / $cmp_y * $cmp_x ) );
  152. $src_y = round( ( $height - ( $height / $cmp_y * $cmp_x ) ) / 2 );
  153.  
  154. }
  155.  
  156. imagecopyresampled( $canvas, $image, 0, 0, $src_x, $src_y, $new_width, $new_height, $src_w, $src_h );
  157.  
  158. } else {
  159.  
  160. // copy and resize part of an image with resampling
  161. imagecopyresampled( $canvas, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height );
  162.  
  163. }
  164.  
  165. if ($filters != '' && function_exists('imagefilter') && defined('IMG_FILTER_NEGATE')) {
  166. // apply filters to image
  167. $filterList = explode("|", $filters);
  168. foreach($filterList as $fl) {
  169. $filterSettings = explode(",", $fl);
  170. if(isset($imageFilters[$filterSettings[0]])) {
  171.  
  172. for($i = 0; $i < 4; $i ++) {
  173. if(!isset($filterSettings[$i])) {
  174. $filterSettings[$i] = null;
  175. }
  176. }
  177.  
  178. switch($imageFilters[$filterSettings[0]][1]) {
  179.  
  180. case 1:
  181.  
  182. imagefilter($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1]);
  183. break;
  184.  
  185. case 2:
  186.  
  187. imagefilter($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1], $filterSettings[2]);
  188. break;
  189.  
  190. case 3:
  191.  
  192. imagefilter($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1], $filterSettings[2], $filterSettings[3]);
  193. break;
  194.  
  195. default:
  196.  
  197. imagefilter($canvas, $imageFilters[$filterSettings[0]][0]);
  198. break;
  199.  
  200. }
  201. }
  202. }
  203. }
  204.  
  205. if ($sharpen > 0 && function_exists('imageconvolution')) {
  206.  
  207. $sharpenMatrix = array(
  208. array(-1,-1,-1),
  209. array(-1,16,-1),
  210. array(-1,-1,-1),
  211. );
  212. $divisor = 8;
  213. $offset = 0;
  214.  
  215. imageconvolution($canvas, $sharpenMatrix, $divisor, $offset);
  216.  
  217. }
  218.  
  219. // output image to browser based on mime type
  220. show_image($mime_type, $canvas);
  221.  
  222. // remove image from memory
  223. imagedestroy($canvas);
  224.  
  225. } else {
  226.  
  227. if (strlen($src)) {
  228. displayError ('image ' . $src . ' not found');
  229. } else {
  230. displayError ('no source specified');
  231. }
  232.  
  233. }
  234.  
  235. /**
  236.  *
  237.  */
  238. function show_image($mime_type, $image_resized) {
  239.  
  240. global $quality;
  241.  
  242. // check to see if we can write to the cache directory
  243. $is_writable = 0;
  244. $cache_file_name = DIRECTORY_CACHE . '/' . get_cache_file();
  245.  
  246. if (touch($cache_file_name)) {
  247.  
  248. // give 666 permissions so that the developer
  249. // can overwrite web server user
  250. chmod ($cache_file_name, 0666);
  251. $is_writable = 1;
  252.  
  253. } else {
  254.  
  255. $cache_file_name = NULL;
  256. header ('Content-type: ' . $mime_type);
  257.  
  258. }
  259.  
  260. switch ($mime_type) {
  261.  
  262. case 'image/jpeg':
  263. imagejpeg($image_resized, $cache_file_name, $quality);
  264. break;
  265.  
  266. default :
  267. $quality = floor ($quality * 0.09);
  268. imagepng($image_resized, $cache_file_name, $quality);
  269.  
  270. }
  271.  
  272. if ($is_writable) {
  273. show_cache_file ($mime_type);
  274. }
  275.  
  276. imagedestroy ($image_resized);
  277.  
  278. displayError ('error showing image');
  279.  
  280. }
  281.  
  282. /**
  283.  *
  284.  */
  285. function get_request( $property, $default = 0 ) {
  286.  
  287. if( isset($_REQUEST[$property]) ) {
  288.  
  289. return $_REQUEST[$property];
  290.  
  291. } else {
  292.  
  293. return $default;
  294.  
  295. }
  296.  
  297. }
  298.  
  299. /**
  300.  *
  301.  */
  302. function open_image($mime_type, $src) {
  303.  
  304. $mime_type = strtolower($mime_type);
  305.  
  306. if (stristr ($mime_type, 'gif')) {
  307.  
  308. $image = imagecreatefromgif($src);
  309.  
  310. } elseif (stristr($mime_type, 'jpeg')) {
  311.  
  312. @ini_set ('gd.jpeg_ignore_warning', 1);
  313. $image = imagecreatefromjpeg($src);
  314.  
  315. } elseif (stristr ($mime_type, 'png')) {
  316.  
  317. $image = imagecreatefrompng($src);
  318.  
  319. }
  320.  
  321. return $image;
  322.  
  323. }
  324.  
  325. /**
  326.  * clean out old files from the cache
  327.  * you can change the number of files to store and to delete per loop in the defines at the top of the code
  328.  */
  329. function cleanCache() {
  330.  
  331. $files = glob("cache/*", GLOB_BRACE);
  332.  
  333. if (count($files) > 0) {
  334.  
  335. $yesterday = time() - (24 * 60 * 60);
  336.  
  337. usort($files, 'filemtime_compare');
  338. $i = 0;
  339.  
  340. if (count($files) > CACHE_SIZE) {
  341.  
  342. foreach ($files as $file) {
  343.  
  344. $i ++;
  345.  
  346. if ($i >= CACHE_CLEAR) {
  347. return;
  348. }
  349.  
  350. if (@filemtime($file) > $yesterday) {
  351. return;
  352. }
  353.  
  354. if (file_exists($file)) {
  355. unlink($file);
  356. }
  357.  
  358. }
  359.  
  360. }
  361.  
  362. }
  363.  
  364. }
  365.  
  366.  
  367. /**
  368.  * compare the file time of two files
  369.  */
  370. function filemtime_compare($a, $b) {
  371.  
  372. return filemtime($a) - filemtime($b);
  373.  
  374. }
  375.  
  376.  
  377. /**
  378.  * determine the file mime type
  379.  */
  380. function mime_type($file) {
  381.  
  382. if (stristr(PHP_OS, 'WIN')) {
  383. $os = 'WIN';
  384. } else {
  385. $os = PHP_OS;
  386. }
  387.  
  388. $mime_type = '';
  389.  
  390. if (function_exists('mime_content_type') && $os != 'WIN') {
  391. $mime_type = mime_content_type($file);
  392. }
  393.  
  394. // use PECL fileinfo to determine mime type
  395. if (!valid_src_mime_type($mime_type)) {
  396. if (function_exists('finfo_open')) {
  397. $finfo = @finfo_open(FILEINFO_MIME);
  398. if ($finfo != '') {
  399. $mime_type = finfo_file($finfo, $file);
  400. finfo_close($finfo);
  401. }
  402. }
  403. }
  404.  
  405. // try to determine mime type by using unix file command
  406. // this should not be executed on windows
  407. if (!valid_src_mime_type($mime_type) && $os != "WIN") {
  408. if (preg_match("/FreeBSD|FREEBSD|LINUX/", $os)) {
  409. $mime_type = trim(@shell_exec('file -bi ' . escapeshellarg($file)));
  410. }
  411. }
  412.  
  413. // use file's extension to determine mime type
  414. if (!valid_src_mime_type($mime_type)) {
  415.  
  416. // set defaults
  417. $mime_type = 'image/png';
  418. // file details
  419. $fileDetails = pathinfo($file);
  420. $ext = strtolower($fileDetails["extension"]);
  421. // mime types
  422. $types = array(
  423. 'jpg' => 'image/jpeg',
  424. 'jpeg' => 'image/jpeg',
  425. 'png' => 'image/png',
  426. 'gif' => 'image/gif'
  427. );
  428.  
  429. if (strlen($ext) && strlen($types[$ext])) {
  430. $mime_type = $types[$ext];
  431. }
  432.  
  433. }
  434.  
  435. return $mime_type;
  436.  
  437. }
  438.  
  439.  
  440. /**
  441.  *
  442.  */
  443. function valid_src_mime_type($mime_type) {
  444.  
  445. if (preg_match("/jpg|jpeg|gif|png/i", $mime_type)) {
  446. return true;
  447. }
  448.  
  449. return false;
  450.  
  451. }
  452.  
  453.  
  454. /**
  455.  *
  456.  */
  457. function check_cache ($mime_type) {
  458.  
  459. // make sure cache dir exists
  460. if (!file_exists(DIRECTORY_CACHE)) {
  461. // give 777 permissions so that developer can overwrite
  462. // files created by web server user
  463. mkdir(DIRECTORY_CACHE);
  464. chmod(DIRECTORY_CACHE, 0777);
  465. }
  466.  
  467. show_cache_file ($mime_type);
  468.  
  469. }
  470.  
  471.  
  472. /**
  473.  *
  474.  */
  475. function show_cache_file ($mime_type) {
  476.  
  477. $cache_file = DIRECTORY_CACHE . '/' . get_cache_file();
  478.  
  479. if (file_exists($cache_file)) {
  480.  
  481. $gmdate_mod = gmdate("D, d M Y H:i:s", filemtime($cache_file));
  482.  
  483. if(! strstr($gmdate_mod, "GMT")) {
  484. $gmdate_mod .= " GMT";
  485. }
  486.  
  487. if (isset($_SERVER["HTTP_IF_MODIFIED_SINCE"])) {
  488.  
  489. // check for updates
  490. $if_modified_since = preg_replace ("/;.*$/", "", $_SERVER["HTTP_IF_MODIFIED_SINCE"]);
  491.  
  492. if ($if_modified_since == $gmdate_mod) {
  493. header("HTTP/1.1 304 Not Modified");
  494. die();
  495. }
  496.  
  497. }
  498.  
  499. $fileSize = filesize ($cache_file);
  500.  
  501. // send headers then display image
  502. header ('Content-Type: ' . $mime_type);
  503. header ('Accept-Ranges: bytes');
  504. header ('Last-Modified: ' . $gmdate_mod);
  505. header ('Content-Length: ' . $fileSize);
  506. header ('Cache-Control: max-age=9999, must-revalidate');
  507. header ('Expires: ' . $gmdate_mod);
  508.  
  509. readfile ($cache_file);
  510.  
  511. die();
  512.  
  513. }
  514.  
  515. }
  516.  
  517.  
  518. /**
  519.  *
  520.  */
  521. function get_cache_file() {
  522.  
  523. global $lastModified;
  524. static $cache_file;
  525.  
  526. if (!$cache_file) {
  527. $cachename = $_SERVER['QUERY_STRING'] . VERSION . $lastModified;
  528. $cache_file = md5($cachename) . '.png';
  529. }
  530.  
  531. return $cache_file;
  532.  
  533. }
  534.  
  535.  
  536. /**
  537.  * check to if the url is valid or not
  538.  */
  539. function valid_extension ($ext) {
  540.  
  541. if (preg_match("/jpg|jpeg|png|gif/i", $ext)) {
  542. return TRUE;
  543. } else {
  544. return FALSE;
  545. }
  546.  
  547. }
  548.  
  549.  
  550. /**
  551.  *
  552.  */
  553. function checkExternal ($src) {
  554.  
  555. $allowedSites = array(
  556. 'flickr.com',
  557. 'picasa.com',
  558. 'blogger.com',
  559. 'wordpress.com',
  560. 'img.youtube.com',
  561. );
  562.  
  563. if (preg_match('/http:\/\//', $src) == true) {
  564.  
  565. $url_info = parse_url ($src);
  566.  
  567. $isAllowedSite = false;
  568. foreach ($allowedSites as $site) {
  569. $site = '/' . addslashes($site) . '/';
  570. if (preg_match($site, $url_info['host']) == true) {
  571. $isAllowedSite = true;
  572. }
  573. }
  574.  
  575. if ($isAllowedSite) {
  576.  
  577. $fileDetails = pathinfo($src);
  578. $ext = strtolower($fileDetails['extension']);
  579.  
  580. $filename = md5($src);
  581. $local_filepath = DIRECTORY_TEMP . '/' . $filename . '.' . $ext;
  582.  
  583. if (!file_exists($local_filepath)) {
  584.  
  585. if (function_exists('curl_init')) {
  586.  
  587. $fh = fopen($local_filepath, 'w');
  588. $ch = curl_init($src);
  589.  
  590. curl_setopt($ch, CURLOPT_URL, $src);
  591. curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
  592. curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
  593. curl_setopt($ch, CURLOPT_HEADER, 0);
  594. curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0');
  595. curl_setopt($ch, CURLOPT_FILE, $fh);
  596.  
  597. if (curl_exec($ch) === FALSE) {
  598. if (file_exists($local_filepath)) {
  599. unlink($local_filepath);
  600. }
  601. displayError('error reading file ' . $src . ' from remote host: ' . curl_error($ch));
  602. }
  603.  
  604. curl_close($ch);
  605. fclose($fh);
  606.  
  607. } else {
  608.  
  609. if (!$img = file_get_contents($src)) {
  610. displayError('remote file for ' . $src . ' can not be accessed. It is likely that the file permissions are restricted');
  611. }
  612.  
  613. if (file_put_contents($local_filepath, $img) == FALSE) {
  614. displayError('error writing temporary file');
  615. }
  616.  
  617. }
  618.  
  619. if (!file_exists($local_filepath)) {
  620. displayError('local file for ' . $src . ' can not be created');
  621. }
  622.  
  623. }
  624.  
  625. $src = $local_filepath;
  626.  
  627. } else {
  628.  
  629. displayError('remote host "' . $url_info['host'] . '" not allowed');
  630.  
  631. }
  632.  
  633. }
  634.  
  635. return $src;
  636.  
  637. }
  638.  
  639.  
  640. /**
  641.  * tidy up the image source url
  642.  */
  643. function cleanSource($src) {
  644.  
  645. $host = str_replace('www.', '', $_SERVER['HTTP_HOST']);
  646. $regex = "/^((ht|f)tp(s|):\/\/)(www\.|)" . $host . "/i";
  647.  
  648. $src = preg_replace ($regex, '', $src);
  649. $src = strip_tags ($src);
  650. $src = checkExternal ($src);
  651.  
  652. // remove slash from start of string
  653. if (strpos($src, '/') === 0) {
  654. $src = substr ($src, -(strlen($src) - 1));
  655. }
  656.  
  657. // don't allow users the ability to use '../'
  658. // in order to gain access to files below document root
  659. $src = preg_replace("/\.\.+\//", "", $src);
  660.  
  661. // get path to image on file system
  662. $src = get_document_root($src) . '/' . $src;
  663.  
  664. return $src;
  665.  
  666. }
  667.  
  668.  
  669. /**
  670.  *
  671.  */
  672. function get_document_root ($src) {
  673.  
  674. // check for unix servers
  675. if(file_exists($_SERVER['DOCUMENT_ROOT'] . '/' . $src)) {
  676. return $_SERVER['DOCUMENT_ROOT'];
  677. }
  678.  
  679. // check from script filename (to get all directories to timthumb location)
  680. $parts = array_diff(explode('/', $_SERVER['SCRIPT_FILENAME']), explode('/', $_SERVER['DOCUMENT_ROOT']));
  681. $path = $_SERVER['DOCUMENT_ROOT'];
  682. foreach ($parts as $part) {
  683. $path .= '/' . $part;
  684. if (file_exists($path . '/' . $src)) {
  685. return $path;
  686. }
  687. }
  688.  
  689. // the relative paths below are useful if timthumb is moved outside of document root
  690. // specifically if installed in wordpress themes like mimbo pro:
  691. // /wp-content/themes/mimbopro/scripts/timthumb.php
  692. $paths = array(
  693. ".",
  694. "..",
  695. "../..",
  696. "../../..",
  697. "../../../..",
  698. "../../../../.."
  699. );
  700.  
  701. foreach ($paths as $path) {
  702. if(file_exists($path . '/' . $src)) {
  703. return $path;
  704. }
  705. }
  706.  
  707. // special check for microsoft servers
  708. if (!isset($_SERVER['DOCUMENT_ROOT'])) {
  709. $path = str_replace("/", "\\", $_SERVER['ORIG_PATH_INFO']);
  710. $path = str_replace($path, "", $_SERVER['SCRIPT_FILENAME']);
  711.  
  712. if (file_exists($path . '/' . $src)) {
  713. return $path;
  714. }
  715. }
  716.  
  717. displayError('file not found ' . $src);
  718.  
  719. }
  720.  
  721.  
  722. /**
  723.  * generic error message
  724.  */
  725. function displayError ($errorString = '') {
  726.  
  727. header('HTTP/1.1 400 Bad Request');
  728. echo '<pre>' . $errorString . '<br />TimThumb version : ' . VERSION . '</pre>';
  729. die();
  730.  
  731. }
  732. ?>

Report this snippet  

You need to login to post a comment.