Thumbnail.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898
  1. <?php
  2. /**
  3. *
  4. * PHP Pro Bid $Id$ MME5qyW9p1utpjGY4jeqeBmsYaLdq7gQZqasRNt7lX8=
  5. *
  6. * @link http://www.phpprobid.com
  7. * @copyright Copyright (c) 2017 Online Ventures Software & CodeCube SRL
  8. * @license http://www.phpprobid.com/license Commercial License
  9. *
  10. * @version 7.10 [rev.7.10.01]
  11. */
  12. /**
  13. * thumbnail view helper class
  14. *
  15. * this view helper will generate thumbnails for images, and if the data input is of a different type, then it will
  16. * add placeholders
  17. *
  18. * 7.5: added image cropping options and the ability to create rectangular thumbnails, not only square ones
  19. * 7.5: smaller images will now be enlarged to the desired dimensions
  20. * 7.10: moved image manipulation functions from uploader model
  21. */
  22. namespace Ppb\View\Helper;
  23. use Cube\View\Helper\AbstractHelper,
  24. Cube\Controller\Front,
  25. Ppb\Service;
  26. class Thumbnail extends AbstractHelper
  27. {
  28. const DEFAULT_EXTENSION = 'png';
  29. /**
  30. * the path for the "no image" pic
  31. */
  32. const IMAGE_PLACEHOLDER = 'image.png';
  33. /**
  34. * video file placeholder
  35. */
  36. const VIDEO_PLACEHOLDER = 'video.png';
  37. /**
  38. * digital download file placeholder
  39. */
  40. const DOWNLOAD_PLACEHOLDER = 'download.png';
  41. /**
  42. * csv file placeholder
  43. */
  44. const CSV_PLACEHOLDER = 'csv.png';
  45. /**
  46. * the path for the "broken image" pic
  47. */
  48. const BROKEN_IMAGE = 'broken.gif';
  49. /**
  50. * minimum width in pixels of a thumbnail image
  51. */
  52. const MIN_WIDTH = 30;
  53. /**
  54. * maximum width in pixels of a thumbnail images
  55. */
  56. const MAX_WIDTH = 1200;
  57. /**
  58. *
  59. * this variable will hold the name of the file which will be displayed
  60. *
  61. * @var string
  62. */
  63. protected $_name;
  64. /**
  65. *
  66. * the extension of the file
  67. *
  68. * @var string
  69. */
  70. protected $_extension = self::DEFAULT_EXTENSION;
  71. /**
  72. *
  73. * destination thumbnail width
  74. *
  75. * @var integer
  76. */
  77. protected $_width = 80;
  78. /**
  79. *
  80. * destination thumbnail height
  81. * - if true then we have a square
  82. * - if null we shrink based on original aspect ratio
  83. * - if set we use a forced aspect ratio
  84. *
  85. * @var integer|bool|null
  86. */
  87. protected $_height = true;
  88. /**
  89. *
  90. * application base url
  91. *
  92. * @var string
  93. */
  94. protected $_baseUrl = null;
  95. /**
  96. *
  97. * crop images to aspect ratio
  98. * if false, will add horizontal/vertical white bars
  99. *
  100. * @var bool
  101. */
  102. protected $_crop = false;
  103. /**
  104. *
  105. * enable / disable lazy load plugin
  106. *
  107. * @var bool
  108. */
  109. protected $_lazyLoad = false;
  110. /**
  111. *
  112. * allowed extensions
  113. *
  114. * @var array
  115. */
  116. protected $_extensions = array(
  117. 'gif', 'jpg', 'jpeg', 'png', 'img',
  118. 'avi', 'mpg', 'mpeg', 'mov', 'mp4', 'flv', 'csv'
  119. );
  120. /**
  121. *
  122. * reserved params
  123. *
  124. * @var array
  125. */
  126. protected $_reservedParams = array(
  127. 'type', 'zoom', 'crop', 'lazyLoad'
  128. );
  129. /**
  130. *
  131. * class constructor
  132. *
  133. * @param array $options
  134. */
  135. public function __construct($options = array())
  136. {
  137. if (!empty($options['crop'])) {
  138. $this->setCrop($options['crop']);
  139. }
  140. if (!empty($options['lazy_load'])) {
  141. $this->setLazyLoad($options['lazy_load']);
  142. }
  143. }
  144. /**
  145. *
  146. * get file name
  147. *
  148. * @return string
  149. */
  150. public function getName()
  151. {
  152. return $this->_name;
  153. }
  154. /**
  155. *
  156. * set file name
  157. *
  158. * @param string $name
  159. *
  160. * @return $this
  161. */
  162. public function setName($name)
  163. {
  164. $name = preg_replace("/[^a-zA-Z0-9_-]/", '', $name);
  165. $this->_name = (string)$name;
  166. return $this;
  167. }
  168. /**
  169. *
  170. * get file extension
  171. *
  172. * @return string
  173. */
  174. public function getExtension()
  175. {
  176. return $this->_extension;
  177. }
  178. /**
  179. *
  180. * set file extension
  181. *
  182. * @param string $extension
  183. *
  184. * @return $this
  185. */
  186. public function setExtension($extension)
  187. {
  188. if (!in_array($extension, $this->_extensions)) {
  189. $extension = self::DEFAULT_EXTENSION;
  190. }
  191. $this->_extension = (string)$extension;
  192. return $this;
  193. }
  194. /**
  195. *
  196. * get destination thumbnail width
  197. *
  198. * @return integer
  199. */
  200. public function getWidth()
  201. {
  202. return $this->_width;
  203. }
  204. /**
  205. *
  206. * set destination thumbnail width
  207. *
  208. * @param int $width
  209. *
  210. * @return $this
  211. */
  212. public function setWidth($width)
  213. {
  214. $width = intval($width);
  215. if ($width < self::MIN_WIDTH) {
  216. $width = self::MIN_WIDTH;
  217. }
  218. if ($width > self::MAX_WIDTH && self::MAX_WIDTH > 0) {
  219. $width = self::MAX_WIDTH;
  220. }
  221. $this->_width = $width;
  222. return $this;
  223. }
  224. /**
  225. *
  226. * get destination thumbnail height
  227. *
  228. * @return bool
  229. */
  230. public function getHeight()
  231. {
  232. return $this->_height;
  233. }
  234. /**
  235. *
  236. * set destination thumbnail height
  237. *
  238. * @param integer|boolean $height
  239. *
  240. * @return $this
  241. */
  242. public function setHeight($height = true)
  243. {
  244. $this->_height = $height;
  245. return $this;
  246. }
  247. /**
  248. *
  249. * set square option (legacy method)
  250. *
  251. * @param bool $square
  252. *
  253. * @return $this
  254. */
  255. public function setSquare($square = true)
  256. {
  257. $this->setHeight((bool)$square);
  258. return $this;
  259. }
  260. /**
  261. *
  262. * get crop option
  263. *
  264. * @return boolean
  265. */
  266. public function getCrop()
  267. {
  268. return $this->_crop;
  269. }
  270. /**
  271. *
  272. * set crop option
  273. *
  274. * @param boolean $crop
  275. *
  276. * @return $this
  277. */
  278. public function setCrop($crop = true)
  279. {
  280. $this->_crop = (bool)$crop;
  281. return $this;
  282. }
  283. /**
  284. *
  285. * check lazy load plugin flag
  286. *
  287. * @return bool
  288. */
  289. public function isLazyLoad()
  290. {
  291. return $this->_lazyLoad;
  292. }
  293. /**
  294. *
  295. * set lazy load plugin flag
  296. *
  297. * @param bool $lazyLoad
  298. *
  299. * @return $this
  300. */
  301. public function setLazyLoad($lazyLoad)
  302. {
  303. $this->_lazyLoad = $lazyLoad;
  304. return $this;
  305. }
  306. /**
  307. *
  308. * get base url
  309. *
  310. * @return string
  311. */
  312. public function getBaseUrl()
  313. {
  314. if ($this->_baseUrl === null) {
  315. $this->setBaseUrl(
  316. Front::getInstance()->getRequest()->getBaseUrl());
  317. }
  318. return $this->_baseUrl;
  319. }
  320. /**
  321. *
  322. * set base url
  323. *
  324. * @param string $baseUrl
  325. *
  326. * @return $this
  327. */
  328. public function setBaseUrl($baseUrl)
  329. {
  330. $this->_baseUrl = $baseUrl;
  331. return $this;
  332. }
  333. /**
  334. *
  335. * generate cached thumbnail and return image link
  336. * (has backwards compatibility for v6's uplimg folder)
  337. *
  338. * @param string $image
  339. * @param int|null $width
  340. * @param bool|int|null $height
  341. * @param array $params
  342. *
  343. * @return string
  344. */
  345. public function generateLink($image, $width = null, $height = null, $params = array())
  346. {
  347. $this->setWidth($width)
  348. ->setHeight($height);
  349. $type = (isset($params['type'])) ? $params['type'] : Service\ListingsMedia::TYPE_IMAGE;
  350. $crop = (isset($params['crop'])) ? $params['crop'] : null;
  351. switch ($type) {
  352. case Service\ListingsMedia::TYPE_VIDEO:
  353. $image = \Ppb\Utility::getPath('img') . \Ppb\Utility::URI_DELIMITER . self::VIDEO_PLACEHOLDER;
  354. break;
  355. case Service\ListingsMedia::TYPE_DOWNLOAD:
  356. $image = \Ppb\Utility::getPath('img') . \Ppb\Utility::URI_DELIMITER . self::DOWNLOAD_PLACEHOLDER;
  357. break;
  358. case Service\ListingsMedia::TYPE_CSV:
  359. $image = \Ppb\Utility::getPath('img') . \Ppb\Utility::URI_DELIMITER . self::CSV_PLACEHOLDER;
  360. break;
  361. default:
  362. if ($image == null) {
  363. $image = \Ppb\Utility::getPath('img') . \Ppb\Utility::URI_DELIMITER . self::IMAGE_PLACEHOLDER;
  364. }
  365. else {
  366. if (!preg_match('#^http(s)?://(.*)+$#i', $image) && !preg_match('#^uplimg/(.*)+$#i', $image)) {
  367. $image = \Ppb\Utility::getFolder('uploads') . \Ppb\Utility::URI_DELIMITER . $image;
  368. }
  369. }
  370. break;
  371. }
  372. return $this->getBaseUrl() . \Ppb\Utility::URI_DELIMITER
  373. . \Ppb\Utility::getFolder('cache') . \Ppb\Utility::URI_DELIMITER
  374. . $this->_generateThumb($image, $crop);
  375. }
  376. /**
  377. *
  378. * generates a path to a media file
  379. * if we have a remote image or a v6 image, return the path unmodified
  380. *
  381. * @param string $image
  382. *
  383. * @return string
  384. */
  385. public function generateImagePath($image)
  386. {
  387. if (preg_match('#^uplimg/(.*)+$#i', $image)) {
  388. // we have a v6 image - add base url
  389. return $this->getBaseUrl() . '/' . $image;
  390. }
  391. else if (!preg_match('#^http(s)?://(.*)+$#i', $image)) {
  392. // we have a v7 image - add base url and uploads folder
  393. return $this->getBaseUrl() . \Ppb\Utility::URI_DELIMITER
  394. . \Ppb\Utility::getFolder('uploads') . \Ppb\Utility::URI_DELIMITER
  395. . $image;
  396. }
  397. return $image;
  398. }
  399. /**
  400. *
  401. * check whether the uploaded file is an image
  402. *
  403. * @param string $fileName
  404. *
  405. * @return bool
  406. */
  407. public function isImage($fileName)
  408. {
  409. $fileInfo = @getimagesize($fileName);
  410. if ($fileInfo === false || $fileInfo[2] > 3) {
  411. return false;
  412. }
  413. return true;
  414. }
  415. /**
  416. *
  417. * output image using corresponding function based on mime
  418. *
  419. * @param mixed $output
  420. * @param string $fileName
  421. * @param string $mime
  422. *
  423. * @return $this
  424. */
  425. public function imageOutputFunction($output, $fileName, $mime = null)
  426. {
  427. if ($mime === null) {
  428. $imgInfo = @getimagesize($fileName);
  429. $mime = $imgInfo['mime'];
  430. }
  431. switch ($mime) {
  432. case 'image/gif':
  433. $imageOutputFunction = 'imagegif';
  434. break;
  435. case 'image/png':
  436. $imageOutputFunction = 'imagepng';
  437. break;
  438. default:
  439. $imageOutputFunction = 'imagejpeg';
  440. break;
  441. }
  442. touch($fileName);
  443. $imageOutputFunction($output, $fileName);
  444. imagedestroy($output);
  445. return $this;
  446. }
  447. /**
  448. *
  449. * image create function based on source image type
  450. *
  451. * @param string $fileName
  452. * @param string $mime
  453. *
  454. * @return mixed
  455. */
  456. public function imageCreateFunction($fileName, $mime = null)
  457. {
  458. if ($mime === null) {
  459. $imgInfo = @getimagesize($fileName);
  460. $mime = $imgInfo['mime'];
  461. }
  462. switch ($mime) {
  463. case 'image/gif':
  464. $imageCreateFunction = 'ImageCreateFromGIF';
  465. break;
  466. case 'image/png':
  467. $imageCreateFunction = 'ImageCreateFromPNG';
  468. break;
  469. default:
  470. $imageCreateFunction = 'ImageCreateFromJPEG';
  471. break;
  472. }
  473. return $imageCreateFunction($fileName);
  474. }
  475. /**
  476. *
  477. * create resized image
  478. *
  479. * @param string $srcImage
  480. * @param bool|null $crop
  481. *
  482. * @return resource
  483. */
  484. public function createResizedImage($srcImage, $crop = null)
  485. {
  486. $fileName = null;
  487. $imgInfo = @getimagesize($srcImage);
  488. list($srcWidth, $srcHeight, $imgType) = $imgInfo;
  489. if ($imgInfo === false || $imgType > 3) {
  490. $srcImage = \Ppb\Utility::getPath('img') . \Ppb\Utility::URI_DELIMITER . self::BROKEN_IMAGE;
  491. $imgInfo = @getimagesize($srcImage);
  492. list($srcWidth, $srcHeight, $imgType) = $imgInfo;
  493. }
  494. if ($crop === null) {
  495. $crop = $this->getCrop();
  496. }
  497. $dstWidth = $tmpWidth = $this->getWidth();
  498. $dstHeight = $this->getHeight();
  499. $tmpHeight = round(($dstWidth * $srcHeight) / $srcWidth);
  500. if ($dstHeight === true) {
  501. $dstHeight = $dstWidth;
  502. }
  503. else if (!is_numeric($dstHeight)) {
  504. $dstHeight = $tmpHeight;
  505. }
  506. $image = $this->imageCreateFunction($srcImage, $imgInfo['mime']);
  507. if (!$image) {
  508. $output = imagecreate($dstWidth, $dstHeight); /* Create a blank image */
  509. $white = imagecolorallocate($output, 255, 255, 255);
  510. $black = imagecolorallocate($output, 0, 0, 0);
  511. imagefilledrectangle($output, 0, 0, 150, 30, $white);
  512. imagestring($output, 1, 5, 5, 'Error loading ' . $srcImage, $black); /* Output an error message */
  513. }
  514. else {
  515. $srcAspect = $srcWidth / $srcHeight;
  516. $dstAspect = $dstWidth / $dstHeight;
  517. /**
  518. * cropping is disabled if source image has at least one side smaller than the destination image
  519. */
  520. if ($srcHeight < $dstHeight || $srcWidth < $dstWidth) {
  521. $crop = false;
  522. }
  523. /**
  524. * if crop, then cut to fit, otherwise add white background to fit
  525. */
  526. if (($crop && ($srcAspect > $dstAspect)) || (!$crop && ($srcAspect < $dstAspect))) {
  527. $tmpHeight = $dstHeight;
  528. $tmpWidth = round($dstHeight * $srcAspect);
  529. }
  530. else {
  531. $tmpWidth = $dstWidth;
  532. $tmpHeight = round($dstWidth / $srcAspect);
  533. }
  534. /**
  535. * first we resize original image to desired dimensions
  536. */
  537. $resized = imagecreatetruecolor($tmpWidth, $tmpHeight);
  538. $backgroundColor = imagecolorallocate($resized, 255, 255, 255);
  539. imagefill($resized, 0, 0, $backgroundColor);
  540. imagecopyresampled(
  541. $resized,
  542. $image,
  543. 0, 0,
  544. 0, 0,
  545. $tmpWidth, $tmpHeight,
  546. $srcWidth, $srcHeight
  547. );
  548. $output = imagecreatetruecolor($dstWidth, $dstHeight);
  549. /**
  550. * now we either crop or add white background and output resulting image
  551. */
  552. if ($crop) {
  553. $srcX = ($tmpWidth - $dstWidth) / 2;
  554. $srcY = ($tmpHeight - $dstHeight) / 2;
  555. imagecopy(
  556. $output,
  557. $resized,
  558. 0, 0,
  559. $srcX, $srcY,
  560. $dstWidth, $dstHeight
  561. );
  562. }
  563. else {
  564. $backgroundColor = imagecolorallocate($output, 255, 255, 255);
  565. imagefill($output, 0, 0, $backgroundColor);
  566. $dstX = ($dstWidth - $tmpWidth) / 2;
  567. $dstY = ($dstHeight - $tmpHeight) / 2;
  568. imagecopy(
  569. $output,
  570. $resized,
  571. $dstX, $dstY,
  572. 0, 0,
  573. $tmpWidth, $tmpHeight
  574. );
  575. }
  576. }
  577. return $output;
  578. }
  579. /**
  580. *
  581. * rotate uploaded image automatically based on exif orientation
  582. *
  583. * @param string $fileName
  584. *
  585. * @return $this
  586. */
  587. public function imageSmartRotate($fileName)
  588. {
  589. $output = null;
  590. if (function_exists('exif_read_data')) {
  591. $exif = @exif_read_data($fileName);
  592. if (!empty($exif['Orientation'])) {
  593. $image = $this->imageCreateFunction($fileName);
  594. switch ($exif['Orientation']) {
  595. case 3:
  596. $output = imagerotate($image, 180, 255);
  597. break;
  598. case 6:
  599. $output = imagerotate($image, -90, 255);
  600. break;
  601. case 8:
  602. $output = imagerotate($image, 90, 255);
  603. break;
  604. }
  605. if ($output !== null) {
  606. $this->imageOutputFunction($output, $fileName);
  607. }
  608. }
  609. }
  610. return $this;
  611. }
  612. /**
  613. *
  614. * add watermark to the image
  615. *
  616. * @param string $fileName
  617. * @param string $watermarkText
  618. *
  619. * @return $this
  620. */
  621. public function addWatermark($fileName, $watermarkText)
  622. {
  623. if ($this->isImage($fileName)) {
  624. $output = $this->imageCreateFunction($fileName);
  625. // Get identifier for white
  626. $white = imagecolorallocate($output, 255, 255, 255);
  627. // Add text to image
  628. imagestring($output, 20, 5, imagesy($output) - 20, $watermarkText, $white);
  629. // Save the image to file and free memory
  630. $this->imageOutputFunction($output, $fileName);
  631. }
  632. return $this;
  633. }
  634. /**
  635. *
  636. * the helper will display a thumbnail image,
  637. * or in case media is uploaded, it will add a default thumbnail
  638. *
  639. * @param string $image
  640. * @param int $width
  641. * @param string $square (Y|N|null)
  642. * @param array $params (reserved params: zoom, crop)
  643. *
  644. * @return mixed
  645. */
  646. public function thumbnail($image = null, $width = null, $square = null, $params = array())
  647. {
  648. $dataSrc = null;
  649. if ($image === null && $width === null && $square === null) {
  650. return $this;
  651. }
  652. $zoom = (isset($params['zoom'])) ? $params['zoom'] : false;
  653. if ($zoom === true) {
  654. $dataSrc = 'data-src="' . $this->generateImagePath($image) . '" ';
  655. // add js
  656. /** @var \Cube\View\Helper\Script $helper */
  657. $helper = $this->getView()->getHelper('script');
  658. $helper->addBodyCode('<script type="text/javascript" src="' . $this->getBaseUrl() . '/js/jquery.zoom.min.js"></script>')
  659. ->addBodyCode("<script type=\"text/javascript\">
  660. $(document).ready(function() {
  661. $('a.jq-zoom').zoom();
  662. });
  663. </script>");
  664. }
  665. $lazyLoad = (isset($params['lazyLoad']) && $this->isLazyLoad()) ? $params['lazyLoad'] : false;
  666. if (!array_key_exists('class', $params)) {
  667. $params['class'] = 'img-thumbnail img-responsive';
  668. }
  669. $src = $this->generateLink($image, $width, $square, $params);
  670. if ($lazyLoad === true) {
  671. // add js
  672. /** @var \Cube\View\Helper\Script $helper */
  673. $helper = $this->getView()->getHelper('script');
  674. $helper->addBodyCode('<script type="text/javascript" src="' . $this->getBaseUrl() . '/js/blazy.min.js"></script>')
  675. ->addBodyCode('<script type="text/javascript">
  676. $(document).ready(function() {
  677. var bLazy = new Blazy();
  678. $(\'a[data-toggle="tab"]\').on(\'shown.bs.tab\', function (e) {
  679. var bLazy = new Blazy();
  680. });
  681. $(\'.carousel\').on(\'slid.bs.carousel\', function () {
  682. var bLazy = new Blazy();
  683. });
  684. });
  685. </script>');
  686. $params['class'] .= ((!empty($params['class'])) ? ' ' : '') . 'b-lazy';
  687. $dataSrc = 'data-src="' . $src . '" ';
  688. $src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
  689. }
  690. foreach ($params as $key => $value) {
  691. if (!in_array($key, $this->_reservedParams)) {
  692. $dataSrc .= $key . '="' . str_replace('"', '', $value) . '" ';
  693. }
  694. }
  695. return '<img src="' . $src . '" '
  696. . $dataSrc
  697. . $this->_endTag;
  698. }
  699. /**
  700. *
  701. * generate cache file name
  702. *
  703. * @param string $name
  704. * @param bool|null $crop
  705. *
  706. * @return string
  707. */
  708. protected function _generateCacheName($name, $crop = null)
  709. {
  710. $extension = $this->getExtension();
  711. $height = $this->getHeight();
  712. $width = $this->getWidth();
  713. if ($height === true) {
  714. $height = $width;
  715. }
  716. if ($crop === null) {
  717. $crop = $this->getCrop();
  718. }
  719. return $name . '-'
  720. . $width
  721. . (($height !== null) ? 'x' . $height : '')
  722. . (($crop === true) ? '-' . 'crop' : '')
  723. . '.'
  724. . $extension;
  725. }
  726. /**
  727. *
  728. * generates a thumbnail of a given image, using the width and height parameters
  729. *
  730. * @param string $image
  731. * @param bool|null $crop
  732. *
  733. * @return string
  734. */
  735. protected function _generateThumb($image, $crop = null)
  736. {
  737. $fileName = null;
  738. $pathInfo = pathinfo($image);
  739. $baseName = (isset($pathInfo['filename'])) ? $pathInfo['filename'] : null;
  740. $extension = (isset($pathInfo['extension'])) ? $pathInfo['extension'] : null;
  741. if (preg_match('#^http(s)?://(.*)+$#i', $image)) {
  742. $baseName = preg_replace('/[^\da-z]/i', '', $image);
  743. }
  744. $this->setName($baseName)
  745. ->setExtension($extension);
  746. $cacheName = $this->_generateCacheName($baseName, $crop);
  747. $cacheFilePath = \Ppb\Utility::getPath('cache') . DIRECTORY_SEPARATOR . $cacheName;
  748. if (file_exists($cacheFilePath)) {
  749. return $cacheName;
  750. }
  751. else {
  752. $output = $this->createResizedImage($image, $crop);
  753. $this->imageOutputFunction($output, $cacheFilePath);
  754. $fileName = $cacheName;
  755. return $fileName;
  756. }
  757. }
  758. }