PageRenderTime 74ms CodeModel.GetById 33ms RepoModel.GetById 0ms app.codeStats 1ms

/system/expressionengine/third_party/ce_img/libraries/Ce_image.php

https://bitbucket.org/studiobreakfast/sync
PHP | 5901 lines | 4299 code | 580 blank | 1022 comment | 856 complexity | 00e446de9ac0bcf9f8e5b5f706fc82f8 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. error_reporting(E_ALL);
  3. ini_set('display_errors', '1');
  4. /**
  5. * CE Image: Powerful image manipulation made easy.
  6. * Last Updated: 19 June 2012
  7. *
  8. * License:
  9. * CE Image is licensed under the Commercial License Agreement found at http://www.causingeffect.com/software/expressionengine/ce-image/license-agreement
  10. * Here are a couple of specific points from the license to note again:
  11. * - One license grants the right to perform one installation of CE Image. Each additional installation of CE Image requires an additional purchased license.
  12. * - You may not reproduce, distribute, or transfer CE Image, or portions thereof, to any third party.
  13. * - You may not sell, rent, lease, assign, or sublet CE Image or portions thereof.
  14. * - You may not grant rights to any other person.
  15. * - You may not use CE Image in violation of any United States or international law or regulation.
  16. * - The only exceptions to the above four (4) points are any methods clearly designated as having an MIT-style license. Those portions of code specifically designated as having an MIT-style license, and only those portions, will remain bound to the terms of that license.
  17. * If you have any questions about the terms of the license, or would like to report abuse of its terms, please contact software@causingeffect.com.
  18. *
  19. * @package CE Image
  20. * @author Causing Effect, Aaron Waldon
  21. * @link http://www.causingeffect.com
  22. * @copyright 2012
  23. * @version 1.6.5
  24. * @license http://www.causingeffect.com/software/expressionengine/ce-image/license-agreement Causing Effect Commercial License Agreement
  25. */
  26. class Ce_image
  27. {
  28. private $valid_filters = array(
  29. //native IMG_FILTER_ filters
  30. 'brightness' => 'imagefilter',
  31. 'colorize' => 'imagefilter',
  32. 'contrast' => 'imagefilter',
  33. 'edgedetect' => 'imagefilter',
  34. 'emboss' => 'imagefilter',
  35. 'grayscale' => 'imagefilter',
  36. 'mean_removal' => 'imagefilter',
  37. 'negate' => 'imagefilter',
  38. 'pixelate' => 'imagefilter',
  39. 'smooth' => 'imagefilter',
  40. //custom filters
  41. '_pixelate' => array( 'self', 'pixelate' ),
  42. 'gaussian_blur' => array( 'self', 'gaussian_blur' ),
  43. 'selective_blur' => array( 'self', 'selective_blur' ),
  44. 'auto_sharpen' => array( 'self', 'auto_sharpen' ),
  45. 'cemboss' => array( 'self', 'emboss_color' ),
  46. 'dot' => array( 'self', 'dot' ),
  47. 'noise' => array( 'self', 'noise' ),
  48. 'opacity' => array( 'self', 'opacity' ),
  49. 'replace_colors' => array( 'self', 'replace_colors' ),
  50. 'scatter' => array( 'self', 'scatter' ),
  51. 'sepia' => array( 'self', 'sepia' ),
  52. 'sharpen' => array( 'self', 'unsharp_mask' ),
  53. 'sobel_edgify' => array( 'self', 'prep_edgify' ) //calls class method before calling filter
  54. );
  55. private $factory_defaults = array(
  56. 'allow_overwrite_original' => false,
  57. 'allow_scale_larger' => false,
  58. 'auto_cache' => false,
  59. 'base' => '',
  60. 'bg_color' => false,
  61. 'bg_color_default' => 'ffffff',
  62. 'border' => false,
  63. 'cache_dir' => '/images/made/',
  64. 'crop' => false,
  65. 'current_domain' => '',
  66. 'dir_permissions' => 0775,
  67. 'disable_xss_check' => false,
  68. 'fallback_src' => '',
  69. 'filename' => '',
  70. 'filename_prefix' => '',
  71. 'filename_suffix' => '',
  72. 'filters' => array(),
  73. 'flip' => false,
  74. 'force_remote' => false,
  75. 'hash_filename' => false,
  76. 'height' => 0,
  77. 'hide_relative_path' => false,
  78. 'image_permissions' => 0644,
  79. 'made_regex' => '',
  80. 'max_height' => 0,
  81. 'max_width' => 0,
  82. 'memory_limit' => 64,
  83. 'min_height' => 0,
  84. 'min_width' => 0,
  85. 'overwrite_cache' => false,
  86. 'quality' => 100,
  87. 'reflection' => false,
  88. 'remote_cache_time' => 1440,
  89. 'remote_dir' => '/images/remote/',
  90. 'rotate' => 0,
  91. 'rounded_corners' => false,
  92. 'save_type' => false,
  93. 'src_regex' => '',
  94. 'text' => false,
  95. 'unique' => 'filename',
  96. 'watermark' => false,
  97. 'width' => 0
  98. );
  99. //---------- don't change anything below here ----------
  100. private $is_open = false; //whether or not an image is actually open
  101. private $is_open_ready = false; //whether or not the image is ready to be opened
  102. private $is_data_ready = false; //whether or not the image data is ready
  103. private $image_data = array( 'width' => '', 'height' => '', 'type' => '', 'ext' => '' );
  104. private $image_data_orig = array( 'width' => '', 'height' => '', 'type' => '', 'ext' => '', 'src' => '' );
  105. private $image_types = array( 'png', 'gif', 'jpg', 'jpeg' );
  106. private $is_remote = false;
  107. private $remote_src = '';
  108. private $x_offset = 0;
  109. private $y_offset = 0;
  110. private $src_x_offset = 0;
  111. private $src_y_offset = 0;
  112. private $width_desired = 0;
  113. private $height_desired = 0;
  114. private $x_options = array('left', 'right', 'center');
  115. private $y_options = array('top', 'bottom', 'center');
  116. private $same_as_source = false;
  117. private $debug_messages = array();
  118. private $is_transparent = false;
  119. private $defaults = array();
  120. //watermark
  121. private $filetime_wm = 0;
  122. private $wm_image_data = array( 'width' => '', 'height' => '', 'type' => '', 'src' => '' );
  123. private $wm_array;
  124. //rounded corners
  125. private $corner_options = array('all', 'tl', 'tr', 'bl', 'br');
  126. private $corners = false;
  127. private $corners_array;
  128. //reflection
  129. private $reflection = false;
  130. private $reflection_array = array();
  131. //flag if actual image dimensions needs to be checked
  132. private $check_size = false;
  133. //flip
  134. private $flip_options = array('h', 'v');
  135. //disable XSS check
  136. private $disable_xss_check = false;
  137. //For dev testing with versions of PHP before 5.2.0, windows has to swap / with \
  138. private $windows_dev = false;
  139. private $final_action = 'none';
  140. /**
  141. * Initiates the class and optionally accepts an array of default settings. Also determines whether or not CodeIgniter is installed and available to use.
  142. *
  143. * @param array $default_settings The default settings.
  144. */
  145. function __construct( $default_settings = array() )
  146. {
  147. //set the factory defaults
  148. $this->defaults = $this->factory_defaults;
  149. //merge the params with the defaults
  150. $this->set_default_settings( $default_settings );
  151. $this->EE =& get_instance();
  152. }
  153. // ---------------------------------------------------------------------------- SETTINGS ----------------------------------------------------------------------------
  154. /**
  155. * Accepts settings to integrate with the default settings.
  156. *
  157. * @param array $default_settings The default settings that will override the previously set default settings.
  158. * @return void
  159. */
  160. public function set_default_settings( $default_settings = array() )
  161. {
  162. $defaults = $this->defaults;
  163. //override the defaults
  164. if ( count( $default_settings ) > 0 )
  165. {
  166. foreach ( $default_settings as $key => $value )
  167. {
  168. if ( ! in_array( $key, $defaults ) )
  169. {
  170. unset( $default_settings[$key] );
  171. }
  172. }
  173. $defaults = array_merge( $defaults, $default_settings );
  174. }
  175. //reset the defaults array
  176. $this->defaults = $defaults;
  177. unset( $defaults );
  178. //now that our default array is created, apply them as class properties
  179. $this->reset_to_default_settings();
  180. }
  181. /**
  182. * Accepts settings to temporarily override the default settings. The settings will not be persistent when subsequent images are opened/made.
  183. *
  184. * @param array $temp_settings The temporary settings that will override any previously set default settings.
  185. * @return void
  186. */
  187. private function set_temp_settings( $temp_settings = array() )
  188. {
  189. //reset class properties
  190. $this->check_size = false;
  191. $this->disable_xss_check = false;
  192. $this->filetime_wm = 0;
  193. $this->height_desired = 0;
  194. $this->is_remote = false;
  195. $this->remote_src = '';
  196. $this->src_x_offset = 0;
  197. $this->src_y_offset = 0;
  198. $this->width_desired = 0;
  199. $this->wm_array = array();
  200. $this->x_offset = 0;
  201. $this->y_offset = 0;
  202. $this->same_as_source = false;
  203. //reset the defaults
  204. $this->reset_to_default_settings();
  205. //set the temp settings
  206. if ( count( $temp_settings ) > 0 )
  207. {
  208. foreach ($temp_settings as $key => $val)
  209. {
  210. if ( in_array( $key, $this->factory_defaults ) )
  211. {
  212. $this->$key = $val;
  213. }
  214. }
  215. }
  216. }
  217. /**
  218. * Resets the class properties to match the default array
  219. *
  220. * @return void
  221. */
  222. private function reset_to_default_settings()
  223. {
  224. $defaults = $this->defaults;
  225. //set the class properties to the defaults array
  226. if ( count( $defaults ) > 0 )
  227. {
  228. foreach ($defaults as $key => $val)
  229. {
  230. $this->$key = $val;
  231. }
  232. }
  233. }
  234. /**
  235. * Resets the settings back to the 'factory defaults'
  236. *
  237. * @return void
  238. */
  239. public function reset_to_factory_settings()
  240. {
  241. $this->defaults = $this->factory_defaults;
  242. $this->reset_to_default_settings();
  243. }
  244. /**
  245. * Retrieves all of the current settings.
  246. *
  247. * @return array
  248. */
  249. private function get_current_settings()
  250. {
  251. $settings = array();
  252. foreach ( $this->factory_defaults as $name => $setting )
  253. {
  254. $settings[$name] = $this->$name;
  255. }
  256. return $settings;
  257. }
  258. /**
  259. * Removes double slashes, except when they are preceded by ':', so that 'http://', etc are preserved.
  260. *
  261. * @param string $str The string from which to remove the double slashes.
  262. * @return string The string with double slashes removed.
  263. */
  264. private function remove_duplicate_slashes( $str )
  265. {
  266. return preg_replace( '#(?<!:)//+#', '/', $str );
  267. }
  268. // ---------------------------------------------------------------------------- OPEN ----------------------------------------------------------------------------
  269. /**
  270. * Opens an image. Call this function if you would like to get data from an image without manipulating it. This function is also called by the 'make' method.
  271. *
  272. * @param string|resource $src The image source. Can be a relative path to document root, a full server (absolute) path, a URL (remote or local), an HTML snippet, or a GD2 image resource.
  273. * @param array $temp_settings The settings that will temporary override the previously set default settings, for this image only.
  274. * @return bool Will return true on success and false on failure.
  275. */
  276. public function open( $src = '', $temp_settings = array() )
  277. {
  278. $is_string = ! is_resource( $src );
  279. $this->set_temp_settings( $temp_settings );
  280. $this->is_data_ready = false;
  281. $this->is_open_ready = false;
  282. $this->is_open = false;
  283. //base path
  284. $base = ( $this->base != '') ? $this->base : $_SERVER['DOCUMENT_ROOT'];
  285. $base = str_replace('\\', '/', $this->EE->security->xss_clean( $base ) );
  286. $this->base = $this->remove_duplicate_slashes( $base . '/' );
  287. $this->debug_messages[] = "Base path: '$this->base'";
  288. if ( $is_string ) //string src
  289. {
  290. $this->src = $src;
  291. //check to make sure the source is not blank
  292. if ( $this->src == '' && $this->fallback_src == '' )
  293. {
  294. $this->debug_messages[] = 'Source and fallback source cannot both be blank.';
  295. return false;
  296. }
  297. $this->src = str_replace('\\', '/', $this->src);
  298. //get the source from the first image tag, if one exists
  299. if ( preg_match('#<img.+src="(.*)".*>#Uims', $this->src, $matches) )
  300. {
  301. $this->src = $matches[1];
  302. }
  303. $this->src = $this->EE->security->xss_clean( $this->src );
  304. $this->fallback_src = str_replace('\\', '/', $this->fallback_src);
  305. $this->fallback_src = $this->EE->security->xss_clean( $this->fallback_src );
  306. //source and fallback source
  307. $this->debug_messages[] = "Source image: '$this->src', Fallback image: '$this->fallback_src'";
  308. if ( $this->src == '' || $this->check_src_image() == false )
  309. {
  310. //source is not readable or does not exist, write debug message and check fallback source
  311. $this->debug_messages[] = "Source image is not readable or does not exist: '$this->src'.";
  312. $this->src = $this->fallback_src;
  313. if ( $this->src == '' || $this->check_src_image() == false )
  314. {
  315. //fallback source is not readable, not much more to do...
  316. $this->debug_messages[] = "Fallback source image is not readable or does not exist: '$this->src'.";
  317. return false;
  318. }
  319. }
  320. //get the path info
  321. $info = pathinfo( $this->src );
  322. //get the relative path
  323. if ( $this->is_above_root ) //normal
  324. {
  325. $this->relative = ( $this->hide_relative_path ) ? '' : preg_replace( '@' . preg_quote( $this->base, '@' ) . '@', '', '/' . $info['dirname'] . '/', 1 );
  326. }
  327. else //we don't want to reveal server info below web root
  328. {
  329. $this->relative = '';
  330. if ( ! $this->hide_relative_path && ! empty( $info['dirname'] ) )
  331. {
  332. $this->relative = substr( md5( $info['dirname'] ), 0, 16 ) . '/';
  333. }
  334. }
  335. }
  336. else //resource
  337. {
  338. $this->src = '';
  339. $this->handle = $src;
  340. $this->is_above_root = true;
  341. $this->relative = '';
  342. }
  343. //auto cache directory
  344. if ( $this->auto_cache != '' && $this->is_above_root )
  345. {
  346. $this->auto_cache = $this->EE->security->xss_clean( $this->remove_duplicate_slashes( '/' . $this->auto_cache . '/' ) );
  347. $this->cache_full = $this->remove_duplicate_slashes( $this->base . $this->relative . $this->auto_cache );
  348. }
  349. else
  350. {
  351. //cache paths
  352. $this->cache_dir = $this->remove_duplicate_slashes( '/' . $this->cache_dir . '/' );
  353. $this->cache_full = $this->remove_duplicate_slashes( $this->base . $this->cache_dir . $this->relative );
  354. }
  355. if ( $this->windows_dev )
  356. {
  357. $this->cache_full = str_replace( '/', '\\', $this->cache_full);
  358. }
  359. if ( $is_string ) //string src
  360. {
  361. //get the image data
  362. $status = $this->get_image_data();
  363. if ( $status === 'try again' )
  364. {
  365. return $this->open( $this->fallback_src );
  366. }
  367. else if ($status === false)
  368. {
  369. return false;
  370. }
  371. //original extension (use this if possible to preserve casing)
  372. if ( isset( $info['extension'] ) )
  373. {
  374. $this->image_data_orig['ext'] = $info['extension'];
  375. }
  376. else
  377. {
  378. $this->image_data_orig['ext'] = '';
  379. }
  380. //get original filename
  381. if ( isset( $info['filename'] ) ) //>= PHP 5.2.0
  382. {
  383. $filename = $info['filename'];
  384. }
  385. else //< PHP 5.2.0
  386. {
  387. $filename = substr_replace( $info['basename'], '', strrpos( $info['basename'], '.' . $this->image_data_orig['ext'] ), strlen( '.' . $this->image_data_orig['ext'] ) );
  388. }
  389. //store original filename
  390. $this->filename_orig = $this->EE->security->sanitize_filename( $filename );
  391. $this->filename_final = $this->filename_orig;
  392. }
  393. else //resource
  394. {
  395. $filename = 'temp';
  396. $width = round( imagesx( $this->handle ) );
  397. $height = round( imagesy( $this->handle ) );
  398. $this->image_data = array( 'width' => $width, 'height' => $height, 'type' => '', 'ext' => '' );
  399. $this->image_data_orig = array( 'width' => $width, 'height' => $height, 'type' => '', 'ext' => '', 'src' => '' );
  400. $this->filename_orig = '';
  401. $this->filename_final = '';
  402. $this->is_open = true;
  403. }
  404. //---------- filename ----------
  405. $temp = trim( $this->filename );
  406. $filename = ( $temp === '' ) ? $filename : $temp;
  407. $this->filename = $this->EE->security->sanitize_filename( $filename );
  408. $this->is_open_ready = true;
  409. $this->is_data_ready = true;
  410. return true;
  411. }
  412. /**
  413. * Retrieves the image data for the current src image.
  414. *
  415. * @return bool Will return true on success and false on failure.
  416. */
  417. private function get_image_data()
  418. {
  419. //get the image info
  420. $data = @getimagesize( $this->src );
  421. $success = true;
  422. if ( ! $data )
  423. {
  424. $success = false;
  425. }
  426. else
  427. {
  428. $ext = '';
  429. switch ( $data[2] )
  430. {
  431. case IMAGETYPE_GIF:
  432. $ext = 'gif';
  433. break;
  434. case IMAGETYPE_PNG:
  435. $ext = 'png';
  436. break;
  437. case IMAGETYPE_JPEG:
  438. $ext = 'jpg';
  439. break;
  440. default:
  441. $success = false;
  442. }
  443. }
  444. if ( ! $success )
  445. {
  446. $this->debug_messages[] = 'Unknown image format.';
  447. //there is a small chance the image was an error page, try and use the fallback source
  448. if ( $this->src != $this->fallback_src && $this->fallback_src != '' ) //retry with the fallback as the source
  449. {
  450. $this->debug_messages[] = 'Reprocessing using the fallback image.';
  451. return 'try again'; //try again
  452. }
  453. return false;
  454. }
  455. //$this->image_data_orig['type'] = $data[2];
  456. $this->image_data = array( 'width' => $data[0], 'height' => $data[1], 'ext' => $ext );
  457. $this->image_data_orig = array( 'width' => $data[0], 'height' => $data[1], 'ext' => $ext, 'type' => $data[2], 'src' => $this->src );
  458. return true;
  459. }
  460. /**
  461. * Opens the actual image resource.
  462. * @param bool $original
  463. * @return bool Returns true on success and false on failure.
  464. */
  465. private function open_real( $original = false )
  466. {
  467. if ( ! $this->is_open_ready )
  468. {
  469. //return false;
  470. $this->open( $this->src );
  471. }
  472. if ( $this->is_open )
  473. {
  474. return true;
  475. }
  476. //set the memory limit
  477. $this->set_memory_limit();
  478. if ( $this->src != '' ) //do not try to open if the src is '', because it's a resource
  479. {
  480. $which = ( $original ) ? 'image_data_orig' : 'image_data';
  481. if ( isset( $this->{$which}['type'] ) && $this->{$which}['type'] != '' )
  482. {
  483. switch ( $this->{$which}['type'] )
  484. {
  485. case IMAGETYPE_GIF:
  486. $type = 'gif';
  487. break;
  488. case IMAGETYPE_PNG:
  489. $type = 'png';
  490. break;
  491. case IMAGETYPE_JPEG:
  492. $type = 'jpg';
  493. break;
  494. default:
  495. $type = '';
  496. }
  497. }
  498. else if (in_array(strtolower($this->{$which}['ext']), $this->image_types))
  499. {
  500. $type = strtolower($this->{$which}['ext']);
  501. }
  502. //open the file and create main image handle
  503. switch ( $type )
  504. {
  505. case 'gif':
  506. $success = @imagecreatefromgif( $this->src );
  507. break;
  508. case 'png':
  509. $success = @imagecreatefrompng( $this->src );
  510. break;
  511. case 'jpg':
  512. case 'jpeg':
  513. $success = @imagecreatefromjpeg( $this->src );
  514. break;
  515. default:
  516. $this->debug_messages[] = 'Unknown image format for image creation.';
  517. $success = false;
  518. }
  519. if ( $success === false )
  520. {
  521. $this->debug_messages[] = "A problem occurred trying to open the image '$this->src'.";
  522. return false;
  523. }
  524. else
  525. {
  526. $this->handle = $success;
  527. }
  528. }
  529. $this->is_open = true;
  530. $this->debug_messages[] = "Image opened '$this->src'.";
  531. return true;
  532. }
  533. /**
  534. * Attempts to determine the server path from the image src parameter. Will also download a remote image if applicable and return its server path.
  535. *
  536. * @return bool Returns true if the image is found successfully and false otherwise.
  537. */
  538. private function check_src_image()
  539. {
  540. //perform any advanced preg_replaces if they exist
  541. $replacements = $this->src_regex;
  542. if ( $replacements != false && is_array( $replacements ) && count( $replacements ) > 0 )
  543. {
  544. $find = array();
  545. $replace = array();
  546. foreach( $replacements as $f => $r )
  547. {
  548. $find[] = '@' . $f . '@';
  549. $replace[] = $r;
  550. }
  551. $this->src = preg_replace( $find, $replace, $this->src );
  552. //show the new source
  553. $this->debug_messages[] = "Regexed source: '$this->src'";
  554. }
  555. //adjust for protocol-relative URLs
  556. if ( substr( $this->src, 0, 3 ) == '://' )
  557. {
  558. if ( isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on' )
  559. {
  560. $this->src = 'https' . $this->src;
  561. }
  562. else
  563. {
  564. $this->src = 'http' . $this->src;
  565. }
  566. }
  567. //check if a URL
  568. if ( substr( $this->src, 0, 4 ) == 'http' )
  569. {
  570. $info = parse_url( $this->src );
  571. if ( $info === false )
  572. {
  573. $this->debug_messages[] = "The url '{$this->src}' could not be parsed. Is your URL malformed?";
  574. return false;
  575. }
  576. $current_domain_override = $this->current_domain;
  577. if ( $current_domain_override == '' ) //no domain specified, try to figure it out
  578. {
  579. $current_domain_override = $this->EE->security->xss_clean( preg_replace( '@' . preg_quote( 'www.', '@' ) . '@', '', $_SERVER['SERVER_NAME'], 1 ) );
  580. }
  581. else //use the current domain value as set in plugin or config
  582. {
  583. $temp = parse_url( $current_domain_override );
  584. if ( $temp === false )
  585. {
  586. $this->debug_messages[] = "The url '{$current_domain_override}' could not be parsed. Is it malformed?";
  587. return false;
  588. }
  589. if ( ! isset( $temp['host'] ) ) //verify that the host key is set
  590. {
  591. $this->debug_messages[] = "The value specified for the 'current_domain' is invalid.";
  592. return false;
  593. }
  594. $current_domain_override = preg_replace( '@' . preg_quote( 'www.', '@') . '@', '', $temp['host'], 1 );
  595. }
  596. $path = isset( $info['path'] ) ? $info['path'] : '';
  597. if ( $this->force_remote || preg_replace( '@' . preg_quote( 'www.', '@') . '@', '', $info['host'], 1 ) != $current_domain_override ) //remote
  598. {
  599. $this->is_remote = true;
  600. $this->remote_src = $this->src;
  601. //get remote_dir param
  602. $this->remote_dir = $this->remove_duplicate_slashes( '/' . $this->remote_dir . '/' );
  603. $temp = $this->base . '/' . $this->remote_dir . $info['scheme'] . '_' . $info['host'] . $path;
  604. //create and sanitize the file path
  605. $temp = $this->EE->security->xss_clean( $this->remove_duplicate_slashes( $temp ) );
  606. $path_info = pathinfo( $temp );
  607. //make sure the query string gets worked in if applicable
  608. if ( isset( $info['query'] ) )
  609. {
  610. $path_info['dirname'] = $this->remove_duplicate_slashes( $path_info['dirname'] . '/' . md5( $info['query'] ) );
  611. }
  612. $remote_cache = $path_info['dirname'];
  613. $remote_filename = $this->EE->security->sanitize_filename( $path_info['basename'] );
  614. $file = $remote_cache . '/' . $remote_filename;
  615. $file_exists = @file_exists( $file );
  616. if ( $file_exists )
  617. {
  618. //determine the course of action for refreshing the remote image depending on the settings
  619. $file_m_time = @filemtime( $file ); //filetime of cached image
  620. if ( $this->remote_cache_time != -1 ) //don't worry about re-downloading the remote image if remote_cache_time is -1
  621. {
  622. //check the timestamp of the image
  623. $remote_timestamp = 0;
  624. //see if the user has curl so we can check the timestamp
  625. if ( $this->remote_cache_time == 0 && function_exists( 'curl_init' ) ) //check if the remote image is newer than the downloaded version if remote_cache_time is 0
  626. {
  627. $this->debug_messages[] = "Checking whether the remote image '{$this->remote_src}' is newer than the cached version via cURL.";
  628. $curl = curl_init( $this->remote_src );
  629. curl_setopt($curl, CURLOPT_NOBODY, true); //only fetch headers
  630. curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); //no output
  631. curl_setopt($curl, CURLOPT_FILETIME, true); //attempt to get date modified
  632. //follow location will throw an error if safe mode or an open basedir restrictions is enabled
  633. if ( ! ini_get('open_basedir') && ! ini_get('safe_mode') )
  634. {
  635. curl_setopt( $curl, CURLOPT_FOLLOWLOCATION, true );
  636. }
  637. if ( curl_exec($curl) !== false)
  638. {
  639. $remote_timestamp = curl_getinfo($curl, CURLINFO_FILETIME);
  640. }
  641. }
  642. $delete_cache = false;
  643. if ( $remote_timestamp != 0 && $remote_timestamp > $file_m_time ) //the remote image is newer
  644. {
  645. $this->debug_messages[] = "The remote image '{$this->remote_src}' is newer than the cached version.";
  646. $delete_cache = true;
  647. }
  648. else if (time() - $file_m_time > $this->remote_cache_time * 60) //the remote file has expired
  649. {
  650. $this->debug_messages[] = "The local cache of the remote image has expired.";
  651. $delete_cache = true;
  652. }
  653. //delete the current remote cache file
  654. if ( $delete_cache )
  655. {
  656. @unlink( $file );
  657. //recheck if the file exists
  658. $file_exists = @file_exists( $file );
  659. }
  660. }
  661. }
  662. //if the image is not on the server, download it
  663. if ( ! $file_exists )
  664. {
  665. if ( $this->windows_dev )
  666. {
  667. $remote_cache = str_replace('/', '\\', $remote_cache);
  668. }
  669. if ( $this->save_remote_image( $remote_cache, $remote_filename ) === false )
  670. {
  671. return false;
  672. }
  673. }
  674. //change the source from the remote image to the downloaded image
  675. $this->src = $this->remove_duplicate_slashes( $remote_cache . '/' . $remote_filename );
  676. }
  677. else //local
  678. {
  679. $this->src = $path;
  680. }
  681. }
  682. //---------- figure out source path ----------
  683. $this->is_above_root = true;
  684. $temp = $this->remove_duplicate_slashes( $this->base . $this->src );
  685. if ( @is_readable( $temp ) === true ) //relative path
  686. {
  687. //create full path for source
  688. $this->src = $this->remove_duplicate_slashes( realpath($temp) );
  689. $this->src = str_replace('\\', '/', $this->src);
  690. }
  691. //see if path below web root
  692. if ( strpos($this->src, $this->base) === false )
  693. {
  694. $this->is_above_root = false;
  695. }
  696. //make sure the image is readable and is not a directory
  697. if ( @is_dir( $this->src ) || @is_readable( $this->src ) !== true )
  698. {
  699. return false;
  700. }
  701. return true;
  702. }
  703. /**
  704. * Saves a remote image.
  705. *
  706. * @param string $remote_cache The server path to the remote images' cache folder.
  707. * @param string $remote_filename The URL of the remote image.
  708. * @return bool Returns true if the image is saved successfully and false otherwise.
  709. */
  710. private function save_remote_image( $remote_cache, $remote_filename )
  711. {
  712. $this->set_memory_limit();
  713. @ini_set('default_socket_timeout', 30);
  714. @ini_set('allow_url_fopen', true);
  715. @ini_set('user_agent', 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:5.0) Gecko/20100101');
  716. $url = str_replace( ' ', '%20', $this->src );
  717. if ( function_exists( 'curl_init' ) ) //try to get the image using cURL
  718. {
  719. $curl = curl_init();
  720. curl_setopt($curl, CURLOPT_URL, $url ); //set the URL
  721. curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); //no output
  722. curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, false); //no timeout
  723. //follow location will throw an error if safe mode or an open basedir restrictions is enabled
  724. if ( ! ini_get('open_basedir') && ! ini_get('safe_mode') )
  725. {
  726. curl_setopt( $curl, CURLOPT_FOLLOWLOCATION, true );
  727. }
  728. $remote_image = curl_exec($curl);
  729. if ( empty( $remote_image ) ) //cURL failed
  730. {
  731. $this->debug_messages[] = 'Could not get remote image using cURL.';
  732. return false;
  733. }
  734. }
  735. else //try to get the image using file_get_contents
  736. {
  737. $remote_image = @file_get_contents( $url );
  738. if ( empty( $remote_image ) ) //file_get_contents failed and cURL is not enabled, not much more we can do...
  739. {
  740. $this->debug_messages[] = 'Could not get remote image using file_get_contents.';
  741. return false;
  742. }
  743. }
  744. if ( $this->disable_xss_check || $this->EE->security->xss_clean( $remote_image, true ) === true )
  745. {
  746. //check if the directory exists
  747. if ( ! @is_dir( $remote_cache ) )
  748. {
  749. //try to make the directory
  750. if ( ! @mkdir( $remote_cache . '/', $this->dir_permissions, true ) )
  751. {
  752. $this->debug_messages[] = "Could not create the cache directory '$remote_cache/' for remote images.";
  753. return false;
  754. }
  755. }
  756. //ensure the directory is writable
  757. if ( ! @is_writable( $remote_cache ) )
  758. {
  759. $this->debug_messages[] = "Cache directory for remote images '$remote_cache' is not writable.";
  760. return false;
  761. }
  762. if ( file_put_contents( $remote_cache . '/' . $remote_filename, $remote_image) === false )
  763. {
  764. $this->debug_messages[] = "Could not write the remote image '{$remote_cache}/{$remote_filename}'.";
  765. return false;
  766. }
  767. }
  768. else //file failed the XSS test
  769. {
  770. $this->debug_messages[] = 'Remote image failed XSS test.';
  771. return false;
  772. }
  773. //the image should have been saved successfully, let's attempt to update permissions
  774. if ( ! @chmod( $remote_cache . '/' . $remote_filename, $this->image_permissions ) )
  775. {
  776. $this->debug_messages[] = "File permissions for '{$remote_cache}/{$remote_filename}' could not be changed to '$this->image_permissions'.";
  777. }
  778. $remote_image = null;
  779. $this->debug_messages[] = "The remote image '{$url}' was downloaded successfully.";
  780. return true;
  781. }
  782. // ---------------------------------------------------------------------------- RETURN FUNCTIONS ----------------------------------------------------------------------------
  783. /**
  784. * The currently open image resource.
  785. *
  786. * @return resource|bool The resource on success and false on failure.
  787. */
  788. public function get_resource()
  789. {
  790. if ( $this->open_real() == false )
  791. {
  792. $this->debug_messages[] = 'A resource could not be returned, because an image is not open.';
  793. return false;
  794. }
  795. if ( isset( $this->handle ) && is_resource($this->handle) )
  796. {
  797. return $this->handle;
  798. }
  799. else
  800. {
  801. $this->debug_messages[] = 'A resource could not be returned, because a valid resource was not found.';
  802. return false;
  803. }
  804. }
  805. /**
  806. * Returns a clone of the currently open image resource.
  807. *
  808. * @return resource|bool The resource clone on success and false on failure.
  809. */
  810. public function clone_resource()
  811. {
  812. if ( $this->open_real() == false )
  813. {
  814. $this->debug_messages[] = 'A resource could not be cloned, because an image is not open.';
  815. return false;
  816. }
  817. if ( isset( $this->handle ) && is_resource( $this->handle ) )
  818. {
  819. $width = round( imagesx( $this->handle ) );
  820. $height = round( imagesy( $this->handle ) );
  821. $clone = imagecreatetruecolor( $width, $height );
  822. if ( @imagecopy( $clone, $this->handle, 0, 0, 0, 0, $width, $height ) )
  823. {
  824. return $clone;
  825. }
  826. else
  827. {
  828. $this->debug_messages[] = 'There was an error cloning the image.';
  829. return false;
  830. }
  831. }
  832. else
  833. {
  834. $this->debug_messages[] = 'There image could not be cloned, because a valid resource was not found.';
  835. return false;
  836. }
  837. }
  838. /**
  839. * Returns the type of action that was taken. Can be one of the following:
  840. * none - No action was taken.
  841. * saved - The image was successfully saved.
  842. * cached - A cached image was found and used.
  843. *
  844. * @return string
  845. */
  846. public function get_final_action()
  847. {
  848. return $this->final_action;
  849. }
  850. /**
  851. * The height of the current image.
  852. *
  853. * @return int The current image's height.
  854. */
  855. public function get_height()
  856. {
  857. return $this->image_data['height'];
  858. }
  859. /**
  860. * The height of the original image.
  861. *
  862. * @return int The original image's height
  863. */
  864. public function get_original_height()
  865. {
  866. return $this->image_data_orig['height'];
  867. }
  868. /**
  869. * The width of the current image.
  870. *
  871. * @return int The current image's width.
  872. */
  873. public function get_width()
  874. {
  875. return $this->image_data['width'];
  876. }
  877. /**
  878. * The width of the original image.
  879. *
  880. * @return int The original image's width.
  881. */
  882. public function get_original_width()
  883. {
  884. return $this->image_data_orig['width'];
  885. }
  886. /**
  887. * The extension of the current image.
  888. *
  889. * @return string The current image's extension.
  890. */
  891. public function get_extension()
  892. {
  893. return ( $this->get_server_path() != '' ) ? $this->image_data['ext'] : '';
  894. }
  895. /**
  896. * The extension of the original image.
  897. *
  898. * @return string The original image's extension.
  899. */
  900. public function get_original_extension()
  901. {
  902. return $this->image_data_orig['ext'];
  903. }
  904. /**
  905. * The relative path (from document root) of the current image.
  906. *
  907. * @return string The current image's relative path.
  908. */
  909. public function get_relative_path()
  910. {
  911. $path = preg_replace( '@' . preg_quote( $this->base, '@' ) . '@', '', '/' . $this->src, 1 );
  912. //perform any advanced preg_replaces if they exist
  913. $replacements = $this->made_regex;
  914. if ( $replacements != false && is_array( $replacements ) && count( $replacements ) > 0 )
  915. {
  916. $find = array();
  917. $replace = array();
  918. foreach( $replacements as $f => $r )
  919. {
  920. $find[] = '#' . $f . '#';
  921. $replace[] = $r;
  922. }
  923. $path = preg_replace( $find, $replace, $path );
  924. //show the new made path
  925. $this->debug_messages[] = "Regexed made: '$path'.";
  926. }
  927. return $path;
  928. }
  929. /**
  930. * The relative path (from document root) of the original image.
  931. *
  932. * @return string The original image's relative path.
  933. */
  934. public function get_original_relative_path()
  935. {
  936. $path = preg_replace( '@' . preg_quote( $this->base, '@' ) . '@', '', '/' . $this->image_data_orig['src'], 1 );
  937. return $path;
  938. }
  939. /**
  940. * The file type of the current image. Will return 'jpg', 'png', or 'gif'.
  941. *
  942. * @return string
  943. */
  944. public function get_type()
  945. {
  946. $type = strtolower( $this->image_data['ext'] );
  947. if ( $type == 'jpeg' )
  948. {
  949. $type = 'jpg';
  950. }
  951. return $type;
  952. }
  953. /**
  954. * The file type of the original image. Will return 'jpg', 'png', or 'gif'.
  955. *
  956. * @return string
  957. */
  958. public function get_type_orig()
  959. {
  960. switch ( $this->image_data_orig['type'] )
  961. {
  962. case 1;
  963. return 'gif';
  964. break;
  965. case 2:
  966. return 'jpg';
  967. break;
  968. case 3:
  969. return 'png';
  970. break;
  971. }
  972. return 'unknown';
  973. }
  974. /**
  975. * The file name of the current image, without the file extension.
  976. *
  977. * @return string The current image's file name.
  978. */
  979. public function get_filename()
  980. {
  981. return ( $this->get_server_path() != '' ) ? $this->filename_final : '';
  982. }
  983. /**
  984. * The file name of the original image, without the file extension.
  985. *
  986. * @return string The original image's file name.
  987. */
  988. public function get_original_filename()
  989. {
  990. return $this->filename_orig;
  991. }
  992. /**
  993. * The server path of the current image.
  994. *
  995. * @return string The current image's server path.
  996. */
  997. public function get_server_path()
  998. {
  999. return $this->src;
  1000. }
  1001. /**
  1002. * The server path of the original image.
  1003. *
  1004. * @return string The original image's server path.
  1005. */
  1006. public function get_original_server_path()
  1007. {
  1008. return $this->image_data_orig['src'];
  1009. }
  1010. /**
  1011. * The array of debug messages.
  1012. *
  1013. * @return array The debug messages.
  1014. */
  1015. public function get_debug_messages()
  1016. {
  1017. return $this->debug_messages;
  1018. }
  1019. /**
  1020. * Returns the file size of the image.
  1021. *
  1022. * @param bool $bytes_only If the file size should be returned in bytes, or converted to a human readable format (default).
  1023. * @return int|string|bool Returns int if $bytes_only is true, string if $bytes_only is false, and false if an error.
  1024. */
  1025. public function get_filesize( $bytes_only = false )
  1026. {
  1027. if ( $this->src != '' && ( $this->is_data_ready || $this->is_open_ready ) )
  1028. {
  1029. $filesize = @filesize( $this->src );
  1030. if ( $filesize !== false)
  1031. {
  1032. return ( $bytes_only ) ? $filesize : Ce_image_tools::convert( $filesize );
  1033. }
  1034. else
  1035. {
  1036. $this->debug_messages[] = "The file size could not be found for '$this->src'.";
  1037. return false;
  1038. }
  1039. }
  1040. else
  1041. {
  1042. $this->debug_messages[] = 'The file size could not be retrieved, because an image is not open.';
  1043. return false;
  1044. }
  1045. }
  1046. /**
  1047. * Returns the file size of the original image.
  1048. *
  1049. * @param bool $bytes_only If the file size should be returned in bytes, or converted to a human readable format (default).
  1050. * @return int|string|bool Returns int if $bytes_only is true, string if $bytes_only is false, and false if an error.
  1051. */
  1052. public function get_original_filesize( $bytes_only = false )
  1053. {
  1054. if ( $this->get_original_server_path() != '' && ( $this->is_data_ready || $this->is_open_ready ) )
  1055. {
  1056. $filesize = @filesize( $this->image_data_orig['src'] );
  1057. if ( $filesize !== false)
  1058. {
  1059. return ( $bytes_only ) ? $filesize : Ce_image_tools::convert( $filesize );
  1060. }
  1061. else
  1062. {
  1063. $this->debug_messages[] = "The original file size could not be found for '{$this->image_data_orig['src']}'.";
  1064. return false;
  1065. }
  1066. }
  1067. else
  1068. {
  1069. $this->debug_messages[] = 'The original file size could not be retrieved, because an image is not open.';
  1070. return false;
  1071. }
  1072. }
  1073. /**
  1074. * Creates a tag for the current image. It will automatically add in the images width, height, and alt tag if they are not passed in as attributes.
  1075. *
  1076. * @param array $attributes The attributes to be used for the image.
  1077. * @param bool $closing_slash Whether or not to include a closing slash (defaults to true).
  1078. * @return string The HTML image tag.
  1079. */
  1080. public function create_tag( $attributes = array(), $closing_slash = true )
  1081. {
  1082. if ( $this->src == '' OR ! $this->is_data_ready )
  1083. {
  1084. $this->debug_messages[] = 'The image tag could not be created, because an image is not open.';
  1085. return false;
  1086. }
  1087. if ( ! array_key_exists( 'src', $attributes ) )
  1088. {
  1089. $attributes['src'] = $this->get_relative_path();
  1090. }
  1091. if ( ! array_key_exists( 'width', $attributes ) )
  1092. {
  1093. $attributes['width'] = $this->get_width();
  1094. }
  1095. if ( ! array_key_exists( 'height', $attributes ) )
  1096. {
  1097. $attributes['height'] = $this->get_height();
  1098. }
  1099. if ( ! array_key_exists( 'alt', $attributes ) )
  1100. {
  1101. $attributes['alt'] = '';
  1102. }
  1103. $attr = '';
  1104. foreach( $attributes as $attribute => $value )
  1105. {
  1106. $value = str_replace('"', '&quot;', $value );
  1107. $attr .= $attribute . '="' . $value . '" ';
  1108. }
  1109. $closing_slash = ($closing_slash) ? '/' : '';
  1110. return '<img ' . $attr . $closing_slash . '>';
  1111. }
  1112. /**
  1113. * Creates a tag for the original image. It will automatically add in the images width, height, and alt tag if they are not passed in as attributes.
  1114. *
  1115. * @param array $attributes The attributes to be used for the image.
  1116. * @param bool $closing_slash Whether or not to include a closing slash (defaults to true).
  1117. * @return string The HTML image tag.
  1118. */
  1119. public function create_original_tag( $attributes = array(), $closing_slash = true )
  1120. {
  1121. if ( $this->get_original_server_path() == '' OR ! $this->is_data_ready )
  1122. {
  1123. $this->debug_messages[] = 'The image tag could not be created, because an image is not open.';
  1124. return false;
  1125. }
  1126. if ( ! array_key_exists( 'src', $attributes ) )
  1127. {
  1128. $attributes['src'] = $this->get_original_relative_path();
  1129. }
  1130. if ( ! array_key_exists( 'width', $attributes ) )
  1131. {
  1132. $attributes['width'] = $this->get_original_width();
  1133. }
  1134. if ( ! array_key_exists( 'height', $attributes ) )
  1135. {
  1136. $attributes['height'] = $this->get_original_height();
  1137. }
  1138. if ( ! array_key_exists( 'alt', $attributes ) )
  1139. {
  1140. $attributes['alt'] = '';
  1141. }
  1142. $attr = '';
  1143. foreach( $attributes as $attribute => $value )
  1144. {
  1145. $value = str_replace('"', '&quot;', $value );
  1146. $attr .= $attribute . '="' . $value . '" ';
  1147. }
  1148. $closing_slash = ($closing_slash) ? '/' : '';
  1149. return '<img ' . $attr . $closing_slash . '>';
  1150. }
  1151. /**
  1152. * Creates ASCII art for an image. Each character represents one pixel from the image.
  1153. *
  1154. * @param bool $use_colors Whether or not to colorize the characters.
  1155. * @param array $ascii_characters The array of characters to be used for the ASCII art.
  1156. * @param bool $repeat Whether or not the characters should repeat in consecutive order (true) or be placed depending on the darkness of the pixel (false).
  1157. * @param bool $space_for_trans If the $repeat parameter is set to true, you can set this parameter to determine whether or not a space should be used for transparent pixels.
  1158. * @return string|bool The HTML for the ASCII art on success, false on failure.
  1159. */
  1160. public function get_ascii_art( $use_colors = true, $ascii_characters = array('#', '@', '%', '=', '+', '*', ':', '-', '.', '&nbsp;'), $repeat = false, $space_for_trans = false )
  1161. {
  1162. //check the settings
  1163. if ( ! is_bool( $use_colors) )
  1164. {
  1165. $use_colors = true;
  1166. }
  1167. //repeat characters?
  1168. if ( ! is_bool( $repeat) )
  1169. {
  1170. $repeat = false;
  1171. }
  1172. //use space character for transparent pixels?
  1173. if ( ! is_bool( $space_for_trans ) )
  1174. {
  1175. $space_for_trans = false;
  1176. }
  1177. if ( $this->open_real() == false )
  1178. {
  1179. $this->debug_messages[] = 'The ASCII art could not be generated, because an image is not open.';
  1180. return false;
  1181. }
  1182. return $this->create_ascii_art( $this->handle, $use_colors, $ascii_characters, $repeat, $space_for_trans );
  1183. }
  1184. /**
  1185. * Organizes the colors used in your image by frequency of occurrence, and groups them by a threshold.
  1186. *
  1187. * @param int $quantity The maximum number of colors (color groups) to return.
  1188. * @param int $threshold Value from 0 (very low grouping) to 100 (very high grouping).
  1189. * @return array|bool On success, returns an array of results with each result being an array with the following keys: 'color', 'color_count', 'color_percent'. On failure, returns false.
  1190. */
  1191. public function get_top_colors( $quantity = 5, $threshold = 33 )
  1192. {
  1193. if ( ! is_numeric( $quantity) )
  1194. {
  1195. $this->debug_messages[] = 'Invalid quantity of return colors for top colors.';
  1196. return false;
  1197. }
  1198. if ( ! is_numeric( $threshold ) || $threshold < 0 || $threshold > 100 )
  1199. {
  1200. $this->debug_messages[] = 'Invalid threshold for top colors. Must be between 0 and 100, inclusive.';
  1201. return false;
  1202. }
  1203. if ( $this->open_real() )
  1204. {
  1205. return $this->find_top_colors( $this->handle, $quantity, $threshold );
  1206. }
  1207. else
  1208. {
  1209. $this->debug_messages[] = 'The top colors could not be retrieved, because an image is not open.';
  1210. return false;
  1211. }
  1212. }
  1213. /**
  1214. * Gets the average color for the image.
  1215. *
  1216. * @return string The hexadecimal color value of the average color of the generated image.
  1217. */
  1218. public function get_average_color()
  1219. {
  1220. if ( $this->open_real() )
  1221. {
  1222. return $this->find_average_color( $this->handle );
  1223. }
  1224. else
  1225. {
  1226. $this->debug_messages[] = 'The average color could not be retrieved, because no image is open.';
  1227. return false;
  1228. }
  1229. }
  1230. // ---------------------------------------------------------------------------- CLOSE ----------------------------------------------------------------------------
  1231. /**
  1232. * Closes the image.
  1233. *
  1234. * @return void
  1235. */
  1236. public function close()
  1237. {
  1238. if ( $this->is_open )
  1239. {
  1240. $this->close_real();
  1241. }
  1242. $this->src = '';
  1243. $this->fallback_src = '';
  1244. $this->image_data = array( 'width' => '', 'height' => '', 'ext' => '');
  1245. $this->image_data_orig = array( 'width' => '', 'height' => '', 'type' => '', 'ext' => '', 'src' => '');
  1246. $this->wm_image_data = array( 'width' => '', 'height' => '', 'type' => '', 'src' => '' );
  1247. $this->debug_messages = array();
  1248. $this->is_data_ready = false;
  1249. }
  1250. /**
  1251. * Closes the open image resource(s).
  1252. *
  1253. * @return void
  1254. */
  1255. private function close_real()
  1256. {
  1257. if ( is_resource( $this->handle ) )
  1258. {
  1259. imagedestroy( $this->handle );
  1260. unset( $this->handle );
  1261. }
  1262. $this->is_open = false;
  1263. }
  1264. // ---------------------------------------------------------------------------- PREPARE SETTINGS ----------------------------------------------------------------------------
  1265. /**
  1266. * Cleans up some of the settings to ensure they are in the correct format for the class to use.
  1267. *
  1268. * @return bool true on success, false on failure
  1269. */
  1270. private function prep_settings()
  1271. {
  1272. //---------- get other params ----------
  1273. //allow_scale_larger parameter
  1274. if ( ! is_bool( $this->allow_scale_larger ) )
  1275. {
  1276. $this->allow_scale_larger = false;
  1277. }
  1278. //get bg_color param
  1279. $this->bg_color = Ce_image_tools::hex_cleanup( $this->bg_color );
  1280. //get bg_color_default param
  1281. $this->bg_color_default = Ce_image_tools::hex_cleanup( $this->bg_color_default );
  1282. if ( $this->bg_color_default == false )
  1283. {
  1284. $this->bg_color_default = 'ffffff';
  1285. }
  1286. //get filter param
  1287. $filter_array = $this->filters;
  1288. if ( ! is_array( $filter_array ) )
  1289. {
  1290. $filter_array = ( trim( $filter_array ) != '' ) ? array( $filter_array ) : array();
  1291. }
  1292. $filters = array();
  1293. $count = count( $filter_array );
  1294. if ( $count != 0 )
  1295. {
  1296. foreach( $filter_array as $filter )
  1297. {
  1298. //make filter an array if applicable
  1299. if ( ! is_array($filter) && trim( $filter ) != '' )
  1300. {
  1301. $filter = array( $filter );
  1302. }
  1303. //make sure the filter has a name
  1304. if ( ! isset( $filter['0'] ) || trim($filter['0']) == '' )
  1305. {
  1306. continue;
  1307. }
  1308. //make sure the filter exists
  1309. $filter_name = trim($filter['0']);
  1310. if ( isset( $this->valid_filters[$filter_name] ) )
  1311. {
  1312. //if a native image filter is being used, make sure it exists with this installation
  1313. if ( $this->valid_filters[$filter_name] === 'imagefilter' && ! defined( 'IMG_FILTER_' . strtoupper($filter_name) ) )
  1314. {
  1315. continue;
  1316. }
  1317. //add the filter
  1318. $filters[] = $filter;
  1319. }
  1320. }
  1321. }
  1322. unset( $filter_array );
  1323. $this->filters = $filters;
  1324. unset( $filters );
  1325. //get crop param
  1326. if ( ! is_array( $this->crop ) )
  1327. {
  1328. $this->crop = array( $this->crop );
  1329. }
  1330. $crop = $this->crop;
  1331. $this->do_crop = ( isset( $crop[0] ) && $crop[0] === true );
  1332. //get border param
  1333. $border = $this->border;
  1334. if ( $border != false && isset( $border[0] ) && is_numeric( $border[0] ) && $border[0] > 0 )
  1335. {
  1336. $this->check_size = true;
  1337. if ( isset( $border[1] ) )
  1338. {
  1339. $temp = Ce_image_tools::hex_cleanup( $border[1] );
  1340. if ( $temp != '' )
  1341. {
  1342. $this->border[1] = $temp;
  1343. }
  1344. else
  1345. {
  1346. $this->border[1] = 'ffffff';
  1347. }
  1348. }
  1349. else
  1350. {
  1351. $this->border[1] = 'ffffff';
  1352. }
  1353. }
  1354. else
  1355. {
  1356. $this->border[0] = 0;
  1357. $this->border[1] = 'ffffff';
  1358. }
  1359. //get rounded_corners param
  1360. $corners = $this->rounded_corners;
  1361. $corners_array = array();
  1362. if ( is_array( $corners ) && count( $corners ) > 0 )
  1363. {
  1364. if ( ! is_array( $corners[0] ) )
  1365. {
  1366. $corners = array( $corners );
  1367. }
  1368. foreach ( $corners as $corner )
  1369. {
  1370. //get the position
  1371. if ( isset( $corner[0] ) && in_array( $corner[0], $this->corner_options ) )
  1372. {
  1373. $corner_array = array();
  1374. $pos = $corner[0];
  1375. //get the radius
  1376. $rad = 15;
  1377. if ( isset( $corner[1] ) && is_numeric( $corner[1] ) )
  1378. {
  1379. $rad = $corner[1];
  1380. }
  1381. //get the color (will end up being: hex, or '')
  1382. $col = '';
  1383. if ( isset( $corner[2] ) )
  1384. {
  1385. $col = Ce_image_tools::hex_cleanup( $corner[2] );
  1386. }
  1387. if ( $pos == 'all' )
  1388. {
  1389. if ( $rad > 0 )
  1390. {
  1391. $corners_array['tl'] = array( $rad, $col );
  1392. $corners_array['tr'] = array( $rad, $col );
  1393. $corners_array['bl'] = array( $rad, $col );
  1394. $corners_array['br'] = array( $rad, $col );
  1395. }
  1396. else
  1397. {
  1398. $corners_array = array();
  1399. }
  1400. }
  1401. else
  1402. {
  1403. if ( $rad > 0 )
  1404. {
  1405. $corners_array[$pos] = array( $rad, $col );
  1406. }
  1407. else
  1408. {
  1409. unset( $corners_array[$pos] );
  1410. }
  1411. }
  1412. }
  1413. }
  1414. }
  1415. $this->corners_array = $corners_array;
  1416. $this->corners = ( count($this->corners_array) > 0 );
  1417. //get flip param
  1418. if ( ! is_array( $this->flip ) && in_array( $this->flip, $this->flip_options ) )
  1419. {
  1420. $this->flip = array( $this->flip );
  1421. }
  1422. $flip = $this->flip;
  1423. if ( is_array( $flip ) )
  1424. {
  1425. foreach( $flip as $i => $f )
  1426. {
  1427. if ( ! in_array( $f, $this->flip_options ) )
  1428. {
  1429. unset( $flip[$i] );
  1430. }
  1431. }
  1432. //remove duplicate values
  1433. $this->flip = array_unique( $flip );
  1434. if ( count( $flip ) > 0 )
  1435. {
  1436. $this->flip = $flip;
  1437. }
  1438. else
  1439. {
  1440. $this->flip = false;
  1441. }
  1442. }
  1443. else
  1444. {
  1445. $this->flip = false;
  1446. }
  1447. //get reflection param
  1448. $ref = $this->reflection;
  1449. $reflection_array = array();
  1450. if ( is_array( $ref ) && count( $ref ) > 0 )
  1451. {
  1452. $reflection_array[0] = ( isset( $ref[0] ) && is_numeric( $ref[0] ) ) ? trim( $ref[0] ) : 0; //gap
  1453. $reflection_array[1] = ( isset( $ref[1]) && is_numeric( $ref[1]) ) ? trim( $ref[1] ): 80; //start opacity
  1454. $reflection_array[2] = ( isset( $ref[2]) && is_numeric( $ref[2]) ) ? trim( $ref[2] ): 0; //end opacity
  1455. $reflection_array[3] = ( isset( $ref[3]) && is_numeric( str_replace( '%', '', $ref[3] ) ) ) ? trim( $ref[3] ) : '50%'; //ref_height
  1456. }
  1457. $this->reflection_array = $reflection_array;
  1458. if ( count($this->reflection_array) > 0 )
  1459. {
  1460. $this->reflection = true;
  1461. $this->check_size = true;
  1462. }
  1463. //get rotate param
  1464. if ( $this->rotate != 0 && is_numeric( $this->rotate ) && $this->rotate % 360 != 0 )
  1465. {
  1466. $this->check_size = true;
  1467. }
  1468. else
  1469. {
  1470. $this->rotate = false;
  1471. }
  1472. //get overwrite_cache param
  1473. if ( ! is_bool( $this->overwrite_cache ) )
  1474. {
  1475. $this->overwrite_cache = false;
  1476. }
  1477. //get hash_filename param
  1478. if ( ! is_bool( $this->hash_filename ) )
  1479. {
  1480. $this->hash_filename = false;
  1481. }
  1482. //get save_type param
  1483. $save_type = trim( $this->save_type );
  1484. if ( $save_type == '' )
  1485. {
  1486. $save_type = ( $this->image_data_orig['ext'] ) ? $this->image_data_orig['ext'] : $this->get_type_orig();
  1487. }
  1488. if ( ! in_array( strtolower( $save_type ), $this->image_types ) )
  1489. {
  1490. $save_type = 'jpg';
  1491. }
  1492. $this->image_data['ext'] = $save_type;
  1493. //check quality to be valid
  1494. if ( ! is_numeric( $this->quality ) || $this->quality < 0 || $this->quality > 100 )
  1495. {
  1496. $this->quality = 100;
  1497. }
  1498. //---------- find new dimensions ----------
  1499. if ( $this->windows_dev )
  1500. {
  1501. $this->src = str_replace('/', '\\', $this->src);
  1502. }
  1503. $result = $this->get_dimensions();
  1504. if ( ! $result )
  1505. {
  1506. return false;
  1507. }
  1508. //prepare the text
  1509. if ( $this->text != false )
  1510. {
  1511. $this->get_text_preference();
  1512. }
  1513. return true;
  1514. }
  1515. /**
  1516. * Determines which text preference, if any, meets the minimum dimensions requirement and sets it as the class' text property.
  1517. *
  1518. * @return void
  1519. */
  1520. function get_text_preference()
  1521. {
  1522. //if a single text array, wrap it in an array
  1523. if ( is_array( $this->text ) && ! is_array( $this->text[0] ) )
  1524. {
  1525. $this->text = array( $this->text );
  1526. }
  1527. //---------- get preference by minimum dimension ----------
  1528. //let's see what preferences are being passed in for minimum dimensions, and see if we can find one that works
  1529. $final_pref_ind = -1;
  1530. foreach ( $this->text as $index => $text_pref )
  1531. {
  1532. //break up the chunks
  1533. if ( is_array( $text_pref ) && count( $text_pref ) > 1 )
  1534. {
  1535. //size limits should be here
  1536. if ( count( $text_pref[1] ) == 2 )
  1537. {
  1538. list( $min_w, $min_h ) = $text_pref[1];
  1539. //check the dimensions
  1540. if ( $this->do_crop == false )
  1541. {
  1542. if ( ($min_w == 0 || $min_w <= $this->width_final) && ($min_h == 0 || $min_h <= $this->height_final) )
  1543. {
  1544. //this pref will work
  1545. $final_pref_ind = $index;
  1546. break 1;
  1547. }
  1548. }
  1549. else
  1550. {
  1551. if ( ($min_w == 0 || $min_w <= $this->width_desired) && ($min_h == 0 || $min_h <= $this->height_desired) )
  1552. {
  1553. //this pref will work
  1554. $final_pref_ind = $index;
  1555. break 1;
  1556. }
  1557. }
  1558. }
  1559. else
  1560. {
  1561. //both params are not there...we'll assume this is the one they wanted
  1562. $final_pref_ind = $index;
  1563. break 1;
  1564. return;
  1565. }
  1566. }
  1567. else
  1568. {
  1569. //no size limits found, so this pref will do
  1570. $final_pref_ind = $index;
  1571. break 1;
  1572. }
  1573. }
  1574. if ( $final_pref_ind == -1 )

Large files files are truncated, but you can click here to view the full file