PageRenderTime 54ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/imageserver.php

https://bitbucket.org/SlimDeluxe/sdlx-image-server
PHP | 519 lines | 373 code | 90 blank | 56 comment | 59 complexity | 670bdbd6eee96a3231b782a567dcbcaa MD5 | raw file
  1. <?php
  2. include 'imageserver.config.php';
  3. if (URI_PROTOCOL == 'REQUEST_URI')
  4. {
  5. $filename = $_SERVER['REQUEST_URI'];
  6. if (isset($_SERVER['QUERY_STRING']))
  7. {
  8. $filename = str_replace("?$_SERVER[QUERY_STRING]", '', $filename);
  9. }
  10. }
  11. else
  12. {
  13. $filename = isset($_SERVER['REDIRECT_URL']) ? $_SERVER['REDIRECT_URL'] : NULL;
  14. }
  15. if ( ! $filename)
  16. {
  17. exit;
  18. }
  19. $filename = DIR_RELATIVE . str_replace(SCRIPT_RELATIVE .'imgs/', '', $filename);
  20. $filename = urldecode($filename);
  21. if ( ! file_exists($filename))
  22. {
  23. //The source image can't be found, so use a default, if it is set
  24. if (defined('REPLACEMENT_IMG') AND file_exists(DIR_RELATIVE.REPLACEMENT_IMG))
  25. {
  26. $location = "http://$_SERVER[HTTP_HOST]". SCRIPT_RELATIVE .'imgs/'. REPLACEMENT_IMG;
  27. if ($_SERVER['QUERY_STRING'])
  28. {
  29. $location .= "?$_SERVER[QUERY_STRING]";
  30. }
  31. imgs_log("File $filename not found, 301 redirect to: $location");
  32. header("Location: $location", TRUE, 307);
  33. }
  34. else
  35. {
  36. imgs_log("File '$filename' not found");
  37. }
  38. exit;
  39. }
  40. if (CACHE_EXPIRES)
  41. {
  42. $exp_time = strtotime(CACHE_EXPIRES);
  43. header('Expires: ' . date(DATE_RFC2822, $exp_time));
  44. header('Pragma: cache');
  45. $seconds = $exp_time - time();
  46. header("Cache-Control: public, max-age=$seconds, pre-check=$seconds");
  47. }
  48. list($orig_width, $orig_height, $type) = getimagesize($filename);
  49. $width = 0;
  50. $height = 0;
  51. /*
  52. * Fetch user defined parameters
  53. */
  54. if (isset($_GET['w']) AND is_numeric($_GET['w']))
  55. {
  56. $width = intval($_GET['w']);
  57. }
  58. if (isset($_GET['h']) AND is_numeric($_GET['h']))
  59. {
  60. $height = intval($_GET['h']);
  61. }
  62. $should_watermark = FALSE;
  63. // If resizing was not requested, but the image is larger than the minimum for watermarking
  64. if (WATERMARK AND ! $width AND ! $height AND ($orig_width >= WATERMARK_MINW OR $orig_height >= WATERMARK_MINH))
  65. {
  66. $width = $orig_width;
  67. $height = $orig_height;
  68. $should_watermark = TRUE;
  69. }
  70. elseif (WATERMARK AND (($width > WATERMARK_MINW OR $height > WATERMARK_MINH)))
  71. {
  72. $should_watermark = TRUE;
  73. }
  74. // If the requested file is the original, non-processed image
  75. if ( ! $width AND ! $height AND ! $should_watermark)
  76. {
  77. // If the file exists, just serve it and finish execution
  78. $details = getimagesize($filename);
  79. if ($details)
  80. {
  81. header('Content-Type: '. $details['mime']);
  82. echo file_get_contents($filename);
  83. exit();
  84. }
  85. }
  86. $should_fill = FALSE;
  87. $should_cut = FALSE;
  88. // If we have both width and height requested, we can fill or cut
  89. if ($width AND $height)
  90. {
  91. if ((isset($_GET['f']) AND $_GET['f'] == 1) OR BG_FILL)
  92. {
  93. $should_fill = TRUE;
  94. }
  95. else
  96. {
  97. // Should we cut the image to fill the requested dimensions?
  98. // -------------------------------------------------------------------------
  99. if (isset($_GET['c']))
  100. {
  101. if ($_GET['c'] == 1)
  102. {
  103. $should_cut = TRUE;
  104. }
  105. }
  106. elseif (CUTTING)
  107. {
  108. $should_cut = TRUE;
  109. }
  110. }
  111. }
  112. $pi = pathinfo($filename);
  113. $target_dir = CACHE_RELATIVE."/{$pi['dirname']}";
  114. $bg_tag = ($should_fill ? '_bg' : '');
  115. $wm_tag = ($should_watermark ? '_wm' : '');
  116. $ct_tag = ($should_cut ? '_c' : '');
  117. // Target file is a resized image
  118. $target_file = "{$target_dir}/{$pi['filename']}_{$width}_{$height}{$bg_tag}{$wm_tag}{$ct_tag}.{$pi['extension']}";
  119. // Has this request already been cached once upon a time?
  120. if (CACHE AND file_exists($target_file) AND (filectime($target_file) > filectime($filename)))
  121. {
  122. imgs_log("Serving from cache");
  123. $details = getimagesize($target_file);
  124. if ($details)
  125. {
  126. header('Content-Type: '. $details['mime']);
  127. echo file_get_contents($target_file);
  128. exit();
  129. }
  130. }
  131. else
  132. {
  133. // Original file exists and resize/resample action is needed
  134. // Does the target directory exist?
  135. if (CACHE AND ! is_dir($target_dir) AND ! mkdir($target_dir, 0775, TRUE))
  136. {
  137. // Directory not found and we were unable to create one...
  138. // TODO: handle target directory creation error
  139. exit();
  140. }
  141. $ratio = $orig_width/$orig_height;
  142. // If one of the dimensions was not specified, use the original scaled by the difference ratio
  143. // If cutting, this will have no effect (cutting requires both dimensions, so neither of these eval as TRUE)
  144. if ($width == 0)
  145. {
  146. $width = round($orig_width * ($height/$orig_height));
  147. }
  148. elseif ($height == 0)
  149. {
  150. $height = round($orig_height * ($width/$orig_width));
  151. }
  152. $resample_width = $width;
  153. $resample_height = $height;
  154. // Preserve aspect ratio
  155. if ($resample_width / $resample_height > $ratio)
  156. {
  157. $resample_width = round($resample_height * $ratio);
  158. }
  159. else
  160. {
  161. $resample_height = round($resample_width / $ratio);
  162. }
  163. $dst_x = 0;
  164. $dst_y = 0;
  165. $src_x = 0;
  166. $src_y = 0;
  167. if ($should_fill AND strlen(BG_RGB) == 7)
  168. {
  169. // If background filling is enabled, create an image with the requested dimension
  170. $new_image = imagecreatetruecolor($width, $height);
  171. // Fill the image with the specified colour
  172. $bg = sscanf(BG_RGB, '#%2x%2x%2x');
  173. $new_image_bg = imagecolorallocate($new_image, $bg[0], $bg[1], $bg[2]);
  174. imagefill($new_image, 0, 0, $new_image_bg);
  175. if ($width == $resample_width)
  176. {
  177. $dst_x = 0;
  178. }
  179. elseif ($width > $resample_width)
  180. {
  181. $dst_x = round(($width - $resample_width) / 2);
  182. }
  183. else
  184. {
  185. $dst_x = round(($resample_width - $width) / 2);
  186. }
  187. if ($height == $resample_height)
  188. {
  189. $dst_y = 0;
  190. }
  191. elseif ($height > $resample_height)
  192. {
  193. $dst_y = round(($height - $resample_height) / 2);
  194. }
  195. else
  196. {
  197. $dst_y = round(($resample_height - $height) / 2);
  198. }
  199. }
  200. elseif ($should_cut)
  201. {
  202. // Will cut, so the requested dimension will be respected
  203. $new_image = imagecreatetruecolor($width, $height);
  204. $target_ar = round($width/$height, 2);
  205. $ratio = round($ratio, 2);
  206. if ($orig_width == $orig_height) // ------------------------------------ Source is square
  207. {
  208. if ($width < $height)
  209. {
  210. // Target is portrait
  211. $resample_height = $height;
  212. $resample_width = round($resample_height * $ratio);
  213. $dst_x = - ceil(($resample_width - $width) / 2);
  214. }
  215. elseif ($width > $height)
  216. {
  217. // Target is landscape
  218. $resample_width = $width;
  219. $resample_height = round($resample_width / $ratio);
  220. $dst_y = - ceil(($resample_height - $height) / 2);
  221. }
  222. }
  223. elseif ($orig_width < $orig_height) // --------------------------------- Source is portrait
  224. {
  225. if ($width >= $height OR $target_ar > $ratio)
  226. {
  227. // Target is square or landscape or less narrow than the original
  228. $resample_width = $width;
  229. $resample_height = round($resample_width / $ratio);
  230. $dst_y = - ceil(($resample_height - $height) / 2);
  231. }
  232. elseif ($width < $height AND $target_ar < $ratio)
  233. {
  234. // Target is portrait or more narrow than the original
  235. $resample_height = $height;
  236. $resample_width = round($resample_height * $ratio);
  237. $dst_x = - ceil(($resample_width - $width) / 2);
  238. }
  239. }
  240. else // ---------------------------------------------------------------- Source is landscape
  241. {
  242. if ($width <= $height OR $target_ar < $ratio)
  243. {
  244. // Target is square or portrait or more narrow than the original
  245. $resample_height = $height;
  246. $resample_width = round($resample_height * $ratio);
  247. $dst_x = - ceil(($resample_width - $width) / 2);
  248. }
  249. elseif ($target_ar > $ratio)
  250. {
  251. // Target is landscape or less narrow than the original
  252. $resample_width = $width;
  253. $resample_height = round($resample_width / $ratio);
  254. $dst_y = - ceil(($resample_height - $height) / 2);
  255. }
  256. }
  257. }
  258. else
  259. {
  260. // No background filling or cutting, create an image with same ratio
  261. $new_image = imagecreatetruecolor($resample_width, $resample_height);
  262. }
  263. // Retain transparency, if any
  264. if ( ! $should_fill)
  265. {
  266. $trans_colour = imagecolorallocatealpha($new_image, 0, 0, 0, 127);
  267. imagefill($new_image, 0, 0, $trans_colour);
  268. imagesavealpha($new_image, TRUE);
  269. }
  270. // TODO: set padding if required
  271. imgs_log("imagecopyresampled($target_file, $filename, $dst_x, $dst_y, $src_x, $src_y, $resample_width, $resample_height, $orig_width, $orig_height)");
  272. switch ($type)
  273. {
  274. // ----
  275. case 1: // GIF
  276. // ----
  277. $image = imagecreatefromgif($filename);
  278. if ($image)
  279. {
  280. if (imagecopyresampled($new_image, $image, $dst_x, $dst_y, $src_x, $src_y, $resample_width, $resample_height, $orig_width, $orig_height))
  281. {
  282. if ($should_watermark)
  283. {
  284. imgs_apply_watermark($new_image);
  285. }
  286. // Save to cache
  287. if (CACHE)
  288. {
  289. imagegif($new_image, $target_file);
  290. //@chmod($target_file,PERMISSION);
  291. }
  292. // Output
  293. header('Content-type: image/gif');
  294. imagegif($new_image);
  295. }
  296. }
  297. break;
  298. // ----
  299. case 2: //JPEG
  300. // ----
  301. $image = imagecreatefromjpeg($filename);
  302. if ($image)
  303. {
  304. if (imagecopyresampled($new_image, $image, $dst_x, $dst_y, $src_x, $src_y, $resample_width, $resample_height, $orig_width, $orig_height))
  305. {
  306. if ($should_watermark)
  307. {
  308. imgs_apply_watermark($new_image);
  309. }
  310. // Save to cache
  311. if (CACHE)
  312. {
  313. imagejpeg($new_image, $target_file, JPEG_QUALITY);
  314. //@chmod($target_file,PERMISSION);
  315. }
  316. // Output
  317. header('Content-type: image/jpeg');
  318. imagejpeg($new_image, NULL, JPEG_QUALITY);
  319. }
  320. }
  321. break;
  322. // ----
  323. case 3: // PNG
  324. // ----
  325. $line = "Creating PNG: ";
  326. $image = imagecreatefrompng($filename);
  327. if ($image)
  328. {
  329. $line .= "OK";
  330. imgs_log($line);
  331. $line = "Resampling: ";
  332. if (imagecopyresampled($new_image, $image, $dst_x, $dst_y, $src_x, $src_y, $resample_width, $resample_height, $orig_width, $orig_height))
  333. {
  334. $line .= "OK";
  335. if ($should_watermark)
  336. {
  337. imgs_apply_watermark($new_image);
  338. }
  339. // Save to cache
  340. if (CACHE)
  341. {
  342. imagepng($new_image, $target_file, PNG_QUALITY);
  343. //@chmod($target_file,PERMISSION);
  344. }
  345. // Output
  346. header('Content-type: image/png');
  347. imagepng($new_image, NULL, PNG_QUALITY);
  348. }
  349. else
  350. {
  351. $line .= "FAILED";
  352. }
  353. }
  354. else
  355. {
  356. $line .= "FAILED";
  357. }
  358. imgs_log($line);
  359. } // -- end type switch
  360. }
  361. function imgs_log($line)
  362. {
  363. if ( ! DEBUG)
  364. {
  365. return;
  366. }
  367. if ( ! file_exists(LOG_PATH) OR ! is_writeable(LOG_PATH))
  368. {
  369. return;
  370. }
  371. $line = date("Y-m-d H:i:s") .": $line\n";
  372. file_put_contents(LOG_PATH, $line, FILE_APPEND | LOCK_EX);
  373. }
  374. /**
  375. * Apply the watermark to the image
  376. * @param resource $image
  377. * @param int $width
  378. * @param int $height
  379. * @return bool
  380. */
  381. function imgs_apply_watermark(&$image)
  382. {
  383. if (file_exists(WATERMARK))
  384. {
  385. $wm = imagecreatefrompng(WATERMARK);
  386. list($wm_width, $wm_height) = getimagesize(WATERMARK);
  387. $width = imagesx($image);
  388. $height = imagesy($image);
  389. // If we want resizing or the watermark is too big for this image
  390. if (WATERMARK_RESIZE OR $wm_width > $width OR $wm_height > $height)
  391. {
  392. $ratio = $wm_width/$wm_height;
  393. $new_wm_height = $height;
  394. $new_wm_width = $width;
  395. // Preserve aspect ratio of the watermark
  396. if ($new_wm_width/$new_wm_height > $ratio)
  397. {
  398. $new_wm_width = round($new_wm_height*$ratio);
  399. }
  400. else
  401. {
  402. $new_wm_height = round($new_wm_width/$ratio);
  403. }
  404. }
  405. else
  406. {
  407. $new_wm_height = $wm_height;
  408. $new_wm_width = $wm_width;
  409. }
  410. switch (WATERMARK_HALIGN)
  411. {
  412. case 'left': $dst_x = 0; break;
  413. case 'right': $dst_x = $width - $new_wm_width; break;
  414. default:
  415. case 'center': $dst_x = intval(($width - $new_wm_width) / 2);
  416. }
  417. switch (WATERMARK_VALIGN)
  418. {
  419. case 'top': $dst_y = 0; break;
  420. case 'bottom': $dst_y = $height - $new_wm_height; break;
  421. default:
  422. case 'center': $dst_y = intval(($height - $new_wm_height) / 2);
  423. }
  424. // Copy resampled watermark
  425. imagecopyresampled($image, $wm, $dst_x, $dst_y, 0, 0, $new_wm_width, $new_wm_height, $wm_width, $wm_height);
  426. return TRUE;
  427. }
  428. return FALSE;
  429. }