ILIAS  Release_4_0_x_branch Revision 61816
 All Data Structures Namespaces Files Functions Variables Groups Pages
CachedServer.php
Go to the documentation of this file.
1 <?php
2 
3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
4 
5 // LICENSE AGREEMENT. If folded, press za here to unfold and read license {{{
6 
40 // }}}
41 
42 // dependencies {{{
43 require_once('Cache/Lite.php');
44 // }}}
45 
57 
58  // {{{ properties
59 
65  private $_cacheByDefault = true;
66 
72  private $_cacheObject = null;
73 
79  private $_serverObject = null;
80 
86  private $_defaultCacheGroup = 'xml_rpc2_server';
87 
95  private $_callHandler = null;
96 
102  private $_callTarget = '';
103 
109  private $_prefix = '';
110 
116  private $_options = array();
117 
123  private $_cacheDebug = false;
124 
130  private $_encoding = 'iso-8859-1';
131 
132  // }}}
133  // {{{ setCacheOptions()
134 
144  private function _setCacheOptions($array)
145  {
146  if (isset($array['defaultCacheGroup'])) {
147  $this->_defaultCacheGroup = $array['defaultCacheGroup'];
148  unset($array['defaultCacheGroup']); // this is a "non standard" option for Cache_Lite
149  }
150  if (isset($array['cacheByDefault'])) {
151  $this->_cacheByDefault = $array['cacheByDefault'];
152  unset($array['CacheByDefault']); // this is a "non standard" option for Cache_Lite
153  }
154  $array['automaticSerialization'] = false; // datas are already serialized in this class
155  if (!isset($array['lifetime'])) {
156  $array['lifetime'] = 3600; // we need a default lifetime
157  }
158  $this->_cacheOptions = $array;
159  $this->_cacheObject = new Cache_Lite($this->_cacheOptions);
160  }
161 
162  // }}}
163  // {{{ constructor
164 
170  protected function __construct($callTarget, $options = array())
171  {
172  if (isset($options['cacheOptions'])) {
173  $cacheOptions = $options['cacheOptions'];
174  $this->_setCacheOptions($cacheOptions);
175  unset($options['cacheOptions']);
176  }
177  if (isset($options['cacheDebug'])) {
178  $this->_cacheDebug = $options['cacheDebug'];
179  unset($options['cacheDebug']); // 'cacheDebug' is not a standard option for XML/RPC2/Server
180  }
181  $this->_options = $options;
182  $this->_callTarget = $callTarget;
183  if (isset($this->_options['encoding'])) {
184  $this->_encoding = $this->_options['encoding'];
185  }
186  if (isset($this->_options['prefix'])) {
187  $this->_prefix = $this->_options['prefix'];
188  }
189  }
190 
191  // }}}
192  // {{{ create()
193 
203  public static function create($callTarget, $options = array())
204  {
205  return new XML_RPC2_CachedServer($callTarget, $options);
206  }
207 
208  // }}}
209  // {{{ handleCall()
210 
215  public function handleCall()
216  {
217  $response = $this->getResponse();
218  $encoding = 'iso-8859-1';
219  if (isset($this->_options['encoding'])) {
220  $encoding = $this->_options['encoding'];
221  }
222  header('Content-type: text/xml; charset=' . $encoding);
223  header('Content-length: ' . $this->getContentLength($response));
224  print $response;
225  }
226 
232  public function getResponse()
233  {
234  if (isset($GLOBALS['HTTP_RAW_POST_DATA'])) {
235  $methodName = $this->_parseMethodName($GLOBALS['HTTP_RAW_POST_DATA']);
236  } else {
237  $methodName = null;
238  }
239  $weCache = $this->_cacheByDefault;
240  $lifetime = $this->_cacheOptions['lifetime'];
241  if ($this->_cacheDebug) {
242  if ($weCache) {
243  print "CACHE DEBUG : default values => weCache=true, lifetime=$lifetime\n";
244  } else {
245  print "CACHE DEBUG : default values => weCache=false, lifetime=$lifetime\n";
246  }
247  }
248  if ($methodName) {
249  // work on reflection API to search for @xmlrpc.caching tags into PHPDOC comments
250  list($weCache, $lifetime) = $this->_reflectionWork($methodName);
251  if ($this->_cacheDebug) {
252  if ($weCache) {
253  print "CACHE DEBUG : phpdoc comments => weCache=true, lifetime=$lifetime\n";
254  } else {
255  print "CACHE DEBUG : phpdoc comments => weCache=false, lifetime=$lifetime\n";
256  }
257  }
258  }
259  if (($weCache) and ($lifetime!=-1)) {
260  if (isset($GLOBALS['HTTP_RAW_POST_DATA'])) {
261  $cacheId = $this->_makeCacheId($GLOBALS['HTTP_RAW_POST_DATA']);
262  } else {
263  $cacheId = 'norawpostdata';
264  }
265  $this->_cacheObject = new Cache_Lite($this->_cacheOptions);
266  $this->_cacheObject->setLifetime($lifetime);
267  if ($data = $this->_cacheObject->get($cacheId, $this->_defaultCacheGroup)) {
268  // cache id hit
269  if ($this->_cacheDebug) {
270  print "CACHE DEBUG : cache is hit !\n";
271  }
272  } else {
273  // cache is not hit
274  if ($this->_cacheDebug) {
275  print "CACHE DEBUG : cache is not hit !\n";
276  }
277  $data = $this->_workWithoutCache();
278  $this->_cacheObject->save($data);
279  }
280  } else {
281  if ($this->_cacheDebug) {
282  print "CACHE DEBUG : we don't cache !\n";
283  }
284  $data = $this->_workWithoutCache();
285  }
286  return $data;
287  }
288 
289  // }}}
290  // {{{ _reflectionWork()
291 
298  private function _reflectionWork($methodName) {
299  $weCache = $this->_cacheByDefault;
300  $lifetime = $this->_cacheOptions['lifetime'];
301  if (is_string($this->_callTarget)) {
302  $className = strtolower($this->_callTarget);
303  } else {
304  $className = get_class($this->_callTarget);
305  }
306  $class = new ReflectionClass($className);
307  $method = $class->getMethod($methodName);
308  $docs = explode("\n", $method->getDocComment());
309  foreach ($docs as $i => $doc) {
310  $doc = trim($doc, " \r\t/*");
311  $res = ereg('@xmlrpc.caching ([+-]{0,1}[a-zA-Z0-9]*)', $doc, $results); // TODO : better/faster regexp ?
312  if ($res>0) {
313  $value = $results[1];
314  if (($value=='yes') or ($value=='true') or ($value=='on')) {
315  $weCache = true;
316  } else if (($value=='no') or ($value=='false') or ($value=='off')) {
317  $weCache = false;
318  } else {
319  $lifetime = (int) $value;
320  if ($lifetime==-1) {
321  $weCache = false;
322  } else {
323  $weCache = true;
324  }
325  }
326  }
327  }
328  return array($weCache, $lifetime);
329  }
330 
331  // }}}
332  // {{{ _parseMethodName()
333 
342  private function _parseMethodName($request)
343  {
344  // TODO : change for "simplexml"
345  $res = ereg('<methodName>' . $this->_prefix . '([a-zA-Z0-9\.,\/]*)</methodName>', $request, $results);
346  if ($res>0) {
347  return $results[1];
348  }
349  return false;
350  }
351 
352  // }}}
353  // {{{ _workWithoutCache()
354 
360  private function _workWithoutCache()
361  {
362  require_once('XML/RPC2/Server.php');
363  $this->_serverObject = XML_RPC2_Server::create($this->_callTarget, $this->_options);
364  return $this->_serverObject->getResponse();
365  }
366 
367  // }}}
368  // {{{ _makeCacheId()
369 
376  private function _makeCacheId($raw_request)
377  {
378  return md5($raw_request . serialize($this->_options));
379  }
380 
381  // }}}
382  // {{{ clean()
383 
387  public function clean()
388  {
389  $this->_cacheObject->clean($this->_defaultCacheGroup, 'ingroup');
390  }
391 
392  // }}}
393  // {{{ getContentLength()
394 
402  protected function getContentLength($content)
403  {
404  if (extension_loaded('mbstring') && (ini_get('mbstring.func_overload') & 2) == 2) {
405  $length = mb_strlen($content, '8bit');
406  } else {
407  $length = strlen((binary)$content);
408  }
409 
410  return $length;
411  }
412 
413  // }}}
414 }
415 
416 ?>