PageRenderTime 73ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/thumb.php

https://github.com/BrianPrz/worklist
PHP | 420 lines | 228 code | 49 blank | 143 comment | 76 complexity | 015d916c3551618903e4f3d3f4ee4ed2 MD5 | raw file
  1. <?php
  2. require_once ("config.php");
  3. if (!defined("ALL_ASSETS")) define("ALL_ASSETS", "all_assets");
  4. $thumb = new thumber();
  5. class thumber {
  6. /**
  7. * This var holds the blob from database
  8. * @var string
  9. */
  10. var $content;
  11. /**
  12. * This var holds the mime type of the image
  13. * @var string
  14. */
  15. var $content_type;
  16. /**
  17. * This var holds the size of the image
  18. * @var int
  19. */
  20. var $size;
  21. /**
  22. * This var holds the image name
  23. * @var string
  24. */
  25. var $filename;
  26. /**
  27. * This is the date the image was created
  28. * @var string
  29. */
  30. var $created;
  31. /**
  32. * This is the date the image was modified
  33. * @var string
  34. */
  35. var $updated;
  36. /**
  37. * This is the requested width
  38. * @var int
  39. */
  40. var $width;
  41. /**
  42. * This is the requested height
  43. * @var int
  44. */
  45. var $height;
  46. /**
  47. * This is flag for zoom crop
  48. * @var int 1|0
  49. */
  50. var $zoom_crop;
  51. /**
  52. * This is the database object used to query the database
  53. * @var $db OBJECT
  54. */
  55. var $db;
  56. /**
  57. * This var holds an array of finerControl objects that represents
  58. * settings which we should NOT cache
  59. * @var array
  60. */
  61. var $blacklist;
  62. /**
  63. * This var holds an array of finerControl objects that represents
  64. * settings which we should cache
  65. * @var array
  66. */
  67. var $whitelist;
  68. /***
  69. * Constructor
  70. * Handles file requests, does initial checking to the server
  71. */
  72. public function __construct() {
  73. // make sure the system has support for what we need
  74. $this->initialChecks();
  75. $this->width = ( int ) $_REQUEST ["w"];
  76. $this->height = ( int ) $_REQUEST ["h"];
  77. $this->zoom_crop = isset($_REQUEST ["zc"]) ? 1 : 0;
  78. /**
  79. // example of files that the script will NOT cache
  80. $this->blacklist = array (
  81. // don't cache files with width = 0 and height =0
  82. new finerControl(0,0),
  83. // don't cache any files that are request from IP 10.10.10.10
  84. new finerControl(NULL,NULL,"10.10.10.10")
  85. );
  86. // example of files that the script will cache
  87. $this->whitelist = array (
  88. // cache files with width = 150 and height = 150 from any IP
  89. new finerControl(150,150),
  90. // cache all file requests that come from ip 10.10.10.11
  91. // disregarding the image dimensions
  92. new finerControl(NULL,NULL,"10.10.10.11")
  93. );
  94. */
  95. $this->db = new Database();
  96. $this->getImage();
  97. }
  98. /**
  99. * Does checks to find out of system has support for us
  100. * and also makes sure that the request has all the info we need
  101. */
  102. protected function initialChecks() {
  103. // check to see if GD function exist
  104. if (! function_exists('imagecreatetruecolor')) {
  105. $this->displayError('GD Library Error: imagecreatetruecolor does not exist - ' . 'please contact your webhost and ask them to install the GD library');
  106. }
  107. if (! isset($_REQUEST ["image"]) && ! isset($_REQUEST ["src"])) {
  108. $this->displayError('Image file is not set');
  109. }
  110. if (! isset($_REQUEST ["w"])) {
  111. $this->displayError('Width is not set');
  112. }
  113. if (! isset($_REQUEST ["h"])) {
  114. $this->displayError('Height is not set');
  115. }
  116. if ($_REQUEST["w"] > MAX_THUMB_SIZE || $_REQUEST["h"] > MAX_THUMB_SIZE) {
  117. $this->displayError('Dimensions exceed '.MAX_THUMB_SIZE.'px');
  118. }
  119. }
  120. /**
  121. * This function looks if the image exists in the database
  122. * with the added requirements. If it exists the image is outputed.
  123. * If it doesn't exist with the required dimensions but exists in the database with its
  124. * default size, the script creates a new image based on the passed dimensions and if
  125. * the image is part of the files we want to cache, a new record is inserted in the database.
  126. * If the original image doesn't exist an error is returned.
  127. * @param string $image
  128. * @param array $dimensions
  129. */
  130. protected function getImage() {
  131. $image = isset($_REQUEST["image"]) ? $_REQUEST["image"] : $_REQUEST["src"];
  132. if(empty($image)){
  133. $image = "no_picture.png";
  134. }
  135. // remove any directories that could be set from the request
  136. // and only get the filename in lowercase chars
  137. if(strrchr($image,"/")){
  138. $image = strtolower(substr(strrchr($image,"/"),1,strlen(strrchr($image,"/"))));
  139. }
  140. $imageName = $this->buildImageName($image);
  141. if ($this->imageExists($imageName)) {
  142. $this->outputImage();
  143. } else {
  144. // here we check to see if there is an image with that name in the db
  145. // if there is, we will adjust accordingly to the dimensions otherwise
  146. // we will return an error
  147. //GJ:FIX:start image transfer before testing for/save in db (writes are slow) - FIXED
  148. if ($this->imageExists($image)) {
  149. $img = $this->resizeImage($this->content);
  150. $this->outputImage($img);
  151. if ($this->saveCache()) {
  152. $this->createCache($img);
  153. }
  154. //$this->outputImage($img);
  155. } else {
  156. //GJ:New Task:provide an error image flag (file or db) [eg: ERR_HTTP_404]
  157. $this->displayError('Image doesn\'t exists');
  158. }
  159. }
  160. }
  161. /**
  162. * Compares the image to the passed list
  163. * @param array $list
  164. * @return bool
  165. */
  166. protected function partOf($list) {
  167. if (empty($list)) { return false; }
  168. foreach ( $list as $fControl ) {
  169. $ipMatch = false;
  170. $wMatch = false;
  171. $hMatch = false;
  172. //GJ:TODO:Map to autoconfig remote address (detects proxy forwards)
  173. if (isset($fControl->ip) && $fControl->ip = $_SERVER ["REMOTE_ADDR"]) {
  174. $ipMatch = true;
  175. }
  176. if (isset($fControl->width) && $fControl->width == $this->width) {
  177. $wMatch = true;
  178. }
  179. if (isset($fControl->height) && $fControl->height == $this->height) {
  180. $hMatch = true;
  181. }
  182. if ($ipMatch && $wMatch && $hMatch) {
  183. return true;
  184. } else if ($ipMatch && $wMatch) {
  185. if (! isset($fControl->height)) {
  186. return true;
  187. }
  188. } else if ($ipMatch && $hMatch) {
  189. if (! isset($fControl->width)) {
  190. return true;
  191. }
  192. } else if ($hMatch && $wMatch) {
  193. if (! isset($fControl->ip)) {
  194. return true;
  195. }
  196. } else if ($ipMatch) {
  197. if (! isset($fControl->width) && ! isset($fControl->height)) {
  198. return true;
  199. }
  200. } else if ($wMatch) {
  201. if (! isset($fControl->ip) && ! isset($fControl->height)) {
  202. return true;
  203. }
  204. } else if ($hMatch) {
  205. if (! isset($fControl->width) && ! isset($fControl->ip)) {
  206. return true;
  207. }
  208. }
  209. }
  210. return false;
  211. }
  212. /**
  213. * Checks to see if we should cache file
  214. */
  215. protected function saveCache() {
  216. if ($this->partOf($this->blacklist)) {
  217. return false;
  218. } else if ($this->partOf($this->whitelist)) {
  219. return true;
  220. } else {
  221. return false;
  222. }
  223. }
  224. /**
  225. * Saves the cache to the database
  226. * @param string $image
  227. */
  228. protected function createCache($image) {
  229. //GJ:BUG?:WHere is this image value being untainted? should value be bound/encdoed?
  230. $sql = "INSERT INTO " . ALL_ASSETS . " " . "(`app`, `content_type`, `content`, `filename`, `created`,) " . "VALUES('".WORKLIST."', 'image/png','" . $image . "', '" . $this->buildImageName($this->filename) . "', NOW())";
  231. $this->db->query($sql);
  232. }
  233. /**
  234. * Builds the image name
  235. * @param string $im
  236. * @return string
  237. */
  238. protected function buildImageName($im) {
  239. return $im . "w:" . $this->width . "h:" . $this->height;
  240. }
  241. /**
  242. * Checks to see if image exists in the database
  243. * @param string $imageName
  244. * @return bool
  245. */
  246. protected function imageExists($imageName) {
  247. $sql = "SELECT * FROM " . ALL_ASSETS . " WHERE filename = '" . mysql_real_escape_string($imageName,$this->db->getLink()) . "'";
  248. $res = $this->db->query($sql);
  249. if (mysql_num_rows($res) > 0) {
  250. $this->assignImageProperties(mysql_fetch_assoc($res));
  251. return true;
  252. } else {
  253. return false;
  254. }
  255. }
  256. /**
  257. * Populates class data members
  258. * @param array $properties
  259. */
  260. protected function assignImageProperties($properties) {
  261. foreach ( $properties as $property => $value ) {
  262. if (!isset($this->$property) || is_null($this->$property)) {
  263. $this->$property = $value;
  264. }
  265. }
  266. }
  267. /**
  268. * Outputs the image to the browser with proper header
  269. * @param bool|image resource $im
  270. */
  271. protected function outputImage($im = false) {
  272. if ($im === false) {
  273. $im = imagecreatefromstring($this->content);
  274. if ($im !== false) {
  275. header('Content-Type: image/png');
  276. imagepng($im);
  277. imagedestroy($im);
  278. } else {
  279. $this->displayError('An error while creating the image occurred.');
  280. }
  281. } else {
  282. header('Content-Type: image/png');
  283. imagepng($im);
  284. imagedestroy($im);
  285. }
  286. }
  287. /**
  288. * generic error message
  289. */
  290. protected function displayError($errorString = '') {
  291. header('HTTP/1.1 400 Bad Request');
  292. echo '<pre>' . $errorString . '</pre>';
  293. die();
  294. }
  295. /*
  296. * The code below is based on:
  297. * TimThumb script created by Tim McDaniels and Darren Hoyt with tweaks by Ben Gillbanks
  298. **/
  299. protected function resizeImage($image) {
  300. $im = imagecreatefromstring($image);
  301. // Get original width and height
  302. $width = imagesx($im);
  303. $height = imagesy($im);
  304. // generate new w/h if not provided
  305. if ($this->width && ! $this->height) {
  306. $this->height = $height * ($this->width / $width);
  307. } elseif ($this->height && ! $this->width) {
  308. $this->width = $width * ($this->height / $height);
  309. } elseif (! $this->width && ! $this->height) {
  310. $this->width = $width;
  311. $this->height = $height;
  312. }
  313. // create a new true color image
  314. $canvas = imagecreatetruecolor($this->width,$this->height);
  315. imagealphablending($canvas,false);
  316. // Create a new transparent color for image
  317. $color = imagecolorallocatealpha($canvas,0,0,0,127);
  318. // Completely fill the background of the new image with allocated color.
  319. imagefill($canvas,0,0,$color);
  320. // Restore transparency blending
  321. imagesavealpha($canvas,true);
  322. if ($this->zoom_crop == 1) {
  323. $src_x = $src_y = 0;
  324. $src_w = $width;
  325. $src_h = $height;
  326. $cmp_x = $width / $this->width;
  327. $cmp_y = $height / $this->height;
  328. // calculate x or y coordinate and width or height of source
  329. if ($cmp_x > $cmp_y) {
  330. $src_w = round(($width / $cmp_x * $cmp_y));
  331. $src_x = round(($width - ($width / $cmp_x * $cmp_y)) / 2);
  332. } elseif ($cmp_y > $cmp_x) {
  333. $src_h = round(($height / $cmp_y * $cmp_x));
  334. $src_y = round(($height - ($height / $cmp_y * $cmp_x)) / 2);
  335. }
  336. imagecopyresampled($canvas,$im,0,0,$src_x,$src_y,$this->width,$this->height,$src_w,$src_h);
  337. } else {
  338. if ($width > $height) {
  339. $factor = ( float ) $this->width / ( float ) $width;
  340. $newer_height = $factor * $height;
  341. $newer_width = $this->width;
  342. } else {
  343. $factor = ( float ) $this->height / ( float ) $height;
  344. $newer_width = $factor * $width;
  345. $newer_height = $this->height;
  346. }
  347. $new_x = ($this->width - $newer_width) / 2;
  348. $new_y = ($this->height - $newer_height) / 2;
  349. // copy and resize part of an image with resampling
  350. imagecopyresampled($canvas,$im,$new_x,$new_y,0,0,$newer_width,$newer_height,$width,$height);
  351. }
  352. return $canvas;
  353. }
  354. }
  355. class finerControl {
  356. public $width = NULL;
  357. public $height = NULL;
  358. public $ip = NULL;
  359. public function __construct($w = NULL, $h = NULL, $ip = NULL) {
  360. if (isset($w)) {
  361. $this->width = $w;
  362. }
  363. if (isset($h)) {
  364. $this->height = $h;
  365. }
  366. if (isset($ip)) {
  367. $this->ip = $ip;
  368. }
  369. }
  370. }