OSDN Git Service

Merge branch 'skinnable-master' of ssh://shizuki@git.sourceforge.jp/gitroot/nucleus...
[nucleus-jp/nucleus-next.git] / nucleus / libs / MANAGER.php
1 <?php\r
2 /*\r
3  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)\r
4  * Copyright (C) 2002-2009 The Nucleus Group\r
5  *\r
6  * This program is free software; you can redistribute it and/or\r
7  * modify it under the terms of the GNU General Public License\r
8  * as published by the Free Software Foundation; either version 2\r
9  * of the License, or (at your option) any later version.\r
10  * (see nucleus/documentation/index.html#license for more info)\r
11  */\r
12 /**\r
13  * This class makes sure each item/weblog/comment object gets requested from\r
14  * the database only once, by keeping them in a cache. The class also acts as\r
15  * a dynamic classloader, loading classes _only_ when they are first needed,\r
16  * hoping to diminish execution time\r
17  *\r
18  * The class is a singleton, meaning that there will be only one object of it\r
19  * active at all times. The object can be requested using Manager::instance()\r
20  *\r
21  * @license http://nucleuscms.org/license.txt GNU General Public License\r
22  * @copyright Copyright (C) 2002-2009 The Nucleus Group\r
23  * @version $Id: MANAGER.php 1731 2012-04-08 15:10:35Z sakamocchi $\r
24  */\r
25 class Manager\r
26 {\r
27         /**\r
28          * Cached ITEM, BLOG, PLUGIN, KARMA and MEMBER objects. When these objects are requested\r
29          * through the global $manager object (getItem, getBlog, ...), only the first call\r
30          * will create an object. Subsequent calls will return the same object.\r
31          *\r
32          * The $items, $blogs, ... arrays map an id to an object (for plugins, the name is used\r
33          * rather than an ID)\r
34          */\r
35         private $items;\r
36         private $blogs;\r
37         private $plugins;\r
38         private $karma;\r
39         private $templates;\r
40         private $members;\r
41         \r
42         /**\r
43          * cachedInfo to avoid repeated SQL queries (see pidInstalled/pluginInstalled/getPidFromName)\r
44          * e.g. which plugins exists?\r
45          *\r
46          * $cachedInfo['installedPlugins'] = array($pid -> $name)\r
47          */\r
48         private $cachedInfo;\r
49         \r
50         /**\r
51          * The plugin subscriptionlist\r
52          *\r
53          * The subcription array has the following structure\r
54          *              $subscriptions[$EventName] = array containing names of plugin classes to be\r
55          *                                                                       notified when that event happens\r
56          * \r
57          * NOTE: this is referred by Comments::addComment() for spamcheck API\r
58          * TODO: we should add new methods to get this\r
59          */\r
60         public $subscriptions;\r
61         \r
62         /**\r
63          * Ticket functions. These are uses by the admin area to make it impossible to simulate certain GET/POST\r
64          * requests. tickets are user specific\r
65          */\r
66         private $currentRequestTicket = '';\r
67         \r
68         /**\r
69          * Returns the only instance of this class. Creates the instance if it\r
70          * does not yet exists. Users should use this function as\r
71          * $manager =& Manager::instance(); to get a reference to the object\r
72          * instead of a copy\r
73          */\r
74         public function &instance()\r
75         {\r
76                 static $instance = array();\r
77                 if ( empty($instance) )\r
78                 {\r
79                         $instance[0] = new Manager();\r
80                 }\r
81                 return $instance[0];\r
82         }\r
83         \r
84         /**\r
85          * The constructor of this class initializes the object caches\r
86          */\r
87         public function __construct()\r
88         {\r
89                 $this->items = array();\r
90                 $this->blogs = array();\r
91                 $this->plugins = array();\r
92                 $this->karma = array();\r
93                 $this->parserPrefs = array();\r
94                 $this->cachedInfo = array();\r
95                 return;\r
96         }\r
97         \r
98         /**\r
99          * Returns the requested item object. If it is not in the cache, it will\r
100          * first be loaded and then placed in the cache.\r
101          * Intended use: $item =& $manager->getItem(1234, 0, 0)\r
102          */\r
103         public function &getItem($itemid, $allowdraft, $allowfuture)\r
104         {\r
105                 /* confirm to cached */\r
106                 if ( !array_key_exists($itemid, $this->items) )\r
107                 {\r
108                         $this->loadClass('ITEM');\r
109                         $item = Item::getitem($itemid, $allowdraft, $allowfuture);\r
110                         $this->items[$itemid] = $item;\r
111                 }\r
112                 \r
113                 $item =& $this->items[$itemid];\r
114                 if ( !$allowdraft && ($item['draft']) )\r
115                 {\r
116                         return 0;\r
117                 }\r
118                 \r
119                 $blog =& $this->getBlog($item['blogid']);\r
120                 if ( !$allowfuture && ($item['timestamp'] > $blog->getCorrectTime()) )\r
121                 {\r
122                         return 0;\r
123                 }\r
124                 \r
125                 return $item;\r
126         }\r
127         \r
128         /**\r
129          * Loads a class if it has not yet been loaded\r
130          */\r
131         public function loadClass($name)\r
132         {\r
133                 $this->_loadClass($name, $name . '.php');\r
134                 return;\r
135         }\r
136         \r
137         /**\r
138          * Checks if an item exists\r
139          */\r
140         public function existsItem($id,$future,$draft)\r
141         {\r
142                 $this->_loadClass('ITEM','ITEM.php');\r
143                 return Item::exists($id,$future,$draft);\r
144         }\r
145         \r
146         /**\r
147          * Checks if a category exists\r
148          */\r
149         public function existsCategory($id)\r
150         {\r
151                 return (DB::getValue('SELECT COUNT(*) as result FROM '.sql_table('category').' WHERE catid='.intval($id)) > 0);\r
152         }\r
153         \r
154         /**\r
155          * Returns the blog object for a given blogid\r
156          */\r
157         public function &getBlog($blogid)\r
158         {\r
159                 $blog =& $this->blogs[$blogid];\r
160                 \r
161                 if ( !$blog )\r
162                 {\r
163                         // load class if needed\r
164                         $this->_loadClass('BLOG','BLOG.php');\r
165                         // load blog object\r
166                         $blog = new Blog($blogid);\r
167                         $this->blogs[$blogid] =& $blog;\r
168                 }\r
169                 return $blog;\r
170         }\r
171         \r
172         /**\r
173          * Checks if a blog exists\r
174          */\r
175         public function existsBlog($name)\r
176         {\r
177                 $this->_loadClass('BLOG','BLOG.php');\r
178                 return Blog::exists($name);\r
179         }\r
180         \r
181         /**\r
182          * Checks if a blog id exists\r
183          */\r
184         public function existsBlogID($id)\r
185         {\r
186                 $this->_loadClass('BLOG','BLOG.php');\r
187                 return Blog::existsID($id);\r
188         }\r
189         \r
190         /**\r
191          * Returns a previously read template\r
192          */\r
193         public function &getTemplate($templateName)\r
194         {\r
195                 $template =& $this->templates[$templateName];\r
196                 \r
197                 if ( !$template )\r
198                 {\r
199                         $template = Template::read($templateName);\r
200                         $this->templates[$templateName] =& $template;\r
201                 }\r
202                 return $template;\r
203         }\r
204         \r
205         /**\r
206          * Returns a KARMA object (karma votes)\r
207          */\r
208         public function &getKarma($itemid)\r
209         {\r
210                 $karma =& $this->karma[$itemid];\r
211                 \r
212                 if ( !$karma )\r
213                 {\r
214                         // load class if needed\r
215                         $this->_loadClass('KARMA','KARMA.php');\r
216                         // create KARMA object\r
217                         $karma = new Karma($itemid);\r
218                         $this->karma[$itemid] =& $karma;\r
219                 }\r
220                 return $karma;\r
221         }\r
222         \r
223         /**\r
224          * Returns a MEMBER object\r
225          */\r
226         public function &getMember($memberid)\r
227         {\r
228                 $mem =& $this->members[$memberid];\r
229                 \r
230                 if ( !$mem )\r
231                 {\r
232                         // load class if needed\r
233                         $this->_loadClass('MEMBER','MEMBER.php');\r
234                         // create MEMBER object\r
235                         $mem =& Member::createFromID($memberid);\r
236                         $this->members[$memberid] =& $mem;\r
237                 }\r
238                 return $mem;\r
239         }\r
240         \r
241         /**\r
242          * Set the global parser preferences\r
243          */\r
244         public function setParserProperty($name, $value)\r
245         {\r
246                 $this->parserPrefs[$name] = $value;\r
247                 return;\r
248         }\r
249         \r
250         /**\r
251          * Get the global parser preferences\r
252          */\r
253         public function getParserProperty($name)\r
254         {\r
255                 return $this->parserPrefs[$name];\r
256         }\r
257         \r
258         /**\r
259          * A helper function to load a class\r
260          * \r
261          *      private\r
262          */\r
263         private function _loadClass($name, $filename)\r
264         {\r
265                 if ( !class_exists($name) )\r
266                 {\r
267                                 global $DIR_LIBS;\r
268                                 include($DIR_LIBS . $filename);\r
269                 }\r
270                 return;\r
271         }\r
272         \r
273         /**\r
274          * Manager::_loadPlugin()\r
275          * loading a certain plugin\r
276          * \r
277          * @param       string $name plugin name\r
278          * @return      void\r
279          */\r
280         private function _loadPlugin($name)\r
281         {\r
282                 global $DIR_PLUGINS, $MYSQL_HANDLER, $MYSQL_PREFIX;\r
283                 \r
284                 if ( class_exists($name) )\r
285                 {\r
286                         return;\r
287                 }\r
288                 \r
289                 $fileName = "{$DIR_PLUGINS}{$name}.php";\r
290                 \r
291                 if ( !file_exists($fileName) )\r
292                 {\r
293                         if ( !defined('_MANAGER_PLUGINFILE_NOTFOUND') )\r
294                         {\r
295                                 define('_MANAGER_PLUGINFILE_NOTFOUND', 'Plugin %s was not loaded (File not found)');\r
296                         }\r
297                         ActionLog::add(WARNING, sprintf(_MANAGER_PLUGINFILE_NOTFOUND, $name)); \r
298                         return 0;\r
299                 }\r
300                 \r
301                 // load plugin\r
302                 include($fileName);\r
303                 \r
304                 // check if class exists (avoid errors in eval'd code)\r
305                 if ( !class_exists($name) )\r
306                 {\r
307                         ActionLog::add(WARNING, sprintf(_MANAGER_PLUGINFILE_NOCLASS, $name));\r
308                         return 0;\r
309                 }\r
310                 \r
311                 // add to plugin array\r
312                 $this->plugins[$name] = new $name();\r
313                 \r
314                 // get plugid\r
315                 $this->plugins[$name]->setID($this->getPidFromName($name));\r
316                 \r
317                 // unload plugin if a prefix is used and the plugin cannot handle this\r
318                 if ( ($MYSQL_PREFIX != '')\r
319                   && !$this->plugins[$name]->supportsFeature('SqlTablePrefix') )\r
320                 {\r
321                         unset($this->plugins[$name]);\r
322                         ActionLog::add(WARNING, sprintf(_MANAGER_PLUGINTABLEPREFIX_NOTSUPPORT, $name));\r
323                         return 0;\r
324                 }\r
325                 \r
326                 // unload plugin if using non-mysql handler and plugin does not support it \r
327                 if ( (!in_array('mysql',$MYSQL_HANDLER))\r
328                   && !$this->plugins[$name]->supportsFeature('SqlApi') )\r
329                 {\r
330                         unset($this->plugins[$name]);\r
331                         ActionLog::add(WARNING, sprintf(_MANAGER_PLUGINSQLAPI_NOTSUPPORT, $name));\r
332                         return 0;\r
333                 }\r
334                 \r
335                 // call init method\r
336                 $this->plugins[$name]->init();\r
337                 \r
338                 return;\r
339         }\r
340 \r
341         /**\r
342          * Manager:getPlugin()\r
343          * Returns a PLUGIN object\r
344          * \r
345          * @param       string  $name   name of plugin\r
346          * @return      object  plugin object\r
347          */\r
348         public function &getPlugin($name)\r
349         {\r
350                 // retrieve the name of the plugin in the right capitalisation\r
351                 $name = $this->getUpperCaseName ($name);\r
352                 \r
353                 // get the plugin       \r
354                 $plugin =& $this->plugins[$name]; \r
355                 \r
356                 if ( !$plugin )\r
357                 {\r
358                         // load class if needed\r
359                         $this->_loadPlugin($name);\r
360                         $plugin =& $this->plugins[$name];\r
361                 }\r
362                 return $plugin;\r
363         }\r
364         \r
365         /**\r
366          * Manager::pluginLoaded()\r
367          * Checks if the given plugin IS loaded or not\r
368          * \r
369          * @param       string  $name   name of plugin\r
370          * @return      object  plugin object\r
371          */\r
372         public function &pluginLoaded($name)\r
373         {\r
374                 $plugin =& $this->plugins[$name];\r
375                 return $plugin;\r
376         }\r
377         \r
378         /**\r
379          * Manager::pidLoaded()\r
380          * \r
381          * @param       integer $pid    id for plugin\r
382          * @return      object  plugin object\r
383          */\r
384         public function &pidLoaded($pid)\r
385         {\r
386                 $plugin=false;\r
387                 reset($this->plugins);\r
388                 while ( list($name) = each($this->plugins) )\r
389                 {\r
390                         if ( $pid!=$this->plugins[$name]->getId() )\r
391                         {\r
392                                 continue;\r
393                         }\r
394                         $plugin= & $this->plugins[$name];\r
395                         break;\r
396                 }\r
397                 return $plugin;\r
398         }\r
399         \r
400         /**\r
401          * Manager::pluginInstalled()\r
402          * checks if the given plugin IS installed or not\r
403          * \r
404          * @param       string  $name   name of plugin\r
405          * @return      boolean exists or not\r
406          */\r
407         public function pluginInstalled($name)\r
408         {\r
409                 $this->_initCacheInfo('installedPlugins');\r
410                 return ($this->getPidFromName($name) != -1);\r
411         }\r
412 \r
413         /**\r
414          * Manager::pidInstalled()\r
415          * checks if the given plugin IS installed or not\r
416          * \r
417          * @param       integer $pid    id of plugin\r
418          * @return      boolean exists or not\r
419          */\r
420         public function pidInstalled($pid)\r
421         {\r
422                 $this->_initCacheInfo('installedPlugins');\r
423                 return ($this->cachedInfo['installedPlugins'][$pid] != '');\r
424         }\r
425         \r
426         /**\r
427          * Manager::getPidFromName()\r
428          * \r
429          * @param       string  $name   name of plugin\r
430          * @return      mixed   id for plugin or -1 if not exists\r
431          */\r
432         public function getPidFromName($name)\r
433         {\r
434                 $this->_initCacheInfo('installedPlugins');\r
435                 foreach ( $this->cachedInfo['installedPlugins'] as $pid => $pfile )\r
436                 {\r
437                         if (strtolower($pfile) == strtolower($name))\r
438                         {\r
439                                 return $pid;\r
440                         }\r
441                 }\r
442                 return -1;\r
443         }\r
444         \r
445         /**\r
446          * Manager::getPluginNameFromPid()\r
447          * \r
448          * @param       string  $pid    ID for plugin\r
449          * @return      string  name of plugin\r
450          */\r
451         public function getPluginNameFromPid($pid)\r
452         {\r
453                 if ( !array_key_exists($pid, $this->cachedInfo['installedPlugins']) )\r
454                 {\r
455                         $query = 'SELECT pfile FROM %s WHERE pid=%d;';\r
456                         $query = sprintf($query, sql_table('plugin'), (integer) $pid);\r
457                         return DB::getValue($query);\r
458                 }\r
459                 return $this->cachedInfo['installedPlugins'][$pid];\r
460         }\r
461         \r
462         /**\r
463          * Manager::getUpperCaseName()\r
464          * Retrieve the name of a plugin in the right capitalisation\r
465          * \r
466          * @param       string  $name   name of plugin\r
467          * @return      string  name according to UpperCamelCase\r
468          */\r
469         public function getUpperCaseName ($name)\r
470         {\r
471                 $this->_initCacheInfo('installedPlugins');\r
472                 foreach ( $this->cachedInfo['installedPlugins'] as $pid => $pfile )\r
473                 {\r
474                         if ( strtolower($pfile) == strtolower($name) )\r
475                         {\r
476                                 return $pfile;\r
477                         }\r
478                 }\r
479                 return -1;\r
480         }\r
481         \r
482         /**\r
483          * Manager::clearCachedInfo()\r
484          * \r
485          * @param       string  $what\r
486          * @return      void\r
487          */\r
488         public function clearCachedInfo($what)\r
489         {\r
490                 unset($this->cachedInfo[$what]);\r
491                 return;\r
492         }\r
493         \r
494         /**\r
495          * Manager::_initCacheInfo()\r
496          * Loads some info on the first call only\r
497          * \r
498          * @param       string  $what   'installedPlugins'\r
499          * @return      void\r
500          */\r
501         private function _initCacheInfo($what)\r
502         {\r
503                 if ( array_key_exists($what, $this->cachedInfo)\r
504                   && is_array($this->cachedInfo[$what]) )\r
505                 {\r
506                         return;\r
507                 }\r
508                 \r
509                 switch ($what)\r
510                 {\r
511                         // 'installedPlugins' = array ($pid => $name)\r
512                         case 'installedPlugins':\r
513                                 $this->cachedInfo['installedPlugins'] = array();\r
514                                 $res = DB::getResult('SELECT pid, pfile FROM ' . sql_table('plugin'));\r
515                                 foreach ( $res as $row )\r
516                                 {\r
517                                         $this->cachedInfo['installedPlugins'][$row['pid']] = $row['pfile'];\r
518                                 }\r
519                                 break;\r
520                 }\r
521                 return;\r
522         }\r
523         \r
524         /**\r
525          * Manager::notify()\r
526          * A function to notify plugins that something has happened. Only the plugins\r
527          * that are subscribed to the event will get notified.\r
528          * Upon the first call, the list of subscriptions will be fetched from the\r
529          * database. The plugins itsself will only get loaded when they are first needed\r
530          *\r
531          * @param       string  $eventName      Name of the event (method to be called on plugins)\r
532          * @param       string  $data           Can contain any type of data,\r
533          *                                                              depending on the event type. Usually this is an itemid, blogid, ...\r
534          *                                                              but it can also be an array containing multiple values\r
535          * @return      void\r
536          */\r
537         public function notify($eventName, $data)\r
538         {\r
539                 // load subscription list if needed\r
540                 if ( !is_array($this->subscriptions) )\r
541                 {\r
542                         $this->_loadSubscriptions();\r
543                 }\r
544                 \r
545                 // get listening objects\r
546                 $listeners = false;\r
547                 if ( array_key_exists($eventName, $this->subscriptions)\r
548                   && !empty($this->subscriptions[$eventName]) )\r
549                 {\r
550                         $listeners = $this->subscriptions[$eventName];\r
551                 }\r
552                 \r
553                 // notify all of them\r
554                 if ( is_array($listeners) )\r
555                 {\r
556                         foreach( $listeners as $listener )\r
557                         {\r
558                                 // load class if needed\r
559                                 $this->_loadPlugin($listener);\r
560                                 \r
561                                 // do notify (if method exists)\r
562                                 if ( array_key_exists($listener, $this->plugins)\r
563                                   && !empty($this->plugins[$listener])\r
564                                   && method_exists($this->plugins[$listener], 'event_' . $eventName) )\r
565                                 {\r
566                                         call_user_func(array(&$this->plugins[$listener],'event_' . $eventName), $data);\r
567                                 }\r
568                         }\r
569                 }\r
570                 return;\r
571         }\r
572         \r
573         /**\r
574          * Manager::_loadSubscriptions()\r
575          * Loads plugin subscriptions\r
576          * \r
577          * @param       void\r
578          * @return      void\r
579          */\r
580         private function _loadSubscriptions()\r
581         {\r
582                 // initialize as array\r
583                 $this->subscriptions = array();\r
584                 \r
585                 $query = "SELECT p.pfile as pfile, e.event as event"\r
586                        . " FROM %s as e, %s as p"\r
587                        . " WHERE e.pid=p.pid ORDER BY p.porder ASC";\r
588                 $query = sprintf($query, sql_table('plugin_event'), sql_table('plugin'));\r
589                 $res = DB::getResult($query);\r
590                 \r
591                 foreach ( $res as $row )\r
592                 {\r
593                         $pluginName = $row['pfile'];\r
594                         $eventName = $row['event'];\r
595                         $this->subscriptions[$eventName][] = $pluginName;\r
596                 }\r
597                 return;\r
598         }\r
599         \r
600         /**\r
601          * Manager::getNumberOfSubscribers()\r
602          * \r
603          * @param       string  $event  name of events\r
604          * @return      integer number of event subscriber\r
605          */\r
606         public function getNumberOfSubscribers($event)\r
607         {\r
608                 $query = 'SELECT COUNT(*) as count FROM %s WHERE event=%s;';\r
609                 $query = sprintf($query, sql_table('plugin_event'), DB::quoteValue($event));\r
610                 return (integer) DB::getValue($query);\r
611         }\r
612         \r
613         /**\r
614          * Manager::addTicketToUrl()\r
615          * GET requests: Adds ticket to URL (URL should NOT be html-encoded!, ticket is added at the end)\r
616          * \r
617          * @param       string  url     string for URI\r
618          * @return      void\r
619          */\r
620         public function addTicketToUrl($url)\r
621         {\r
622                 $ticketCode = 'ticket=' . $this->_generateTicket();\r
623                 if ( i18n::strpos($url, '?') === FALSE )\r
624                 {\r
625                         $ticketCode = "{$url}?{$ticketCode}";\r
626                 }\r
627                 else\r
628                 {\r
629                         $ticketCode = "{$url}&{$ticketCode}";\r
630                 }\r
631                 return $ticketCode;\r
632         }\r
633         \r
634         /**\r
635          * Manager::addTicketHidden()\r
636          * POST requests: Adds ticket as hidden formvar\r
637          * \r
638          * @param       void\r
639          * @return      void\r
640          */\r
641         public function addTicketHidden()\r
642         {\r
643                 $ticket = $this->_generateTicket();\r
644                 echo '<input type="hidden" name="ticket" value="', Entity::hsc($ticket), '" />';\r
645                 return;\r
646         }\r
647         \r
648         /**\r
649          * Manager::getNewTicket()\r
650          * Get a new ticket\r
651          * (xmlHTTPRequest AutoSaveDraft uses this to refresh the ticket)\r
652          * \r
653          * @param       void\r
654          * @return      string  string of ticket\r
655          */\r
656         public function getNewTicket()\r
657         {\r
658                 $this->currentRequestTicket = '';\r
659                 return $this->_generateTicket();\r
660         }\r
661         \r
662         /**\r
663          * Manager::checkTicket()\r
664          * Checks the ticket that was passed along with the current request\r
665          * \r
666          * @param       void\r
667          * @return      boolean correct or not\r
668          */\r
669         public function checkTicket()\r
670         {\r
671                 global $member;\r
672                 \r
673                 // get ticket from request\r
674                 $ticket = requestVar('ticket');\r
675                 \r
676                 // no ticket -> don't allow\r
677                 if ( $ticket == '' )\r
678                 {\r
679                         return FALSE;\r
680                 }\r
681                 \r
682                 // remove expired tickets first\r
683                 $this->_cleanUpExpiredTickets();\r
684                 \r
685                 // get member id\r
686                 if (!$member->isLoggedIn())\r
687                 {\r
688                         $memberId = -1;\r
689                 }\r
690                 else\r
691                 {\r
692                         $memberId = $member->getID();\r
693                 }\r
694                 \r
695                 // check if ticket is a valid one\r
696                 $query = sprintf('SELECT COUNT(*) as result FROM %s WHERE member=%d and ticket=%s',\r
697                         sql_table('tickets'),\r
698                         intval($memberId),\r
699                         DB::quoteValue($ticket)\r
700                 );\r
701                 \r
702                 /*\r
703                  * NOTE:\r
704                  * [in the original implementation, the checked ticket was deleted. This would lead to invalid\r
705                  * tickets when using the browsers back button and clicking another link/form\r
706                  * leaving the keys in the database is not a real problem, since they're member-specific and\r
707                  * only valid for a period of one hour]\r
708                  */\r
709                 if ( DB::getValue($query) != 1 )\r
710                 {\r
711                         return FALSE;\r
712                 }\r
713                 \r
714                 return TRUE;\r
715         }\r
716 \r
717         /**\r
718          * Manager::_cleanUpExpiredTickets()\r
719          * Removes the expired tickets\r
720          * \r
721          * @param       void\r
722          * @return      void\r
723          */\r
724         private function _cleanUpExpiredTickets()\r
725         {\r
726                 // remove tickets older than 1 hour\r
727                 $oldTime = time() - 60 * 60;\r
728                 $query = 'DELETE FROM %s WHERE ctime < %s';\r
729                 $query = sprintf($query, sql_table('tickets'), DB::formatDateTime($oldTime));\r
730                 DB::execute($query);\r
731                 return;\r
732         }\r
733         \r
734         /**\r
735          * Manager::_generateTicket()\r
736          * Generates/returns a ticket (one ticket per page request)\r
737          * \r
738          * @param       void\r
739          * @return      void\r
740          */\r
741         private function _generateTicket()\r
742         {\r
743                 if ( $this->currentRequestTicket == '' )\r
744                 {\r
745                         // generate new ticket (only one ticket will be generated per page request)\r
746                         // and store in database\r
747                         global $member;\r
748                         // get member id\r
749                         if ( !$member->isLoggedIn() )\r
750                         {\r
751                                 $memberId = -1;\r
752                         }\r
753                         else\r
754                         {\r
755                                 $memberId = $member->getID();\r
756                         }\r
757                         \r
758                         $ok = false;\r
759                         while ( !$ok )\r
760                         {\r
761                                 // generate a random token\r
762                                 srand((double)microtime()*1000000);\r
763                                 $ticket = md5(uniqid(rand(), true));\r
764                                 \r
765                                 // add in database as non-active\r
766                                 $query = 'INSERT INTO %s (ticket, member, ctime) VALUES (%s, %d, %s)';\r
767                                 $query = sprintf($query, sql_table('tickets'), DB::quoteValue($ticket), (integer) $memberId, DB::formatDateTime());\r
768                                 \r
769                                 if ( DB::execute($query) !== FALSE )\r
770                                 {\r
771                                         $ok = true;\r
772                                 }\r
773                         }\r
774                         $this->currentRequestTicket = $ticket;\r
775                 }\r
776                 return $this->currentRequestTicket;\r
777         }\r
778 }\r
779 \r