mirror of
https://github.com/ACSPRI/queXS
synced 2024-04-02 12:12:16 +00:00
699 lines
23 KiB
PHP
699 lines
23 KiB
PHP
<?php
|
|
/**
|
|
* OO AJAX Implementation for PHP
|
|
*
|
|
* @category HTML
|
|
* @package AJAX
|
|
* @author Joshua Eichorn <josh@bluga.net>
|
|
* @copyright 2005 Joshua Eichorn
|
|
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
|
* @version Release: 0.5.2
|
|
*/
|
|
|
|
/**
|
|
* Require the main AJAX library
|
|
*/
|
|
require_once 'HTML/AJAX.php';
|
|
|
|
/**
|
|
* Class for creating an external AJAX server
|
|
*
|
|
* 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
|
|
* and then run handle request
|
|
*
|
|
* Or you can extend it and add init{className} methods for each class you want to export
|
|
*
|
|
* Client js generation is exposed through 2 _GET params client and stub
|
|
* Setting the _GET param client to `all` will give you all the js classes needed
|
|
* Setting the _GET param stub to `all` will give you stubs of all registered classes, you can also set it too just 1 class
|
|
*
|
|
* @category HTML
|
|
* @package AJAX
|
|
* @author Joshua Eichorn <josh@bluga.net>
|
|
* @copyright 2005 Joshua Eichorn
|
|
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
|
* @version Release: 0.5.2
|
|
* @link http://pear.php.net/package/PackageName
|
|
*/
|
|
class HTML_AJAX_Server
|
|
{
|
|
|
|
/**
|
|
* Client options array if set to true the code looks at _GET
|
|
* @var bool|array
|
|
*/
|
|
var $options = true;
|
|
|
|
/**
|
|
* HTML_AJAX instance
|
|
* @var HTML_AJAX
|
|
*/
|
|
var $ajax;
|
|
|
|
/**
|
|
* Set to true if your extending the server to add init{className methods}
|
|
* @var boolean
|
|
* @access public
|
|
*/
|
|
var $initMethods = false;
|
|
|
|
/**
|
|
* Location on filesystem of client javascript library
|
|
* @var false|string if false the default pear data dir location is used
|
|
*/
|
|
var $clientJsLocation = false;
|
|
|
|
/**
|
|
* An array of options that tell the server howto Cache output
|
|
*
|
|
* The rules are functions that make etag hash used to see if the client needs to download updated content
|
|
* If you extend this class you can make your own rule function the naming convention is _cacheRule{RuleName}
|
|
*
|
|
* <code>
|
|
* array(
|
|
* 'httpCacheClient' => true, // send 304 headers for responses to ?client=* requests
|
|
* 'ClientCacheRule' => 'File', // create a hash from file names and modified times, options: file|content
|
|
* 'ClientCacheExpects'=> 'files', // what type of content to send to the hash function, options: files|classes|content
|
|
* 'httpCacheStub' => true, // send 304 headers for responses to ?stub=* requests
|
|
* 'StubCacheRule' => 'Api', // create a hash from the exposed api, options: api|content
|
|
* 'StubCacheExpects'=> 'classes', // what type of content to send to the hash function, options: files|classes|content
|
|
* )
|
|
* </code>
|
|
*
|
|
* @var array
|
|
* @access public
|
|
*/
|
|
var $cacheOptions = array(
|
|
'httpCacheClient' => true,
|
|
'ClientCacheRule' => 'file',
|
|
'ClientCacheExpects' => 'files',
|
|
'httpCacheStub' => true,
|
|
'StubCacheRule' => 'api',
|
|
'StubCacheExpects' => 'classes',
|
|
);
|
|
|
|
/**
|
|
* Javascript library names and there path
|
|
*
|
|
* the return of $this->clientJsLocation(), is prepended before running readfile on them
|
|
*
|
|
* @access public
|
|
* @var array
|
|
*/
|
|
var $javascriptLibraries = array(
|
|
'all' => 'HTML_AJAX.js',
|
|
'html_ajax' => 'HTML_AJAX.js',
|
|
'html_ajax_lite'=> 'HTML_AJAX_lite.js',
|
|
'json' => 'serializer/JSON.js',
|
|
'request' => 'Request.js',
|
|
'main' => array('Compat.js','Main.js','clientPool.js'),
|
|
'httpclient' => 'HttpClient.js',
|
|
'dispatcher' => 'Dispatcher.js',
|
|
'util' => 'util.js',
|
|
'loading' => 'Loading.js',
|
|
'phpserializer' => 'serializer/phpSerializer.js',
|
|
'urlserializer' => 'serializer/UrlSerializer.js',
|
|
'haserializer' => 'serializer/haSerializer.js',
|
|
'clientpool' => 'clientPool.js',
|
|
'iframe' => 'IframeXHR.js',
|
|
'alias' => 'Alias.js',
|
|
'queues' => 'Queue.js',
|
|
'behavior' => array('behavior/behavior.js','behavior/cssQuery-p.js'),
|
|
|
|
// rules to help you use a minimal library set
|
|
'standard' => array('Compat.js','clientPool.js','util.js','Main.js','HttpClient.js','Request.js','serializer/JSON.js',
|
|
'Loading.js','serializer/UrlSerializer.js','Alias.js','behavior/behavior.js','behavior/cssQuery-p.js'),
|
|
'jsonrpc' => array('Compat.js','util.js','Main.js','clientPool.js','HttpClient.js','Request.js','serializer/JSON.js'),
|
|
'proxyobjects' => array('Compat.js','util.js','Main.js','clientPool.js','Request.js','serializer/JSON.js','Dispatcher.js'),
|
|
|
|
// BC rules
|
|
'priorityqueue' => 'Queue.js',
|
|
'orderedqueue' => 'Queue.js',
|
|
);
|
|
|
|
/**
|
|
* Custom paths to use for javascript libraries, if not set {@link clientJsLocation} is used to find the system path
|
|
*
|
|
* @access public
|
|
* @var array
|
|
* @see registerJsLibrary
|
|
*/
|
|
var $javascriptLibraryPaths = array();
|
|
|
|
/**
|
|
* Array of className => init methods to call, generated from constructor from initClassName methods
|
|
*
|
|
* @access protected
|
|
*/
|
|
var $_initLookup = array();
|
|
|
|
|
|
/**
|
|
* Constructor creates the HTML_AJAX instance
|
|
*
|
|
* @param string $serverUrl (Optional) the url the client should be making a request too
|
|
*/
|
|
function HTML_AJAX_Server($serverUrl = false)
|
|
{
|
|
$this->ajax = new HTML_AJAX();
|
|
|
|
// parameters for HTML::AJAX
|
|
$parameters = array('stub', 'client');
|
|
|
|
// keep in the query string all the parameters that don't belong to AJAX
|
|
// we remove all string like "parameter=something&". Final '&' can also
|
|
// be '&' (to be sure) and is optional. '=something' is optional too.
|
|
$querystring = '';
|
|
if (isset($_SERVER['QUERY_STRING'])) {
|
|
$querystring = preg_replace('/(' . join('|', $parameters) . ')(?:=[^&]*(?:&(?:amp;)?|$))?/', '', $this->ajax->_getServer('QUERY_STRING'));
|
|
}
|
|
|
|
// call the server with this query string
|
|
if ($serverUrl === false) {
|
|
$serverUrl = htmlentities($this->ajax->_getServer('PHP_SELF'));
|
|
}
|
|
|
|
if (substr($serverUrl,-1) != '?') {
|
|
$serverUrl .= '?';
|
|
}
|
|
$this->ajax->serverUrl = $serverUrl . htmlentities($querystring);
|
|
|
|
$methods = get_class_methods($this);
|
|
foreach($methods as $method) {
|
|
if (preg_match('/^init([a-zA-Z0-9_]+)$/',$method,$match)) {
|
|
$this->_initLookup[strtolower($match[1])] = $method;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle a client request, either generating a client or having HTML_AJAX handle the request
|
|
*
|
|
* @return boolean true if request was handled, false otherwise
|
|
*/
|
|
function handleRequest()
|
|
{
|
|
if ($this->options == true) {
|
|
$this->_loadOptions();
|
|
}
|
|
//basically a hook for iframe but allows processing of data earlier
|
|
$this->ajax->populatePayload();
|
|
if (!isset($_GET['c']) && (count($this->options['client']) > 0 || count($this->options['stub']) > 0) ) {
|
|
$this->generateClient();
|
|
return true;
|
|
} else {
|
|
if (!empty($_GET['c'])) {
|
|
$this->_init($this->_cleanIdentifier($this->ajax->_getVar('c')));
|
|
}
|
|
return $this->ajax->handleRequest();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Register method passthrough to HTML_AJAX
|
|
*
|
|
* @see HTML_AJAX::registerClass for docs
|
|
*/
|
|
function registerClass(&$instance, $exportedName = false, $exportedMethods = false)
|
|
{
|
|
$this->ajax->registerClass($instance,$exportedName,$exportedMethods);
|
|
}
|
|
|
|
/**
|
|
* Change default serialization - important for exporting classes
|
|
*
|
|
* I wanted this for the xml serializer :)
|
|
*/
|
|
function setSerializer($type)
|
|
{
|
|
$this->ajax->serializer = $type;
|
|
$this->ajax->unserializer = $type;
|
|
}
|
|
|
|
/**
|
|
* Register a new js client library
|
|
*
|
|
* @param string $libraryName name you'll reference the library as
|
|
* @param string|array $fileName actual filename with no path, for example customLib.js
|
|
* @param string|false $path Optional, if not set the result from jsClientLocation is used
|
|
*/
|
|
function registerJSLibrary($libraryName,$fileName,$path = false) {
|
|
$libraryName = strtolower($libraryName);
|
|
$this->javascriptLibraries[$libraryName] = $fileName;
|
|
|
|
if ($path !== false) {
|
|
$this->javascriptLibraryPaths[$libraryName] = $path;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Register init methods from an external class
|
|
*
|
|
* @param object $instance an external class with initClassName methods
|
|
*/
|
|
function registerInitObject(&$instance) {
|
|
$instance->server =& $this;
|
|
$methods = get_class_methods($instance);
|
|
foreach($methods as $method) {
|
|
if (preg_match('/^init([a-zA-Z0-9_]+)$/',$method,$match)) {
|
|
$this->_initLookup[strtolower($match[1])] = array(&$instance,$method);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Register a callback to be exported to the client
|
|
*
|
|
* This function uses the PHP callback pseudo-type
|
|
*
|
|
*/
|
|
function registerPhpCallback($callback)
|
|
{
|
|
if (!is_callable($callback)) {
|
|
// invalid callback
|
|
return false;
|
|
}
|
|
|
|
if (is_array($callback) && is_object($callback[0])) {
|
|
// object method
|
|
$this->registerClass($callback[0], strtolower(get_class($callback[0])), array($callback[1]));
|
|
return true;
|
|
}
|
|
|
|
// static callback
|
|
$this->ajax->registerPhpCallback($callback);
|
|
}
|
|
|
|
/**
|
|
* Generate client js
|
|
*
|
|
* @todo this is going to need tests to cover all the options
|
|
*/
|
|
function generateClient()
|
|
{
|
|
$headers = array();
|
|
|
|
ob_start();
|
|
|
|
// create a list list of js files were going to need to output
|
|
// index is the full file and so is the value, this keeps duplicates out of $fileList
|
|
$fileList = array();
|
|
|
|
if(!is_array($this->options['client'])) {
|
|
$this->options['client'] = array();
|
|
}
|
|
foreach($this->options['client'] as $library) {
|
|
if (isset($this->javascriptLibraries[$library])) {
|
|
$lib = (array)$this->javascriptLibraries[$library];
|
|
foreach($lib as $file) {
|
|
if (isset($this->javascriptLibraryPaths[$library])) {
|
|
$fileList[$this->javascriptLibraryPaths[$library].$file] = $this->javascriptLibraryPaths[$library].$file;
|
|
}
|
|
else {
|
|
$fileList[$this->clientJsLocation().$file] = $this->clientJsLocation().$file;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// do needed class init if were running an init server
|
|
if(!is_array($this->options['stub'])) {
|
|
$this->options['stub'] = array();
|
|
}
|
|
$classList = $this->options['stub'];
|
|
if ($this->initMethods) {
|
|
if (isset($this->options['stub'][0]) && $this->options['stub'][0] === 'all') {
|
|
$this->_initAll();
|
|
} else {
|
|
foreach($this->options['stub'] as $stub) {
|
|
$this->_init($stub);
|
|
}
|
|
}
|
|
}
|
|
if (isset($this->options['stub'][0]) && $this->options['stub'][0] === 'all') {
|
|
$classList = array_keys($this->ajax->_exportedInstances);
|
|
}
|
|
|
|
// if were doing stub and client we have to wait for both ETags before we can compare with the client
|
|
$combinedOutput = false;
|
|
if ($classList != false && count($classList) > 0 && count($fileList) > 0) {
|
|
$combinedOutput = true;
|
|
}
|
|
|
|
|
|
if ($classList != false && count($classList) > 0) {
|
|
|
|
// were setup enough to make a stubETag if the input it wants is a class list
|
|
if ($this->cacheOptions['httpCacheStub'] &&
|
|
$this->cacheOptions['StubCacheExpects'] == 'classes')
|
|
{
|
|
$stubETag = $this->_callCacheRule('Stub',$classList);
|
|
}
|
|
|
|
// if were not in combined output compare etags, if method returns true were done
|
|
if (!$combinedOutput && isset($stubETag)) {
|
|
if ($this->_compareEtags($stubETag)) {
|
|
ob_end_clean();
|
|
return;
|
|
}
|
|
}
|
|
|
|
// output the stubs for all the classes in our list
|
|
foreach($classList as $class) {
|
|
echo $this->ajax->generateClassStub($class);
|
|
}
|
|
|
|
// if were cacheing and the rule expects content make a tag and check it, if the check is true were done
|
|
if ($this->cacheOptions['httpCacheStub'] &&
|
|
$this->cacheOptions['StubCacheExpects'] == 'content')
|
|
{
|
|
$stubETag = $this->_callCacheRule('Stub',ob_get_contents());
|
|
}
|
|
|
|
// if were not in combined output compare etags, if method returns true were done
|
|
if (!$combinedOutput && isset($stubETag)) {
|
|
if ($this->_compareEtags($stubETag)) {
|
|
ob_end_clean();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (count($fileList) > 0) {
|
|
// if were caching and need a file list build our jsETag
|
|
if ($this->cacheOptions['httpCacheClient'] &&
|
|
$this->cacheOptions['ClientCacheExpects'] === 'files')
|
|
{
|
|
$jsETag = $this->_callCacheRule('Client',$fileList);
|
|
|
|
}
|
|
|
|
// if were not in combined output compare etags, if method returns true were done
|
|
if (!$combinedOutput && isset($jsETag)) {
|
|
if ($this->_compareEtags($jsETag)) {
|
|
ob_end_clean();
|
|
return;
|
|
}
|
|
}
|
|
|
|
// output the needed client js files
|
|
foreach($fileList as $file) {
|
|
$this->_readFile($file);
|
|
}
|
|
|
|
// if were caching and need content build the etag
|
|
if ($this->cacheOptions['httpCacheClient'] &&
|
|
$this->cacheOptions['ClientCacheExpects'] === 'content')
|
|
{
|
|
$jsETag = $this->_callCacheRule('Client',ob_get_contents());
|
|
}
|
|
|
|
// if were not in combined output compare etags, if method returns true were done
|
|
if (!$combinedOutput && isset($jsETag)) {
|
|
if ($this->_compareEtags($jsETag)) {
|
|
ob_end_clean();
|
|
return;
|
|
}
|
|
}
|
|
// were in combined output, merge the 2 ETags and compare
|
|
else if (isset($jsETag) && isset($stubETag)) {
|
|
if ($this->_compareEtags(md5($stubETag.$jsETag))) {
|
|
ob_end_clean();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// were outputting content, add our length header and send the output
|
|
$length = ob_get_length();
|
|
$output = ob_get_contents();
|
|
ob_end_clean();
|
|
|
|
if ($this->ajax->packJavaScript) {
|
|
$output = $this->ajax->packJavaScript($output);
|
|
$length = strlen($output);
|
|
}
|
|
if ($length > 0 && $this->ajax->_sendContentLength()) {
|
|
//$headers['Content-Length'] = $length;
|
|
}
|
|
$headers['Content-Type'] = 'text/javascript; charset=utf-8';
|
|
$this->ajax->_sendHeaders($headers);
|
|
echo($output);
|
|
}
|
|
|
|
/**
|
|
* Run readfile on input with basic error checking
|
|
*
|
|
* @param string $file file to read
|
|
* @access private
|
|
* @todo is addslashes enough encoding for js?
|
|
*/
|
|
function _readFile($file)
|
|
{
|
|
if (file_exists($file)) {
|
|
readfile($file);
|
|
} else {
|
|
$file = addslashes($file);
|
|
echo "alert('Unable to find javascript file: $file');";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the location of the client js
|
|
* To override the default pear datadir location set $this->clientJsLocation
|
|
*
|
|
* @return string
|
|
*/
|
|
function clientJsLocation()
|
|
{
|
|
if (!$this->clientJsLocation) {
|
|
$path = '/usr/share/php/data'.DIRECTORY_SEPARATOR.'HTML_AJAX'.DIRECTORY_SEPARATOR.'js'.DIRECTORY_SEPARATOR;
|
|
if(strpos($path, '@'.'data-dir@') === 0)
|
|
{
|
|
$path = realpath(dirname(__FILE__).DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR.'js').DIRECTORY_SEPARATOR;
|
|
}
|
|
return $path;
|
|
} else {
|
|
return $this->clientJsLocation;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set the location of the client js
|
|
*
|
|
* @access public
|
|
* @param string $location Location
|
|
* @return void
|
|
*/
|
|
function setClientJsLocation($location)
|
|
{
|
|
$this->clientJsLocation = $location;
|
|
}
|
|
|
|
/**
|
|
* Set the path to a Javascript libraries
|
|
*
|
|
* @access public
|
|
* @param string $library Library name
|
|
* @param string $path Path
|
|
* @return void
|
|
*/
|
|
function setJavascriptLibraryPath($library, $path)
|
|
{
|
|
$this->javascriptLibraryPaths[$library] = $path;
|
|
}
|
|
|
|
/**
|
|
* Set the path to more than one Javascript libraries at once
|
|
*
|
|
* @access public
|
|
* @param array $paths Paths
|
|
* @return void
|
|
*/
|
|
function setJavascriptLibraryPaths($paths)
|
|
{
|
|
if (is_array($paths)) {
|
|
$this->javascriptLibraryPaths = array_merge($this->javascriptLibraryPaths, $paths);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Load options from _GET
|
|
*
|
|
* @access private
|
|
*/
|
|
function _loadOptions()
|
|
{
|
|
$this->options = array('client'=>array(),'stub'=>array());
|
|
if (isset($_GET['client'])) {
|
|
$clients = explode(',',$this->ajax->_getVar('client'));
|
|
$client = array();
|
|
foreach($clients as $val) {
|
|
$cleanVal = $this->_cleanIdentifier($val);
|
|
if (!empty($cleanVal)) {
|
|
$client[] = strtolower($cleanVal);
|
|
}
|
|
}
|
|
|
|
if (count($client) > 0) {
|
|
$this->options['client'] = $client;
|
|
}
|
|
}
|
|
if (isset($_GET['stub'])) {
|
|
$stubs = explode(',',$this->ajax->_getVar('stub'));
|
|
$stub = array();
|
|
foreach($stubs as $val) {
|
|
$cleanVal = $this->_cleanIdentifier($val);
|
|
if (!empty($cleanVal)) {
|
|
$stub[] = strtolower($cleanVal);
|
|
}
|
|
}
|
|
|
|
if (count($stub) > 0) {
|
|
$this->options['stub'] = $stub;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Clean an identifier like a class name making it safe to use
|
|
*
|
|
* @param string $input
|
|
* @return string
|
|
* @access private
|
|
*/
|
|
function _cleanIdentifier($input) {
|
|
return trim(preg_replace('/[^A-Za-z_0-9]/','',$input));
|
|
}
|
|
|
|
/**
|
|
* Run every init method on the class
|
|
*
|
|
* @access private
|
|
*/
|
|
function _initAll()
|
|
{
|
|
if ($this->initMethods) {
|
|
foreach($this->_initLookup as $class => $method) {
|
|
$this->_init($class);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Init one class
|
|
*
|
|
* @param string $className
|
|
* @access private
|
|
*/
|
|
function _init($className)
|
|
{
|
|
$className = strtolower($className);
|
|
if ($this->initMethods) {
|
|
if (isset($this->_initLookup[$className])) {
|
|
$method =& $this->_initLookup[$className];
|
|
if (is_array($method)) {
|
|
call_user_func($method);
|
|
}
|
|
else {
|
|
$this->$method();
|
|
}
|
|
} else {
|
|
trigger_error("Could find an init method for class: " . $className);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generate a hash from a list of files
|
|
*
|
|
* @param array $files file list
|
|
* @return string a hash that can be used as an etag
|
|
* @access private
|
|
*/
|
|
function _cacheRuleFile($files) {
|
|
$signature = "";
|
|
foreach($files as $file) {
|
|
if (file_exists($file)) {
|
|
$signature .= $file.filemtime($file);
|
|
}
|
|
}
|
|
return md5($signature);
|
|
}
|
|
|
|
/**
|
|
* Generate a hash from the api of registered classes
|
|
*
|
|
* @param array $classes class list
|
|
* @return string a hash that can be used as an etag
|
|
* @access private
|
|
*/
|
|
function _cacheRuleApi($classes) {
|
|
$signature = "";
|
|
foreach($classes as $class) {
|
|
if (isset($this->ajax->_exportedInstances[$class])) {
|
|
$signature .= $class.implode(',',$this->ajax->_exportedInstances[$class]['exportedMethods']);
|
|
}
|
|
}
|
|
return md5($signature);
|
|
}
|
|
|
|
/**
|
|
* Generate a hash from the raw content
|
|
*
|
|
* @param array $content
|
|
* @return string a hash that can be used as an etag
|
|
* @access private
|
|
*/
|
|
function _cacheRuleContent($content) {
|
|
return md5($content);
|
|
}
|
|
|
|
/**
|
|
* Send cache control headers
|
|
* @access private
|
|
*/
|
|
function _sendCacheHeaders($etag,$notModified) {
|
|
header('Cache-Control: must-revalidate');
|
|
header('ETag: '.$etag);
|
|
if ($notModified) {
|
|
header('HTTP/1.0 304 Not Modified',false,304);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Compare eTags
|
|
*
|
|
* @param string $serverETag server eTag
|
|
* @return boolean
|
|
* @access private
|
|
*/
|
|
function _compareEtags($serverETag) {
|
|
if (isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
|
|
if (strcmp($this->ajax->_getServer('HTTP_IF_NONE_MATCH'),$serverETag) == 0) {
|
|
$this->_sendCacheHeaders($serverETag,true);
|
|
return true;
|
|
}
|
|
}
|
|
$this->_sendCacheHeaders($serverETag,false);
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Call a cache rule and return its retusn
|
|
*
|
|
* @param string $rule Stub|Client
|
|
* @param mixed $payload
|
|
* @return boolean
|
|
* @access private
|
|
* @todo decide if error checking is needed
|
|
*/
|
|
function _callCacheRule($rule,$payload) {
|
|
$method = '_cacheRule'.$this->cacheOptions[$rule.'CacheRule'];
|
|
return call_user_func(array(&$this,$method),$payload);
|
|
}
|
|
}
|
|
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
|
?>
|