/include/file_functions.php
PHP | 416 lines | 286 code | 57 blank | 73 comment | 80 complexity | 22782f9e0e63941e828c4a74ec5a2712 MD5 | raw file
- <?php
- /**
- *
- * @package xbtBB3cker
- * @copyright (c) 2015 PPK
- * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
- *
- */
- /**
- * @ignore
- */
- if (!defined('IN_PHPBB'))
- {
- exit;
- }
- //From /includes/constants.php
- define('CHMOD_ALL', 7);// - all permissions (7)
- define('CHMOD_READ', 4);// - read permission (4)
- define('CHMOD_WRITE', 2);// - write permission (2)
- define('CHMOD_EXECUTE', 1);// - execute permission (1)
- //From /includes/functions.php
- function phpbb_chmod($filename, $perms = CHMOD_READ)
- {
- static $_chmod_info;
- // Return if the file no longer exists.
- if (!file_exists($filename))
- {
- return false;
- }
- // Determine some common vars
- if (empty($_chmod_info))
- {
- if (!function_exists('fileowner') || !function_exists('filegroup'))
- {
- // No need to further determine owner/group - it is unknown
- $_chmod_info['process'] = false;
- }
- else
- {
- global $phpbb_root_path, $phpEx;
- // Determine owner/group of common.php file and the filename we want to change here
- $common_php_owner = @fileowner($phpbb_root_path . 'common.' . $phpEx);
- $common_php_group = @filegroup($phpbb_root_path . 'common.' . $phpEx);
- // And the owner and the groups PHP is running under.
- $php_uid = (function_exists('posix_getuid')) ? @posix_getuid() : false;
- $php_gids = (function_exists('posix_getgroups')) ? @posix_getgroups() : false;
- // If we are unable to get owner/group, then do not try to set them by guessing
- if (!$php_uid || empty($php_gids) || !$common_php_owner || !$common_php_group)
- {
- $_chmod_info['process'] = false;
- }
- else
- {
- $_chmod_info = array(
- 'process' => true,
- 'common_owner' => $common_php_owner,
- 'common_group' => $common_php_group,
- 'php_uid' => $php_uid,
- 'php_gids' => $php_gids,
- );
- }
- }
- }
- if ($_chmod_info['process'])
- {
- $file_uid = @fileowner($filename);
- $file_gid = @filegroup($filename);
- // Change owner
- if (@chown($filename, $_chmod_info['common_owner']))
- {
- clearstatcache();
- $file_uid = @fileowner($filename);
- }
- // Change group
- if (@chgrp($filename, $_chmod_info['common_group']))
- {
- clearstatcache();
- $file_gid = @filegroup($filename);
- }
- // If the file_uid/gid now match the one from common.php we can process further, else we are not able to change something
- if ($file_uid != $_chmod_info['common_owner'] || $file_gid != $_chmod_info['common_group'])
- {
- $_chmod_info['process'] = false;
- }
- }
- // Still able to process?
- if ($_chmod_info['process'])
- {
- if ($file_uid == $_chmod_info['php_uid'])
- {
- $php = 'owner';
- }
- else if (in_array($file_gid, $_chmod_info['php_gids']))
- {
- $php = 'group';
- }
- else
- {
- // Since we are setting the everyone bit anyway, no need to do expensive operations
- $_chmod_info['process'] = false;
- }
- }
- // We are not able to determine or change something
- if (!$_chmod_info['process'])
- {
- $php = 'other';
- }
- // Owner always has read/write permission
- $owner = CHMOD_READ | CHMOD_WRITE;
- if (is_dir($filename))
- {
- $owner |= CHMOD_EXECUTE;
- // Only add execute bit to the permission if the dir needs to be readable
- if ($perms & CHMOD_READ)
- {
- $perms |= CHMOD_EXECUTE;
- }
- }
- switch ($php)
- {
- case 'owner':
- $result = @chmod($filename, ($owner << 6) + (0 << 3) + (0 << 0));
- clearstatcache();
- if (is_readable($filename) && phpbb_is_writable($filename))
- {
- break;
- }
- case 'group':
- $result = @chmod($filename, ($owner << 6) + ($perms << 3) + (0 << 0));
- clearstatcache();
- if ((!($perms & CHMOD_READ) || is_readable($filename)) && (!($perms & CHMOD_WRITE) || phpbb_is_writable($filename)))
- {
- break;
- }
- case 'other':
- $result = @chmod($filename, ($owner << 6) + ($perms << 3) + ($perms << 0));
- clearstatcache();
- if ((!($perms & CHMOD_READ) || is_readable($filename)) && (!($perms & CHMOD_WRITE) || phpbb_is_writable($filename)))
- {
- break;
- }
- default:
- return false;
- break;
- }
- return $result;
- }
- function phpbb_is_writable($file)
- {
- if (strtolower(substr(PHP_OS, 0, 3)) === 'win' || !function_exists('is_writable'))
- {
- if (file_exists($file))
- {
- // Canonicalise path to absolute path
- $file = phpbb_realpath($file);
- if (is_dir($file))
- {
- // Test directory by creating a file inside the directory
- $result = @tempnam($file, 'i_w');
- if (is_string($result) && file_exists($result))
- {
- unlink($result);
- // Ensure the file is actually in the directory (returned realpathed)
- return (strpos($result, $file) === 0) ? true : false;
- }
- }
- else
- {
- $handle = @fopen($file, 'r+');
- if (is_resource($handle))
- {
- fclose($handle);
- return true;
- }
- }
- }
- else
- {
- // file does not exist test if we can write to the directory
- $dir = dirname($file);
- if (file_exists($dir) && is_dir($dir) && phpbb_is_writable($dir))
- {
- return true;
- }
- }
- return false;
- }
- else
- {
- return is_writable($file);
- }
- }
- function phpbb_own_realpath($path)
- {
- // Now to perform funky shizzle
- // Switch to use UNIX slashes
- $path = str_replace(DIRECTORY_SEPARATOR, '/', $path);
- $path_prefix = '';
- // Determine what sort of path we have
- if (is_absolute($path))
- {
- $absolute = true;
- if ($path[0] == '/')
- {
- // Absolute path, *NIX style
- $path_prefix = '';
- }
- else
- {
- // Absolute path, Windows style
- // Remove the drive letter and colon
- $path_prefix = $path[0] . ':';
- $path = substr($path, 2);
- }
- }
- else
- {
- // Relative Path
- // Prepend the current working directory
- if (function_exists('getcwd'))
- {
- // This is the best method, hopefully it is enabled!
- $path = str_replace(DIRECTORY_SEPARATOR, '/', getcwd()) . '/' . $path;
- $absolute = true;
- if (preg_match('#^[a-z]:#i', $path))
- {
- $path_prefix = $path[0] . ':';
- $path = substr($path, 2);
- }
- else
- {
- $path_prefix = '';
- }
- }
- else if (isset($_SERVER['SCRIPT_FILENAME']) && !empty($_SERVER['SCRIPT_FILENAME']))
- {
- // Warning: If chdir() has been used this will lie!
- // Warning: This has some problems sometime (CLI can create them easily)
- $path = str_replace(DIRECTORY_SEPARATOR, '/', dirname($_SERVER['SCRIPT_FILENAME'])) . '/' . $path;
- $absolute = true;
- $path_prefix = '';
- }
- else
- {
- // We have no way of getting the absolute path, just run on using relative ones.
- $absolute = false;
- $path_prefix = '.';
- }
- }
- // Remove any repeated slashes
- $path = preg_replace('#/{2,}#', '/', $path);
- // Remove the slashes from the start and end of the path
- $path = trim($path, '/');
- // Break the string into little bits for us to nibble on
- $bits = explode('/', $path);
- // Remove any . in the path, renumber array for the loop below
- $bits = array_values(array_diff($bits, array('.')));
- // Lets get looping, run over and resolve any .. (up directory)
- for ($i = 0, $max = count($bits); $i < $max; $i++)
- {
- // @todo Optimise
- if ($bits[$i] == '..' )
- {
- if (isset($bits[$i - 1]))
- {
- if ($bits[$i - 1] != '..')
- {
- // We found a .. and we are able to traverse upwards, lets do it!
- unset($bits[$i]);
- unset($bits[$i - 1]);
- $i -= 2;
- $max -= 2;
- $bits = array_values($bits);
- }
- }
- else if ($absolute) // ie. !isset($bits[$i - 1]) && $absolute
- {
- // We have an absolute path trying to descend above the root of the filesystem
- // ... Error!
- return false;
- }
- }
- }
- // Prepend the path prefix
- array_unshift($bits, $path_prefix);
- $resolved = '';
- $max = count($bits) - 1;
- // Check if we are able to resolve symlinks, Windows cannot.
- $symlink_resolve = (function_exists('readlink')) ? true : false;
- foreach ($bits as $i => $bit)
- {
- if (@is_dir("$resolved/$bit") || ($i == $max && @is_file("$resolved/$bit")))
- {
- // Path Exists
- if ($symlink_resolve && is_link("$resolved/$bit") && ($link = readlink("$resolved/$bit")))
- {
- // Resolved a symlink.
- $resolved = $link . (($i == $max) ? '' : '/');
- continue;
- }
- }
- else
- {
- // Something doesn't exist here!
- // This is correct realpath() behaviour but sadly open_basedir and safe_mode make this problematic
- // return false;
- }
- $resolved .= $bit . (($i == $max) ? '' : '/');
- }
- // @todo If the file exists fine and open_basedir only has one path we should be able to prepend it
- // because we must be inside that basedir, the question is where...
- // @internal The slash in is_dir() gets around an open_basedir restriction
- if (!@file_exists($resolved) || (!@is_dir($resolved . '/') && !is_file($resolved)))
- {
- return false;
- }
- // Put the slashes back to the native operating systems slashes
- $resolved = str_replace('/', DIRECTORY_SEPARATOR, $resolved);
- // Check for DIRECTORY_SEPARATOR at the end (and remove it!)
- if (substr($resolved, -1) == DIRECTORY_SEPARATOR)
- {
- return substr($resolved, 0, -1);
- }
- return $resolved; // We got here, in the end!
- }
- if (!function_exists('realpath'))
- {
- /**
- * A wrapper for realpath
- * @ignore
- */
- function phpbb_realpath($path)
- {
- return phpbb_own_realpath($path);
- }
- }
- else
- {
- /**
- * A wrapper for realpath
- */
- function phpbb_realpath($path)
- {
- $realpath = realpath($path);
- // Strangely there are provider not disabling realpath but returning strange values. :o
- // We at least try to cope with them.
- if ($realpath === $path || $realpath === false)
- {
- return phpbb_own_realpath($path);
- }
- // Check for DIRECTORY_SEPARATOR at the end (and remove it!)
- if (substr($realpath, -1) == DIRECTORY_SEPARATOR)
- {
- $realpath = substr($realpath, 0, -1);
- }
- return $realpath;
- }
- }
- ?>