File "file.php"

Full Path: /home/asmplong/www/ancien-site-2019/site/libraries/joomla/cache/storage/file.php
File size: 14.92 KB
MIME-type: text/x-php
Charset: utf-8

<?php
/**
 * @package     Joomla.Platform
 * @subpackage  Cache
 *
 * @copyright   Copyright (C) 2005 - 2011 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE
 */

defined('JPATH_PLATFORM') or die;

jimport('joomla.filesystem.file');

/**
 * File cache storage handler
 *
 * @package     Joomla.Platform
 * @subpackage  Cache
 * @since       11.1
 */
class JCacheStorageFile extends JCacheStorage
{
	/**
	 * @var    string
	 * @since  11.1
	 */
	protected $_root;

	/**
	 * Constructor
	 *
	 * @param   array    $options optional parameters
	 * @since   11.1
	 */
	public function __construct($options = array())
	{
		parent::__construct($options);
		$this->_root	= $options['cachebase'];
	}

	// NOTE: raw php calls are up to 100 times faster than JFile or JFolder

	/**
	 * Get cached data from a file by id and group
	 *
	 * @param   string   $id         The cache data id
	 * @param   string   $group      The cache data group
	 * @param   boolean  $checkTime  True to verify cache time expiration threshold
	 *
	 * @return  mixed  Boolean false on failure or a cached data string
	 *
	 * @since   11.1
	 */
	public function get($id, $group, $checkTime = true)
	{
		$data = false;

		$path = $this->_getFilePath($id, $group);

		if ($checkTime == false || ($checkTime == true && $this->_checkExpire($id, $group) === true)) {
			if (file_exists($path)) {
				$data = file_get_contents($path);
				if ($data) {
					// Remove the initial die() statement
					$data = str_replace('<?php die("Access Denied"); ?>#x#', '', $data);
				}
			}

			return $data;
		} else {
			return false;
		}
	}

	/**
	 * Get all cached data
	 *
	 * @return  array  The cached data
	 *
	 * @since   11.1
	 */
	public function getAll()
	{
		parent::getAll();

		$path		= $this->_root;
		$folders 	= $this->_folders($path);
		$data 		= array();

		foreach ($folders as $folder) {
			$files 	= array();
			$files 	= $this->_filesInFolder($path . '/' . $folder);
			$item 	= new JCacheStorageHelper($folder);

			foreach ($files as $file) {
				$item->updateSize(filesize($path . '/' . $folder . '/' . $file) / 1024);
			}
			$data[$folder] = $item;
		}

		return $data;
	}

	/**
	 * Store the data to a file by id and group
	 *
	 * @param   string  $id     The cache data id
	 * @param   string  $group  The cache data group
	 * @param   string  $data   The data to store in cache
	 *
	 * @return  boolean  True on success, false otherwise
	 *
	 * @since   11.1
	 */
	public function store($id, $group, $data)
	{
		$written	= false;
		$path		= $this->_getFilePath($id, $group);
		$die		= '<?php die("Access Denied"); ?>#x#';

		// Prepend a die string
		$data		= $die.$data;

		$_fileopen = @fopen($path, "wb");

		if ($_fileopen) {
			$len = strlen($data);
			@fwrite($_fileopen, $data, $len);
			$written = true;
		}

		// Data integrity check
		if ($written && ($data == file_get_contents($path))) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Remove a cached data file by id and group
	 *
	 * @param   string  $id     The cache data id
	 * @param   string  $group  The cache data group
	 *
	 * @return  boolean  True on success, false otherwise
	 *
	 * @since   11.1
	 */
	public function remove($id, $group)
	{
		$path = $this->_getFilePath($id, $group);
		if (!@unlink($path)) {
			return false;
		}
		return true;
	}

	/**
	 * Clean cache for a group given a mode.
	 *
	 * @param   string  $group  The cache data group
	 * @param   string  $mode   The mode for cleaning cache [group|notgroup]
	 *                          group mode     : cleans all cache in the group
	 *                          notgroup mode  : cleans all cache not in the group
	 *
	 * @return  boolean  True on success, false otherwise
	 *
	 * @since   11.1
	 */
	public function clean($group, $mode = null)
	{
		$return = true;
		$folder	= $group;

		if (trim($folder) == '') {
			$mode = 'notgroup';
		}

		switch ($mode) {
			case 'notgroup':
				$folders = $this->_folders($this->_root);
				for ($i=0, $n=count($folders); $i<$n; $i++) {
					if ($folders[$i] != $folder) {
						$return |= $this->_deleteFolder($this->_root . '/' . $folders[$i]);
					}
				}
				break;
			case 'group':
			default:
				if (is_dir($this->_root . '/' . $folder)) {
					$return = $this->_deleteFolder($this->_root . '/' . $folder);
				}
				break;
		}
		return $return;
	}

	/**
	 * Garbage collect expired cache data
	 *
	 * @return  boolean  True on success, false otherwise.
	 * @since   11.1
	 */
	public function gc()
	{
		$result = true;
		// files older than lifeTime get deleted from cache
		$files = $this->_filesInFolder($this->_root, '', true, true, array('.svn', 'CVS','.DS_Store','__MACOSX', 'index.html'));
		foreach($files As $file) {
			$time = @filemtime($file);
			if (($time + $this->_lifetime) < $this->_now || empty($time)) {
				$result |= @unlink($file);
			}
		}
		return $result;
	}

	/**
	 * Test to see if the cache storage is available.
	 *
	 * @return  boolean  True on success, false otherwise.
	 * @since   11.1
	 */
	public static function test()
	{
		$conf = JFactory::getConfig();
		return is_writable($conf->get('cache_path', JPATH_CACHE));
	}

	/**
	 * Lock cached item
	 *
	 * @param   string   $id        The cache data id
	 * @param   string   $group     The cache data group
	 * @param   integer  $locktime  Cached item max lock time
	 *
	 * @return  boolean  True on success, false otherwise.
	 *
	 * @since   11.1
	 */
	public function lock($id,$group,$locktime)
	{
		$returning = new stdClass;
		$returning->locklooped = false;

		$looptime 	= $locktime * 10;
		$path		= $this->_getFilePath($id, $group);

		$_fileopen = @fopen($path, "r+b");

		if ($_fileopen) {
				$data_lock = @flock($_fileopen, LOCK_EX);
		} else {
			$data_lock = false;
		}

		if ($data_lock === false) {

			$lock_counter = 0;

			// loop until you find that the lock has been released.  that implies that data get from other thread has finished
			while ($data_lock === false) {

				if ($lock_counter > $looptime) {
					$returning->locked 		= false;
					$returning->locklooped 	= true;
					break;
				}

				usleep(100);
				$data_lock =  @flock($_fileopen, LOCK_EX);
				$lock_counter++;
			}

		}
		$returning->locked = $data_lock;

		return $returning;
	}

	/**
	 * Unlock cached item
	 *
	 * @param   string  $id     The cache data id
	 * @param   string  $group  The cache data group
	 *
	 * @return  boolean  True on success, false otherwise.
	 *
	 * @since   11.1
	 */
	public function unlock($id, $group = null)
	{
		$path = $this->_getFilePath($id, $group);

		$_fileopen = @fopen($path, "r+b");

		if ($_fileopen) {
				$ret = @flock($_fileopen, LOCK_UN);
				@fclose($_fileopen);
		}

		return $ret;
	}

	/**
	 * Check to make sure cache is still valid, if not, delete it.
	 *
	 * @param   string  $id     Cache key to expire.
	 * @param   string  $group  The cache data group.
	 *
	 * @return  boolean  False if not valid
	 *
	 * @since   11.1
	 */
	protected function _checkExpire($id, $group)
	{
		$path = $this->_getFilePath($id, $group);

		// check prune period
		if (file_exists($path)) {
			$time = @filemtime($path);
			if (($time + $this->_lifetime) < $this->_now || empty($time)) {
				@unlink($path);
				return false;
			}
			return true;
		}
		return false;
	}

	/**
	 * Get a cache file path from an id/group pair
	 *
	 * @param   string  $id     The cache data id
	 * @param   string  $group  The cache data group
	 *
	 * @return  string   The cache file path
	 *
	 * @since   11.1
	 */
	protected function _getFilePath($id, $group)
	{
		$name	= $this->_getCacheId($id, $group);
		$dir	= $this->_root . '/' . $group;

		// If the folder doesn't exist try to create it
		if (!is_dir($dir)) {

			// Make sure the index file is there
			$indexFile = $dir.'/index.html';
			@ mkdir($dir) && file_put_contents($indexFile, '<!DOCTYPE html><title></title>');
		}

		// Make sure the folder exists
		if (!is_dir($dir)) {
			return false;
		}
		return $dir . '/' . $name.'.php';
	}

	/**
	 * Quickly delete a folder of files
	 *
	 * @param   string  The path to the folder to delete.
	 *
	 * @return  boolean  True on success.
	 *
	 * @since   11.1
	 */
	protected function _deleteFolder($path)
	{
	// Sanity check
		if (!$path || !is_dir($path) || empty($this->_root)) {
			// Bad programmer! Bad Bad programmer!
			JError::raiseWarning(500, 'JCacheStorageFile::_deleteFolder ' . JText::_('JLIB_FILESYSTEM_ERROR_DELETE_BASE_DIRECTORY'));
			return false;
		}

		$path = $this->_cleanPath($path);

		// Check to make sure path is inside cache folder, we do not want to delete Joomla root!
		$pos = strpos($path, $this->_cleanPath($this->_root));

		if ($pos === false || $pos > 0) {
			JError::raiseWarning(500, 'JCacheStorageFile::_deleteFolder' . JText::sprintf('JLIB_FILESYSTEM_ERROR_PATH_IS_NOT_A_FOLDER', $path));
			return false;
		}

		// Remove all the files in folder if they exist; disable all filtering
		$files = $this->_filesInFolder($path, '.', false, true, array(), array());

		if (!empty($files) && !is_array($files)) {
			if (@unlink($files) !== true) {
				return false;
			}
		} else if (!empty($files) && is_array($files)) {

			foreach ($files as $file)
			{
				$file = $this->_cleanPath($file);

				// In case of restricted permissions we zap it one way or the other
				// as long as the owner is either the webserver or the ftp
				if (@unlink($file)) {
					// Do nothing
				} else {
					$filename = basename($file);
					JError::raiseWarning('SOME_ERROR_CODE', 'JCacheStorageFile::_deleteFolder' . JText::sprintf('JLIB_FILESYSTEM_DELETE_FAILED', $filename));
					return false;
				}
			}
		}

		// Remove sub-folders of folder; disable all filtering
		$folders = $this->_folders($path, '.', false, true, array(), array());

		foreach ($folders as $folder) {
			if (is_link($folder)) {
				// Don't descend into linked directories, just delete the link.
				if (@unlink($folder) !== true) {
					return false;
				}
			} elseif ($this->_deleteFolder($folder) !== true) {
				return false;
			}
		}

		// In case of restricted permissions we zap it one way or the other
		// as long as the owner is either the webserver or the ftp
		if (@rmdir($path)) {
			$ret = true;
		} else {
			JError::raiseWarning('SOME_ERROR_CODE', 'JCacheStorageFile::_deleteFolder' . JText::sprintf('JLIB_FILESYSTEM_ERROR_FOLDER_DELETE', $path));
			$ret = false;
		}
		return $ret;
	}

	/**
	 * Function to strip additional / or \ in a path name
	 *
	 * @param   string  The path to clean
	 * @param   string  Directory separator (optional)
	 *
	 * @return  string  The cleaned path
	 *
	 * @since   11.1
	 */
	protected function _cleanPath($path, $ds = DS)
	{
		$path = trim($path);

		if (empty($path)) {
			$path = $this->_root;
		} else {
			// Remove double slashes and backslahses and convert all slashes and backslashes to DS
			$path = preg_replace('#[/\\\\]+#', $ds, $path);
		}

		return $path;
	}


	/**
	 * Utility function to quickly read the files in a folder.
	 *
	 * @param   string  The path of the folder to read.
	 * @param   string  A filter for file names.
	 * @param   mixed   True to recursively search into sub-folders, or an
	 *                  integer to specify the maximum depth.
	 * @param   boolean True to return the full path to the file.
	 * @param   array   Array with names of files which should not be shown in
	 *                  the result.
	 *
	 * @return  array  Files in the given folder.
	 *
	 * @since   11.1
	 */
	protected function _filesInFolder($path, $filter = '.', $recurse = false, $fullpath = false, $exclude = array('.svn', 'CVS','.DS_Store','__MACOSX'), $excludefilter = array('^\..*','.*~'))
	{
		// Initialise variables.
		$arr = array();

		// Check to make sure the path valid and clean
		$path = $this->_cleanPath($path);

		// Is the path a folder?
		if (!is_dir($path)) {
			JError::raiseWarning(21, 'JCacheStorageFile::_filesInFolder' . JText::sprintf('JLIB_FILESYSTEM_ERROR_PATH_IS_NOT_A_FOLDER', $path));
			return false;
		}

		// Read the source directory.
		$handle = opendir($path);
		if (count($excludefilter)) {
			$excludefilter = '/('. implode('|', $excludefilter) .')/';
		} else {
			$excludefilter = '';
		}
		while (($file = readdir($handle)) !== false)
		{
			if (($file != '.') && ($file != '..') && (!in_array($file, $exclude)) && (!$excludefilter || !preg_match($excludefilter, $file))) {
				$dir = $path . '/' . $file;
				$isDir = is_dir($dir);
				if ($isDir) {
					if ($recurse) {
						if (is_integer($recurse)) {
							$arr2 = $this->_filesInFolder($dir, $filter, $recurse - 1, $fullpath);
						} else {
							$arr2 = $this->_filesInFolder($dir, $filter, $recurse, $fullpath);
						}

						$arr = array_merge($arr, $arr2);
					}
				} else {
					if (preg_match("/$filter/", $file)) {
						if ($fullpath) {
							$arr[] = $path . '/' . $file;
						} else {
							$arr[] = $file;
						}
					}
				}
			}
		}
		closedir($handle);

		return $arr;
	}

	/**
	 * Utility function to read the folders in a folder.
	 *
	 * @param   string   The path of the folder to read.
	 * @param   string   A filter for folder names.
	 * @param   mixed    True to recursively search into sub-folders, or an
	 *                   integer to specify the maximum depth.
	 * @param   boolean  True to return the full path to the folders.
	 * @param   array    Array with names of folders which should not be shown in
	 *                   the result.
	 * @param   array    Array with regular expressions matching folders which
	 *                   should not be shown in the result.
	 *
	 * @return  array  Folders in the given folder.
	 *
	 * @since   11.1
	 */
	protected function _folders($path, $filter = '.', $recurse = false, $fullpath = false, $exclude = array('.svn', 'CVS','.DS_Store','__MACOSX'), $excludefilter = array('^\..*'))
	{
		// Initialise variables.
		$arr = array();

		// Check to make sure the path valid and clean
		$path = $this->_cleanPath($path);

		// Is the path a folder?
		if (!is_dir($path)) {
			JError::raiseWarning(21, 'JCacheStorageFile::_folders' . JText::sprintf('JLIB_FILESYSTEM_ERROR_PATH_IS_NOT_A_FOLDER', $path));
			return false;
		}

		// read the source directory
		$handle = opendir($path);

		if (count($excludefilter)) {
			$excludefilter_string = '/('. implode('|', $excludefilter) .')/';
		} else {
			$excludefilter_string = '';
		}
		while (($file = readdir($handle)) !== false)
		{
			if (($file != '.') && ($file != '..') && (!in_array($file, $exclude)) && (empty($excludefilter_string) || !preg_match($excludefilter_string, $file))) {
				$dir = $path . '/' . $file;
				$isDir = is_dir($dir);
				if ($isDir) {
					// Removes filtered directories
					if (preg_match("/$filter/", $file)) {
						if ($fullpath) {
							$arr[] = $dir;
						} else {
							$arr[] = $file;
						}
					}
					if ($recurse) {
						if (is_integer($recurse)) {
						$arr2 = $this->_folders($dir, $filter, $recurse - 1, $fullpath, $exclude, $excludefilter);
						} else {
						$arr2 = $this->_folders($dir, $filter, $recurse, $fullpath, $exclude, $excludefilter);
						}

						$arr = array_merge($arr, $arr2);
					}
				}
			}
		}
		closedir($handle);

		return $arr;
	}
}