Skip to content

Instantly share code, notes, and snippets.

@subhashdasyam
Last active January 25, 2017 08:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save subhashdasyam/4c3f95de476072573d373e7471c7eb75 to your computer and use it in GitHub Desktop.
Save subhashdasyam/4c3f95de476072573d373e7471c7eb75 to your computer and use it in GitHub Desktop.
<?php
class LittleUtils{
private static $systemRequirementsJsonFilePath;
/**
* Checks if system meets requirements
* @return string If all the requirements are satisfied then it return "Success" else "Error message"
*/
private function __checkSystemRequirements(){
$result = array();
//Get disabled php functions and check if "exec" command is disabled or not.
$disabled = array_map('trim', explode(',', ini_get('disable_functions')));
if(in_array('exec', $disabled)){
$result['exec'] = array("success"=>false,"msg"=>"CW Image Optimizer requires exec(). Your system administrator has disabled this function.");
}
else{
$result['exec'] = array("success"=>true,"msg"=>"");
}
//Check if required executable libraries are installed
$missingLibraries = array();
$requiredLibraries = array(
'PNG' => 'opt-png',
'JPG' => 'opt-jpg',
'GIF' => 'opt-gif',
);
foreach($requiredLibraries as $imageType => $requiredLibrary){
$res = trim(exec('which ' . $requiredLibrary));
if(empty($res)){
$missingLibraries[] = $requiredLibrary;
}
}
$missingLibrariesString = implode(', ', $missingLibraries);
if(!empty($missingLibrariesString)){
$result['missing'] = array("success"=>false, "msg"=>"CW Image Optimizer requires http://sourceforge.net/projects/littleutils. You are missing: $missingLibrariesString.");
}
else{
$result['missing'] = array("success"=>true,"msg"=>"All required libraries found");
}
if ( FALSE === is_writable(dirname(self::$systemRequirementsJsonFilePath)) ) {
$result['file_write_perm'] = array("success"=> false, msg="Unable to write the requirements file ".self::$systemRequirementsJsonFilePath.". Please make sure the path is writable");
//Utils::ErrorReportAndQuit(__LINE__, __FILE__, "Unable to write the requirements file ".self::$systemRequirementsJsonFilePath.". Please make sure the path is writable");
}
else{
$result['file_write_perm'] = array("success"=> true, msg="");
}
$fHandle = file_put_contents(self::$systemRequirementsJsonFilePath,json_encode($result));
if($fHandle)
$result['file_write'] = array("success"=> true, msg="");
else
$result['file_write'] = array("success"=> false, msg="Unable to Write contents to ".self::$systemRequirementsJsonFilePath.". Please make sure the path is writable");
foreach($result as $key=>$value){
if(!$value['success']){
return $value['msg'];
}
}
return "Success";
}
/**
* Checks if file already exists and if system requirements were already met or we should do a check
*/
private function checkSystemRequirements(){
// If requirements file doesn't exists check the requirements and write to file
if ( FALSE === file_exists(self::$systemRequirementsJsonFilePath) || FALSE === is_file(self::$systemRequirementsJsonFilePath)) {
return $this->__checkSystemRequirements() === "Success"?true:false; // Check the System Requirements and
}
// File Exists
//Read the file
$content = json_decode(file_get_contents(self::$systemRequirementsJsonFilePath),true);
// if the requirement file exists but if doesn't have required info check requirements again and rewrite the fresh file
if(!isset($content['exec']) || !isset($content['missing'])){
return $this->__checkSystemRequirements() === "Success"?true:false;
}
// if the requirements file exists and if the requirements are false check again.
if($content['exec']['success'] === false || $content['missing']['success'] === false){
//echo $content['exec']['msg']."<br/>".$content['missing']['msg'];
//***********TODO: this function is not well coded. What happens if the code reaches this point? ********
// There is no additional check done. If the check fails again, the code will continue running.
// here is the content is false that means the Little utils or php doesn't have required functions to continue,
// so recursive checks are not needed, install the functions and packages then run the code again that should fix this
return $this->__checkSystemRequirements() === "Success"?true:false;
}
// Passed all hurdles then it seems everything is passed, continue.
return true;
}
public static function verifyFileNameElseQuit($fileName){
// Changed to if not << if file name has a-z and 1-2 it matches so this function always throws error for valid
// file names, so changed to if not
if(!preg_match('/[^a-zA-Z0-9\-]+/',$fileName,$matches)){
Utils::ErrorReportAndQuit(__LINE__, __FILE__, "Filename to save images contains invalid characters. Only alpha-numeric and dash are allowed: ". $fileName);
}
}
/**
* Optimizes an image given filepath. Works for gif, jpeg, and png
* @param string $fileName
* @return array
*/
public function optimize($fileName){
//Verify if filename doesn't have invalid characters, else quit
$this->verifyFileNameElseQuit($fileName);
$thisFolder = dirname(__FILE__).DIRECTORY_SEPARATOR;
self::$systemRequirementsJsonFilePath = $thisFolder.'check.json';
if(!self::checkSystemRequirements())
return false;
//Force file path to be inside the cache folder
$filePath = $thisFolder. "cache". DIRECTORY_SEPARATOR. $fileName;
//Check if File Exists
if ( FALSE === file_exists($filePath) || FALSE === is_file($filePath) ) {
$msg = sprintf("Could not find %s", $filePath);
return array("success"=>false, "message"=> $msg, "savings"=> NULL);
}
//Check that the file is writable
if ( FALSE === is_writable($filePath) ) {
$msg = sprintf("%s is not writable", $filePath);
return array("success"=>false, "message"=> $msg, "savings"=> NULL);
}
if(function_exists('getimagesize')){
$type = getimagesize($filePath);
if(false !== $type){
$type = $type['mime'];
}
}elseif(function_exists('mime_content_type')){
$type = mime_content_type($filePath);
}else{
return array("success"=>false, "message"=> 'Missing getimagesize() and mime_content_type() PHP functions', "savings"=> NULL);
}
switch($type){
case 'image/jpeg':
$command = 'opt-jpg';
break;
case 'image/png':
$command = 'opt-png';
break;
case 'image/gif':
$command = 'opt-gif';
break;
default:
return array("success"=>false, "message"=> 'Unknown type: ' . $type, "savings"=> NULL);
}
$result = exec($command . ' ' . escapeshellarg($filePath));
$result = str_replace($filePath . ': ', '', $result);
if($result == 'unchanged') {
return array("success"=>true, "message"=> 'No savings', "savings"=>0);
}
if(strpos($result, ' vs. ') !== false) {
$s = explode(' vs. ', $result);
$savings = intval($s[0]) - intval($s[1]);
$savingsString = $this->getBytesInHumanFriendlyFormat($savings, 1);
$savingsString = str_replace(' ', '&nbsp;', $savingsString);
$percent = 100 - (100 * ($s[1] / $s[0]));
$resultMessage = sprintf("Reduced by %01.1f%% (%s)",$percent,$savingsString);
return array("success"=>true, "message"=> $resultMessage, "savings"=>$percent);
}
return array("success"=>false, "message"=> 'Bad response from optimizer', "savings"=> NULL);
}
/**
* Returns a string with a human friendly reading of bytes
* @param int $bytes
* @param int $precision
* @return string
*/
private function getBytesInHumanFriendlyFormat($bytes, $precision = 2) {
$units = array('B', 'KB', 'MB', 'GB', 'TB');
$bytes = max($bytes, 0);
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
$pow = min($pow, count($units) - 1);
$bytes /= pow(1024, $pow);
return round($bytes, $precision) . ' ' . $units[$pow];
}
}
@subhashdasyam
Copy link
Author

    1  cd /usr/local/src/
    2  sudo wget http://downloads.sourceforge.net/project/littleutils/littleutils-source/1.0.27/littleutils-1.0.27.tar.bz2
    3  sudo tar jxvf littleutils-1.0.27.tar.bz2 && cd littleutils-1.0.27
    4  sudo ./configure --prefix=/usr
    5  sudo apt-get install python-software-properties
    6  sudo add-apt-repository ppa:ondrej/php
    7  sudo apt-get update
    8  sudo apt-get install -y php5.6 php5.6-common php5.6-gd
   

#Copy the above file

usage

$lu = new LittleUtils();
print_r($lu->optimize('a.gif'));

a.gif will be image path

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment