Introducción

És habitual tener en cualquier proyecto web una gran cantidad de imagenes, muchas de las cuales no han sido comprimidas adecuadamente. Por suerte smushit nos soluciona la papeleta.

Basicamente la idea consiste en recorrer toda la estructura de directorios del servidor buscando archivos con mimetype [jpg|gif|png] para luego pasarselos a smush it (mediante el uso de la clase creada por Mathew Davies que tambien puedes ver aquí), de este modo vamos pasandole al servicio de yahoo TODAS la imagenes que hay en nuestro servidor y este se encarga de recomprimirlas (sólo si hay una ganancia) tenenido así un ahorro en disco pero sobretodo ahorrando ancho de banda cosa que implica una mejora en la velocidad de caga de la página web y por tanto una mejor experiencia de usuario.

Script php (compress_images.php)

Recuerda cambiar BASEPATH y BASEURL por los valores de tu servidor y dominio!

<?php
/*
 * Script que haciendo uso del servicio de Yahoo! de optimización de imagenes
 * va pasandole la imagenes que queremos comprima de mejor manera.
 */

  
include ('./smushit.inc.php');

  
// Path desde dónde empieza a buscar las imagenes
  
define ('BASEPATH''/var/www/vespre.com/'); // TODO: CAMBIAR ESTO POR TU PATH ORIGINAL
  
define ('BASEURL''http://vespre.com/'); // TODO: Y ESTO POR TU URL
  
define ('MIN_TIME'2500000); // uTime, modificado hace mínimo una fase lunar (aprox. 29 dias)
  
define ('ORIGINAL_POSTFIX''_orig');

  
$smush = new smushit();

  
// find para encontrar TODAS las imagenes
  
exec('find ' BASEPATH ' -type f -not -name "*' ORIGINAL_POSTFIX '*" -exec file --mime-type {} \; | grep -e "image/png" -e  "image/gif" -e "image/jpeg"'$findRes);

  
// convertimos la salida del comando en un array trabajable.
  
foreach ($findRes as $k=>$v) {
    
$fileInfo explode(': ' ,$v);

    
$files[$k]['path'] = $fileInfo[0];
    
$files[$k]['filename'] = substr($files[$k]['path'], strrpos($files[$k]['path'], '/') +1);
    
$files[$k]['extension'] = substr($files[$k]['path'], strrpos($files[$k]['path'], '.'));
    
$files[$k]['pathsmush'] = substr($files[$k]['path'], 0strrpos($files[$k]['path'], '.')) . ORIGINAL_POSTFIX $files[$k]['extension'];  
    
$files[$k]['url'] = BASEURL str_replace(BASEPATH''$files[$k]['path']);
    
$files[$k]['mimetype'] = $fileInfo[1];
  }

  
// init variables stats
  
$totalCompress 0;
  
$sumCompress 0;
  
$bytesAhorro 0;

  foreach (
$files as $file) {

    
// sólo si no es gif pues smushit los pasa a png 
    // y de momento no nos interesa por los cambios de
    // código que implica.
    
if ($file['extension'] != '.gif') {
      try {
        
// comprovar que no existe ya optimizado de hace poco...
        
if ((time() - (filemtime($file['path']))) > MIN_TIME) {
          
$compressRes $smush->compress($file['url']);

          
// sólo si el fichero es menor que el original (cosa que debe ser siempre, pues sinó salta una exception)
          
if ($compressRes->src_size $compressRes->dest_size) {

            
// Realizamos copia del original
            // pero solo si no existe el original ya.
            
if (!file_exists($file['pathsmush'])) {
              echo 
'Realizamos copia del original ' PHP_EOL 'cp ' $file['path'] . ' ' $file['pathsmush'] . PHP_EOL;
              
exec('cp ' $file['path'] . ' ' $file['pathsmush']);
            } else {
              echo 
'No realizamos copia de seguridad, ya existe. ' $file['pathsmush'] . PHP_EOL;
            }

            
// Bajamos el fichero "bien" comprimido
            
echo 'downloading: ' $file['path'] . PHP_EOL 'from: ' $compressRes->dest ' (' $compressRes->percent '%)' PHP_EOL PHP_EOL ;
            
exec('wget --output-document=' $file['path'] . ' ' $compressRes->dest);

            
// calulamos estadístcas.
            
$bytesAhorro += $compressRes->src_size $compressRes->dest_size
            
$sumCompress += $compressRes->percent;
            
$totalCompress ++;

          } else {
            echo 
'No hay mejora en la compresión, no lo bajamos.' PHP_EOL;
          }
        } else {
          echo 
'Ya se optimizó hace menos de ' MIN_TIME ' segundos.' PHP_EOL;
        }
      } catch (
Exception $e) {
        echo 
'Exception smushit. ' $e->getMessage() . ' on file: ' $file['url'] . PHP_EOL PHP_EOL;
      }
    }

    
// TODO
    // habilitar esto si queremos un test limitado por numero de files.
    /*
    if ($totalCompress == 2) {
      echo PHP_EOL . PHP_EOL . 'Smush finalizado:' . PHP_EOL;
      echo                     '-----------------' . PHP_EOL;
      echo PHP_EOL . 'Ficheros totales comprimidos = ' . $totalCompress;
      echo PHP_EOL . 'Compresión media = ' . ($sumCompress/$totalCompress);
      echo PHP_EOL . 'Bytes total ahorrados = ' . ($bytesAhorro) . PHP_EOL;

      die('we stop at 2 ... ' . PHP_EOL);
    }
    */
  
}

  
// Mostramos resumen.
  
echo PHP_EOL PHP_EOL 'Smush finalizado:' PHP_EOL;
  echo                     
'-----------------' PHP_EOL;
  echo 
PHP_EOL 'Ficheros totales comprimidos = ' $totalCompress;
  if (
$totalCompress == 0$totalCompress 1// Evita un divided by 0.
  
echo PHP_EOL 'Compresión media = ' . ($sumCompress/$totalCompress) . ' %';
  echo 
PHP_EOL 'Bytes total ahorrados = ' . ($bytesAhorro) . PHP_EOL;

?>

Clase de acceso a smushit (smushit.inc.php)

<?php
/**
 * Description: Compresses images using Smush.it
 * 
 * @license MIT
 * @author  Mathew Davies <thepixeldeveloper@googlemail.com>
 */
class smushit 
{
    const 
user_agent 'Smush.it PHP Class (+http://mathew-davies.co.uk)';

    private 
$curl NULL;

    
/**
     * Smush.it request URL
     */
    
const url 'http://www.smushit.com/ysmush.it/ws.php';

    
/**
     * Make sure any prerequisite are installed.
     */
    
public function __construct() {
        if ( ! 
extension_loaded'json' ) ) {
            throw new 
RuntimeException('The json extension was not found');
        }
        if ( ! 
extension_loaded'curl' ) ) {
            throw new 
RuntimeException('The cURL extension was not found.');
        }

        
// cURL handler
        
$this->curl curl_init();

        
// Return HTTP response
        
curl_setopt$this->curlCURLOPT_RETURNTRANSFERTRUE );
    }
    
    
/**
     * Compress image using smush.it. Image must be available online
     *
     * @param  string url to image.
     * @throws Smush_exception
     * @return object
     * 
     *  src       = source location of input image
     *  src_size  = size of the source image in bytes
     *  dest      = temporary location of the compressed image
     *  dest_size = size of compressed image in bytes
     *  percent   = how much smaller the compressed image is
     */
    
public function compress($image) {
        
// Set appropriate URL.
        
curl_setopt$this->curlCURLOPT_URLself::url.'?'.http_build_query( array('img' => $image ) ) );

        
// Set user agent
        
curl_setopt$this->curlCURLOPT_USERAGENTself::user_agent );

        
// Execute the HTTP request
        
$request curl_exec($this->curl);

        
// JSON response
        
$result json_decode($request);

        if ( isset ( 
$result->error ) ) {
            throw new 
Smush_exception($result->error$image);
        }
        
        
$result->dest urldecode($result->dest);
        
        
// Return response data
        
return $result;
    }
}

/**
 * Custom exception handler
 */
class Smush_exception extends Exception {

    
/**
     * Path to image
     * @var string $image
     */
    
private $image '';

    
/**
     * Overload the exception construct so we can provide an image name
     * @param string $message
     * @param string $image
     */
    
public function  __construct($message$image) {
        
$this->image $image;
        
parent::__construct($message);
    }

    
// Return image path.
    
final function getImage() {
        return 
$this->image;

    }
}