From 67c826cef3c0dcbf930606b13b6eadbedabba82c Mon Sep 17 00:00:00 2001 From: pdontthink Date: Thu, 20 Nov 2008 21:46:12 +0000 Subject: [PATCH] Add a functions file for file utility functions (say that 10 times fast) along with some new file functions git-svn-id: https://svn.code.sf.net/p/squirrelmail/code/trunk/squirrelmail@13321 7612ce4b-ef26-0410-bec9-ea0150e637f0 --- functions/files.php | 265 +++++++++++++++++++++++++++++++++++++++++++ functions/global.php | 139 +---------------------- include/init.php | 1 + 3 files changed, 268 insertions(+), 137 deletions(-) create mode 100644 functions/files.php diff --git a/functions/files.php b/functions/files.php new file mode 100644 index 00000000..0a297eaa --- /dev/null +++ b/functions/files.php @@ -0,0 +1,265 @@ += 4.3.2 we can be truly atomic here + $filemods = check_php_version(4, 3, 2) ? 'x' : 'w'; + + for ($try = 0; $try < $maximum_tries; ++$try) { + + $localfilename = GenerateRandomString(32, '', 7); + $full_localfilename = $directory . DIRECTORY_SEPARATOR . $localfilename; + + // filename collision. try again + if ( file_exists($full_localfilename) ) { + continue; + } + + // try to open for (binary) writing + $fp = @fopen( $full_localfilename, $filemods); + + if ($fp !== FALSE) { + // success! make sure it's not readable, close and return filename + chmod($full_localfilename, 0600); + fclose($fp); + return $localfilename; + } + + } + + // we tried as many times as we could but didn't succeed. + return FALSE; + +} + + +/** + * PHP's is_writable() is broken in some versions due to either + * safe_mode or because of problems correctly determining the + * actual file permissions under Windows. Under safe_mode or + * Windows, we'll try to actually write something in order to + * see for sure... + * + * @param string $path The full path to the file or directory to + * be tested + * + * @return boolean Whether or not the file or directory exists + * and is writable + * + * @since 1.5.2 + * + **/ +function sq_is_writable($path) { + + global $server_os; + + + // under *nix with safe_mode off, use the native is_writable() + // + if ($server_os == '*nix' && !(bool)ini_get('safe_mode')) + return is_writable($path); + + + // if it's a directory, that means we have to create a temporary + // file therein + // + $delete_temp_file = FALSE; + if (@is_dir($path) && ($temp_filename = @sq_create_tempfile($path))) + { + $path .= DIRECTORY_SEPARATOR . $temp_filename; + $delete_temp_file = TRUE; + } + + + // try to open the file for writing (without trying to create it) + // + if (!@is_dir($path) && ($FILE = @fopen($path, 'r+'))) + { + @fclose($FILE); + + // delete temp file if needed + // + if ($delete_temp_file) + @unlink($path); + + return TRUE; + } + + + // delete temp file if needed + // + if ($delete_temp_file) + @unlink($path); + + return FALSE; + +} + + +/** + * Find files and/or directories in a given directory optionally + * limited to only those with the given file extension. If the + * directory is not found or cannot be opened, no error is generated; + * only an empty file list is returned. +FIXME: do we WANT to throw an error or a notice or... or return FALSE? + * + * @param string $directory_path The path (relative or absolute) + * to the desired directory. + * @param mixed $extension The file extension filter - either + * an array of desired extension(s), + * or a comma-separated list of same + * (optional; default is to return + * all files (dirs). + * @param boolean $return_filenames_only When TRUE, only file/dir names + * are returned, otherwise the + * $directory_path string is + * prepended to each file/dir in + * the returned list (optional; + * default is filename/dirname only) + * @param boolean $include_directories When TRUE, directories are + * included (optional; default + * DO include directories). + * @param boolean $directories_only When TRUE, ONLY directories + * are included (optional; default + * is to include files too). + * @param boolean $separate_files_and_directories When TRUE, files and + * directories are returned + * in separate lists, so + * the return value is + * formatted as a two-element + * array with the two keys + * "FILES" and "DIRECTORIES", + * where corresponding values + * are lists of either all + * files or all directories + * (optional; default do not + * split up return array). + * @param boolean $only_sm When TRUE, a security check will + * limit directory access to only + * paths within the SquirrelMail + * installation currently being used + * (optional; default TRUE) + * + * @return array The requested file/directory list(s). + * + * @since 1.5.2 + * + */ +function list_files($directory_path, $extensions='', $return_filenames_only=TRUE, + $include_directories=TRUE, $directories_only=FALSE, + $separate_files_and_directories=FALSE, $only_sm=TRUE) { + + $files = array(); + $directories = array(); + + + // make sure requested path is under SM_PATH if needed + // + if ($only_sm) { + if (strpos(realpath($directory_path), realpath(SM_PATH)) !== 0) { + //plain_error_message(_("Illegal filesystem access was requested")); + echo _("Illegal filesystem access was requested"); + exit; + } + } + + + // validate given directory + // + if (empty($directory_path) + || !is_dir($directory_path) + || !($DIR = opendir($directory_path))) { + return $files; + } + + + // ensure extensions is an array and is properly formatted + // + if (!empty($extensions)) { + if (!is_array($extensions)) + $extensions = explode(',', $extensions); + $temp_extensions = array(); + foreach ($extensions as $ext) + $temp_extensions[] = '.' . trim(trim($ext), '.'); + $extensions = $temp_extensions; + } else $extensions = array(); + + + $directory_path = rtrim($directory_path, '/'); + + + // parse through the files + // + while (($file = readdir($DIR)) !== false) { + + if ($file == '.' || $file == '..') continue; + + if (!empty($extensions)) + foreach ($extensions as $ext) + if (strrpos($file, $ext) !== (strlen($file) - strlen($ext))) + continue 2; + + // only use is_dir() if we really need to (be as efficient as possible) + // + $is_dir = FALSE; + if (!$include_directories || $directories_only + || $separate_files_and_directories) { + if (is_dir($directory_path . '/' . $file)) { + if (!$include_directories) continue; + $is_dir = TRUE; + $directories[] = ($return_filenames_only + ? $file + : $directory_path . '/' . $file); + } + if ($directories_only) continue; + } + + if (!$separate_files_and_directories + || ($separate_files_and_directories && !$is_dir)) { + $files[] = ($return_filenames_only + ? $file + : $directory_path . '/' . $file); + } + + } + closedir($DIR); + + + if ($directories_only) return $directories; + if ($separate_files_and_directories) return array('FILES' => $files, + 'DIRECTORIES' => $directories); + return $files; + +} + + diff --git a/functions/global.php b/functions/global.php index 2916858c..7a77c256 100644 --- a/functions/global.php +++ b/functions/global.php @@ -623,143 +623,6 @@ function php_self () { } -/** - * Find files and/or directories in a given directory optionally - * limited to only those with the given file extension. If the - * directory is not found or cannot be opened, no error is generated; - * only an empty file list is returned. -FIXME: do we WANT to throw an error or a notice or... or return FALSE? - * - * @param string $directory_path The path (relative or absolute) - * to the desired directory. - * @param mixed $extension The file extension filter - either - * an array of desired extension(s), - * or a comma-separated list of same - * (optional; default is to return - * all files (dirs). - * @param boolean $return_filenames_only When TRUE, only file/dir names - * are returned, otherwise the - * $directory_path string is - * prepended to each file/dir in - * the returned list (optional; - * default is filename/dirname only) - * @param boolean $include_directories When TRUE, directories are - * included (optional; default - * DO include directories). - * @param boolean $directories_only When TRUE, ONLY directories - * are included (optional; default - * is to include files too). - * @param boolean $separate_files_and_directories When TRUE, files and - * directories are returned - * in separate lists, so - * the return value is - * formatted as a two-element - * array with the two keys - * "FILES" and "DIRECTORIES", - * where corresponding values - * are lists of either all - * files or all directories - * (optional; default do not - * split up return array). - * @param boolean $only_sm When TRUE, a security check will - * limit directory access to only - * paths within the SquirrelMail - * installation currently being used - * (optional; default TRUE) - * - * @return array The requested file/directory list(s). - * - * @since 1.5.2 - * - */ -function list_files($directory_path, $extensions='', $return_filenames_only=TRUE, - $include_directories=TRUE, $directories_only=FALSE, - $separate_files_and_directories=FALSE, $only_sm=TRUE) { - - $files = array(); - $directories = array(); - - - // make sure requested path is under SM_PATH if needed - // - if ($only_sm) { - if (strpos(realpath($directory_path), realpath(SM_PATH)) !== 0) { - //plain_error_message(_("Illegal filesystem access was requested")); - echo _("Illegal filesystem access was requested"); - exit; - } - } - - - // validate given directory - // - if (empty($directory_path) - || !is_dir($directory_path) - || !($DIR = opendir($directory_path))) { - return $files; - } - - - // ensure extensions is an array and is properly formatted - // - if (!empty($extensions)) { - if (!is_array($extensions)) - $extensions = explode(',', $extensions); - $temp_extensions = array(); - foreach ($extensions as $ext) - $temp_extensions[] = '.' . trim(trim($ext), '.'); - $extensions = $temp_extensions; - } else $extensions = array(); - - - $directory_path = rtrim($directory_path, '/'); - - - // parse through the files - // - while (($file = readdir($DIR)) !== false) { - - if ($file == '.' || $file == '..') continue; - - if (!empty($extensions)) - foreach ($extensions as $ext) - if (strrpos($file, $ext) !== (strlen($file) - strlen($ext))) - continue 2; - - // only use is_dir() if we really need to (be as efficient as possible) - // - $is_dir = FALSE; - if (!$include_directories || $directories_only - || $separate_files_and_directories) { - if (is_dir($directory_path . '/' . $file)) { - if (!$include_directories) continue; - $is_dir = TRUE; - $directories[] = ($return_filenames_only - ? $file - : $directory_path . '/' . $file); - } - if ($directories_only) continue; - } - - if (!$separate_files_and_directories - || ($separate_files_and_directories && !$is_dir)) { - $files[] = ($return_filenames_only - ? $file - : $directory_path . '/' . $file); - } - - } - closedir($DIR); - - - if ($directories_only) return $directories; - if ($separate_files_and_directories) return array('FILES' => $files, - 'DIRECTORIES' => $directories); - return $files; - -} - - /** * Print variable * @@ -856,3 +719,5 @@ function sq_htmlspecialchars($value, $quote_style=ENT_QUOTES) { return $value; } + + diff --git a/include/init.php b/include/init.php index 228999cc..a024f8f1 100644 --- a/include/init.php +++ b/include/init.php @@ -190,6 +190,7 @@ require(SM_PATH . 'include/constants.php'); require(SM_PATH . 'functions/global.php'); require(SM_PATH . 'functions/strings.php'); require(SM_PATH . 'functions/arrays.php'); +require(SM_PATH . 'functions/files.php'); /* load default configuration */ require(SM_PATH . 'config/config_default.php'); -- 2.25.1