home *** CD-ROM | disk | FTP | other *** search
/ Cricao de Sites - 650 Layouts Prontos / WebMasters.iso / Servidores / xampp-win32-1.6.7-installer.exe / php / PEAR / HTML / AJAX / Server.php < prev   
Encoding:
PHP Script  |  2008-07-02  |  23.9 KB  |  726 lines

  1. <?php
  2. /**
  3.  * OO AJAX Implementation for PHP
  4.  *
  5.  * SVN Rev: $Id$
  6.  *
  7.  * @category   HTML
  8.  * @package    AJAX
  9.  * @author     Joshua Eichorn <josh@bluga.net>
  10.  * @copyright  2005 Joshua Eichorn
  11.  * @license    http://www.opensource.org/licenses/lgpl-license.php  LGPL
  12.  * @version    Release: 0.5.6
  13.  */
  14.  
  15. /**
  16.  * Require the main AJAX library
  17.  */
  18. require_once 'HTML/AJAX.php';
  19.  
  20. /**
  21.  * Class for creating an external AJAX server
  22.  *
  23.  * Can be used in 2 different modes, registerClass mode where you create an instance of the server and add the classes that will be registered
  24.  * and then run handle request
  25.  *
  26.  * Or you can extend it and add init{className} methods for each class you want to export
  27.  *
  28.  * Client js generation is exposed through 2 _GET params client and stub
  29.  *  Setting the _GET param client to `all` will give you all the js classes needed
  30.  *  Setting the _GET param stub to `all` will give you stubs of all registered classes, you can also set it too just 1 class
  31.  *
  32.  * @category   HTML
  33.  * @package    AJAX
  34.  * @author     Joshua Eichorn <josh@bluga.net>
  35.  * @copyright  2005 Joshua Eichorn
  36.  * @license    http://www.opensource.org/licenses/lgpl-license.php  LGPL
  37.  * @version    Release: 0.5.6
  38.  * @link       http://pear.php.net/package/PackageName
  39.  */
  40. class HTML_AJAX_Server 
  41. {
  42.  
  43.     /**
  44.      * Client options array if set to true the code looks at _GET
  45.      * @var bool|array
  46.      */
  47.     var $options = true;
  48.  
  49.     /**
  50.      * HTML_AJAX instance
  51.      * @var HTML_AJAX
  52.      */
  53.     var $ajax;
  54.  
  55.     /**
  56.      * Set to true if your extending the server to add init{className methods}
  57.      * @var boolean
  58.      * @access  public
  59.      */
  60.     var $initMethods = false;
  61.  
  62.     /**
  63.      * Location on filesystem of client javascript library
  64.      * @var false|string if false the default pear data dir location is used
  65.      */
  66.     var $clientJsLocation = false;
  67.  
  68.     /** 
  69.      * An array of options that tell the server howto Cache output
  70.      *
  71.      * The rules are functions that make etag hash used to see if the client needs to download updated content
  72.      * If you extend this class you can make your own rule function the naming convention is _cacheRule{RuleName}
  73.      *
  74.      * <code>
  75.      * array(
  76.      *  'httpCacheClient' => true,   // send 304 headers for responses to ?client=* requests
  77.      *  'ClientCacheRule' => 'File', // create a hash from file names and modified times, options: file|content
  78.      *  'ClientCacheExpects'=> 'files', // what type of content to send to the hash function, options: files|classes|content
  79.      *  'httpCacheStub'   => true,   // send 304 headers for responses to ?stub=* requests
  80.      *  'StubCacheRule'   => 'Api',  // create a hash from the exposed api, options: api|content
  81.      *  'StubCacheExpects'=> 'classes', // what type of content to send to the hash function, options: files|classes|content
  82.      * )
  83.      * </code>
  84.      *
  85.      * @var array
  86.      * @access  public
  87.      */
  88.     var $cacheOptions = array(
  89.         'httpCacheClient'       => true, 
  90.         'ClientCacheRule'       => 'file',
  91.         'ClientCacheExpects'    => 'files',
  92.         'httpCacheStub'         => true, 
  93.         'StubCacheRule'         => 'api', 
  94.         'StubCacheExpects'      => 'classes', 
  95.         );
  96.  
  97.     /**
  98.      * Compression Options
  99.      *
  100.      * <code>
  101.      * array(
  102.      *  'enabled'   => false,   // enable compression
  103.      *  'type'      => 'gzip'   // the type of compression to do, options: gzip
  104.      * )
  105.      * </code>
  106.      *
  107.      * @var array
  108.      * @access public
  109.      */
  110.     var $compression = array(
  111.         'enabled'       => false,
  112.         'type'          => 'gzip'
  113.     );
  114.  
  115.     /**
  116.      * Javascript library names and there path 
  117.      *
  118.      * the return of $this->clientJsLocation(), is prepended before running readfile on them
  119.      *
  120.      * @access  public
  121.      * @var array
  122.      */
  123.     var $javascriptLibraries = array(
  124.         'all'           =>  'HTML_AJAX.js',
  125.         'html_ajax'     =>  'HTML_AJAX.js',
  126.         'html_ajax_lite'=>  'HTML_AJAX_lite.js',
  127.         'json'          =>  'serializer/JSON.js',
  128.         'request'       =>  'Request.js',
  129.         'main'          =>  array('Compat.js','Main.js','clientPool.js'),
  130.         'httpclient'    =>  'HttpClient.js',
  131.         'dispatcher'    =>  'Dispatcher.js',
  132.         'util'          =>  'util.js',
  133.         'loading'       =>  'Loading.js',
  134.         'phpserializer' =>  'serializer/phpSerializer.js',
  135.         'urlserializer' =>  'serializer/UrlSerializer.js',
  136.         'haserializer'  =>  'serializer/haSerializer.js',
  137.         'clientpool'    =>  'clientPool.js',
  138.         'iframe'        =>  'IframeXHR.js',
  139.         'alias'         =>  'Alias.js',
  140.         'queues'        =>  'Queue.js',
  141.         'behavior'      =>  array('behavior/behavior.js','behavior/cssQuery-p.js'),
  142.  
  143.         // rules to help you use a minimal library set
  144.         'standard'      =>  array('Compat.js','clientPool.js','util.js','Main.js','HttpClient.js','Request.js','serializer/JSON.js',
  145.                                     'Loading.js','serializer/UrlSerializer.js','Alias.js','behavior/behavior.js','behavior/cssQuery-p.js'),
  146.         'jsonrpc'       =>  array('Compat.js','util.js','Main.js','clientPool.js','HttpClient.js','Request.js','serializer/JSON.js'),
  147.         'proxyobjects'  =>  array('Compat.js','util.js','Main.js','clientPool.js','Request.js','serializer/JSON.js','Dispatcher.js'),
  148.  
  149.         // BC rules
  150.         'priorityqueue' =>  'Queue.js',
  151.         'orderedqueue'  =>  'Queue.js',
  152.     );
  153.  
  154.     /**
  155.      * Custom paths to use for javascript libraries, if not set {@link clientJsLocation} is used to find the system path
  156.      *
  157.      * @access public
  158.      * @var array
  159.      * @see registerJsLibrary
  160.      */
  161.     var $javascriptLibraryPaths = array();
  162.  
  163.     /**
  164.      * Array of className => init methods to call, generated from constructor from initClassName methods
  165.      *
  166.      * @access protected
  167.      */
  168.     var $_initLookup = array();
  169.     
  170.  
  171.     /**
  172.      * Constructor creates the HTML_AJAX instance
  173.      *
  174.      * @param string $serverUrl (Optional) the url the client should be making a request too
  175.      */
  176.     function HTML_AJAX_Server($serverUrl = false) 
  177.     {
  178.         $this->ajax = new HTML_AJAX();
  179.  
  180.         // parameters for HTML::AJAX
  181.         $parameters = array('stub', 'client');
  182.  
  183.         // keep in the query string all the parameters that don't belong to AJAX
  184.         // we remove all string like "parameter=something&". Final '&' can also
  185.         // be '&' (to be sure) and is optional. '=something' is optional too.
  186.         $querystring = '';
  187.         if (isset($_SERVER['QUERY_STRING'])) {
  188.             $querystring = preg_replace('/(' . join('|', $parameters) . ')(?:=[^&]*(?:&(?:amp;)?|$))?/', '', $this->ajax->_getServer('QUERY_STRING'));
  189.         }
  190.  
  191.         // call the server with this query string
  192.         if ($serverUrl === false) {
  193.             $serverUrl = htmlentities($this->ajax->_getServer('PHP_SELF'));
  194.         }
  195.  
  196.         if (substr($serverUrl,-1) != '?') {
  197.             $serverUrl .= '?';
  198.         }
  199.         $this->ajax->serverUrl =  $serverUrl . $querystring;
  200.         
  201.         $methods = get_class_methods($this);
  202.         foreach($methods as $method) {
  203.             if (preg_match('/^init([a-zA-Z0-9_]+)$/',$method,$match)) {
  204.                 $this->_initLookup[strtolower($match[1])] = $method;
  205.             }
  206.         }
  207.     }
  208.  
  209.     /**
  210.      * Handle a client request, either generating a client or having HTML_AJAX handle the request
  211.      *
  212.      * @return boolean true if request was handled, false otherwise
  213.      */
  214.     function handleRequest() 
  215.     {
  216.         if ($this->options == true) {
  217.             $this->_loadOptions();
  218.         }
  219.         //basically a hook for iframe but allows processing of data earlier
  220.         $this->ajax->populatePayload();
  221.         if (!isset($_GET['c']) && (count($this->options['client']) > 0 || count($this->options['stub']) > 0) ) {
  222.             $this->generateClient();
  223.             return true;
  224.         } else {
  225.             if (!empty($_GET['c'])) {
  226.                 $this->_init($this->_cleanIdentifier($this->ajax->_getVar('c')));
  227.             }
  228.             return $this->ajax->handleRequest();
  229.         }
  230.     }
  231.  
  232.     /**
  233.      * Register method passthrough to HTML_AJAX
  234.      *
  235.      * @see HTML_AJAX::registerClass for docs
  236.      */
  237.     function registerClass(&$instance, $exportedName = false, $exportedMethods = false) 
  238.     {
  239.         $this->ajax->registerClass($instance,$exportedName,$exportedMethods);
  240.     }
  241.  
  242.     /**
  243.      * Change default serialization - important for exporting classes
  244.      *
  245.      * I wanted this for the xml serializer :)
  246.      */
  247.     function setSerializer($type) 
  248.     {
  249.         $this->ajax->serializer = $type;
  250.         $this->ajax->unserializer = $type;
  251.     }
  252.  
  253.     /**
  254.      * Register a new js client library
  255.      *
  256.      * @param string          $libraryName name you'll reference the library as
  257.      * @param string|array    $fileName   actual filename with no path, for example customLib.js
  258.      * @param string|false    $path   Optional, if not set the result from jsClientLocation is used
  259.      */
  260.     function registerJSLibrary($libraryName,$fileName,$path = false) {
  261.         $libraryName = strtolower($libraryName);
  262.         $this->javascriptLibraries[$libraryName] = $fileName;
  263.  
  264.         if ($path !== false) {
  265.             $this->javascriptLibraryPaths[$libraryName] = $path;
  266.         }
  267.     }
  268.  
  269.     /**
  270.      * Register init methods from an external class
  271.      *
  272.      * @param object    $instance an external class with initClassName methods
  273.      */
  274.     function registerInitObject(&$instance) {
  275.         $instance->server =& $this;
  276.         $methods = get_class_methods($instance);
  277.         foreach($methods as $method) {
  278.             if (preg_match('/^init([a-zA-Z0-9_]+)$/',$method,$match)) {
  279.                 $this->_initLookup[strtolower($match[1])] = array(&$instance,$method);
  280.             }
  281.         }
  282.     }
  283.  
  284.     /**
  285.      * Register a callback to be exported to the client
  286.      *
  287.      * This function uses the PHP callback pseudo-type
  288.      *
  289.      */
  290.     function registerPhpCallback($callback)
  291.     {
  292.         if (!is_callable($callback)) {
  293.             // invalid callback
  294.             return false;
  295.         }
  296.         
  297.         if (is_array($callback) && is_object($callback[0])) {
  298.             // object method
  299.             $this->registerClass($callback[0], strtolower(get_class($callback[0])), array($callback[1]));
  300.             return true;
  301.         }
  302.         
  303.         // static callback
  304.         $this->ajax->registerPhpCallback($callback);
  305.     }
  306.  
  307.     /**
  308.      * Generate client js
  309.      *
  310.      * @todo    this is going to need tests to cover all the options
  311.      */
  312.     function generateClient() 
  313.     {
  314.         $headers = array();
  315.  
  316.         ob_start();
  317.  
  318.         // create a list list of js files were going to need to output
  319.         // index is the full file and so is the value, this keeps duplicates out of $fileList
  320.         $fileList = array();
  321.  
  322.         if(!is_array($this->options['client'])) {
  323.             $this->options['client'] = array();
  324.         }
  325.         foreach($this->options['client'] as $library) {
  326.             if (isset($this->javascriptLibraries[$library])) {
  327.                 $lib = (array)$this->javascriptLibraries[$library];
  328.                 foreach($lib as $file) {
  329.                     if (isset($this->javascriptLibraryPaths[$library])) {
  330.                         $fileList[$this->javascriptLibraryPaths[$library].$file] = $this->javascriptLibraryPaths[$library].$file;
  331.                     }
  332.                     else {
  333.                         $fileList[$this->clientJsLocation().$file] = $this->clientJsLocation().$file;
  334.                     }
  335.                 }
  336.             }
  337.         }
  338.  
  339.         // do needed class init if were running an init server
  340.         if(!is_array($this->options['stub'])) {
  341.             $this->options['stub'] = array();
  342.         }
  343.         $classList = $this->options['stub'];
  344.         if ($this->initMethods) {
  345.             if (isset($this->options['stub'][0]) && $this->options['stub'][0] === 'all') {
  346.                     $this->_initAll();
  347.             } else {
  348.                 foreach($this->options['stub'] as $stub) {
  349.                     $this->_init($stub);
  350.                 }
  351.             }
  352.         }
  353.         if (isset($this->options['stub'][0]) && $this->options['stub'][0] === 'all') {
  354.             $classList = array_keys($this->ajax->_exportedInstances);
  355.         }
  356.  
  357.         // if were doing stub and client we have to wait for both ETags before we can compare with the client
  358.         $combinedOutput = false;
  359.         if ($classList != false && count($classList) > 0 && count($fileList) > 0) {
  360.             $combinedOutput = true;
  361.         }
  362.  
  363.  
  364.         if ($classList != false && count($classList) > 0) {
  365.  
  366.             // were setup enough to make a stubETag if the input it wants is a class list
  367.             if ($this->cacheOptions['httpCacheStub'] && 
  368.                 $this->cacheOptions['StubCacheExpects'] == 'classes') 
  369.             {
  370.                 $stubETag = $this->_callCacheRule('Stub',$classList);
  371.             }
  372.  
  373.             // if were not in combined output compare etags, if method returns true were done
  374.             if (!$combinedOutput && isset($stubETag)) {
  375.                 if ($this->_compareEtags($stubETag)) {
  376.                     ob_end_clean();
  377.                     return;
  378.                 }
  379.             }
  380.  
  381.             // output the stubs for all the classes in our list
  382.             foreach($classList as $class) {
  383.                     echo $this->ajax->generateClassStub($class);
  384.             }
  385.  
  386.             // if were cacheing and the rule expects content make a tag and check it, if the check is true were done
  387.             if ($this->cacheOptions['httpCacheStub'] && 
  388.                 $this->cacheOptions['StubCacheExpects'] == 'content') 
  389.             {
  390.                 $stubETag = $this->_callCacheRule('Stub',ob_get_contents());
  391.             }
  392.  
  393.             // if were not in combined output compare etags, if method returns true were done
  394.             if (!$combinedOutput && isset($stubETag)) {
  395.                 if ($this->_compareEtags($stubETag)) {
  396.                     ob_end_clean();
  397.                     return;
  398.                 }
  399.             }
  400.         }
  401.  
  402.         if (count($fileList) > 0) {
  403.             // if were caching and need a file list build our jsETag
  404.             if ($this->cacheOptions['httpCacheClient'] && 
  405.                 $this->cacheOptions['ClientCacheExpects'] === 'files') 
  406.             {
  407.                 $jsETag = $this->_callCacheRule('Client',$fileList);
  408.  
  409.             }
  410.  
  411.             // if were not in combined output compare etags, if method returns true were done
  412.             if (!$combinedOutput && isset($jsETag)) {
  413.                 if ($this->_compareEtags($jsETag)) {
  414.                     ob_end_clean();
  415.                     return;
  416.                 }
  417.             }
  418.  
  419.             // output the needed client js files
  420.             foreach($fileList as $file) {
  421.                 $this->_readFile($file);
  422.             }
  423.  
  424.             // if were caching and need content build the etag
  425.             if ($this->cacheOptions['httpCacheClient'] && 
  426.                 $this->cacheOptions['ClientCacheExpects'] === 'content') 
  427.             {
  428.                 $jsETag = $this->_callCacheRule('Client',ob_get_contents());
  429.             }
  430.  
  431.             // if were not in combined output compare etags, if method returns true were done
  432.             if (!$combinedOutput && isset($jsETag)) {
  433.                 if ($this->_compareEtags($jsETag)) {
  434.                     ob_end_clean();
  435.                     return;
  436.                 }
  437.             }
  438.             // were in combined output, merge the 2 ETags and compare
  439.             else if (isset($jsETag) && isset($stubETag)) {
  440.                 if ($this->_compareEtags(md5($stubETag.$jsETag))) {
  441.                     ob_end_clean();
  442.                     return;
  443.                 }
  444.             }
  445.         }
  446.  
  447.  
  448.         // were outputting content, add our length header and send the output
  449.         $length = ob_get_length();
  450.         $output = ob_get_contents();
  451.         ob_end_clean();
  452.  
  453.         if ($this->ajax->packJavaScript) {
  454.             $output = $this->ajax->packJavaScript($output);
  455.             $length = strlen($output);
  456.         }
  457.  
  458.         if ($this->compression['enabled'] && $this->compression['type'] == 'gzip' && strpos($_SERVER["HTTP_ACCEPT_ENCODING"], "gzip") !== false) {
  459.             $output = gzencode($output,9);
  460.             $length = strlen($output);
  461.             $headers['Content-Encoding'] = 'gzip';
  462.         }
  463.  
  464.         if ($length > 0 && $this->ajax->_sendContentLength()) { 
  465.             $headers['Content-Length'] = $length;
  466.         }
  467.         $headers['Content-Type'] = 'text/javascript; charset=utf-8';
  468.         $this->ajax->_sendHeaders($headers);
  469.         echo($output);
  470.     }
  471.  
  472.     /**
  473.      * Run readfile on input with basic error checking
  474.      *
  475.      * @param   string  $file   file to read
  476.      * @access  private
  477.      * @todo    is addslashes enough encoding for js?
  478.      */
  479.     function _readFile($file) 
  480.     {
  481.         if (file_exists($file)) {
  482.             readfile($file);
  483.         } else {
  484.             $file = addslashes($file);
  485.             echo "alert('Unable to find javascript file: $file');";
  486.         }
  487.     }
  488.  
  489.     /**
  490.      * Get the location of the client js
  491.      * To override the default pear datadir location set $this->clientJsLocation
  492.      *
  493.      * @return  string
  494.      */
  495.     function clientJsLocation() 
  496.     {
  497.         if (!$this->clientJsLocation) {
  498.             $path = 'C:\php5\pear\data'.DIRECTORY_SEPARATOR.'HTML_AJAX'.DIRECTORY_SEPARATOR.'js'.DIRECTORY_SEPARATOR;
  499.             if(strpos($path, '@'.'data-dir@') === 0)
  500.             {
  501.                 $path = realpath(dirname(__FILE__).DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR.'js').DIRECTORY_SEPARATOR;
  502.             }
  503.             return $path;
  504.         } else {
  505.             return $this->clientJsLocation;
  506.         }
  507.     }
  508.  
  509.     /**
  510.      * Set the location of the client js
  511.      *
  512.      * @access  public
  513.      * @param   string  $location   Location
  514.      * @return  void
  515.      */
  516.     function setClientJsLocation($location) 
  517.     {
  518.         $this->clientJsLocation = $location;
  519.     }
  520.  
  521.     /**
  522.      * Set the path to a Javascript libraries
  523.      *
  524.      * @access  public
  525.      * @param   string  $library    Library name
  526.      * @param   string  $path       Path
  527.      * @return  void
  528.      */
  529.     function setJavascriptLibraryPath($library, $path) 
  530.     {
  531.         $this->javascriptLibraryPaths[$library] = $path;
  532.     }
  533.  
  534.     /**
  535.      * Set the path to more than one Javascript libraries at once
  536.      *
  537.      * @access  public
  538.      * @param   array   $paths  Paths
  539.      * @return  void
  540.      */
  541.     function setJavascriptLibraryPaths($paths) 
  542.     {
  543.         if (is_array($paths)) {
  544.             $this->javascriptLibraryPaths = array_merge($this->javascriptLibraryPaths, $paths);
  545.         }
  546.     }
  547.  
  548.     /**
  549.      * Load options from _GET
  550.      *
  551.      * @access private
  552.      */
  553.     function _loadOptions() 
  554.     {
  555.         $this->options = array('client'=>array(),'stub'=>array());
  556.         if (isset($_GET['client'])) {
  557.             $clients = explode(',',$this->ajax->_getVar('client'));
  558.             $client = array();
  559.             foreach($clients as $val) {
  560.                 $cleanVal = $this->_cleanIdentifier($val);
  561.                 if (!empty($cleanVal)) {
  562.                     $client[] = strtolower($cleanVal);
  563.                 }
  564.             }
  565.  
  566.             if (count($client) > 0) {
  567.                 $this->options['client'] = $client;
  568.             }
  569.         }
  570.         if (isset($_GET['stub'])) {
  571.             $stubs = explode(',',$this->ajax->_getVar('stub'));
  572.             $stub = array();
  573.             foreach($stubs as $val) {
  574.                 $cleanVal = $this->_cleanIdentifier($val);
  575.                 if (!empty($cleanVal)) {
  576.                     $stub[] = strtolower($cleanVal);
  577.                 }
  578.             }
  579.  
  580.             if (count($stub) > 0) {
  581.                 $this->options['stub'] = $stub;
  582.             }
  583.         }
  584.     }
  585.  
  586.     /**
  587.      * Clean an identifier like a class name making it safe to use
  588.      *
  589.      * @param   string  $input
  590.      * @return  string
  591.      * @access  private
  592.      */
  593.     function _cleanIdentifier($input) {
  594.             return trim(preg_replace('/[^A-Za-z_0-9]/','',$input));
  595.     }
  596.  
  597.     /**
  598.      * Run every init method on the class
  599.      *
  600.      * @access private
  601.      */
  602.     function _initAll() 
  603.     {
  604.         if ($this->initMethods) {
  605.             foreach($this->_initLookup as $class => $method) {
  606.                 $this->_init($class);
  607.             }
  608.         }
  609.     }
  610.  
  611.     /**
  612.      * Init one class
  613.      *
  614.      * @param   string  $className
  615.      * @access private
  616.      */
  617.     function _init($className) 
  618.     {
  619.         $className = strtolower($className);
  620.         if ($this->initMethods) {
  621.             if (isset($this->_initLookup[$className])) {
  622.                 $method =& $this->_initLookup[$className];
  623.                 if (is_array($method)) {
  624.                     call_user_func($method);
  625.                 }
  626.                 else {
  627.                     $this->$method();
  628.                 }
  629.             } else {
  630.                 trigger_error("Could find an init method for class: " . $className);
  631.             }
  632.         }
  633.     }
  634.  
  635.     /**
  636.      * Generate a hash from a list of files
  637.      *
  638.      * @param   array   $files  file list
  639.      * @return  string  a hash that can be used as an etag
  640.      * @access  private
  641.      */
  642.     function _cacheRuleFile($files) {
  643.         $signature = "";
  644.         foreach($files as $file) {
  645.             if (file_exists($file)) {
  646.                 $signature .= $file.filemtime($file);
  647.             }
  648.         }
  649.         return md5($signature);
  650.     }
  651.  
  652.     /**
  653.      * Generate a hash from the api of registered classes
  654.      *
  655.      * @param   array   $classes class list
  656.      * @return  string  a hash that can be used as an etag
  657.      * @access  private
  658.      */
  659.     function _cacheRuleApi($classes) {
  660.         $signature = "";
  661.         foreach($classes as $class) {
  662.             if (isset($this->ajax->_exportedInstances[$class])) {
  663.                 $signature .= $class.implode(',',$this->ajax->_exportedInstances[$class]['exportedMethods']);
  664.             }
  665.         }
  666.         return md5($signature);
  667.     }
  668.  
  669.     /**
  670.      * Generate a hash from the raw content
  671.      *
  672.      * @param   array   $content
  673.      * @return  string  a hash that can be used as an etag
  674.      * @access  private
  675.      */
  676.     function _cacheRuleContent($content) {
  677.         return md5($content);
  678.     }
  679.  
  680.     /**
  681.      * Send cache control headers
  682.      * @access  private
  683.      */
  684.     function _sendCacheHeaders($etag,$notModified) {
  685.         header('Cache-Control: must-revalidate');
  686.         header('ETag: '.$etag);
  687.         if ($notModified) {
  688.             header('HTTP/1.0 304 Not Modified',false,304);
  689.         }
  690.     }
  691.  
  692.     /**
  693.      * Compare eTags
  694.      *
  695.      * @param   string  $serverETag server eTag
  696.      * @return  boolean
  697.      * @access  private
  698.      */
  699.     function _compareEtags($serverETag) {
  700.         if (isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
  701.             if (strcmp($this->ajax->_getServer('HTTP_IF_NONE_MATCH'),$serverETag) == 0) {
  702.                 $this->_sendCacheHeaders($serverETag,true);
  703.                 return true;
  704.             }
  705.         }
  706.         $this->_sendCacheHeaders($serverETag,false);
  707.         return false;
  708.     }
  709.  
  710.     /**
  711.      * Call a cache rule and return its retusn
  712.      *
  713.      * @param   string  $rule Stub|Client
  714.      * @param   mixed   $payload
  715.      * @return  boolean
  716.      * @access  private
  717.      * @todo    decide if error checking is needed
  718.      */
  719.     function _callCacheRule($rule,$payload) {
  720.         $method = '_cacheRule'.$this->cacheOptions[$rule.'CacheRule'];
  721.         return call_user_func(array(&$this,$method),$payload);
  722.     }
  723. }
  724. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  725. ?>
  726.