Current Path : /var/www/alh/system/journal2/lib/ |
Current File : /var/www/alh/system/journal2/lib/SmushIt.php |
<?php /** * Smush.it PHP Library, a simple PHP library for accessing the Yahoo! Smush.it™ * lossless image compressor * @author Ghislain PHU <contact@ghislainphu.fr> * @version 1.0 */ class SmushIt { /** * Flag used to preserve objects with errors */ const KEEP_ERRORS = 0x01; /** * Flag used to throw exceptions when an error * occurred */ const THROW_EXCEPTION = 0x02; /** * Internal flag used to notify that the current * source is a local file */ const LOCAL_ORIGIN = 0x04; /** * Internal flag used to notify that the current * source is a remote file (source is an URL) */ const REMOTE_ORIGIN = 0x08; /** * The base URL of the Yahoo! Smush.it™ API */ const SERVICE_API_URL = "http://www.smushit.com/ysmush.it/ws.php"; /** * Maximum filesize allowed by Yahoo! Smush.it™ API */ const SERVICE_API_LIMIT = 1048576; // 1MB limitation /** * Error message * @access public * @var string | null */ public $error; /** * Source URI * @access public * @var string | null */ public $source; /** * Compressed image URL * @access public * @var string | null */ public $destination; /** * Filesize of the source image (in Bytes) * @access public * @var int | null */ public $sourceSize; /** * Filesize of the compressed image (in Bytes) * @access public * @var int | null */ public $destinationSize; /** * Saving percentage * @access public * @var float | null */ public $savings; /** * Effective flags * @access private * @var int | null */ private $flags = null; /** * Array of SmushIt objects * @access private * @var array */ private $items = array(); /** * Smush.it constructor * @access public * @param array | string $sources List of files to compress * @param int $flags List of flags * @return object * @see SmushIt::KEEP_ERRORS * @see SmushIt::THROW_EXCEPTION */ public function __construct($sources, $flags = null) { $this->flags = $flags; $sources = $this->clean($sources); if (is_string($sources)) { if ($this->check($sources)) { $this->smush(); } } else { foreach($sources as $source) { $smush = new SmushIt($source, $flags); $smushResult = $smush->get(); if (!empty($smushResult)) { $this->items[] = $smushResult; } } } } /** * Return the list of SmushIt objects * @access public * @return array * @see SmushIt::$items */ public function get() { return $this->items; } /** * Sometimes, Yahoo! Smush.it converts files (from gif to png, jpg to png) * during compression process. This function check for this case, based on * source and destination extensions. * @access public * @return bool * @throws LogicException */ public function hasBeenConverted() { if ($this->hasFlag(self::THROW_EXCEPTION) AND (empty($this->source) OR empty($this->destination))) { throw new LogicException('Can\'t compare extensions: source or destination is empty'); } return mb_strtolower(pathinfo($this->source, PATHINFO_EXTENSION)) !== mb_strtolower(pathinfo($this->destination, PATHINFO_EXTENSION)); } /** * Clean the $sources parameter from SmushIt::__construct() * (flatten array and remove non-string values) * @access private * @param string | array $sources List of files to compress * @return string | array * @throws InvalidArgumentException */ private function clean($sources) { if (is_array($sources)) { $clean = array(); array_walk_recursive($sources, function($line) use (&$clean) { $clean[] = $line; }); $sources = array_filter(array_map(function($line) { if (!empty($line) AND is_string($line)) { return $line; } }, array_unique($clean))); } else if (!is_string($sources)) { $sources = null; } if (empty($sources) AND $this->hasFlag(self::THROW_EXCEPTION)) { throw new InvalidArgumentException('Sources can\'t be empty'); } return $sources; } /** * Check if source is a readable local file and doesn't exceed filesize limit * @access private * @param string $path Location of the current image to compress * @return bool * @throws Exception */ private function check($path) { if ($this->setSource($path) === false) { $this->error = "$path is not a valid path"; } else if ($this->hasFlag(self::LOCAL_ORIGIN)) { if (!is_readable($path)) { $this->error = "$path is not readable"; } else if(filesize($path) > self::SERVICE_API_LIMIT) { $this->error = "$path exceeds 1MB size limit"; } } if (!empty($this->error)) { if ($this->hasFlag(self::THROW_EXCEPTION)) { throw new Exception($this->error); } return false; } return true; } /** * Check if the flag $flag is set in the current object * @access private * @param int $flag The flag to check * @return bool */ private function hasFlag($flag) { return (bool)($this->flags & $flag); } /** * Set SmushIt::$source and check if it's a local or remote file * @access private * @param string $flag The source to set * @return false | null */ private function setSource($source) { $this->source = $source; if (filter_var($this->source, FILTER_VALIDATE_URL) !== false) { $this->flags |= self::REMOTE_ORIGIN; } else if (file_exists($this->source) AND !is_dir($this->source)) { $this->flags |= self::LOCAL_ORIGIN; } else { return false; } } /** * Send current source to the API and get response * @access private * @throws Exception */ private function smush() { $handle = curl_init(); curl_setopt($handle, CURLOPT_RETURNTRANSFER, 1); curl_setopt($handle, CURLOPT_CONNECTTIMEOUT, 5); if ($this->hasFlag(self::LOCAL_ORIGIN)) { curl_setopt($handle, CURLOPT_URL, self::SERVICE_API_URL); curl_setopt($handle, CURLOPT_POST, true); curl_setopt($handle, CURLOPT_POSTFIELDS, array('files' => '@' . $this->source)); } else { curl_setopt($handle, CURLOPT_URL, self::SERVICE_API_URL . '?img=' . $this->source); } $json = curl_exec($handle); if ($json === false) { if (self::hasFlag(self::THROW_EXCEPTION)) { throw new Exception('Curl error: ' . curl_error($handle)); } return; } $this->set($json); } /** * Set API response data to the current object * @access private * @throws Exception */ private function set($json) { $response = json_decode($json); if (empty($response)) { if (self::hasFlag(self::THROW_EXCEPTION)) { throw new Exception('Empty JSON response'); } return; } $this->error = empty($response->error) ? $this->error : $response->error; $this->destination = empty($response->dest) ? null : $response->dest; $this->sourceSize = empty($response->src_size) ? null : intval($response->src_size); $this->destinationSize = empty($response->dest_size) ? null : intval($response->dest_size); $this->savings = empty($response->percent) ? null : floatval($response->percent); if (!empty($this->error) AND $this->hasFlag(self::THROW_EXCEPTION)) { throw new Exception($this->error); } else if (empty($this->error) OR $this->hasFlag(self::KEEP_ERRORS)) { $this->items[] = $this; } } }