PageRenderTime 46ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-content/themes/PureType/timthumb.php

https://github.com/jao/jpcamargo
PHP | 614 lines | 308 code | 155 blank | 151 comment | 64 complexity | 2e58080f484b7e7a673dbfc5c38b167d MD5 | raw file
  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. MIT License: http://www.opensource.org/licenses/mit-license.php
  6. Paramters
  7. ---------
  8. w: width
  9. h: height
  10. zc: zoom crop (0 or 1)
  11. q: quality (default is 75 and max is 100)
  12. HTML example: <img src="/scripts/timthumb.php?src=/images/whatever.jpg&w=150&h=200&zc=1" alt="" />
  13. */
  14. /*
  15. $sizeLimits = array(
  16. "100x100",
  17. "150x150",
  18. );
  19. */
  20. define ('CACHE_SIZE', 250); // number of files to store before clearing cache
  21. define ('CACHE_CLEAR', 5); // maximum number of files to delete on each cache clear
  22. define ('VERSION', '1.09'); // version number (to force a cache refresh
  23. $imageFilters = array(
  24. "1" => array(IMG_FILTER_NEGATE, 0),
  25. "2" => array(IMG_FILTER_GRAYSCALE, 0),
  26. "3" => array(IMG_FILTER_BRIGHTNESS, 1),
  27. "4" => array(IMG_FILTER_CONTRAST, 1),
  28. "5" => array(IMG_FILTER_COLORIZE, 4),
  29. "6" => array(IMG_FILTER_EDGEDETECT, 0),
  30. "7" => array(IMG_FILTER_EMBOSS, 0),
  31. "8" => array(IMG_FILTER_GAUSSIAN_BLUR, 0),
  32. "9" => array(IMG_FILTER_SELECTIVE_BLUR, 0),
  33. "10" => array(IMG_FILTER_MEAN_REMOVAL, 0),
  34. "11" => array(IMG_FILTER_SMOOTH, 0),
  35. );
  36. // sort out image source
  37. $src = get_request("src", "");
  38. if($src == "" || strlen($src) <= 3) {
  39. displayError("no image specified");
  40. }
  41. // clean params before use
  42. $src = cleanSource($src);
  43. // last modified time (for caching)
  44. $lastModified = filemtime($src);
  45. // get properties
  46. $new_width = preg_replace("/[^0-9]+/", "", get_request("w", 0));
  47. $new_height = preg_replace("/[^0-9]+/", "", get_request("h", 0));
  48. $zoom_crop = preg_replace("/[^0-9]+/", "", get_request("zc", 1));
  49. $quality = preg_replace("/[^0-9]+/", "", get_request("q", 80));
  50. $filters = get_request("f", "");
  51. if ($new_width == 0 && $new_height == 0) {
  52. $new_width = 100;
  53. $new_height = 100;
  54. }
  55. // set path to cache directory (default is ./cache)
  56. // this can be changed to a different location
  57. $cache_dir = './cache';
  58. // get mime type of src
  59. $mime_type = mime_type($src);
  60. // check to see if this image is in the cache already
  61. check_cache( $cache_dir, $mime_type );
  62. // if not in cache then clear some space and generate a new file
  63. cleanCache();
  64. ini_set('memory_limit', "30M");
  65. // make sure that the src is gif/jpg/png
  66. if(!valid_src_mime_type($mime_type)) {
  67. displayError("Invalid src mime type: " .$mime_type);
  68. }
  69. // check to see if GD function exist
  70. if(!function_exists('imagecreatetruecolor')) {
  71. displayError("GD Library Error: imagecreatetruecolor does not exist");
  72. }
  73. if(strlen($src) && file_exists($src)) {
  74. // open the existing image
  75. $image = open_image($mime_type, $src);
  76. if($image === false) {
  77. displayError('Unable to open image : ' . $src);
  78. }
  79. // Get original width and height
  80. $width = imagesx($image);
  81. $height = imagesy($image);
  82. // don't allow new width or height to be greater than the original
  83. if( $new_width > $width ) {
  84. $new_width = $width;
  85. }
  86. if( $new_height > $height ) {
  87. $new_height = $height;
  88. }
  89. // generate new w/h if not provided
  90. if( $new_width && !$new_height ) {
  91. $new_height = $height * ( $new_width / $width );
  92. } elseif($new_height && !$new_width) {
  93. $new_width = $width * ( $new_height / $height );
  94. } elseif(!$new_width && !$new_height) {
  95. $new_width = $width;
  96. $new_height = $height;
  97. }
  98. // create a new true color image
  99. $canvas = imagecreatetruecolor( $new_width, $new_height );
  100. imagealphablending($canvas, false);
  101. // Create a new transparent color for image
  102. $color = imagecolorallocatealpha($canvas, 0, 0, 0, 127);
  103. // Completely fill the background of the new image with allocated color.
  104. imagefill($canvas, 0, 0, $color);
  105. // Restore transparency blending
  106. imagesavealpha($canvas, true);
  107. if( $zoom_crop ) {
  108. $src_x = $src_y = 0;
  109. $src_w = $width;
  110. $src_h = $height;
  111. $cmp_x = $width / $new_width;
  112. $cmp_y = $height / $new_height;
  113. // calculate x or y coordinate and width or height of source
  114. if ( $cmp_x > $cmp_y ) {
  115. $src_w = round( ( $width / $cmp_x * $cmp_y ) );
  116. $src_x = round( ( $width - ( $width / $cmp_x * $cmp_y ) ) / 2 );
  117. } elseif ( $cmp_y > $cmp_x ) {
  118. $src_h = round( ( $height / $cmp_y * $cmp_x ) );
  119. $src_y = round( ( $height - ( $height / $cmp_y * $cmp_x ) ) / 2 );
  120. }
  121. imagecopyresampled( $canvas, $image, 0, 0, $src_x, $src_y, $new_width, $new_height, $src_w, $src_h );
  122. } else {
  123. // copy and resize part of an image with resampling
  124. imagecopyresampled( $canvas, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height );
  125. }
  126. if ($filters != "") {
  127. // apply filters to image
  128. $filterList = explode("|", $filters);
  129. foreach($filterList as $fl) {
  130. $filterSettings = explode(",", $fl);
  131. if(isset($imageFilters[$filterSettings[0]])) {
  132. for($i = 0; $i < 4; $i ++) {
  133. if(!isset($filterSettings[$i])) {
  134. $filterSettings[$i] = null;
  135. }
  136. }
  137. switch($imageFilters[$filterSettings[0]][1]) {
  138. case 1:
  139. imagefilter($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1]);
  140. break;
  141. case 2:
  142. imagefilter($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1], $filterSettings[2]);
  143. break;
  144. case 3:
  145. imagefilter($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1], $filterSettings[2], $filterSettings[3]);
  146. break;
  147. default:
  148. imagefilter($canvas, $imageFilters[$filterSettings[0]][0]);
  149. break;
  150. }
  151. }
  152. }
  153. }
  154. // output image to browser based on mime type
  155. show_image($mime_type, $canvas, $cache_dir);
  156. // remove image from memory
  157. imagedestroy($canvas);
  158. } else {
  159. if(strlen($src)) {
  160. displayError("image " . $src . " not found");
  161. } else {
  162. displayError("no source specified");
  163. }
  164. }
  165. /**
  166. *
  167. */
  168. function show_image($mime_type, $image_resized, $cache_dir) {
  169. global $quality;
  170. // check to see if we can write to the cache directory
  171. $is_writable = 0;
  172. $cache_file_name = $cache_dir . '/' . get_cache_file();
  173. if(touch($cache_file_name)) {
  174. // give 666 permissions so that the developer
  175. // can overwrite web server user
  176. chmod($cache_file_name, 0666);
  177. $is_writable = 1;
  178. } else {
  179. $cache_file_name = NULL;
  180. header('Content-type: ' . $mime_type);
  181. }
  182. $quality = floor($quality * 0.09);
  183. imagepng($image_resized, $cache_file_name, $quality);
  184. if($is_writable) {
  185. show_cache_file($cache_dir, $mime_type);
  186. }
  187. imagedestroy($image_resized);
  188. displayError("error showing image");
  189. }
  190. /**
  191. *
  192. */
  193. function get_request( $property, $default = 0 ) {
  194. if( isset($_REQUEST[$property]) ) {
  195. return $_REQUEST[$property];
  196. } else {
  197. return $default;
  198. }
  199. }
  200. /**
  201. *
  202. */
  203. function open_image($mime_type, $src) {
  204. if(stristr($mime_type, 'gif')) {
  205. $image = imagecreatefromgif($src);
  206. } elseif(stristr($mime_type, 'jpeg')) {
  207. @ini_set('gd.jpeg_ignore_warning', 1);
  208. $image = imagecreatefromjpeg($src);
  209. } elseif( stristr($mime_type, 'png')) {
  210. $image = imagecreatefrompng($src);
  211. }
  212. return $image;
  213. }
  214. /**
  215. * clean out old files from the cache
  216. * you can change the number of files to store and to delete per loop in the defines at the top of the code
  217. */
  218. function cleanCache() {
  219. $files = glob("cache/*", GLOB_BRACE);
  220. $yesterday = time() - (24 * 60 * 60);
  221. if (count($files) > 0) {
  222. usort($files, "filemtime_compare");
  223. $i = 0;
  224. if (count($files) > CACHE_SIZE) {
  225. foreach ($files as $file) {
  226. $i ++;
  227. if ($i >= CACHE_CLEAR) {
  228. return;
  229. }
  230. if (filemtime($file) > $yesterday) {
  231. return;
  232. }
  233. unlink($file);
  234. }
  235. }
  236. }
  237. }
  238. /**
  239. * compare the file time of two files
  240. */
  241. function filemtime_compare($a, $b) {
  242. return filemtime($a) - filemtime($b);
  243. }
  244. /**
  245. * determine the file mime type
  246. */
  247. function mime_type($file) {
  248. if (stristr(PHP_OS, 'WIN')) {
  249. $os = 'WIN';
  250. } else {
  251. $os = PHP_OS;
  252. }
  253. $mime_type = '';
  254. if (function_exists('mime_content_type')) {
  255. $mime_type = mime_content_type($file);
  256. }
  257. // use PECL fileinfo to determine mime type
  258. if (!valid_src_mime_type($mime_type)) {
  259. if (function_exists('finfo_open')) {
  260. $finfo = finfo_open(FILEINFO_MIME);
  261. $mime_type = finfo_file($finfo, $file);
  262. finfo_close($finfo);
  263. }
  264. }
  265. // try to determine mime type by using unix file command
  266. // this should not be executed on windows
  267. if (!valid_src_mime_type($mime_type) && $os != "WIN") {
  268. if (preg_match("/FREEBSD|LINUX/", $os)) {
  269. $mime_type = trim(@shell_exec('file -bi "' . $file . '"'));
  270. }
  271. }
  272. // use file's extension to determine mime type
  273. if (!valid_src_mime_type($mime_type)) {
  274. // set defaults
  275. $mime_type = 'image/png';
  276. // file details
  277. $fileDetails = pathinfo($file);
  278. $ext = strtolower($fileDetails["extension"]);
  279. // mime types
  280. $types = array(
  281. 'jpg' => 'image/jpeg',
  282. 'jpeg' => 'image/jpeg',
  283. 'png' => 'image/png',
  284. 'gif' => 'image/gif'
  285. );
  286. if (strlen($ext) && strlen($types[$ext])) {
  287. $mime_type = $types[$ext];
  288. }
  289. }
  290. return $mime_type;
  291. }
  292. /**
  293. *
  294. */
  295. function valid_src_mime_type($mime_type) {
  296. if (preg_match("/jpg|jpeg|gif|png/i", $mime_type)) {
  297. return true;
  298. }
  299. return false;
  300. }
  301. /**
  302. *
  303. */
  304. function check_cache($cache_dir, $mime_type) {
  305. // make sure cache dir exists
  306. if (!file_exists($cache_dir)) {
  307. // give 777 permissions so that developer can overwrite
  308. // files created by web server user
  309. mkdir($cache_dir);
  310. chmod($cache_dir, 0777);
  311. }
  312. show_cache_file($cache_dir, $mime_type);
  313. }
  314. /**
  315. *
  316. */
  317. function show_cache_file($cache_dir) {
  318. $cache_file = $cache_dir . '/' . get_cache_file();
  319. if (file_exists($cache_file)) {
  320. $gmdate_mod = gmdate("D, d M Y H:i:s", filemtime($cache_file));
  321. if(! strstr($gmdate_mod, "GMT")) {
  322. $gmdate_mod .= " GMT";
  323. }
  324. if (isset($_SERVER["HTTP_IF_MODIFIED_SINCE"])) {
  325. // check for updates
  326. $if_modified_since = preg_replace("/;.*$/", "", $_SERVER["HTTP_IF_MODIFIED_SINCE"]);
  327. if ($if_modified_since == $gmdate_mod) {
  328. header("HTTP/1.1 304 Not Modified");
  329. exit;
  330. }
  331. }
  332. $fileSize = filesize($cache_file);
  333. // send headers then display image
  334. header("Content-Type: image/png");
  335. header("Accept-Ranges: bytes");
  336. header("Last-Modified: " . $gmdate_mod);
  337. header("Content-Length: " . $fileSize);
  338. header("Cache-Control: max-age=9999, must-revalidate");
  339. header("Expires: " . $gmdate_mod);
  340. readfile($cache_file);
  341. exit;
  342. }
  343. }
  344. /**
  345. *
  346. */
  347. function get_cache_file() {
  348. global $lastModified;
  349. static $cache_file;
  350. if(!$cache_file) {
  351. $cachename = $_SERVER['QUERY_STRING'] . VERSION . $lastModified;
  352. $cache_file = md5($cachename) . '.png';
  353. }
  354. return $cache_file;
  355. }
  356. /**
  357. * check to if the url is valid or not
  358. */
  359. function valid_extension ($ext) {
  360. if (preg_match("/jpg|jpeg|png|gif/i", $ext)) {
  361. return TRUE;
  362. } else {
  363. return FALSE;
  364. }
  365. }
  366. /**
  367. * tidy up the image source url
  368. */
  369. function cleanSource($src) {
  370. // remove slash from start of string
  371. if(strpos($src, "/") == 0) {
  372. $src = substr($src, -(strlen($src) - 1));
  373. }
  374. // remove http/ https/ ftp
  375. $src = preg_replace("/^((ht|f)tp(s|):\/\/)/i", "", $src);
  376. // remove domain name from the source url
  377. $host = $_SERVER["HTTP_HOST"];
  378. $src = str_replace($host, "", $src);
  379. $host = str_replace("www.", "", $host);
  380. $src = str_replace($host, "", $src);
  381. // don't allow users the ability to use '../'
  382. // in order to gain access to files below document root
  383. // src should be specified relative to document root like:
  384. // src=images/img.jpg or src=/images/img.jpg
  385. // not like:
  386. // src=../images/img.jpg
  387. $src = preg_replace("/\.\.+\//", "", $src);
  388. // get path to image on file system
  389. $src = get_document_root($src) . '/' . $src;
  390. return $src;
  391. }
  392. /**
  393. *
  394. */
  395. function get_document_root ($src) {
  396. // check for unix servers
  397. if(@file_exists($_SERVER['DOCUMENT_ROOT'] . '/' . $src)) {
  398. return $_SERVER['DOCUMENT_ROOT'];
  399. }
  400. // check from script filename (to get all directories to timthumb location)
  401. $parts = array_diff(explode('/', $_SERVER['SCRIPT_FILENAME']), explode('/', $_SERVER['DOCUMENT_ROOT']));
  402. $path = $_SERVER['DOCUMENT_ROOT'] . '/';
  403. foreach ($parts as $part) {
  404. $path .= $part . '/';
  405. if (file_exists($path . $src)) {
  406. return $path;
  407. }
  408. }
  409. // the relative paths below are useful if timthumb is moved outside of document root
  410. // specifically if installed in wordpress themes like mimbo pro:
  411. // /wp-content/themes/mimbopro/scripts/timthumb.php
  412. $paths = array(
  413. ".",
  414. "..",
  415. "../..",
  416. "../../..",
  417. "../../../..",
  418. "../../../../.."
  419. );
  420. foreach($paths as $path) {
  421. if(@file_exists($path . '/' . $src)) {
  422. return $path;
  423. }
  424. }
  425. // special check for microsoft servers
  426. if(!isset($_SERVER['DOCUMENT_ROOT'])) {
  427. $path = str_replace("/", "\\", $_SERVER['ORIG_PATH_INFO']);
  428. $path = str_replace($path, "", $_SERVER['SCRIPT_FILENAME']);
  429. if( @file_exists( $path . '/' . $src ) ) {
  430. return $path;
  431. }
  432. }
  433. displayError('file not found ' . $src);
  434. }
  435. /**
  436. * generic error message
  437. */
  438. function displayError($errorString = '') {
  439. header('HTTP/1.1 400 Bad Request');
  440. die($errorString);
  441. }
  442. ?>