Source for file Pxxo.php

Documentation is available at Pxxo.php

  1. <?php
  2. // vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 fdm=marker encoding=utf8 :
  3. /**
  4.  * Pxxo - build self-supported and interoperable Web graphical components
  5.  *
  6.  * Copyright (c) 2008, Nicolas Thouvenin
  7.  *
  8.  * All rights reserved.
  9.  *
  10.  * Redistribution and use in source and binary forms, with or without
  11.  * modification, are permitted provided that the following conditions are met:
  12.  *
  13.  *     * Redistributions of source code must retain the above copyright
  14.  *       notice, this list of conditions and the following disclaimer.
  15.  *     * Redistributions in binary form must reproduce the above copyright
  16.  *       notice, this list of conditions and the following disclaimer in the
  17.  *       documentation and/or other materials provided with the distribution.
  18.  *     * Neither the name of the author nor the names of its contributors may be
  19.  *       used to endorse or promote products derived from this software without
  20.  *       specific prior written permission.
  21.  *
  22.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
  23.  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  24.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  25.  * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
  26.  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  27.  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  28.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  29.  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  30.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  31.  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32.  
  33.  * @package    Pxxo
  34.  * @copyright  Copyright (c) 2008 Nicolas Thouvenin
  35.  * @license    http://opensource.org/licenses/bsd-license.php
  36.  * @version    $Id$
  37.  */
  38. if (!defined('PXXO_ZEND_PATH')) {
  39.     define('PXXO_ZEND_PATH'realpath(rtrim(dirname(__FILE__),DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR.'ZendFramework'));
  40.     $include_path ini_get('include_path');
  41.     if ((PXXO_ZEND_PATH !== false&& (strpos($include_pathPXXO_ZEND_PATH=== false))
  42.         ini_set('include_path'$include_path.PATH_SEPARATOR.PXXO_ZEND_PATH);
  43. }
  44.  
  45. require_once 'Zend/Cache.php';
  46.  
  47. /**
  48.  * Caclul le md5 d'un tableau de chaines
  49.  *
  50.  * @package    Pxxo
  51.  * @param    array 
  52.  * @return   array 
  53.  */
  54. if (!function_exists('array_md5')) {
  55.     function array_md5($array{
  56.         return md5(implode(''$array));
  57.     }
  58. }
  59.  
  60. define('P_C_BASIC',      4);
  61. define('P_C_TEMPLATE',   8);
  62. define('P_C_RESOURCE',  16);
  63. define('P_C_XSLT',      32);
  64. define('P_C_WIDGET',    64);
  65. define('P_C_USER',     128);
  66. define('P_C_WIDGET2',  256);
  67. define('P_C_HTTP',     512);
  68.  
  69. /**
  70.  * Classe principale :
  71.  * Elle donne à tous les objets la notion de cache, de trace et de bench.
  72.  *
  73.  * @package    Pxxo
  74.  * @copyright  Copyright (c) 2008 Nicolas Thouvenin
  75.  * @license    http://opensource.org/licenses/bsd-license.php
  76.  */
  77. class Pxxo
  78. {
  79.     // {{{ Variables
  80.     /**
  81.      * Cache actif ou non
  82.      * @var        boolean 
  83.      */
  84.     private $_caching = null;
  85.     /**
  86.      * Niveau de cache
  87.      * @var        integer 
  88.      */
  89.     private $_levelcache;
  90.     /**
  91.      * Identifiant interne pour gérer le cache
  92.      * @var        integer 
  93.      */
  94.     private $_idcache = 0;
  95.     /**
  96.      * @var        array tableau permettant de calculer un identifiant unique pour chaque action
  97.      */
  98.     private $_ids = array();
  99.     /**
  100.      * Objet cache
  101.      * @var        Zend_Cache 
  102.      */
  103.     private $_cache = null;
  104.     /**
  105.      * Options du cache
  106.      * @var        array 
  107.      */
  108.     private $_cache_options = array();
  109.     /**
  110.      * Options du cache par défaut
  111.      * @var        array 
  112.      */
  113.     private $_cache_options_default = array(
  114.         // Pxxo
  115.         'convertStringType'         => 'strval',
  116.         'convertNumericType'        => 'strval',
  117.         'convertArrayType'          => 'array_md5',
  118.         'stats'                     => false,
  119.         'hits'                      => 'cache.hits',
  120.         'misses'                    => 'cache.misses',
  121.         'entries'                   => 'cache.entries',
  122.         'mode'                      => 'normal',     // (normal | refresh | force | ignore)
  123.         'backend'                   => 'auto',        // auto | File | APC
  124.         'frontendCore'              => array(
  125.             'lifeTime'                  => 3600,
  126.             'logging'                   => false,
  127.             'write_control'             => false,
  128.             'automatic_serialization'   => false,
  129.             'automatic_cleaning_factor' => 100,
  130.         ),
  131.         'backendFile'               => array(
  132.             'cache_dir'                 => '/tmp',
  133.             'file_locking'              => false,
  134.             'read_control'              => true,
  135.             'read_control_type'         => 'strlen',
  136.             'hashed_directory_level'    => 2,
  137.             'file_name_prefix'          => 'pxxo_cache',
  138.         ),
  139.         'backendAPC'               => array(),
  140.     );
  141.     /**
  142.      * Objet bench
  143.      * @var        Benchmark_Timer 
  144.      */
  145.     protected $_bench = array('timer'=>null'profiler'=>null);
  146.     /**
  147.      * mode debug actif ou non
  148.      * @var        string 
  149.      */
  150.     private $_debugging = false;
  151.     /**
  152.      * Options pour le mode debug
  153.      * @var        array 
  154.      */
  155.     private $_debug_options = array();
  156.     /**
  157.      * Options du cache par défaut
  158.      * @var        array 
  159.      */
  160.     private $_debug_options_default = array(
  161.         'filter' => 'cpnt',       //  Permet d'obtenir une regex prédéfinie : all, cpnt, none
  162.         'regex'  => '',            //  Expression régulière permettant de filtrer les messages de trace
  163.         'show'   => 'tree',         //  type d'affichage : tree, plain
  164.         'output' => 'html',         //  type de sortie : html, text, firebug
  165.     );
  166.     // }}}
  167.     // {{{ Constructeur
  168.     /**
  169.      * Constructeur
  170.      */
  171.     function __construct()
  172.     {
  173.         if (strcasecmp($this->getCacheOption('backend')'auto'== 0{
  174.             if (extension_loaded('apc')) $backend 'APC';
  175.             else $backend 'File';
  176.             $this->setCacheOption('backend'$backend);
  177.         }
  178.     }
  179.     // }}}
  180.     // {{{ enableDebug
  181.     /**
  182.      * active le mode debug
  183.      */
  184.     public function enableDebug()
  185.     {
  186.         $this->_debugging = true;
  187.     }
  188.     // }}}
  189.     // {{{ disableDebug
  190.     /**
  191.      * désactive le mode debug
  192.      */
  193.     public function disableDebug()
  194.     {
  195.         $this->_debugging = false;
  196.     }
  197.     // }}}
  198.     // {{{ traceDebug
  199.     /**
  200.      * Affichage d'un message de trace de Debug
  201.      *
  202.      * @param string un message
  203.      */
  204.     public function traceDebug($msg)
  205.     {
  206.         if ($this->isDebugging()) {
  207.             $p '';
  208.             $l $this->getDebugOption('level');
  209.             $s '';
  210.             for($i 0$i $l$i++{
  211.                 if ($i 0$s .= '|  ';
  212.             }
  213.             if ($l 0$p $s.'|_ '.$p;
  214.             $msg .= sprintf("\tcache(State:%d, Level:%d, Id:%s)"$this->isCaching()$this->getCacheLevel()$this->getCacheID());
  215.             if ($this->getDebugOption('filter'== 'all'$this->setDebugOption('regex'',.*,');
  216.             if ($this->getDebugOption('filter'== 'cpnt'$this->setDebugOption('regex'',COMPONENT,');
  217.             if ($this->getDebugOption('filter'== 'none'$this->setDebugOption('regex''');
  218.             if ( (strpos(PHP_SAPI'cli'!== false)) $this->setDebugOption('output''text');
  219.             $regex $this->getDebugOption('regex');
  220.             if (empty($regexor is_null($regex)) return;
  221.             if (!preg_match($regex$msg)) return;
  222.  
  223.             $output $this->getDebugOption('output');
  224.             $show   $this->getDebugOption('show');
  225.             if ($output == 'html'{
  226.                 if ($show == 'tree'$msg $p.$msg;
  227.                 echo str_replace(' '' ''<pre style="display:inline">'.$msg."</pre><br/>\n");
  228.             }
  229.             elseif ($output == 'firebug'{
  230.                 $charlist "'\\";
  231.                 $msgtab explode("\t"preg_replace('/,\s/'','$msg));
  232.                 if (is_array($msgtaband count($msgtab2{
  233.                     printf("<script type=\"text/javascript\">\n");
  234.                     printf("var l = $l;\nvar lll = ll-l;\n if (ll >= l{\nfor(i=0; i <= llli++) {\nconsole.groupEnd();\n}\n}\n");
  235.                     $groupname array_shift($msgtab)."\t".array_shift($msgtab);
  236.                     printf("console.group('%s');\n"addcslashes($groupname$charlist));
  237.                     foreach($msgtab as $item{
  238.                         if (preg_match(',(\w+)\((.*)\),'$item$match)) {
  239.                             if (!isset($match[1]or !isset($match[2])) continue;
  240.                             $section  $match[1];
  241.                             $values   explode(','$match[2]);
  242.                             if ($section == 'mode' and preg_match('/[^:]+:(.*),[^:]+:(.*)/',  $match[2]$match)) {
  243.                                 if (isset($match[1]and !isset($match[2])) continue;
  244.                                 printf("console.log('%s\t%s');\n"addcslashes($match[1]$charlist),addcslashes($match[2]$charlist));
  245.                             }
  246.                             else {
  247.                                 printf("a = new Array();\n");
  248.                                 printf("a['%s'] = new Array();\n"addcslashes($section$charlist));
  249.                                 foreach($values as $value{
  250.                                     $pos strpos($value':');
  251.                                     if ($pos === falsecontinue;
  252.                                     $n substr($value0$pos);
  253.                                     $v substr($value$pos+1);
  254.                                     printf("a['%s']['%s'] = '%s';\n"addcslashes($section$charlist)addcslashes($n$charlist)addcslashes($v$charlist));
  255.                                 }
  256.                                 printf("console.dir(a);\n");
  257.                             }
  258.                         }
  259.                     }
  260.                     //                    printf("console.groupEnd();\n");
  261.                     printf("var ll=%s;"addcslashes($l$charlist));
  262.                     printf("</script>\n");
  263.                 }
  264.             }
  265.             else {
  266.                 if ($show == 'tree'$msg $p.$msg;
  267.                 echo preg_replace(',\s+,'' '$msg)"\n";
  268.             }
  269.         }
  270.     }
  271.     // }}}
  272.     // {{{ enableCache
  273.     /**
  274.      * mise en route du cache
  275.      *
  276.      * @uses Zend_Cache
  277.      */
  278.     public function enableCache()
  279.     {
  280.         $this->_caching = true;
  281.     }
  282.     // }}}
  283.     // {{{ disableCache
  284.     /**
  285.      * désactive la mise en cache
  286.      */
  287.     public function disableCache()
  288.     {
  289.         $this->_caching = false;
  290.         unset($this->_cache);
  291.         $this->_cache = null;
  292.     }
  293.     // }}}
  294.     // {{{ isCaching
  295.     /**
  296.      * Le cache est-il actif
  297.      *
  298.      * true : le cache a été activé
  299.      * false : le cache a été désactivé
  300.      * null : le cache n' apas été réglé
  301.      *
  302.      * @return   boolean  true / false / null
  303.      */
  304.     public function isCaching()
  305.     {
  306.         return $this->_caching;
  307.     }
  308.     // }}}
  309.     // {{{ isDebugging
  310.     /**
  311.      * Le mode debug est-il actif
  312.      *
  313.      * @return   boolean 
  314.      */
  315.     public function isDebugging()
  316.     {
  317.         return $this->_debugging;
  318.     }
  319.     // }}}
  320.     // {{{ setCacheLevel
  321.     /**
  322.      * Changer le niveau du cache
  323.      *
  324.      * @param    integer 
  325.      */
  326.     public function setCacheLevel($level)
  327.     {
  328.         if ($level === 0$this->setCacheLevel(P_C_BASIC P_C_RESOURCE P_C_TEMPLATE P_C_USER);return;}
  329.         if ($level === 1$this->setCacheLevel(P_C_BASIC P_C_RESOURCE P_C_TEMPLATE P_C_USER P_C_WIDGET)return;}
  330.  
  331.         $this->_levelcache = $level;
  332.     }
  333.     // }}}
  334.     // {{{ setCacheLevel
  335.     /**
  336.      * ajout un niveau du cache
  337.      *
  338.      * @param    integer 
  339.      */
  340.     public function addCacheLevel($level)
  341.     {
  342.         if $this->testCacheLevel($level)) 
  343.             $this->setCacheLevel($this->getCacheLevel($level);
  344.     }
  345.     // }}}
  346.     // {{{ getCacheLevel
  347.     /**
  348.      * retourne le niveau  du cache
  349.      *
  350.      * @param    integer 
  351.      */
  352.     public function getCacheLevel()
  353.     {
  354.         return $this->_levelcache;
  355.     }
  356.     // }}}
  357.     //  {{{ testCacheLevel
  358.     /**
  359.      * permet de savoir si un niveau de cache est actif
  360.      *
  361.      * @param    string 
  362.      */
  363.     function testCacheLevel($level)
  364.     {
  365.         return (($this->_levelcache $level== $level);
  366.     }
  367.     // }}}
  368.     //  {{{ setCacheID
  369.     /**
  370.      * Choisir un identifiant de cache
  371.      *
  372.      * @param    mixed 
  373.      */
  374.     public function setCacheID($i)
  375.     {
  376.         $this->_idcache = $i;
  377.     }
  378.     // }}}
  379.     //  {{{ resetCacheID
  380.     /**
  381.      * RAZ de l'identifiant de cache
  382.      */
  383.     public function resetCacheID()
  384.     {
  385.         $this->_idcache = 0;
  386.     }
  387.     // }}}
  388.     //  {{{ initCache
  389.     /**
  390.      * Création de l'objet de getsion du cache
  391.      */
  392.     protected function initCache()
  393.     {
  394.         $frontend 'Core';
  395.         $backend $this->getCacheOption('backend');
  396.         $frontendOptions $this->getCacheOption('frontend'.$frontend);
  397.         $backendOptions $this->getCacheOption('backend'.$backend);
  398.         $this->_cache = Zend_Cache::factory($frontend$backend$frontendOptions$backendOptions);
  399.         if ($backend == 'File' && isset($this->_cache_options['backendFile']['cache_dir'])) {
  400.             $p rtrim($this->_cache_options['backendFile']['cache_dir']DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR;
  401.             if (!isset($this->_cache_options['hits'])) $this->_cache_options['hits'$p.'pxxo_cache.hits';
  402.             if (!isset($this->_cache_options['misses'])) $this->_cache_options['misses'$p.'pxxo_cache.misses';
  403.             if (!isset($this->_cache_options['entries'])) $this->_cache_options['entries'$p.'pxxo_cache.entries';
  404.         }
  405.     }
  406.     // }}}
  407.     //  {{{ resetCache
  408.     /**
  409.      * Réinitilaise le cache (utile quand on a modifié en cours de route le paramètrage)
  410.      *
  411.      */
  412.     public function resetCache()
  413.     {
  414.         unset($this->_cache);
  415.         $this->_cache = null;
  416.     }
  417.     // {{{ cleanCache
  418.     /**
  419.      * Supprime le cache courant
  420.      */
  421.     public function cleanCache()
  422.     {
  423.         if ($this->isCaching()) {
  424.             if (is_null($this->_cache)) $this->initCache();
  425.             return $this->_cache->clean();
  426.         }
  427.         else
  428.             return false;
  429.     }
  430.     // }}}
  431.     // {{{ getCacheID
  432.     /**
  433.      * Retroune l'identifiant de cache courant
  434.      * Au passage on le calcul
  435.      *
  436.      * @return   string 
  437.      */
  438.     public function getCacheID()
  439.     {
  440.         $func $this->getCacheOption('convertArrayType');
  441.  
  442.         if ($this->_idcache === 0{
  443.             $this->_idcache = $func($this->_ids);
  444.             if (is_int($this->_idcacheand $this->_idcache < 0$this->_idcache = strtr($this->_idcache'-''3');
  445.         }
  446.         if (isset($this->_idcache[0]and $this->_idcache[0== '-'$this->_idcache[0'z';
  447.         return $this->_idcache;
  448.     }
  449.     // }}}
  450.     // {{{ getinCache
  451.     /**
  452.      * recupere les données stockés dans le cache
  453.      *
  454.      * @param    string   ID
  455.      * @param    string   LEVEL niveau de cache
  456.      * @return    mixed     DATA
  457.      */
  458.     public function getinCache($id$level P_C_USER)
  459.     {
  460.         if ($this->isCaching(&& $this->testCacheLevel($level)) {
  461.             if (is_null($this->_cache)) $this->initCache();
  462.             if (is_null($id)) $id $this->getCacheID();
  463.             $id md5($id);
  464.             if ($this->getCacheOption('stats')) {
  465.                 if ($this->_cache->test($id!== false{
  466.                     if ($this->getCacheOption('backend'== 'File'file_put_contents($this->getCacheOption('hits')'.'FILE_APPEND LOCK_EX);
  467.                     elseif ($this->getCacheOption('backend'== 'APC'apc_store($this->getCacheOption('hits'),apc_fetch($this->getCacheOption('hits')) 1);
  468.                 }
  469.                 else {
  470.                     if ($this->getCacheOption('backend'== 'File'file_put_contents($this->getCacheOption('misses')'.'FILE_APPEND LOCK_EX);
  471.                     elseif ($this->getCacheOption('backend'== 'APC'apc_store($this->getCacheOption('misses'),apc_fetch($this->getCacheOption('misses')) 1);
  472.                 }
  473.             }
  474.             return $this->_cache->get($id);
  475.