Compression GZ, log, cache, tout en un.

ViPHP
ViPHP | 4039 Messages

04 avr. 2008, 16:53

J'ai un petit script sympa la, dont l'utilisation est fort simple, qui permet, directement, d'ajouter des fonctionnalités de compression, de cache, d'entregistrement, ou tout ce que vous voulez, à votre script.

Pour faire simple, j'utilise le buffer de sortie, lié à des observateurs, pour gérer la sortie du script.

Voilà l'objet principal:
class output
  {
  private static $instance;
  public $observers;
  private $method;

  /* 
   * Partie fonctionnement, construction et destruction du machin.
   */
  private function __construct($method)
    {
    ob_start();
    $this->method = $method;
    }

  public static function get_instance($method)
  	{
  	if (!isset(self::$instance))
  		{
  		$temp = __CLASS__;
  		self::$instance = new $temp($method);
  		}
  	return self::$instance;
  	}

  function __destruct()
    {
    switch ($this->method)
      {
      case "clean" :
        $this->callback(ob_get_clean());
        break;
      case "get" :
      default:
        $this->callback(ob_get_contents());
      }
    }

  function callback($data)
    {
    $this->notify($data);
    //return $data;
    return'';
    }

  /* --------------------
   * Partie observateurs.
   */
  function notify($data)
    {
    foreach ($this->observers as $obs)
      {
      $obs->notify($data);
      }
    }
  function add($obs)
    {
    $this->observers[]=$obs;
    }
  }
Pour le lancer, il suffit d'en demander l'instance (c'est un singleton) en début de script:
$gestion_sortie=output::get_instance("clean");
(le paramètre ne sert pas a grand chôse. J'utilise le script en CLI aussi, et le tampon est géré différemment)

La magie après, ce sont les observateurs qu'on peut lier.
Voici leur interface (pour faire propre):
interface observer
  {
  function notify($data);
  }
Voici par exemple celui pour compresser la page:
class gzip implements observer
  {
  private $gz_ok = false;
  function __construct()
    {
    if (strstr($_SERVER['HTTP_USER_AGENT'], 'W3C_Validator')===false ||
      strstr($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip')!==false )
      {
      $this->gz_ok=true;
      }
    }
  function notify($data)
    {
      if (!$this->gz_ok || strlen($data)<2000)
        {
        echo $data;
        }
      else
        {
        //echo strlen($data);
        header("Content-Encoding: gzip");
        echo gzencode($data);
        }
    }
  }
Qui se crée et s'ajoute tout simplement:
$out_gz = new gzip();
$gestion_sortie->add($out_gz);
Ou encore celui qui s'occupe du cache (APC):
class little_cache implements observer
  {
  private $id;
  function __construct($id)
    {
    if ($cach = apc_fetch($id))
      {
      echo $cach;
      exit;
      }
    $this->id = $id;
    }
  function notify($data)
    {
    if (!apc_fetch($this->id))
    	apc_store($this->id,$data);
    }
  }
La différence, c'est qu'il nécessite un moyen d'identifier la page:
$l_cache = new little_cache(md5( $_SERVER["REQUEST_URI"]));
$gestion_sortie->add($l_cache);
Après, vous ajoutez ce que vous voulez comme observateur. Il sera appelé avec en paramètre le contenu de la page a afficher.

C'est loin d'être parfait, les observateurs ne peuvent pas être enlevés, le cache ne vérifie pas la mise à jour de la page, mais ça fonctionne, libre à vous de l'utiliser et de le modifier (et de faire coucou).

(pour l'utiliser, il suffit de coller le code des classes et l'interface dans un fichier, l'inclure dans votre script, et initialiser le tout (attraper une instance, et ajouter les observateurs) en début de script. Le reste se fait tout seul).
Mais qu'importe. (je suis ici - dernier petit projet)
Berze going social.

Eléphant du PHP | 121 Messages

04 avr. 2008, 17:03

J'ai laissé tombé la compression de mes sorties depuis que j'ai réalisé que la plupart des hébergeurs le font automatiquement. D'ailleurs une double compression (PHP puis Apache) fait planter Firefox une fois sur deux.

ViPHP
ViPHP | 4039 Messages

04 avr. 2008, 19:34

c'est vrai :wink:

Mais bon, je gère les serveurs sur lesquels ça tourne, donc c'est une dimension que je ne dois pas prendre en compte (pour mon usage).
Mais qu'importe. (je suis ici - dernier petit projet)
Berze going social.

ViPHP
ViPHP | 4039 Messages

16 avr. 2008, 17:20

Et hop, un nouvel observer.

Celui-ci permet de controler le cache côté client. Cependant, il faut avoir installé le module http (extended http support)

Pour linux:
http://pecl.php.net/package/pecl_http
Pour windows:
http://pecl4win.php.net/ext.php/php_http.dll

Qui rajoute toute une série de fonctions:
http://www.php.net/manual/en/ref.http.php

Et voici l'object:
class client_cache implements observer
	{
  	private $last_update;
  	private $max_age;
  	private $expire;
  	private $etag;
  	private $cache_control;

	function __construct($last_update)
		{
		$this->last_update = $last_update;
		$this->max_age = 60*60*24*100; // 100 jours.

		$this->expires = $this->last_update + $this->max_age;
		//$this->expires = time() + $this->max_age;
		$this->etag = crc32($_SERVER["REQUEST_URI"].$this->last_update);
		$this->cache_control = "must-revalidate, proxy-revalidate, max-age=" . $this->max_age . ", s-maxage=" . $this->max_age;

		$this->send_headers();

		}

	function send_headers()
		{
		header( "Last-Modified: " . date( "r", $this->last_update ) );
		header( "Expires: " . date( "r", $this->expires ) );
		header( "ETag: " . $this->etag );
		header( "Cache-Control: " . $this->cache_control );

		// Vérification si pas déjà dans le cache.
		if ( http_match_modified( $this->last_update) || http_match_etag( $this->etag ) )
			{
	        header( "HTTP/1.1 304 Not Modified" );
	        exit;
   	 		}
		}

	function notify($data)
		{
		return '';
		}
	}
Qui se crée et s'ajoute comme les deux précédents:
$client_cache = new client_cache (/* timestamp de la dernière modification du fichier*/ );
$gestion_sortie>add($client_cache);
A noter cependant qu'il faut un certain ordre dans les ajouts:
D'abord le cache client, puis le gzip, puis le cache serveur.
Mais qu'importe. (je suis ici - dernier petit projet)
Berze going social.