/** * @package Joomla.Platform * @subpackage FileSystem * * @copyright Copyright (C) 2005 - 2014 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE */ defined('JPATH_PLATFORM') or die; // Define a boolean constant as true if a Windows based host define('JPATH_ISWIN', (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN')); // Define a boolean constant as true if a Mac based host define('JPATH_ISMAC', (strtoupper(substr(PHP_OS, 0, 3)) === 'MAC')); if (!defined('DS')) { // Define a string constant shortcut for the DIRECTORY_SEPARATOR define define('DS', DIRECTORY_SEPARATOR); } if (!defined('JPATH_ROOT')) { // Define a string constant for the root directory of the file system in native format define('JPATH_ROOT', JPath::clean(JPATH_SITE)); } /** * A Path handling class * * @package Joomla.Platform * @subpackage FileSystem * @since 11.1 */ class JPath { /** * Checks if a path's permissions can be changed. * * @param string $path Path to check. * * @return boolean True if path can have mode changed. * * @since 11.1 */ public static function canChmod($path) { $perms = fileperms($path); if ($perms !== false) { if (@chmod($path, $perms ^ 0001)) { @chmod($path, $perms); return true; } } return false; } /** * Chmods files and directories recursively to given permissions. * * @param string $path Root path to begin changing mode [without trailing slash]. * @param string $filemode Octal representation of the value to change file mode to [null = no change]. * @param string $foldermode Octal representation of the value to change folder mode to [null = no change]. * * @return boolean True if successful [one fail means the whole operation failed]. * * @since 11.1 */ public static function setPermissions($path, $filemode = '0644', $foldermode = '0755') { // Initialise return value $ret = true; if (is_dir($path)) { $dh = opendir($path); while ($file = readdir($dh)) { if ($file != '.' && $file != '..') { $fullpath = $path . '/' . $file; if (is_dir($fullpath)) { if (!JPath::setPermissions($fullpath, $filemode, $foldermode)) { $ret = false; } } else { if (isset($filemode)) { if (!@ chmod($fullpath, octdec($filemode))) { $ret = false; } } } } } closedir($dh); if (isset($foldermode)) { if (!@ chmod($path, octdec($foldermode))) { $ret = false; } } } else { if (isset($filemode)) { $ret = @ chmod($path, octdec($filemode)); } } return $ret; } /** * Get the permissions of the file/folder at a give path. * * @param string $path The path of a file/folder. * * @return string Filesystem permissions. * * @since 11.1 */ public static function getPermissions($path) { $path = JPath::clean($path); $mode = @ decoct(@ fileperms($path) & 0777); if (strlen($mode) < 3) { return '---------'; } $parsed_mode = ''; for ($i = 0; $i < 3; $i++) { // read $parsed_mode .= ($mode{$i} & 04) ? "r" : "-"; // write $parsed_mode .= ($mode{$i} & 02) ? "w" : "-"; // execute $parsed_mode .= ($mode{$i} & 01) ? "x" : "-"; } return $parsed_mode; } /** * Checks for snooping outside of the file system root. * * @param string $path A file system path to check. * @param string $ds Directory separator (optional). * * @return string A cleaned version of the path or exit on error. * * @since 11.1 */ public static function check($path, $ds = DIRECTORY_SEPARATOR) { if (strpos($path, '..') !== false) { JError::raiseError(20, 'JPath::check Use of relative paths not permitted'); jexit(); } $path = JPath::clean($path); if ((JPATH_ROOT != '') && strpos($path, JPath::clean(JPATH_ROOT)) !== 0) { // Don't translate JError::raiseError(20, 'JPath::check Snooping out of bounds @ ' . $path); jexit(); } return $path; } /** * Function to strip additional / or \ in a path name. * * @param string $path The path to clean. * @param string $ds Directory separator (optional). * * @return string The cleaned path. * * @since 11.1 * @throws UnexpectedValueException */ public static function clean($path, $ds = DIRECTORY_SEPARATOR) { if (!is_string($path) && !empty($path)) { throw new UnexpectedValueException('JPath::clean: $path is not a string.'); } $path = trim($path); if (empty($path)) { $path = JPATH_ROOT; } // Remove double slashes and backslashes and convert all slashes and backslashes to DIRECTORY_SEPARATOR // If dealing with a UNC path don't forget to prepend the path with a backslash. elseif (($ds == '\\') && ($path[0] == '\\' ) && ( $path[1] == '\\' )) { $path = "\\" . preg_replace('#[/\\\\]+#', $ds, $path); } else { $path = preg_replace('#[/\\\\]+#', $ds, $path); } return $path; } /** * Method to determine if script owns the path. * * @param string $path Path to check ownership. * * @return boolean True if the php script owns the path passed. * * @since 11.1 */ public static function isOwner($path) { jimport('joomla.filesystem.file'); $tmp = md5(JUserHelper::genRandomPassword(16)); $ssp = ini_get('session.save_path'); $jtp = JPATH_SITE . '/tmp'; // Try to find a writable directory $dir = is_writable('/tmp') ? '/tmp' : false; $dir = (!$dir && is_writable($ssp)) ? $ssp : false; $dir = (!$dir && is_writable($jtp)) ? $jtp : false; if ($dir) { $test = $dir . '/' . $tmp; // Create the test file $blank = ''; JFile::write($test, $blank, false); // Test ownership $return = (fileowner($test) == fileowner($path)); // Delete the test file JFile::delete($test); return $return; } return false; } /** * Searches the directory paths for a given file. * * @param mixed $paths An path string or array of path strings to search in * @param string $file The file name to look for. * * @return mixed The full path and file name for the target file, or boolean false if the file is not found in any of the paths. * * @since 11.1 */ public static function find($paths, $file) { settype($paths, 'array'); //force to array // Start looping through the path set foreach ($paths as $path) { // Get the path to the file $fullname = $path . '/' . $file; // Is the path based on a stream? if (strpos($path, '://') === false) { // Not a stream, so do a realpath() to avoid directory // traversal attempts on the local file system. $path = realpath($path); // needed for substr() later $fullname = realpath($fullname); } // The substr() check added to make sure that the realpath() // results in a directory registered so that // non-registered directories are not accessible via directory // traversal attempts. if (file_exists($fullname) && substr($fullname, 0, strlen($path)) == $path) { return $fullname; } } // Could not find the file in the set of paths return false; } }