includes/plugins.php
changeset 590 03a60844c7c5
parent 568 3700f7124c2b
child 593 4f9bec0d65c1
equal deleted inserted replaced
589:88d4ed0a2898 590:03a60844c7c5
    62    */
    62    */
    63   
    63   
    64   function loadAll() 
    64   function loadAll() 
    65   {
    65   {
    66     global $db, $session, $paths, $template, $plugins; // Common objects
    66     global $db, $session, $paths, $template, $plugins; // Common objects
       
    67     $GLOBALS['plugins_cache'] = array();
    67     
    68     
    68     // if we're in an upgrade, just skip this step
    69     // if we're in an upgrade, just skip this step
    69     if ( defined('IN_ENANO_UPGRADE') )
    70     if ( defined('IN_ENANO_UPGRADE') )
    70     {
    71     {
    71       $this->load_list = array();
    72       $this->load_list = array();
   249   
   250   
   250   /**
   251   /**
   251    * Reads all plugins in the filesystem and cross-references them with the database, providing a very complete summary of plugins
   252    * Reads all plugins in the filesystem and cross-references them with the database, providing a very complete summary of plugins
   252    * on the site.
   253    * on the site.
   253    * @param array If specified, will restrict scanned files to this list. Defaults to null, which means all PHP files will be scanned.
   254    * @param array If specified, will restrict scanned files to this list. Defaults to null, which means all PHP files will be scanned.
       
   255    * @param bool If true, allows using cached information. Defaults to true.
   254    * @return array
   256    * @return array
   255    */
   257    */
   256   
   258   
   257   function get_plugin_list($restrict = null)
   259   function get_plugin_list($restrict = null, $use_cache = true)
   258   {
   260   {
   259     global $db, $session, $paths, $template, $plugins; // Common objects
   261     global $db, $session, $paths, $template, $plugins; // Common objects
   260     
   262     
   261     // Scan all plugins
   263     // Scan all plugins
   262     $plugin_list = array();
   264     $plugin_list = array();
       
   265     $ta = 0;
       
   266     // won't load twice (failsafe automatic skip)
       
   267     $this->load_plugins_cache();
       
   268     if ( $use_cache )
       
   269     {
       
   270       global $plugins_cache;
       
   271     }
       
   272     else
       
   273     {
       
   274       // blank array - effectively skips importing the cache
       
   275       $plugins_cache = array();
       
   276     }
   263     
   277     
   264     if ( $dirh = @opendir( ENANO_ROOT . '/plugins' ) )
   278     if ( $dirh = @opendir( ENANO_ROOT . '/plugins' ) )
   265     {
   279     {
   266       while ( $dh = @readdir($dirh) )
   280       while ( $dh = @readdir($dirh) )
   267       {
   281       {
   270         
   284         
   271         if ( is_array($restrict) )
   285         if ( is_array($restrict) )
   272           if ( !in_array($dh, $restrict) )
   286           if ( !in_array($dh, $restrict) )
   273             continue;
   287             continue;
   274           
   288           
       
   289         // it's a PHP file, attempt to read metadata
   275         $fullpath = ENANO_ROOT . "/plugins/$dh";
   290         $fullpath = ENANO_ROOT . "/plugins/$dh";
   276         // it's a PHP file, attempt to read metadata
   291         // first can we use cached info?
   277         // pass 1: try to read a !info block
   292         if ( isset($plugins_cache[$dh]) && $plugins_cache[$dh]['file md5'] === $this->md5_header($fullpath) )
   278         $blockdata = $this->parse_plugin_blocks($fullpath, 'info');
       
   279         if ( empty($blockdata) )
       
   280         {
   293         {
   281           // no !info block, check for old header
   294           $plugin_meta = $plugins_cache[$dh];
   282           $fh = @fopen($fullpath, 'r');
       
   283           if ( !$fh )
       
   284             // can't read, bail out
       
   285             continue;
       
   286           $plugin_data = array();
       
   287           for ( $i = 0; $i < 8; $i++ )
       
   288           {
       
   289             $plugin_data[] = @fgets($fh, 8096);
       
   290           }
       
   291           // close our file handle
       
   292           fclose($fh);
       
   293           // is the header correct?
       
   294           if ( trim($plugin_data[0]) != '<?php' || trim($plugin_data[1]) != '/*' )
       
   295           {
       
   296             // nope. get out.
       
   297             continue;
       
   298           }
       
   299           // parse all the variables
       
   300           $plugin_meta = array();
       
   301           for ( $i = 2; $i <= 7; $i++ )
       
   302           {
       
   303             if ( !preg_match('/^([A-z0-9 ]+?): (.+?)$/', trim($plugin_data[$i]), $match) )
       
   304               continue 2;
       
   305             $plugin_meta[ strtolower($match[1]) ] = $match[2];
       
   306           }
       
   307         }
   295         }
   308         else
   296         else
   309         {
   297         {
   310           // parse JSON block
   298           // the cache is out of date if we reached here -- regenerate
   311           $plugin_data =& $blockdata[0]['value'];
   299           if ( $use_cache )
   312           $plugin_data = enano_clean_json(enano_trim_json($plugin_data));
   300             $this->generate_plugins_cache();
   313           try
   301           
       
   302           // pass 1: try to read a !info block
       
   303           $blockdata = $this->parse_plugin_blocks($fullpath, 'info');
       
   304           if ( empty($blockdata) )
   314           {
   305           {
   315             $plugin_meta_uc = enano_json_decode($plugin_data);
   306             // no !info block, check for old header
       
   307             $fh = @fopen($fullpath, 'r');
       
   308             if ( !$fh )
       
   309               // can't read, bail out
       
   310               continue;
       
   311             $plugin_data = array();
       
   312             for ( $i = 0; $i < 8; $i++ )
       
   313             {
       
   314               $plugin_data[] = @fgets($fh, 8096);
       
   315             }
       
   316             // close our file handle
       
   317             fclose($fh);
       
   318             // is the header correct?
       
   319             if ( trim($plugin_data[0]) != '<?php' || trim($plugin_data[1]) != '/*' )
       
   320             {
       
   321               // nope. get out.
       
   322               continue;
       
   323             }
       
   324             // parse all the variables
       
   325             $plugin_meta = array();
       
   326             for ( $i = 2; $i <= 7; $i++ )
       
   327             {
       
   328               if ( !preg_match('/^([A-z0-9 ]+?): (.+?)$/', trim($plugin_data[$i]), $match) )
       
   329                 continue 2;
       
   330               $plugin_meta[ strtolower($match[1]) ] = $match[2];
       
   331             }
   316           }
   332           }
   317           catch ( Exception $e )
   333           else
   318           {
   334           {
   319             continue;
   335             // parse JSON block
   320           }
   336             $plugin_data =& $blockdata[0]['value'];
   321           // convert all the keys to lowercase
   337             $plugin_data = enano_clean_json(enano_trim_json($plugin_data));
   322           $plugin_meta = array();
   338             try
   323           foreach ( $plugin_meta_uc as $key => $value )
   339             {
   324           {
   340               $plugin_meta_uc = enano_json_decode($plugin_data);
   325             $plugin_meta[ strtolower($key) ] = $value;
   341             }
       
   342             catch ( Exception $e )
       
   343             {
       
   344               continue;
       
   345             }
       
   346             // convert all the keys to lowercase
       
   347             $plugin_meta = array();
       
   348             foreach ( $plugin_meta_uc as $key => $value )
       
   349             {
       
   350               $plugin_meta[ strtolower($key) ] = $value;
       
   351             }
   326           }
   352           }
   327         }
   353         }
   328         if ( !isset($plugin_meta) || !is_array(@$plugin_meta) )
   354         if ( !isset($plugin_meta) || !is_array(@$plugin_meta) )
   329         {
   355         {
   330           // parsing didn't work.
   356           // parsing didn't work.
   380     // done
   406     // done
   381     return $plugin_list;
   407     return $plugin_list;
   382   }
   408   }
   383   
   409   
   384   /**
   410   /**
       
   411    * Attempts to cache plugin information in a file to speed fetching.
       
   412    */
       
   413   
       
   414   function generate_plugins_cache()
       
   415   {
       
   416     if ( getConfig('cache_thumbs') != '1' )
       
   417       return;
       
   418     
       
   419     // fetch the most current info
       
   420     $plugin_info = $this->get_plugin_list(null, false);
       
   421     foreach ( $plugin_info as $plugin => &$info )
       
   422     {
       
   423       $info['file md5'] = $this->md5_header(ENANO_ROOT . "/plugins/$plugin");
       
   424     }
       
   425     
       
   426     $this->update_plugins_cache($plugin_info);
       
   427     $GLOBALS['plugins_cache'] = $plugin_info;
       
   428     @define('ENANO_PLUGINS_CACHE_LOADED', true);
       
   429   }
       
   430   
       
   431   /**
       
   432    * Writes an information array to the cache file.
       
   433    * @param array
       
   434    * @access private
       
   435    */
       
   436   
       
   437   function update_plugins_cache($plugin_info)
       
   438   {
       
   439     $plugin_info = Language::var_export_string($plugin_info);
       
   440     
       
   441     $file = ENANO_ROOT . '/cache/cache_plugins.php';
       
   442     $fh = @fopen($file, 'w');
       
   443     if ( !$fh )
       
   444       // can't open for writing
       
   445       return false;
       
   446       
       
   447     $contents = <<<EOF
       
   448 <?php
       
   449 /**
       
   450  * Cache of plugin files. Automatically generated, any modifications will soon be lost
       
   451  */
       
   452 
       
   453 @define('ENANO_PLUGINS_CACHE_LOADED', true);
       
   454 \$GLOBALS['plugins_cache'] = $plugin_info;
       
   455 
       
   456 EOF;
       
   457     fwrite($fh, $contents);
       
   458     fclose($fh);
       
   459   }
       
   460   
       
   461   /**
       
   462    * Loads the plugins cache if any.
       
   463    */
       
   464   
       
   465   function load_plugins_cache()
       
   466   {
       
   467     if ( file_exists(ENANO_ROOT . '/cache/cache_plugins.php') && !defined('ENANO_PLUGINS_CACHE_LOADED') )
       
   468     {
       
   469       require(ENANO_ROOT . '/cache/cache_plugins.php');
       
   470     }
       
   471   }
       
   472   
       
   473   /**
       
   474    * Calculates the MD5 sum of the first 10 lines of a file. Useful for caching plugin header information.
       
   475    * @param string File
       
   476    * @return string
       
   477    */
       
   478   
       
   479   function md5_header($file)
       
   480   {
       
   481     $fh = @fopen($file, 'r');
       
   482     if ( !$fh )
       
   483       return false;
       
   484     $i = 0;
       
   485     $h = '';
       
   486     while ( $i < 10 )
       
   487     {
       
   488       $line = fgets($fh, 8096);
       
   489       $h .= $line . "\n";
       
   490       $i++;
       
   491     }
       
   492     fclose($fh);
       
   493     return md5($h);
       
   494   }
       
   495   
       
   496   /**
   385    * Installs a plugin.
   497    * Installs a plugin.
   386    * @param string Filename of plugin.
   498    * @param string Filename of plugin.
   387    * @param array The list of plugins as output by pluginLoader::get_plugin_list(). If not passed, the function is called, possibly wasting time.
   499    * @param array The list of plugins as output by pluginLoader::get_plugin_list(). If not passed, the function is called, possibly wasting time.
   388    * @return array JSON-formatted but not encoded response
   500    * @return array JSON-formatted but not encoded response
   389    */
   501    */