Source for file file.php

Documentation is available at file.php

  1. <?php
  2. /**
  3.  * @package     Joomla.Platform
  4.  * @subpackage  Cache
  5.  *
  6.  * @copyright   Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
  7.  * @license     GNU General Public License version 2 or later; see LICENSE
  8.  */
  9.  
  10. defined('JPATH_PLATFORM'or die;
  11.  
  12. /**
  13.  * File cache storage handler
  14.  *
  15.  * @package     Joomla.Platform
  16.  * @subpackage  Cache
  17.  * @since       11.1
  18.  */
  19. {
  20.     /**
  21.      * Root path
  22.      *
  23.      * @var    string 
  24.      * @since  11.1
  25.      */
  26.     protected $_root;
  27.  
  28.     /**
  29.      * Constructor
  30.      *
  31.      * @param   array  $options  Optional parameters
  32.      *
  33.      * @since   11.1
  34.      */
  35.     public function __construct($options array())
  36.     {
  37.         parent::__construct($options);
  38.         $this->_root = $options['cachebase'];
  39.     }
  40.  
  41.     // NOTE: raw php calls are up to 100 times faster than JFile or JFolder
  42.  
  43.     /**
  44.      * Get cached data from a file by id and group
  45.      *
  46.      * @param   string   $id         The cache data id
  47.      * @param   string   $group      The cache data group
  48.      * @param   boolean  $checkTime  True to verify cache time expiration threshold
  49.      *
  50.      * @return  mixed  Boolean false on failure or a cached data string
  51.      *
  52.      * @since   11.1
  53.      */
  54.     public function get($id$group$checkTime true)
  55.     {
  56.         $data false;
  57.  
  58.         $path $this->_getFilePath($id$group);
  59.  
  60.         if ($checkTime == false || ($checkTime == true && $this->_checkExpire($id$group=== true))
  61.         {
  62.             if (file_exists($path))
  63.             {
  64.                 $data file_get_contents($path);
  65.                 if ($data)
  66.                 {
  67.                     // Remove the initial die() statement
  68.                     $data str_replace('<?php die("Access Denied"); ?>#x#'''$data);
  69.                 }
  70.             }
  71.  
  72.             return $data;
  73.         }
  74.         else
  75.         {
  76.             return false;
  77.         }
  78.     }
  79.  
  80.     /**
  81.      * Get all cached data
  82.      *
  83.      * @return  array  The cached data
  84.      *
  85.      * @since   11.1
  86.      */
  87.     public function getAll()
  88.     {
  89.         parent::getAll();
  90.  
  91.         $path $this->_root;
  92.         $folders $this->_folders($path);
  93.         $data array();
  94.  
  95.         foreach ($folders as $folder)
  96.         {
  97.             $files $this->_filesInFolder($path '/' $folder);
  98.             $item new JCacheStorageHelper($folder);
  99.  
  100.             foreach ($files as $file)
  101.             {
  102.                 $item->updateSize(filesize($path '/' $folder '/' $file1024);
  103.             }
  104.             $data[$folder$item;
  105.         }
  106.  
  107.         return $data;
  108.     }
  109.  
  110.     /**
  111.      * Store the data to a file by id and group
  112.      *
  113.      * @param   string  $id     The cache data id
  114.      * @param   string  $group  The cache data group
  115.      * @param   string  $data   The data to store in cache
  116.      *
  117.      * @return  boolean  True on success, false otherwise
  118.      *
  119.      * @since   11.1
  120.      */
  121.     public function store($id$group$data)
  122.     {
  123.         $written false;
  124.         $path $this->_getFilePath($id$group);
  125.         $die '<?php die("Access Denied"); ?>#x#';
  126.  
  127.         // Prepend a die string
  128.         $data $die $data;
  129.  
  130.         $_fileopen @fopen($path"wb");
  131.  
  132.         if ($_fileopen)
  133.         {
  134.             $len strlen($data);
  135.             @fwrite($_fileopen$data$len);
  136.             $written true;
  137.         }
  138.  
  139.         // Data integrity check
  140.         if ($written && ($data == file_get_contents($path)))
  141.         {
  142.             return true;
  143.         }
  144.         else
  145.         {
  146.             return false;
  147.         }
  148.     }
  149.  
  150.     /**
  151.      * Remove a cached data file by id and group
  152.      *
  153.      * @param   string  $id     The cache data id
  154.      * @param   string  $group  The cache data group
  155.      *
  156.      * @return  boolean  True on success, false otherwise
  157.      *
  158.      * @since   11.1
  159.      */
  160.     public function remove($id$group)
  161.     {
  162.         $path $this->_getFilePath($id$group);
  163.         if (!@unlink($path))
  164.         {
  165.             return false;
  166.         }
  167.         return true;
  168.     }
  169.  
  170.     /**
  171.      * Clean cache for a group given a mode.
  172.      *
  173.      * @param   string  $group  The cache data group
  174.      * @param   string  $mode   The mode for cleaning cache [group|notgroup]
  175.      *  group mode     : cleans all cache in the group
  176.      *  notgroup mode  : cleans all cache not in the group
  177.      *
  178.      * @return  boolean  True on success, false otherwise
  179.      *
  180.      * @since   11.1
  181.      */
  182.     public function clean($group$mode null)
  183.     {
  184.         $return true;
  185.         $folder $group;
  186.  
  187.         if (trim($folder== '')
  188.         {
  189.             $mode 'notgroup';
  190.         }
  191.  
  192.         switch ($mode)
  193.         {
  194.             case 'notgroup':
  195.                 $folders $this->_folders($this->_root);
  196.                 for ($i 0$n count($folders)$i $n$i++)
  197.                 {
  198.                     if ($folders[$i!= $folder)
  199.                     {
  200.                         $return |= $this->_deleteFolder($this->_root . '/' $folders[$i]);
  201.                     }
  202.                 }
  203.                 break;
  204.             case 'group':
  205.             default:
  206.                 if (is_dir($this->_root . '/' $folder))
  207.                 {
  208.                     $return $this->_deleteFolder($this->_root . '/' $folder);
  209.                 }
  210.                 break;
  211.         }
  212.         return $return;
  213.     }
  214.  
  215.     /**
  216.      * Garbage collect expired cache data
  217.      *
  218.      * @return  boolean  True on success, false otherwise.
  219.      *
  220.      * @since   11.1
  221.      */
  222.     public function gc()
  223.     {
  224.         $result true;
  225.  
  226.         // Files older than lifeTime get deleted from cache
  227.         $files $this->_filesInFolder($this->_root''truetruearray('.svn''CVS''.DS_Store''__MACOSX''index.html'));
  228.         foreach ($files as $file)
  229.         {
  230.             $time @filemtime($file);
  231.             if (($time $this->_lifetime$this->_now || empty($time))
  232.             {
  233.                 $result |= @unlink($file);
  234.             }
  235.         }
  236.         return $result;
  237.     }
  238.  
  239.     /**
  240.      * Test to see if the cache storage is available.
  241.      *
  242.      * @return  boolean  True on success, false otherwise.
  243.      *
  244.      * @since   12.1
  245.      */
  246.     public static function isSupported()
  247.     {
  248.         $conf JFactory::getConfig();
  249.         return is_writable($conf->get('cache_path'JPATH_CACHE));
  250.     }
  251.  
  252.     /**
  253.      * Lock cached item
  254.      *
  255.      * @param   string   $id        The cache data id
  256.      * @param   string   $group     The cache data group
  257.      * @param   integer  $locktime  Cached item max lock time
  258.      *
  259.      * @return  boolean  True on success, false otherwise.
  260.      *
  261.      * @since   11.1
  262.      */
  263.     public function lock($id$group$locktime)
  264.     {
  265.         $returning new stdClass;
  266.         $returning->locklooped false;
  267.  
  268.         $looptime $locktime 10;
  269.         $path $this->_getFilePath($id$group);
  270.  
  271.         $_fileopen @fopen($path"r+b");
  272.  
  273.         if ($_fileopen)
  274.         {
  275.             $data_lock @flock($_fileopenLOCK_EX);
  276.         }
  277.         else
  278.         {
  279.             $data_lock false;
  280.         }
  281.  
  282.         if ($data_lock === false)
  283.         {
  284.  
  285.             $lock_counter 0;
  286.  
  287.             // Loop until you find that the lock has been released.
  288.             // That implies that data get from other thread has finished
  289.             while ($data_lock === false)
  290.             {
  291.  
  292.                 if ($lock_counter $looptime)
  293.                 {
  294.                     $returning->locked false;
  295.                     $returning->locklooped true;
  296.                     break;
  297.                 }
  298.  
  299.                 usleep(100);
  300.                 $data_lock @flock($_fileopenLOCK_EX);
  301.                 $lock_counter++;
  302.             }
  303.  
  304.         }
  305.         $returning->locked $data_lock;
  306.  
  307.         return $returning;
  308.     }
  309.  
  310.     /**
  311.      * Unlock cached item
  312.      *
  313.      * @param   string  $id     The cache data id
  314.      * @param   string  $group  The cache data group
  315.      *
  316.      * @return  boolean  True on success, false otherwise.
  317.      *
  318.      * @since   11.1
  319.      */
  320.     public function unlock($id$group null)
  321.     {
  322.         $path $this->_getFilePath($id$group);
  323.  
  324.         $_fileopen @fopen($path"r+b");
  325.  
  326.         if ($_fileopen)
  327.         {
  328.             $ret @flock($_fileopenLOCK_UN);
  329.             @fclose($_fileopen);
  330.         }
  331.  
  332.         return $ret;
  333.     }
  334.  
  335.     /**
  336.      * Check to make sure cache is still valid, if not, delete it.
  337.      *
  338.      * @param   string  $id     Cache key to expire.
  339.      * @param   string  $group  The cache data group.
  340.      *
  341.      * @return  boolean  False if not valid
  342.      *
  343.      * @since   11.1
  344.      */
  345.     protected function _checkExpire($id$group)
  346.     {
  347.         $path $this->_getFilePath($id$group);
  348.  
  349.         // Check prune period
  350.         if (file_exists($path))
  351.         {
  352.             $time @filemtime($path);
  353.             if (($time $this->_lifetime$this->_now || empty($time))
  354.             {
  355.                 @unlink($path);
  356.                 return false;
  357.             }
  358.             return true;
  359.         }
  360.         return false;
  361.     }
  362.  
  363.     /**
  364.      * Get a cache file path from an id/group pair
  365.      *
  366.      * @param   string  $id     The cache data id
  367.      * @param   string  $group  The cache data group
  368.      *
  369.      * @return  string   The cache file path
  370.      *
  371.      * @since   11.1
  372.      */
  373.     protected function _getFilePath($id$group)
  374.     {
  375.         $name $this->_getCacheId($id$group);
  376.         $dir $this->_root . '/' $group;
  377.  
  378.         // If the folder doesn't exist try to create it
  379.         if (!is_dir($dir))
  380.         {
  381.  
  382.             // Make sure the index file is there
  383.             $indexFile $dir '/index.html';
  384.             mkdir($dir&& file_put_contents($indexFile'<!DOCTYPE html><title></title>');
  385.         }
  386.  
  387.         // Make sure the folder exists
  388.         if (!is_dir($dir))
  389.         {
  390.             return false;
  391.         }
  392.         return $dir '/' $name '.php';
  393.     }
  394.  
  395.     /**
  396.      * Quickly delete a folder of files
  397.      *
  398.      * @param   string  $path  The path to the folder to delete.
  399.      *
  400.      * @return  boolean  True on success.
  401.      *
  402.      * @since   11.1
  403.      */
  404.     protected function _deleteFolder($path)
  405.     {
  406.         // Sanity check
  407.         if (!$path || !is_dir($path|| empty($this->_root))
  408.         {
  409.             // Bad programmer! Bad Bad programmer!
  410.             JLog::add('JCacheStorageFile::_deleteFolder ' JText::_('JLIB_FILESYSTEM_ERROR_DELETE_BASE_DIRECTORY')JLog::WARNING'jerror');
  411.             return false;
  412.         }
  413.  
  414.         $path $this->_cleanPath($path);
  415.  
  416.         // Check to make sure path is inside cache folder, we do not want to delete Joomla root!
  417.         $pos strpos($path$this->_cleanPath($this->_root));
  418.  
  419.         if ($pos === false || $pos 0)
  420.         {
  421.             JLog::add('JCacheStorageFile::_deleteFolder' JText::sprintf('JLIB_FILESYSTEM_ERROR_PATH_IS_NOT_A_FOLDER'$path)JLog::WARNING'jerror');
  422.             return false;
  423.         }
  424.  
  425.         // Remove all the files in folder if they exist; disable all filtering
  426.         $files $this->_filesInFolder($path'.'falsetruearray()array());
  427.  
  428.         if (!empty($files&& !is_array($files))
  429.         {
  430.             if (@unlink($files!== true)
  431.             {
  432.                 return false;
  433.             }
  434.         }
  435.         elseif (!empty($files&& is_array($files))
  436.         {
  437.  
  438.             foreach ($files as $file)
  439.             {
  440.                 $file $this->_cleanPath($file);
  441.  
  442.                 // In case of restricted permissions we zap it one way or the other
  443.                 // as long as the owner is either the webserver or the ftp
  444.                 if (@unlink($file))
  445.                 {
  446.                     // Do nothing
  447.                 }
  448.                 else
  449.                 {
  450.                     $filename basename($file);
  451.                     JLog::add('JCacheStorageFile::_deleteFolder' JText::sprintf('JLIB_FILESYSTEM_DELETE_FAILED'$filename)JLog::WARNING'jerror');
  452.                     return false;
  453.                 }
  454.             }
  455.         }
  456.  
  457.         // Remove sub-folders of folder; disable all filtering
  458.         $folders $this->_folders($path'.'falsetruearray()array());
  459.  
  460.         foreach ($folders as $folder)
  461.         {
  462.             if (is_link($folder))
  463.             {
  464.                 // Don't descend into linked directories, just delete the link.
  465.                 if (@unlink($folder!== true)
  466.                 {
  467.                     return false;
  468.                 }
  469.             }
  470.             elseif ($this->_deleteFolder($folder!== true)
  471.             {
  472.                 return false;
  473.             }
  474.         }
  475.  
  476.         // In case of restricted permissions we zap it one way or the other
  477.         // as long as the owner is either the webserver or the ftp
  478.         if (@rmdir($path))
  479.         {
  480.             $ret true;
  481.         }
  482.         else
  483.         {
  484.             JLog::add('JCacheStorageFile::_deleteFolder' JText::sprintf('JLIB_FILESYSTEM_ERROR_FOLDER_DELETE'$path)JLog::WARNING'jerror');
  485.             $ret false;
  486.         }
  487.         return $ret;
  488.     }
  489.  
  490.     /**
  491.      * Function to strip additional / or \ in a path name
  492.      *
  493.      * @param   string  $path  The path to clean
  494.      * @param   string  $ds    Directory separator (optional)
  495.      *
  496.      * @return  string  The cleaned path
  497.      *
  498.      * @since   11.1
  499.      */
  500.     protected function _cleanPath($path$ds DIRECTORY_SEPARATOR)
  501.     {
  502.         $path trim($path);
  503.  
  504.         if (empty($path))
  505.         {
  506.             $path $this->_root;
  507.         }
  508.         else
  509.         {
  510.             // Remove double slashes and backslahses and convert all slashes and backslashes to DIRECTORY_SEPARATOR
  511.             $path preg_replace('#[/\\\\]+#'$ds$path);
  512.         }
  513.  
  514.         return $path;
  515.     }
  516.  
  517.     /**
  518.      * Utility function to quickly read the files in a folder.
  519.      *
  520.      * @param   string   $path           The path of the folder to read.
  521.      * @param   string   $filter         A filter for file names.
  522.      * @param   mixed    $recurse        True to recursively search into sub-folders, or an
  523.      *                                    integer to specify the maximum depth.
  524.      * @param   boolean  $fullpath       True to return the full path to the file.
  525.      * @param   array    $exclude        Array with names of files which should not be shown in
  526.      *                                    the result.
  527.      * @param   array    $excludefilter  Array of folder names to exclude
  528.      *
  529.      * @return  array    Files in the given folder.
  530.      *
  531.      * @since   11.1
  532.      */
  533.     protected function _filesInFolder($path$filter '.'$recurse false$fullpath false
  534.         $exclude array('.svn''CVS''.DS_Store''__MACOSX')$excludefilter array('^\..*''.*~'))
  535.     {
  536.         $arr array();
  537.  
  538.         // Check to make sure the path valid and clean
  539.         $path $this->_cleanPath($path);
  540.  
  541.         // Is the path a folder?
  542.         if (!is_dir($path))
  543.         {
  544.             JLog::add('JCacheStorageFile::_filesInFolder' JText::sprintf('JLIB_FILESYSTEM_ERROR_PATH_IS_NOT_A_FOLDER'$path)JLog::WARNING'jerror');
  545.             return false;
  546.         }
  547.  
  548.         // Read the source directory.
  549.         if (!($handle @opendir($path)))
  550.         {
  551.             return $arr;
  552.         }
  553.  
  554.         if (count($excludefilter))
  555.         {
  556.             $excludefilter '/(' implode('|'$excludefilter')/';
  557.         }
  558.         else
  559.         {
  560.             $excludefilter '';
  561.         }
  562.         while (($file readdir($handle)) !== false)
  563.         {
  564.             if (($file != '.'&& ($file != '..'&& (!in_array($file$exclude)) && (!$excludefilter || !preg_match($excludefilter$file)))
  565.             {
  566.                 $dir $path '/' $file;
  567.                 $isDir is_dir($dir);
  568.                 if ($isDir)
  569.                 {
  570.                     if ($recurse)
  571.                     {
  572.                         if (is_int($recurse))
  573.                         {
  574.                             $arr2 $this->_filesInFolder($dir$filter$recurse 1$fullpath);
  575.                         }
  576.                         else
  577.                         {
  578.                             $arr2 $this->_filesInFolder($dir$filter$recurse$fullpath);
  579.                         }
  580.  
  581.                         $arr array_merge($arr$arr2);
  582.                     }
  583.                 }
  584.                 else
  585.                 {
  586.                     if (preg_match("/$filter/"$file))
  587.                     {
  588.                         if ($fullpath)
  589.                         {
  590.                             $arr[$path '/' $file;
  591.                         }
  592.                         else
  593.                         {
  594.                             $arr[$file;
  595.                         }
  596.                     }
  597.                 }
  598.             }
  599.         }
  600.         closedir($handle);
  601.  
  602.         return $arr;
  603.     }
  604.  
  605.     /**
  606.      * Utility function to read the folders in a folder.
  607.      *
  608.      * @param   string   $path           The path of the folder to read.
  609.      * @param   string   $filter         A filter for folder names.
  610.      * @param   mixed    $recurse        True to recursively search into sub-folders, or an integer to specify the maximum depth.
  611.      * @param   boolean  $fullpath       True to return the full path to the folders.
  612.      * @param   array    $exclude        Array with names of folders which should not be shown in the result.
  613.      * @param   array    $excludefilter  Array with regular expressions matching folders which should not be shown in the result.
  614.      *
  615.      * @return  array  Folders in the given folder.
  616.      *
  617.      * @since   11.1
  618.      */
  619.     protected function _folders($path$filter '.'$recurse false$fullpath false
  620.         $exclude array('.svn''CVS''.DS_Store''__MACOSX')$excludefilter array('^\..*'))
  621.     {
  622.         $arr array();
  623.  
  624.         // Check to make sure the path valid and clean
  625.         $path $this->_cleanPath($path);
  626.  
  627.         // Is the path a folder?
  628.         if (!is_dir($path))
  629.         {
  630.             JLog::add('JCacheStorageFile::_folders' JText::sprintf('JLIB_FILESYSTEM_ERROR_PATH_IS_NOT_A_FOLDER'$path)JLog::WARNING'jerror');
  631.             return false;
  632.         }
  633.  
  634.         // Read the source directory
  635.         if (!($handle @opendir($path)))
  636.         {
  637.             return $arr;
  638.         }
  639.  
  640.         if (count($excludefilter))
  641.         {
  642.             $excludefilter_string '/(' implode('|'$excludefilter')/';
  643.         }
  644.         else
  645.         {
  646.             $excludefilter_string '';
  647.         }
  648.         while (($file readdir($handle)) !== false)
  649.         {
  650.             if (($file != '.'&& ($file != '..')
  651.                 && (!in_array($file$exclude))
  652.                 && (empty($excludefilter_string|| !preg_match($excludefilter_string$file)))
  653.             {
  654.                 $dir $path '/' $file;
  655.                 $isDir is_dir($dir);
  656.                 if ($isDir)
  657.                 {
  658.                     // Removes filtered directories
  659.                     if (preg_match("/$filter/"$file))
  660.                     {
  661.                         if ($fullpath)
  662.                         {
  663.                             $arr[$dir;
  664.                         }
  665.                         else
  666.                         {
  667.                             $arr[$file;
  668.                         }
  669.                     }
  670.                     if ($recurse)
  671.                     {
  672.                         if (is_int($recurse))
  673.                         {
  674.                             $arr2 $this->_folders($dir$filter$recurse 1$fullpath$exclude$excludefilter);
  675.                         }
  676.                         else
  677.                         {
  678.                             $arr2 $this->_folders($dir$filter$recurse$fullpath$exclude$excludefilter);
  679.                         }
  680.  
  681.                         $arr array_merge($arr$arr2);
  682.                     }
  683.                 }
  684.             }
  685.         }
  686.         closedir($handle);
  687.  
  688.         return $arr;
  689.     }
  690. }

Documentation generated on Tue, 19 Nov 2013 15:03:10 +0100 by phpDocumentor 1.4.3