X-Git-Url: https://vcs.fsf.org/?p=squirrelmail.git;a=blobdiff_plain;f=functions%2Fglobal.php;h=bd984edaca80f980716c85fc99d4f8e96c462350;hp=b9d63097676b9ba9bc4bafa85376d3ee88d4e86d;hb=45ca696232838b8cf8d6069f5fa2740b61dcc340;hpb=d7c82551df7a28530139681c44a283836be6b6fc diff --git a/functions/global.php b/functions/global.php index b9d63097..bd984eda 100644 --- a/functions/global.php +++ b/functions/global.php @@ -1,144 +1,998 @@ 0) { + foreach ($array as $index=>$value) { + if (is_array($array[$index])) { + sqstripslashes($array[$index]); + } + else { + $array[$index] = stripslashes($value); + } + } + } +} + +/** + * Add a variable to the session. + * @param mixed $var the variable to register + * @param string $name the name to refer to this variable + * @return void + */ +function sqsession_register ($var, $name) { + + sqsession_is_active(); + + $_SESSION[$name] = $var; +} + +/** + * Delete a variable from the session. + * @param string $name the name of the var to delete + * @return void */ +function sqsession_unregister ($name) { + sqsession_is_active(); -/* convert old-style superglobals to current method - * this is executed if you are running PHP 4.0.x. - * it is run via a require_once directive in validate.php - * and redirect.php. Patch submitted by Ray Black. - */ + unset($_SESSION[$name]); -if ( (float)substr(PHP_VERSION,0,3) < 4.1 ) { - global $_COOKIE, $_ENV, $_FILES, $_GET, $_POST, $_SERVER, $_SESSION; - global $HTTP_COOKIE_VARS, $HTTP_ENV_VARS, $HTTP_POST_FILES, $HTTP_GET_VARS, - $HTTP_POST_VARS, $HTTP_SERVER_VARS, $HTTP_SESSION_VARS; - $_COOKIE =& $HTTP_COOKIE_VARS; - $_ENV =& $HTTP_ENV_VARS; - $_FILES =& $HTTP_POST_FILES; - $_GET =& $HTTP_GET_VARS; - $_POST =& $HTTP_POST_VARS; - $_SERVER =& $HTTP_SERVER_VARS; - $_SESSION =& $HTTP_SESSION_VARS; + session_unregister("$name"); } -/* if running with register_globals = 0 and - magic_quotes_gpc then strip the slashes - from POST and GET global arrays */ +/** + * Checks to see if a variable has already been registered + * in the session. + * @param string $name the name of the var to check + * @return bool whether the var has been registered + */ +function sqsession_is_registered ($name) { + $test_name = &$name; + $result = false; -if (get_magic_quotes_gpc()) { - if (ini_get('register_globals') == 0) { - sqstripslashes($_GET); - sqstripslashes($_POST); + if (isset($_SESSION[$test_name])) { + $result = true; } + + return $result; } -/* strip any tags added to the url from PHP_SELF. - This fixes hand crafted url XXS expoits for any - page that uses PHP_SELF as the FORM action */ -strip_tags($_SERVER['PHP_SELF']); +/** + * Retrieves a form variable, from a set of possible similarly named + * form variables, based on finding a different, single field. This + * is intended to allow more than one same-named inputs in a single + *
, where the submit button that is clicked tells us which + * input we should retrieve. An example is if we have: + * + * + * + * and we want to know which one of the select inputs should be + * returned as $startMessage (without the suffix!), this function + * decides by looking for either "form_submit_1" or "form_submit_2" + * (both should not appear). In this example, $name should be + * "startMessage" and $indicator_field should be "form_submit". + * + * NOTE that form widgets must be named with the suffix "_1", "_2", "_3" + * and so on, or this function will not work. + * + * If more than one of the indicator fields is found, the first one + * (numerically) will win. + * + * If an indicator field is found without a matching input ($name) + * field, FALSE is returned. + * + * If no indicator fields are found, a field of $name *without* any + * suffix is searched for (but only if $fallback_no_suffix is TRUE), + * and if not found, FALSE is ultimately returned. + * + * It should also be possible to use the same string for both + * $name and $indicator_field to look for the first possible + * widget with a suffix that can be found (and possibly fallback + * to a widget without a suffix). + * + * @param string name the name of the var to search + * @param mixed value the variable to return + * @param string indicator_field the name of the field upon which to base + * our decision upon (see above) + * @param int search constant defining where to look + * @param bool fallback_no_suffix whether or not to look for $name with + * no suffix when nothing else is found + * @param mixed default the value to assign to $value when nothing is found + * @param int typecast force variable to be cast to given type (please + * use SQ_TYPE_XXX constants or set to FALSE (default) + * to leave variable type unmolested) + * + * @return bool whether variable is found. + */ +function sqGetGlobalVarMultiple($name, &$value, $indicator_field, + $search = SQ_INORDER, + $fallback_no_suffix=TRUE, $default=NULL, + $typecast=FALSE) { -function sqstripslashes(&$array) { - foreach ($array as $index=>$value) { - if (is_array($array["$index"])) { - sqstripslashes($array["$index"]); + // Set arbitrary max limit -- should be much lower except on the + // search results page, if there are many (50 or more?) mailboxes + // shown, this may not be high enough. Is there some way we should + // automate this value? + // + $max_form_search = 100; + + for ($i = 1; $i <= $max_form_search; $i++) { + if (sqGetGlobalVar($indicator_field . '_' . $i, $temp, $search)) { + return sqGetGlobalVar($name . '_' . $i, $value, $search, $default, $typecast); } - else { - $array["$index"] = stripslashes($value); + } + + + // no indicator field found; just try without suffix if allowed + // + if ($fallback_no_suffix) { + return sqGetGlobalVar($name, $value, $search, $default, $typecast); + } + + + // no dice, set default and return FALSE + // + if (!is_null($default)) { + $value = $default; + } + return FALSE; + +} + + +/** + * Search for the var $name in $_SESSION, $_POST, $_GET, $_COOKIE, or $_SERVER + * and set it in provided var. + * + * If $search is not provided, or if it is SQ_INORDER, it will search $_SESSION, + * then $_POST, then $_GET. If $search is SQ_FORM it will search $_POST and + * $_GET. Otherwise, use one of the defined constants to look for a var in one + * place specifically. + * + * Note: $search is an int value equal to one of the constants defined above. + * + * Example: + * sqgetGlobalVar('username',$username,SQ_SESSION); + * // No quotes around last param, it's a constant - not a string! + * + * @param string name the name of the var to search + * @param mixed value the variable to return + * @param int search constant defining where to look + * @param mixed default the value to assign to $value when nothing is found + * @param int typecast force variable to be cast to given type (please + * use SQ_TYPE_XXX constants or set to FALSE (default) + * to leave variable type unmolested) + * + * @return bool whether variable is found. + */ +function sqgetGlobalVar($name, &$value, $search = SQ_INORDER, $default = NULL, $typecast = false) { + + $result = false; + + switch ($search) { + /* we want the default case to be first here, + so that if a valid value isn't specified, + all three arrays will be searched. */ + default: + case SQ_INORDER: // check session, post, get + case SQ_SESSION: + if( isset($_SESSION[$name]) ) { + $value = $_SESSION[$name]; + $result = TRUE; + break; + } elseif ( $search == SQ_SESSION ) { + break; + } + case SQ_FORM: // check post, get + case SQ_POST: + if( isset($_POST[$name]) ) { + $value = $_POST[$name]; + $result = TRUE; + break; + } elseif ( $search == SQ_POST ) { + break; + } + case SQ_GET: + if ( isset($_GET[$name]) ) { + $value = $_GET[$name]; + $result = TRUE; + break; + } + /* NO IF HERE. FOR SQ_INORDER CASE, EXIT after GET */ + break; + case SQ_COOKIE: + if ( isset($_COOKIE[$name]) ) { + $value = $_COOKIE[$name]; + $result = TRUE; + break; + } + break; + case SQ_SERVER: + if ( isset($_SERVER[$name]) ) { + $value = $_SERVER[$name]; + $result = TRUE; + break; + } + break; + } + if ($result && $typecast) { + switch ($typecast) { + case SQ_TYPE_INT: $value = (int) $value; break; + case SQ_TYPE_STRING: $value = (string) $value; break; + case SQ_TYPE_BOOL: $value = (bool) $value; break; + default: break; } + } else if (!$result && !is_null($default)) { + $value = $default; } + return $result; } -function sqsession_register ($var, $name) { - if ( (float)substr(PHP_VERSION,0,3) < 4.1 ) { - global $HTTP_SESSION_VARS; - $HTTP_SESSION_VARS["$name"] = $var; +/** + * Deletes an existing session, more advanced than the standard PHP + * session_destroy(), it explicitly deletes the cookies and global vars. + * + * WARNING: Older PHP versions have some issues with session management. + * See http://bugs.php.net/11643 (warning, spammed bug tracker) and + * http://bugs.php.net/13834. SID constant is not destroyed in PHP 4.1.2, + * 4.2.3 and maybe other versions. If you restart session after session + * is destroyed, affected PHP versions produce PHP notice. Bug should + * be fixed only in 4.3.0 + */ +function sqsession_destroy() { + + /* + * php.net says we can kill the cookie by setting just the name: + * http://www.php.net/manual/en/function.setcookie.php + * maybe this will help fix the session merging again. + * + * Changed the theory on this to kill the cookies first starting + * a new session will provide a new session for all instances of + * the browser, we don't want that, as that is what is causing the + * merging of sessions. + */ + + global $base_uri, $_COOKIE, $_SESSION; + + if (isset($_COOKIE[session_name()]) && session_name()) sqsetcookie(session_name(), '', 0, $base_uri); + if (isset($_COOKIE['username']) && $_COOKIE['username']) sqsetcookie('username','',0,$base_uri); + if (isset($_COOKIE['key']) && $_COOKIE['key']) sqsetcookie('key','',0,$base_uri); + + $sessid = session_id(); + if (!empty( $sessid )) { + $_SESSION = array(); + @session_destroy(); } - else { - $_SESSION["$name"] = $var; +} + +/** + * Function to verify a session has been started. If it hasn't + * start a session up. php.net doesn't tell you that $_SESSION + * (even though autoglobal), is not created unless a session is + * started, unlike $_POST, $_GET and such + * Update: (see #1685031) the session ID is left over after the + * session is closed in some PHP setups; this function just becomes + * a passthru to sqsession_start(), but leaving old code in for + * edification. + */ +function sqsession_is_active() { + //$sessid = session_id(); + //if ( empty( $sessid ) ) { + sqsession_start(); + //} +} + +/** + * Function to start the session and store the cookie with the session_id as + * HttpOnly cookie which means that the cookie isn't accessible by javascript + * (IE6 only) + * Note that as sqsession_is_active() no longer discriminates as to when + * it calls this function, session_start() has to have E_NOTICE suppression + * (thus the @ sign). + */ +function sqsession_start() { + global $base_uri; + + @session_start(); + $session_id = session_id(); + + // session_starts sets the sessionid cookie buth without the httponly var + // setting the cookie again sets the httponly cookie attribute + sqsetcookie(session_name(),$session_id,false,$base_uri); +} + + +/** + * Set a cookie + * @param string $sName The name of the cookie. + * @param string $sValue The value of the cookie. + * @param int $iExpire The time the cookie expires. This is a Unix timestamp so is in number of seconds since the epoch. + * @param string $sPath The path on the server in which the cookie will be available on. + * @param string $sDomain The domain that the cookie is available. + * @param boolean $bSecure Indicates that the cookie should only be transmitted over a secure HTTPS connection. + * @param boolean $bHttpOnly Disallow JS to access the cookie (IE6 only) + * @return void + */ +function sqsetcookie($sName,$sValue='deleted',$iExpire=0,$sPath="",$sDomain="",$bSecure=false,$bHttpOnly=true) { + // if we have a secure connection then limit the cookies to https only. + if ($sName && isset($_SERVER['HTTPS']) && $_SERVER['HTTPS']) { + $bSecure = true; + } + + // admin config can override the restriction of secure-only cookies + global $only_secure_cookies; + if (!$only_secure_cookies) + $bSecure = false; + + if (false && check_php_version(5,2)) { + // php 5 supports the httponly attribute in setcookie, but because setcookie seems a bit + // broken we use the header function for php 5.2 as well. We might change that later. + //setcookie($sName,$sValue,(int) $iExpire,$sPath,$sDomain,$bSecure,$bHttpOnly); + } else { + if (!empty($Domain)) { + // Fix the domain to accept domains with and without 'www.'. + if (strtolower(substr($Domain, 0, 4)) == 'www.') $Domain = substr($Domain, 4); + $Domain = '.' . $Domain; + + // Remove port information. + $Port = strpos($Domain, ':'); + if ($Port !== false) $Domain = substr($Domain, 0, $Port); + } + if (!$sValue) $sValue = 'deleted'; + header('Set-Cookie: ' . rawurlencode($sName) . '=' . rawurlencode($sValue) + . (empty($iExpires) ? '' : '; expires=' . gmdate('D, d-M-Y H:i:s', $iExpires) . ' GMT') + . (empty($sPath) ? '' : '; path=' . $sPath) + . (empty($sDomain) ? '' : '; domain=' . $sDomain) + . (!$bSecure ? '' : '; secure') + . (!$bHttpOnly ? '' : '; HttpOnly'), false); } } -function sqsession_unregister ($name) { - if ( (float)substr(PHP_VERSION,0,3) < 4.1 ) { - global $HTTP_SESSION_VARS; - unset($HTTP_SESSION_VARS["$name"]); + +/** + * session_regenerate_id replacement for PHP < 4.3.2 + * + * This code is borrowed from Gallery, session.php version 1.53.2.1 + */ +if (!function_exists('session_regenerate_id')) { + function make_seed() { + list($usec, $sec) = explode(' ', microtime()); + return (float)$sec + ((float)$usec * 100000); + } + + function php_combined_lcg() { + mt_srand(make_seed()); + $tv = gettimeofday(); + $lcg['s1'] = $tv['sec'] ^ (~$tv['usec']); + $lcg['s2'] = mt_rand(); + $q = (int) ($lcg['s1'] / 53668); + $lcg['s1'] = (int) (40014 * ($lcg['s1'] - 53668 * $q) - 12211 * $q); + if ($lcg['s1'] < 0) { + $lcg['s1'] += 2147483563; + } + $q = (int) ($lcg['s2'] / 52774); + $lcg['s2'] = (int) (40692 * ($lcg['s2'] - 52774 * $q) - 3791 * $q); + if ($lcg['s2'] < 0) { + $lcg['s2'] += 2147483399; + } + $z = (int) ($lcg['s1'] - $lcg['s2']); + if ($z < 1) { + $z += 2147483562; + } + return $z * 4.656613e-10; + } + + function session_regenerate_id() { + global $base_uri; + $tv = gettimeofday(); + sqgetGlobalVar('REMOTE_ADDR',$remote_addr,SQ_SERVER); + $buf = sprintf("%.15s%ld%ld%0.8f", $remote_addr, $tv['sec'], $tv['usec'], php_combined_lcg() * 10); + session_id(md5($buf)); + if (ini_get('session.use_cookies')) { + // at a later stage we use sqsetcookie. At this point just do + // what session_regenerate_id would do + setcookie(session_name(), session_id(), NULL, $base_uri); + } + return TRUE; + } +} + + +/** + * php_self + * + * Creates an URL for the page calling this function, using either the PHP global + * REQUEST_URI, or the PHP global PHP_SELF with QUERY_STRING added. Before 1.5.1 + * function was stored in function/strings.php. + * + * @return string the complete url for this page + * @since 1.2.3 + */ +function php_self () { + if ( sqgetGlobalVar('REQUEST_URI', $req_uri, SQ_SERVER) && !empty($req_uri) ) { + return $req_uri; } - else { - unset($_SESSION["$name"]); + + if ( sqgetGlobalVar('PHP_SELF', $php_self, SQ_SERVER) && !empty($php_self) ) { + + // need to add query string to end of PHP_SELF to match REQUEST_URI + // + if ( sqgetGlobalVar('QUERY_STRING', $query_string, SQ_SERVER) && !empty($query_string) ) { + $php_self .= '?' . $query_string; + } + + return $php_self; } + + return ''; } -function sqsession_is_registered ($name) { - $test_name = &$name; - $result = false; - if ( (float)substr(PHP_VERSION,0,3) < 4.1 ) { - global $HTTP_SESSION_VARS; - if (isset($HTTP_SESSION_VARS[$test_name])) { - $result = true; + + +/** + * 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; } } - else { - if (isset($_SESSION[$test_name])) { - $result = true; + + + // 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); + } + } - return $result; + closedir($DIR); + + + if ($directories_only) return $directories; + if ($separate_files_and_directories) return array('FILES' => $files, + 'DIRECTORIES' => $directories); + return $files; + } /** - * Search for the var $name in $_SESSION, $_POST, $_GET - * (in that order) and register it as a global var. + * Print variable + * + * sm_print_r($some_variable, [$some_other_variable [, ...]]); + * + * Debugging function - does the same as print_r, but makes sure special + * characters are converted to htmlentities first. This will allow + * values like to be displayed. + * The output is wrapped in <
> and <
> tags. + * Since 1.4.2 accepts unlimited number of arguments. + * @since 1.4.1 + * @return void */ -function sqextractGlobalVar ($name) { - if ( (float)substr(PHP_VERSION,0,3) < 4.1 ) { - global $_SESSION, $_GET, $_POST; +function sm_print_r() { + ob_start(); // Buffer output + foreach(func_get_args() as $var) { + print_r($var); + echo "\n"; + // php has get_class_methods function that can print class methods + if (is_object($var)) { + // get class methods if $var is object + $aMethods=get_class_methods(get_class($var)); + // make sure that $aMethods is array and array is not empty + if (is_array($aMethods) && $aMethods!=array()) { + echo "Object methods:\n"; + foreach($aMethods as $method) { + echo '* ' . $method . "\n"; + } + } + echo "\n"; + } } - global $$name; - if( isset($_SESSION[$name]) ) { - $$name = $_SESSION[$name]; + $buffer = ob_get_contents(); // Grab the print_r output + ob_end_clean(); // Silently discard the output & stop buffering + print '
';
+    print htmlentities($buffer);
+    print '
'; +} + + +/** + * SquirrelMail wrapper for popen()/proc_open() + * + * This emulates popen() by using proc_open() if at all + * possible (reverts seamlessly to popen() if proc_open() + * is not supported in current PHP installation). + * + * This is intended for use with the related sq_pclose(), + * sq_get_pipe_stdout() and sq_get_pipe_stderr() functions, + * the latter of which add an easy interface for retrieving + * output from a child process that was opened with traditional + * popen() syntax (in write mode), while not breaking under + * earlier versions of PHP. + * + * @param string $command The command identifying what to + * execute in the child process. + * @param string $mode The desired mode for the + * unidirectional pipe that is returned; + * either 'r' for read or 'w' for write. + * + * @return resource A handle on the desired read or write pipe + * to the child process, or FALSE if the + * process cannot be created. + * + * @since 1.5.2 + * + */ +function sq_popen($command, $mode) { + + $mode = strtolower($mode{0}); + + + if (!function_exists('proc_open')) + return popen($command, $mode); + + + // set up our process store if not done already + // + global $processes; + if (empty($processes)) + $processes = array(); + + + // define read, write and error pipes + // + $descriptors = array(0 => array('pipe', 'r'), + 1 => array('pipe', 'w'), + 2 => array('pipe', 'w')); + + + // start the child process + // + $proc = proc_open($command, $descriptors, $pipes); + if (!is_resource($proc)) + return FALSE; + + + // when in read mode, we'll return a handle to the child's write pipe + // + if ($mode == 'r') + $return_value = $pipes[1]; + else if ($mode == 'w') + $return_value = $pipes[0]; + else + die('sq_popen() expects $mode to be "r" or "w"'); + + + // store the handle to the process and its pipes + // internally, keyed by whatever handle we'll be + // returning + // + $processes[$return_value] = array($proc, $pipes); + + + return $return_value; + +} + + +/** + * Get STDERR output from a child process + * + * This is designed to be used with processes that were + * opened with sq_popen(), and will return any output + * that may be available from STDERR of the child process + * at the current time. + * + * If a value is given for $timeout_seconds, this function + * will wait that long for output in case there is none + * right now. + * + * In PHP environments that do not support proc_open(), + * an empty string will always be returned. + * + * @param resource $handle The handle to the child process, + * as returned from sq_popen(). + * @param int $timeout_seconds The number of seconds to wait + * for output if there is none + * available immediately (OPTIONAL; + * default is not to wait) + * @param boolean $quiet When TRUE, errors are silently + * ignored (OPTIONAL; default is TRUE). + * + * @return string Any STDERR output that may have been found. + * + * @since 1.5.2 + * + */ +function sq_get_pipe_stderr($handle, $timeout_seconds=0, $quiet=TRUE) { + + // yes, we are testing for proc_OPEN + // because we need to know how the + // handle was actually OPENED + // + if (!function_exists('proc_open')) + return ''; + + + // get our process out of the process store + // + global $processes; + if (!is_array($processes) || !isset($processes[$handle])) { + if (!quiet) { + plain_error_message(_("Failed to find corresponding open process handle")); + } + return ''; } - if( isset($_POST[$name]) ) { - $$name = $_POST[$name]; + $proc = $processes[$handle]; + + + // get all we can from stderr, don't wait longer + // than our timeout for input + // + $contents = ''; + $read = array($proc[1][2]); + $write = NULL; + $except = NULL; + if (stream_select($read, $write, $except, $timeout_seconds)) + while (!feof($proc[1][2])) $contents .= fread($proc[1][2], 8192); + return $contents; + +} + + +/** + * Get STDOUT output from a child process + * + * This is designed to be used with processes that were + * opened with sq_popen(), and will return any output + * that may be available from STDOUT of the child process + * at the current time. + * + * If a value is given for $timeout_seconds, this function + * will wait that long for output in case there is none + * right now. + * + * In PHP environments that do not support proc_open(), + * an empty string will always be returned. + * + * @param resource $handle The handle to the child process, + * as returned from sq_popen(). + * @param int $timeout_seconds The number of seconds to wait + * for output if there is none + * available immediately (OPTIONAL; + * default is not to wait) + * @param boolean $quiet When TRUE, errors are silently + * ignored (OPTIONAL; default is TRUE). + * + * @return string Any STDOUT output that may have been found. + * + * @since 1.5.2 + * + */ +function sq_get_pipe_stdout($handle, $timeout_seconds=0, $quiet=TRUE) { + + // yes, we are testing for proc_OPEN + // because we need to know how the + // handle was actually OPENED + // + if (!function_exists('proc_open')) + return ''; + + + // get our process out of the process store + // + global $processes; + if (!is_array($processes) || !isset($processes[$handle])) { + if (!quiet) { + plain_error_message(_("Failed to find corresponding open process handle")); + } + return ''; } - else if ( isset($_GET[$name]) ) { - $$name = $_GET[$name]; + $proc = $processes[$handle]; + + + // get all we can from stdout, don't wait longer + // than our timeout for input + // + $contents = ''; + $read = array($proc[1][1]); + $write = NULL; + $except = NULL; + if (stream_select($read, $write, $except, $timeout_seconds)) + while (!feof($proc[1][1])) $contents .= fread($proc[1][1], 8192); + return $contents; + +} + + +/** + * SquirrelMail wrapper for pclose()/proc_close() + * + * This is designed to be used with processes that were + * opened with sq_popen(), and will correctly close + * all pipes/handles that were opened as well as the + * child process itself. + * + * @param resource $handle The handle to the child process, + * as returned from sq_popen(). + * @param boolean $quiet When TRUE, errors are silently + * ignored (OPTIONAL; default is TRUE). + * + * @return int The termination status of the child process. + * + * @since 1.5.2 + * + */ +function sq_pclose($handle, $quiet=TRUE) { + + // yes, we are testing for proc_OPEN + // because we need to know how the + // handle was actually OPENED + // + if (!function_exists('proc_open')) + return pclose($handle); + + + // get our process out of the process store + // + global $processes; + if (!is_array($processes) || !isset($processes[$handle])) { + if (!quiet) { + plain_error_message(_("Failed to find corresponding open process handle")); + } + return 127; } + $proc = $processes[$handle]; + unset($processes[$handle]); + + + // close all pipes + // + fclose($proc[1][0]); + fclose($proc[1][1]); + fclose($proc[1][2]); + + + // close process + // + return proc_close($proc[0]); + } -function sqsession_destroy() { - global $base_uri; - - if ( (float)substr(PHP_VERSION , 0 , 3) < 4.1) { - global $HTTP_SESSION_VARS; - $HTTP_SESSION_VARS = array(); - } - else { - $_SESSION = array(); - } - - /* - * now reset cookies to 5 seconds ago to delete from browser - */ - - @session_destroy(); - $cookie_params = session_get_cookie_params(); - setcookie(session_name(), '', time() - 5, $cookie_params['path'], - $cookie_params['domain']); - setcookie('username', '', time() - 5, $base_uri); - setcookie('key', '', time() - 5 , $base_uri); - -} - -?> + +/** + * Sanitize a value using htmlspecialchars() or similar, but also + * recursively run htmlspecialchars() (or similar) on array keys + * and values. + * + * If $value is not a string or an array with strings in it, + * the value is returned as is. + * + * @param mixed $value The value to be sanitized. + * @param mixed $quote_style Either boolean or an integer. If it + * is an integer, it must be the PHP + * constant indicating if/how to escape + * quotes: ENT_QUOTES, ENT_COMPAT, or + * ENT_NOQUOTES. If it is a boolean value, + * it must be TRUE and thus indicates + * that the only sanitizing to be done + * herein is to replace single and double + * quotes with ' and ", no other + * changes are made to $value. If it is + * boolean and FALSE, behavior reverts + * to same as if the value was ENT_QUOTES + * (OPTIONAL; default is ENT_QUOTES). + * + * @return mixed The sanitized value. + * + * @since 1.5.2 + * + **/ +function sq_htmlspecialchars($value, $quote_style=ENT_QUOTES) { + + if ($quote_style === FALSE) $quote_style = ENT_QUOTES; + + // array? go recursive... + // + if (is_array($value)) { + $return_array = array(); + foreach ($value as $key => $val) { + $return_array[sq_htmlspecialchars($key, $quote_style)] + = sq_htmlspecialchars($val, $quote_style); + } + return $return_array; + + // sanitize strings only + // + } else if (is_string($value)) { + if ($quote_style === TRUE) + return str_replace(array('\'', '"'), array(''', '"'), $value); + else + return htmlspecialchars($value, $quote_style); + } + + // anything else gets returned with no changes + // + return $value; + +}