[ Index ]

PHP Cross Reference of Nucleus CMS 3.32

title

Body

[close]

/nucleus/libs/ -> MANAGER.php (source)

   1  <?php
   2  /*
   3   * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
   4   * Copyright (C) 2002-2007 The Nucleus Group
   5   *
   6   * This program is free software; you can redistribute it and/or
   7   * modify it under the terms of the GNU General Public License
   8   * as published by the Free Software Foundation; either version 2
   9   * of the License, or (at your option) any later version.
  10   * (see nucleus/documentation/index.html#license for more info)
  11   */
  12  /**
  13   * This class makes sure each item/weblog/comment object gets requested from
  14   * the database only once, by keeping them in a cache. The class also acts as
  15   * a dynamic classloader, loading classes _only_ when they are first needed,
  16   * hoping to diminish execution time
  17   *
  18   * The class is a singleton, meaning that there will be only one object of it
  19   * active at all times. The object can be requested using MANAGER::instance()
  20   *
  21   * @license http://nucleuscms.org/license.txt GNU General Public License
  22   * @copyright Copyright (C) 2002-2007 The Nucleus Group
  23   * @version $Id: MANAGER.php 1150 2007-05-19 23:26:02Z kaigreve $
  24   */
  25  class MANAGER {
  26  
  27      /**
  28       * Cached ITEM, BLOG, PLUGIN, KARMA and MEMBER objects. When these objects are requested
  29       * through the global $manager object (getItem, getBlog, ...), only the first call
  30       * will create an object. Subsequent calls will return the same object.
  31       *
  32       * The $items, $blogs, ... arrays map an id to an object (for plugins, the name is used
  33       * rather than an ID)
  34       */
  35      var $items;
  36      var $blogs;
  37      var $plugins;
  38      var $karma;
  39      var $templates;
  40      var $members;
  41  
  42      /**
  43       * cachedInfo to avoid repeated SQL queries (see pidInstalled/pluginInstalled/getPidFromName)
  44       * e.g. which plugins exists?
  45       *
  46       * $cachedInfo['installedPlugins'] = array($pid -> $name)
  47       */
  48      var $cachedInfo;
  49  
  50      /**
  51        * The plugin subscriptionlist
  52        *
  53        * The subcription array has the following structure
  54        *        $subscriptions[$EventName] = array containing names of plugin classes to be
  55        *                                     notified when that event happens
  56        */
  57      var $subscriptions;
  58  
  59      /**
  60        * Returns the only instance of this class. Creates the instance if it
  61        * does not yet exists. Users should use this function as
  62        * $manager =& MANAGER::instance(); to get a reference to the object
  63        * instead of a copy
  64        */
  65      function &instance() {
  66          static $instance = array();
  67          if (empty($instance)) {
  68              $instance[0] =& new MANAGER();
  69          }
  70          return $instance[0];
  71      }
  72  
  73      /**
  74        * The constructor of this class initializes the object caches
  75        */
  76  	function MANAGER() {
  77          $this->items = array();
  78          $this->blogs = array();
  79          $this->plugins = array();
  80          $this->karma = array();
  81          $this->parserPrefs = array();
  82          $this->cachedInfo = array();
  83      }
  84  
  85      /**
  86        * Returns the requested item object. If it is not in the cache, it will
  87        * first be loaded and then placed in the cache.
  88        * Intended use: $item =& $manager->getItem(1234)
  89        */
  90      function &getItem($itemid, $allowdraft, $allowfuture) {
  91          $item =& $this->items[$itemid];
  92  
  93          // check the draft and future rules if the item was already cached
  94          if ($item) {
  95              if ((!$allowdraft) && ($item['draft']))
  96                  return 0;
  97  
  98              $blog =& $this->getBlog(getBlogIDFromItemID($itemid));
  99              if ((!$allowfuture) && ($item['timestamp'] > $blog->getCorrectTime()))
 100                  return 0;
 101          }
 102          if (!$item) {
 103              // load class if needed
 104              $this->loadClass('ITEM');
 105              // load item object
 106              $item = ITEM::getitem($itemid, $allowdraft, $allowfuture);
 107              $this->items[$itemid] = $item;
 108          }
 109          return $item;
 110      }
 111  
 112      /**
 113        * Loads a class if it has not yet been loaded
 114        */
 115  	function loadClass($name) {
 116          $this->_loadClass($name, $name . '.php');
 117      }
 118  
 119      /**
 120        * Checks if an item exists
 121        */
 122  	function existsItem($id,$future,$draft) {
 123          $this->_loadClass('ITEM','ITEM.php');
 124          return ITEM::exists($id,$future,$draft);
 125      }
 126  
 127      /**
 128        * Checks if a category exists
 129        */
 130  	function existsCategory($id) {
 131          return (quickQuery('SELECT COUNT(*) as result FROM '.sql_table('category').' WHERE catid='.intval($id)) > 0);
 132      }
 133  
 134      function &getBlog($blogid) {
 135          $blog =& $this->blogs[$blogid];
 136  
 137          if (!$blog) {
 138              // load class if needed
 139              $this->_loadClass('BLOG','BLOG.php');
 140              // load blog object
 141              $blog =& new BLOG($blogid);
 142              $this->blogs[$blogid] =& $blog;
 143          }
 144          return $blog;
 145      }
 146  
 147  	function existsBlog($name) {
 148          $this->_loadClass('BLOG','BLOG.php');
 149          return BLOG::exists($name);
 150      }
 151  
 152  	function existsBlogID($id) {
 153          $this->_loadClass('BLOG','BLOG.php');
 154          return BLOG::existsID($id);
 155      }
 156  
 157      /**
 158       * Returns a previously read template
 159       */
 160      function &getTemplate($templateName) {
 161          $template =& $this->templates[$templateName];
 162  
 163          if (!$template) {
 164              $template = TEMPLATE::read($templateName);
 165              $this->templates[$templateName] =& $template;
 166          }
 167          return $template;
 168      }
 169  
 170      /**
 171       * Returns a KARMA object (karma votes)
 172       */
 173      function &getKarma($itemid) {
 174          $karma =& $this->karma[$itemid];
 175  
 176          if (!$karma) {
 177              // load class if needed
 178              $this->_loadClass('KARMA','KARMA.php');
 179              // create KARMA object
 180              $karma =& new KARMA($itemid);
 181              $this->karma[$itemid] =& $karma;
 182          }
 183          return $karma;
 184      }
 185  
 186      /**
 187       * Returns a MEMBER object
 188       */
 189      function &getMember($memberid) {
 190          $mem =& $this->members[$memberid];
 191  
 192          if (!$mem) {
 193              // load class if needed
 194              $this->_loadClass('MEMBER','MEMBER.php');
 195              // create MEMBER object
 196              $mem =& MEMBER::createFromID($memberid);
 197              $this->members[$memberid] =& $mem;
 198          }
 199          return $mem;
 200      }
 201  
 202      /**
 203       * Global parser preferences
 204       */
 205  	function setParserProperty($name, $value) {
 206          $this->parserPrefs[$name] = $value;
 207      }
 208  	function getParserProperty($name) {
 209          return $this->parserPrefs[$name];
 210      }
 211  
 212      /**
 213        * A private helper class to load classes
 214        */
 215  	function _loadClass($name, $filename) {
 216          if (!class_exists($name)) {
 217                  global $DIR_LIBS;
 218                  include($DIR_LIBS . $filename);
 219          }
 220      }
 221  
 222  	function _loadPlugin($name) {
 223          if (!class_exists($name)) {
 224                  global $DIR_PLUGINS;
 225  
 226                  $fileName = $DIR_PLUGINS . $name . '.php';
 227  
 228                  if (!file_exists($fileName))
 229                  {
 230                      ACTIONLOG::add(WARNING, 'Plugin ' . $name . ' was not loaded (File not found)');
 231                      return 0;
 232                  }
 233  
 234                  // load plugin
 235                  include($fileName);
 236  
 237                  // check if class exists (avoid errors in eval'd code)
 238                  if (!class_exists($name))
 239                  {
 240                      ACTIONLOG::add(WARNING, 'Plugin ' . $name . ' was not loaded (Class not found in file, possible parse error)');
 241                      return 0;
 242                  }
 243  
 244                  // add to plugin array
 245                  eval('$this->plugins[$name] =& new ' . $name . '();');
 246  
 247                  // get plugid
 248                  $this->plugins[$name]->plugid = $this->getPidFromName($name);
 249  
 250                  // unload plugin if a prefix is used and the plugin cannot handle this^
 251                  global $MYSQL_PREFIX;
 252                  if (($MYSQL_PREFIX != '') && !$this->plugins[$name]->supportsFeature('SqlTablePrefix'))
 253                  {
 254                      unset($this->plugins[$name]);
 255                      ACTIONLOG::add(WARNING, 'Plugin ' . $name . ' was not loaded (does not support SqlTablePrefix)');
 256                      return 0;
 257                  }
 258  
 259                  // call init method
 260                  $this->plugins[$name]->init();
 261  
 262          }
 263      }
 264  
 265      function &getPlugin($name) {
 266          $plugin =& $this->plugins[$name];
 267  
 268          if (!$plugin) {
 269              // load class if needed
 270              $this->_loadPlugin($name);
 271              $plugin =& $this->plugins[$name];
 272          }
 273          return $plugin;
 274      }
 275  
 276      /**
 277        * checks if the given plugin IS loaded or not
 278        */
 279      function &pluginLoaded($name) {
 280          $plugin =& $this->plugins[$name];
 281          return $plugin;
 282      }
 283      function &pidLoaded($pid) {
 284          $plugin=false;
 285          reset($this->plugins);
 286          while (list($name) = each($this->plugins)) {
 287              if ($pid!=$this->plugins[$name]->getId()) continue;
 288              $plugin= & $this->plugins[$name];
 289              break;
 290          }
 291          return $plugin;
 292      }
 293  
 294      /**
 295        * checks if the given plugin IS installed or not
 296        */
 297  	function pluginInstalled($name) {
 298          $this->_initCacheInfo('installedPlugins');
 299          return ($this->getPidFromName($name) != -1);
 300      }
 301  	function pidInstalled($pid) {
 302          $this->_initCacheInfo('installedPlugins');
 303          return ($this->cachedInfo['installedPlugins'][$pid] != '');
 304      }
 305  	function getPidFromName($name) {
 306          $this->_initCacheInfo('installedPlugins');
 307          foreach ($this->cachedInfo['installedPlugins'] as $pid => $pfile)
 308          {
 309              if ($pfile == $name)
 310                  return $pid;
 311          }
 312          return -1;
 313      }
 314  	function clearCachedInfo($what) {
 315          unset($this->cachedInfo[$what]);
 316      }
 317  
 318      /**
 319       * Loads some info on the first call only
 320       */
 321  	function _initCacheInfo($what)
 322      {
 323          if (isset($this->cachedInfo[$what]) && is_array($this->cachedInfo[$what]))
 324              return;
 325          switch ($what)
 326          {
 327              // 'installedPlugins' = array ($pid => $name)
 328              case 'installedPlugins':
 329                  $this->cachedInfo['installedPlugins'] = array();
 330                  $res = sql_query('SELECT pid, pfile FROM ' . sql_table('plugin'));
 331                  while ($o = mysql_fetch_object($res))
 332                  {
 333                      $this->cachedInfo['installedPlugins'][$o->pid] = $o->pfile;
 334                  }
 335                  break;
 336          }
 337      }
 338  
 339      /**
 340        * A function to notify plugins that something has happened. Only the plugins
 341        * that are subscribed to the event will get notified.
 342        * Upon the first call, the list of subscriptions will be fetched from the
 343        * database. The plugins itsself will only get loaded when they are first needed
 344        *
 345        * @param $eventName
 346        *        Name of the event (method to be called on plugins)
 347        * @param $data
 348        *        Can contain any type of data, depending on the event type. Usually this is
 349        *        an itemid, blogid, ... but it can also be an array containing multiple values
 350        */
 351  	function notify($eventName, $data) {
 352          // load subscription list if needed
 353          if (!is_array($this->subscriptions))
 354              $this->_loadSubscriptions();
 355  
 356  
 357          // get listening objects
 358          $listeners = false;
 359          if (isset($this->subscriptions[$eventName])) {
 360              $listeners = $this->subscriptions[$eventName];
 361          }
 362  
 363          // notify all of them
 364          if (is_array($listeners)) {
 365              foreach($listeners as $listener) {
 366                  // load class if needed
 367                  $this->_loadPlugin($listener);
 368                  // do notify (if method exists)
 369                  if (method_exists($this->plugins[$listener], 'event_' . $eventName))
 370                      call_user_func(array(&$this->plugins[$listener],'event_' . $eventName), $data);
 371              }
 372          }
 373  
 374      }
 375  
 376      /**
 377        * Loads plugin subscriptions
 378        */
 379  	function _loadSubscriptions() {
 380          // initialize as array
 381          $this->subscriptions = array();
 382  
 383          $res = sql_query('SELECT p.pfile as pfile, e.event as event FROM '.sql_table('plugin_event').' as e, '.sql_table('plugin').' as p WHERE e.pid=p.pid ORDER BY p.porder ASC');
 384          while ($o = mysql_fetch_object($res)) {
 385              $pluginName = $o->pfile;
 386              $eventName = $o->event;
 387              $this->subscriptions[$eventName][] = $pluginName;
 388          }
 389  
 390      }
 391  
 392      /*
 393          Ticket functions. These are uses by the admin area to make it impossible to simulate certain GET/POST
 394          requests. tickets are user specific
 395      */
 396  
 397      var $currentRequestTicket = '';
 398  
 399      /**
 400       * GET requests: Adds ticket to URL (URL should NOT be html-encoded!, ticket is added at the end)
 401       */
 402  	function addTicketToUrl($url)
 403      {
 404          $ticketCode = 'ticket=' . $this->_generateTicket();
 405          if (strstr($url, '?'))
 406              return $url . '&' . $ticketCode;
 407          else
 408              return $url . '?' . $ticketCode;
 409      }
 410  
 411      /**
 412       * POST requests: Adds ticket as hidden formvar
 413       */
 414  	function addTicketHidden()
 415      {
 416          $ticket = $this->_generateTicket();
 417  
 418          echo '<input type="hidden" name="ticket" value="', htmlspecialchars($ticket), '" />';
 419      }
 420  
 421      /**
 422       * Get a new ticket
 423       * (xmlHTTPRequest AutoSaveDraft uses this to refresh the ticket)
 424       */
 425  	function getNewTicket()
 426      {
 427          $this->currentRequestTicket = '';
 428          return $this->_generateTicket();
 429      }
 430  
 431      /**
 432       * Checks the ticket that was passed along with the current request
 433       */
 434  	function checkTicket()
 435      {
 436          global $member;
 437  
 438          // get ticket from request
 439          $ticket = requestVar('ticket');
 440  
 441          // no ticket -> don't allow
 442          if ($ticket == '')
 443              return false;
 444  
 445          // remove expired tickets first
 446          $this->_cleanUpExpiredTickets();
 447  
 448          // get member id
 449          if (!$member->isLoggedIn())
 450              $memberId = -1;
 451          else
 452              $memberId = $member->getID();
 453  
 454          // check if ticket is a valid one
 455          $query = 'SELECT COUNT(*) as result FROM ' . sql_table('tickets') . ' WHERE member=' . intval($memberId). ' and ticket=\''.addslashes($ticket).'\'';
 456          if (quickQuery($query) == 1)
 457          {
 458              // [in the original implementation, the checked ticket was deleted. This would lead to invalid
 459              //  tickets when using the browsers back button and clicking another link/form
 460              //  leaving the keys in the database is not a real problem, since they're member-specific and
 461              //  only valid for a period of one hour
 462              // ]
 463              // sql_query('DELETE FROM '.sql_table('tickets').' WHERE member=' . intval($memberId). ' and ticket=\''.addslashes($ticket).'\'');
 464              return true;
 465          } else {
 466              // not a valid ticket
 467              return false;
 468          }
 469  
 470      }
 471  
 472      /**
 473       * (internal method) Removes the expired tickets
 474       */
 475  	function _cleanUpExpiredTickets()
 476      {
 477          // remove tickets older than 1 hour
 478          $oldTime = time() - 60 * 60;
 479          $query = 'DELETE FROM ' . sql_table('tickets'). ' WHERE ctime < \'' . date('Y-m-d H:i:s',$oldTime) .'\'';
 480          sql_query($query);
 481      }
 482  
 483      /**
 484       * (internal method) Generates/returns a ticket (one ticket per page request)
 485       */
 486  	function _generateTicket()
 487      {
 488          if ($this->currentRequestTicket == '')
 489          {
 490              // generate new ticket (only one ticket will be generated per page request)
 491              // and store in database
 492              global $member;
 493              // get member id
 494              if (!$member->isLoggedIn())
 495                  $memberId = -1;
 496              else
 497                  $memberId = $member->getID();
 498  
 499              $ok = false;
 500              while (!$ok)
 501              {
 502                  // generate a random token
 503                  srand((double)microtime()*1000000);
 504                  $ticket = md5(uniqid(rand(), true));
 505  
 506                  // add in database as non-active
 507                  $query = 'INSERT INTO ' . sql_table('tickets') . ' (ticket, member, ctime) ';
 508                  $query .= 'VALUES (\'' . addslashes($ticket). '\', \'' . intval($memberId). '\', \'' . date('Y-m-d H:i:s',time()) . '\')';
 509                  if (sql_query($query))
 510                      $ok = true;
 511              }
 512  
 513              $this->currentRequestTicket = $ticket;
 514          }
 515          return $this->currentRequestTicket;
 516      }
 517  
 518  }
 519  
 520  ?>


Generated: Tue Feb 12 15:34:36 2008 Cross-referenced by PHPXref 0.7