X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2FGlobalFunctions.php;h=7f5f3a82bd329a0f8ad1501464246e7c89abe95f;hb=4b1811dcb088d5eb589a7a43559c03003d3b9f71;hp=0ea76e5955dc783d619a2e4509df3d69bfbd49d8;hpb=d8e90514ab1a80545fad0dbe420a61480b177104;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/GlobalFunctions.php b/includes/GlobalFunctions.php index 0ea76e5955..7f5f3a82bd 100644 --- a/includes/GlobalFunctions.php +++ b/includes/GlobalFunctions.php @@ -9,33 +9,26 @@ * Some globals and requires needed */ -/** - * Total number of articles - * @global integer $wgNumberOfArticles - */ +/** Total number of articles */ $wgNumberOfArticles = -1; # Unset -/** - * Total number of views - * @global integer $wgTotalViews - */ + +/** Total number of views */ $wgTotalViews = -1; -/** - * Total number of edits - * @global integer $wgTotalEdits - */ + +/** Total number of edits */ $wgTotalEdits = -1; -require_once( 'DatabaseFunctions.php' ); -require_once( 'UpdateClasses.php' ); require_once( 'LogPage.php' ); require_once( 'normal/UtfNormalUtil.php' ); +require_once( 'XmlFunctions.php' ); /** * Compatibility functions - * PHP <4.3.x is not actively supported; 4.1.x and 4.2.x might or might not work. - * <4.1.x will not work, as we use a number of features introduced in 4.1.0 - * such as the new autoglobals. + * + * We more or less support PHP 5.0.x and up. + * Re-implementations of newer functions or functions in non-standard + * PHP extensions may be included here. */ if( !function_exists('iconv') ) { # iconv support is not in the default configuration and so may not be present. @@ -49,25 +42,10 @@ if( !function_exists('iconv') ) { } } -if( !function_exists('file_get_contents') ) { - # Exists in PHP 4.3.0+ - function file_get_contents( $filename ) { - return implode( '', file( $filename ) ); - } -} - -if( !function_exists('is_a') ) { - # Exists in PHP 4.2.0+ - function is_a( $object, $class_name ) { - return - (strcasecmp( get_class( $object ), $class_name ) == 0) || - is_subclass_of( $object, $class_name ); - } -} - # UTF-8 substr function based on a PHP manual comment if ( !function_exists( 'mb_substr' ) ) { function mb_substr( $str, $start ) { + $ar = array(); preg_match_all( '/./us', $str, $ar ); if( func_num_args() >= 3 ) { @@ -79,17 +57,6 @@ if ( !function_exists( 'mb_substr' ) ) { } } -if( !function_exists( 'floatval' ) ) { - /** - * First defined in PHP 4.2.0 - * @param mixed $var; - * @return float - */ - function floatval( $var ) { - return (float)$var; - } -} - if ( !function_exists( 'array_diff_key' ) ) { /** * Exists in PHP 5.1.0+ @@ -98,7 +65,7 @@ if ( !function_exists( 'array_diff_key' ) ) { */ function array_diff_key( $left, $right ) { $result = $left; - foreach ( $left as $key => $value ) { + foreach ( $left as $key => $unused ) { if ( isset( $right[$key] ) ) { unset( $result[$key] ); } @@ -107,31 +74,27 @@ if ( !function_exists( 'array_diff_key' ) ) { } } -// If it doesn't exist no ctype_* stuff will -if ( ! function_exists( 'ctype_alnum' ) ) - require_once 'compatability/ctype.php'; +/** + * Wrapper for clone(), for compatibility with PHP4-friendly extensions. + * PHP 5 won't let you declare a 'clone' function, even conditionally, + * so it has to be a wrapper with a different name. + */ +function wfClone( $object ) { + return clone( $object ); +} /** * Where as we got a random seed - * @var bool $wgTotalViews */ $wgRandomSeeded = false; /** * Seed Mersenne Twister - * Only necessary in PHP < 4.2.0 - * - * @return bool + * No-op for compatibility; only necessary in PHP < 4.2.0 */ function wfSeedRandom() { - global $wgRandomSeeded; - - if ( ! $wgRandomSeeded && version_compare( phpversion(), '4.2.0' ) < 0 ) { - $seed = hexdec(substr(md5(microtime()),-8)) & 0x7fffffff; - mt_srand( $seed ); - $wgRandomSeeded = true; - } + /* No-op */ } /** @@ -144,7 +107,7 @@ function wfSeedRandom() { function wfRandom() { # The maximum random value is "only" 2^31-1, so get two random # values to reduce the chance of dupes - $max = mt_getrandmax(); + $max = mt_getrandmax() + 1; $rand = number_format( (mt_rand() * $max + mt_rand()) / $max / $max, 12, '.', '' ); return $rand; @@ -154,7 +117,7 @@ function wfRandom() { * We want / and : to be included as literal characters in our title URLs. * %2F in the page titles seems to fatally break for some reason. * - * @param string $s + * @param $s String: * @return string */ function wfUrlencode ( $s ) { @@ -175,18 +138,30 @@ function wfUrlencode ( $s ) { * $wgDebugRawPage - if false, 'action=raw' hits will not result in debug output. * $wgDebugComments - if on, some debug items may appear in comments in the HTML output. * - * @param string $text - * @param bool $logonly Set true to avoid appearing in HTML when $wgDebugComments is set + * @param $text String + * @param $logonly Bool: set true to avoid appearing in HTML when $wgDebugComments is set */ function wfDebug( $text, $logonly = false ) { global $wgOut, $wgDebugLogFile, $wgDebugComments, $wgProfileOnly, $wgDebugRawPage; + static $recursion = 0; # Check for raw action using $_GET not $wgRequest, since the latter might not be initialised yet if ( isset( $_GET['action'] ) && $_GET['action'] == 'raw' && !$wgDebugRawPage ) { return; } - if ( isset( $wgOut ) && $wgDebugComments && !$logonly ) { + if ( $wgDebugComments && !$logonly ) { + if ( !isset( $wgOut ) ) { + return; + } + if ( !StubObject::isRealObject( $wgOut ) ) { + if ( $recursion ) { + return; + } + $recursion++; + $wgOut->_unstub(); + $recursion--; + } $wgOut->debug( $text ); } if ( '' != $wgDebugLogFile && !$wgProfileOnly ) { @@ -201,16 +176,18 @@ function wfDebug( $text, $logonly = false ) { * Send a line to a supplementary debug log file, if configured, or main debug log if not. * $wgDebugLogGroups[$logGroup] should be set to a filename to send to a separate log. * - * @param string $logGroup - * @param string $text - * @param bool $public Whether to log the event in the public log if no private + * @param $logGroup String + * @param $text String + * @param $public Bool: whether to log the event in the public log if no private * log file is specified, (default true) */ function wfDebugLog( $logGroup, $text, $public = true ) { - global $wgDebugLogGroups, $wgDBname; + global $wgDebugLogGroups; if( $text{strlen( $text ) - 1} != "\n" ) $text .= "\n"; if( isset( $wgDebugLogGroups[$logGroup] ) ) { - @error_log( "$wgDBname: $text", 3, $wgDebugLogGroups[$logGroup] ); + $time = wfTimestamp( TS_DB ); + $wiki = wfWikiID(); + @error_log( "$time $wiki: $text", 3, $wgDebugLogGroups[$logGroup] ); } else if ( $public === true ) { wfDebug( $text, true ); } @@ -218,7 +195,7 @@ function wfDebugLog( $logGroup, $text, $public = true ) { /** * Log for database errors - * @param string $text Database error message. + * @param $text String: database error message. */ function wfLogDBError( $text ) { global $wgDBerrorLog; @@ -232,16 +209,13 @@ function wfLogDBError( $text ) { /** * @todo document */ -function logProfilingData() { +function wfLogProfilingData() { global $wgRequestTime, $wgDebugLogFile, $wgDebugRawPage, $wgRequest; global $wgProfiling, $wgUser; - $now = wfTime(); - - list( $usec, $sec ) = explode( ' ', $wgRequestTime ); - $start = (float)$sec + (float)$usec; - $elapsed = $now - $start; if ( $wgProfiling ) { - $prof = wfGetProfilingOutput( $start, $elapsed ); + $now = wfTime(); + $elapsed = $now - $wgRequestTime; + $prof = wfGetProfilingOutput( $wgRequestTime, $elapsed ); $forward = ''; if( !empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) $forward = ' forwarded for ' . $_SERVER['HTTP_X_FORWARDED_FOR']; @@ -251,7 +225,8 @@ function logProfilingData() { $forward .= ' from ' . $_SERVER['HTTP_FROM']; if( $forward ) $forward = "\t(proxied via {$_SERVER['REMOTE_ADDR']}{$forward})"; - if( is_object($wgUser) && $wgUser->isAnon() ) + // Don't unstub $wgUser at this late stage just for statistics purposes + if( StubObject::isRealObject($wgUser) && $wgUser->isAnon() ) $forward .= ' anon'; $log = sprintf( "%s\t%04.3f\t%s\n", gmdate( 'YmdHis' ), $elapsed, @@ -271,28 +246,26 @@ function logProfilingData() { function wfReadOnly() { global $wgReadOnlyFile, $wgReadOnly; - if ( $wgReadOnly ) { - return true; + if ( !is_null( $wgReadOnly ) ) { + return (bool)$wgReadOnly; } if ( '' == $wgReadOnlyFile ) { return false; } - - // Set $wgReadOnly and unset $wgReadOnlyFile, for faster access next time + // Set $wgReadOnly for faster access next time if ( is_file( $wgReadOnlyFile ) ) { $wgReadOnly = file_get_contents( $wgReadOnlyFile ); } else { $wgReadOnly = false; } - $wgReadOnlyFile = ''; - return $wgReadOnly; + return (bool)$wgReadOnly; } /** * Get a message from anywhere, for the current user language. * - * Use wfMsgForContent() instead if the message should NOT + * Use wfMsgForContent() instead if the message should NOT * change depending on the user preferences. * * Note that the message may contain HTML, and is therefore @@ -300,8 +273,12 @@ function wfReadOnly() { * addWikiText will do the escaping for you. Use wfMsgHtml() * if you need an escaped message. * - * @param string lookup key for the message, usually + * @param $key String: lookup key for the message, usually * defined in languages/Language.php + * + * This function also takes extra optional parameters (not + * shown in the function definition), which can by used to + * insert variable text into the predefined message. */ function wfMsg( $key ) { $args = func_get_args(); @@ -315,29 +292,29 @@ function wfMsg( $key ) { function wfMsgNoTrans( $key ) { $args = func_get_args(); array_shift( $args ); - return wfMsgReal( $key, $args, true, false ); + return wfMsgReal( $key, $args, true, false, false ); } /** * Get a message from anywhere, for the current global language * set with $wgLanguageCode. - * - * Use this if the message should NOT change dependent on the - * language set in the user's preferences. This is the case for - * most text written into logs, as well as link targets (such as - * the name of the copyright policy page). Link titles, on the + * + * Use this if the message should NOT change dependent on the + * language set in the user's preferences. This is the case for + * most text written into logs, as well as link targets (such as + * the name of the copyright policy page). Link titles, on the * other hand, should be shown in the UI language. * - * Note that MediaWiki allows users to change the user interface - * language in their preferences, but a single installation + * Note that MediaWiki allows users to change the user interface + * language in their preferences, but a single installation * typically only contains content in one language. - * - * Be wary of this distinction: If you use wfMsg() where you should - * use wfMsgForContent(), a user of the software may have to + * + * Be wary of this distinction: If you use wfMsg() where you should + * use wfMsgForContent(), a user of the software may have to * customize over 70 messages in order to, e.g., fix a link in every * possible language. * - * @param string lookup key for the message, usually + * @param $key String: lookup key for the message, usually * defined in languages/Language.php */ function wfMsgForContent( $key ) { @@ -391,30 +368,32 @@ function wfMsgNoDBForContent( $key ) { /** * Really get a message - */ -function wfMsgReal( $key, $args, $useDB, $forContent=false, $transform = true ) { - $fname = 'wfMsgReal'; - wfProfileIn( $fname ); - + * @param $key String: key to get. + * @param $args + * @param $useDB Boolean + * @param $transform Boolean: Whether or not to transform the message. + * @param $forContent Boolean + * @return String: the requested message. + */ +function wfMsgReal( $key, $args, $useDB = true, $forContent=false, $transform = true ) { $message = wfMsgGetKey( $key, $useDB, $forContent, $transform ); $message = wfMsgReplaceArgs( $message, $args ); - wfProfileOut( $fname ); return $message; } /** - * This function provides the message source for messages to be edited which are *not* stored in the database -*/ - + * This function provides the message source for messages to be edited which are *not* stored in the database. + * @param $key String: + */ function wfMsgWeirdKey ( $key ) { $subsource = str_replace ( ' ' , '_' , $key ) ; - $source = wfMsg ( $subsource ) ; - if ( $source == "<{$subsource}>" ) { + $source = wfMsgForContentNoTrans( $subsource ) ; + if ( wfEmptyMsg( $subsource, $source) ) { # Try again with first char lower case $subsource = strtolower ( substr ( $subsource , 0 , 1 ) ) . substr ( $subsource , 1 ) ; - $source = wfMsg ( $subsource ) ; + $source = wfMsgForContentNoTrans( $subsource ) ; } - if ( $source == "<{$subsource}>" ) { + if ( wfEmptyMsg( $subsource, $source ) ) { # Didn't work either, return blank text $source = "" ; } @@ -427,14 +406,14 @@ function wfMsgWeirdKey ( $key ) { * @param bool $useDB * @param bool $forContent * @return string - * @access private + * @private */ function wfMsgGetKey( $key, $useDB, $forContent = false, $transform = true ) { - global $wgParser, $wgMsgParserOptions, $wgContLang, $wgMessageCache, $wgLang; + global $wgParser, $wgContLang, $wgMessageCache, $wgLang; if ( is_object( $wgMessageCache ) ) $transstat = $wgMessageCache->getTransform(); - + if( is_object( $wgMessageCache ) ) { if ( ! $transform ) $wgMessageCache->disableTransform(); @@ -457,13 +436,13 @@ function wfMsgGetKey( $key, $useDB, $forContent = false, $transform = true ) { if($message === false) $message = Language::getMessage($key); if ( $transform && strstr( $message, '{{' ) !== false ) { - $message = $wgParser->transformMsg($message, $wgMsgParserOptions); + $message = $wgParser->transformMsg($message, $wgMessageCache->getParserOptions() ); } } if ( is_object( $wgMessageCache ) && ! $transform ) $wgMessageCache->setTransform( $transstat ); - + return $message; } @@ -473,7 +452,7 @@ function wfMsgGetKey( $key, $useDB, $forContent = false, $transform = true ) { * @param string $message * @param array $args * @return string - * @access private + * @private */ function wfMsgReplaceArgs( $message, $args ) { # Fix windows line-endings @@ -481,16 +460,19 @@ function wfMsgReplaceArgs( $message, $args ) { $message = str_replace( "\r", '', $message ); // Replace arguments - if ( count( $args ) ) - if ( is_array( $args[0] ) ) - foreach ( $args[0] as $key => $val ) + if ( count( $args ) ) { + if ( is_array( $args[0] ) ) { + foreach ( $args[0] as $key => $val ) { $message = str_replace( '$' . $key, $val, $message ); - else { - foreach( $args as $n => $param ) - $replacementKeys['$' . ($n + 1)] = $param; - $message = strtr( $message, $replacementKeys ); + } + } else { + foreach( $args as $n => $param ) { + $replacementKeys['$' . ($n + 1)] = $param; + } + $message = strtr( $message, $replacementKeys ); + } } - + return $message; } @@ -529,15 +511,73 @@ function wfMsgWikiHtml( $key ) { return wfMsgReplaceArgs( $wgOut->parse( wfMsgGetKey( $key, true ), /* can't be set to false */ true ), $args ); } +/** + * Returns message in the requested format + * @param string $key Key of the message + * @param array $options Processing rules: + * parse: parses wikitext to html + * parseinline: parses wikitext to html and removes the surrounding p's added by parser or tidy + * escape: filters message trough htmlspecialchars + * replaceafter: parameters are substituted after parsing or escaping + * parsemag: ?? + */ +function wfMsgExt( $key, $options ) { + global $wgOut, $wgParser; + + $args = func_get_args(); + array_shift( $args ); + array_shift( $args ); + + if( !is_array($options) ) { + $options = array($options); + } + + $string = wfMsgGetKey( $key, true, false, false ); + + if( !in_array('replaceafter', $options) ) { + $string = wfMsgReplaceArgs( $string, $args ); + } + + if( in_array('parse', $options) ) { + $string = $wgOut->parse( $string, true, true ); + } elseif ( in_array('parseinline', $options) ) { + $string = $wgOut->parse( $string, true, true ); + $m = array(); + if( preg_match( "~^
(.*)\n?
$~", $string, $m ) ) { + $string = $m[1]; + } + } elseif ( in_array('parsemag', $options) ) { + global $wgTitle; + $parser = new Parser(); + $parserOptions = new ParserOptions(); + $parserOptions->setInterfaceMessage( true ); + $parser->startExternalParse( $wgTitle, $parserOptions, OT_MSG ); + $string = $parser->transformMsg( $string, $parserOptions ); + } + + if ( in_array('escape', $options) ) { + $string = htmlspecialchars ( $string ); + } + + if( in_array('replaceafter', $options) ) { + $string = wfMsgReplaceArgs( $string, $args ); + } + + return $string; +} + + /** * Just like exit() but makes a note of it. * Commits open transactions except if the error parameter is set + * + * @obsolete Please return control to the caller or throw an exception */ function wfAbruptExit( $error = false ){ global $wgLoadBalancer; static $called = false; if ( $called ){ - exit(); + exit( -1 ); } $called = true; @@ -552,43 +592,60 @@ function wfAbruptExit( $error = false ){ wfDebug('WARNING: Abrupt exit\n'); } - wfProfileClose(); - logProfilingData(); + wfLogProfilingData(); if ( !$error ) { $wgLoadBalancer->closeAll(); } - exit(); + exit( -1 ); } /** - * @todo document + * @obsolete Please return control the caller or throw an exception */ function wfErrorExit() { wfAbruptExit( true ); } /** - * Die with a backtrace - * This is meant as a debugging aid to track down where bad data comes from. - * Shouldn't be used in production code except maybe in "shouldn't happen" areas. + * Print a simple message and die, returning nonzero to the shell if any. + * Plain die() fails to return nonzero to the shell if you pass a string. + * @param string $msg + */ +function wfDie( $msg='' ) { + echo $msg; + die( 1 ); +} + +/** + * Throw a debugging exception. This function previously once exited the process, + * but now throws an exception instead, with similar results. * * @param string $msg Message shown when dieing. */ function wfDebugDieBacktrace( $msg = '' ) { - global $wgCommandLineMode; + throw new MWException( $msg ); +} - $backtrace = wfBacktrace(); - if ( $backtrace !== false ) { - if ( $wgCommandLineMode ) { - $msg .= "\nBacktrace:\n$backtrace"; - } else { - $msg .= "\nBacktrace:
\n$backtrace"; - } +/** + * Fetch server name for use in error reporting etc. + * Use real server name if available, so we know which machine + * in a server farm generated the current page. + * @return string + */ +function wfHostname() { + if ( function_exists( 'posix_uname' ) ) { + // This function not present on Windows + $uname = @posix_uname(); + } else { + $uname = false; + } + if( is_array( $uname ) && isset( $uname['nodename'] ) ) { + return $uname['nodename']; + } else { + # This may be a virtual server. + return $_SERVER['SERVER_NAME']; } - echo $msg; - echo wfReportTime()."\n"; - die( -1 ); } /** @@ -600,25 +657,10 @@ function wfDebugDieBacktrace( $msg = '' ) { global $wgRequestTime; $now = wfTime(); - list( $usec, $sec ) = explode( ' ', $wgRequestTime ); - $start = (float)$sec + (float)$usec; - $elapsed = $now - $start; - - # Use real server name if available, so we know which machine - # in a server farm generated the current page. - if ( function_exists( 'posix_uname' ) ) { - $uname = @posix_uname(); - } else { - $uname = false; - } - if( is_array( $uname ) && isset( $uname['nodename'] ) ) { - $hostname = $uname['nodename']; - } else { - # This may be a virtual server. - $hostname = $_SERVER['SERVER_NAME']; - } - $com = sprintf( "", - $hostname, $elapsed ); + $elapsed = $now - $wgRequestTime; + + $com = sprintf( "", + wfHostname(), $elapsed ); return $com; } @@ -693,7 +735,7 @@ function wfShowingResultsNum( $offset, $limit, $num ) { * @todo document */ function wfViewPrevNext( $offset, $limit, $link, $query = '', $atend = false ) { - global $wgUser, $wgLang; + global $wgLang; $fmtLimit = $wgLang->formatNum( $limit ); $prev = wfMsg( 'prevn', $fmtLimit ); $next = wfMsg( 'nextn', $fmtLimit ); @@ -707,7 +749,6 @@ function wfViewPrevNext( $offset, $limit, $link, $query = '', $atend = false ) { } } - $sk = $wgUser->getSkin(); if ( 0 != $offset ) { $po = $offset - $limit; if ( $po < 0 ) { $po = 0; } @@ -738,7 +779,7 @@ function wfViewPrevNext( $offset, $limit, $link, $query = '', $atend = false ) { * @todo document */ function wfNumLink( $offset, $limit, &$title, $query = '' ) { - global $wgUser, $wgLang; + global $wgLang; if ( '' == $query ) { $q = ''; } else { $q = $query.'&'; } $q .= 'limit='.$limit.'&offset='.$offset; @@ -758,6 +799,7 @@ function wfClientAcceptsGzip() { global $wgUseGzip; if( $wgUseGzip ) { # FIXME: we may want to blacklist some broken browsers + $m = array(); if( preg_match( '/\bgzip(?:;(q)=([0-9]+(?:\.[0-9]+)))?\b/', $_SERVER['HTTP_ACCEPT_ENCODING'], @@ -771,7 +813,13 @@ function wfClientAcceptsGzip() { } /** - * Yay, more global functions! + * Obtain the offset and limit values from the request string; + * used in special pages + * + * @param $deflimit Default limit if none supplied + * @param $optionname Name of a user preference to check against + * @return array + * */ function wfCheckLimits( $deflimit = 50, $optionname = 'rclimit' ) { global $wgRequest; @@ -790,8 +838,8 @@ function wfCheckLimits( $deflimit = 50, $optionname = 'rclimit' ) { */ function wfEscapeWikiText( $text ) { $text = str_replace( - array( '[', '|', '\'', 'ISBN ' , '://' , "\n=", '{{' ), - array( '[', '|', ''', 'ISBN ', '://' , "\n=", '{{' ), + array( '[', '|', '\'', 'ISBN ', 'RFC ', '://', "\n=", '{{' ), + array( '[', '|', ''', 'ISBN ', 'RFC ', '://', "\n=", '{{' ), htmlspecialchars($text) ); return $text; } @@ -817,46 +865,13 @@ function wfQuotedPrintable( $string, $charset = '' ) { return $out; } -/** - * Returns an escaped string suitable for inclusion in a string literal - * for JavaScript source code. - * Illegal control characters are assumed not to be present. - * - * @param string $string - * @return string - */ -function wfEscapeJsString( $string ) { - // See ECMA 262 section 7.8.4 for string literal format - $pairs = array( - "\\" => "\\\\", - "\"" => "\\\"", - '\'' => '\\\'', - "\n" => "\\n", - "\r" => "\\r", - - # To avoid closing the element or CDATA section - "<" => "\\x3c", - ">" => "\\x3e", - ); - return strtr( $string, $pairs ); -} /** * @todo document * @return float */ function wfTime() { - $st = explode( ' ', microtime() ); - return (float)$st[0] + (float)$st[1]; -} - -/** - * Changes the first character to an HTML entity - */ -function wfHtmlEscapeFirst( $text ) { - $ord = ord($text); - $newText = substr($text, 1); - return "$ord;$newText"; + return microtime(true); } /** @@ -934,7 +949,29 @@ function wfEscapeShellArg( ) { } if ( wfIsWindows() ) { - $retVal .= '"' . str_replace( '"','\"', $arg ) . '"'; + // Escaping for an MSVC-style command line parser + // Ref: http://mailman.lyra.org/pipermail/scite-interest/2002-March/000436.html + // Double the backslashes before any double quotes. Escape the double quotes. + $tokens = preg_split( '/(\\\\*")/', $arg, -1, PREG_SPLIT_DELIM_CAPTURE ); + $arg = ''; + $delim = false; + foreach ( $tokens as $token ) { + if ( $delim ) { + $arg .= str_replace( '\\', '\\\\', substr( $token, 0, -1 ) ) . '\\"'; + } else { + $arg .= $token; + } + $delim = !$delim; + } + // Double the backslashes before the end of the string, because + // we will soon add a quote + $m = array(); + if ( preg_match( '/^(.*?)(\\\\+)$/', $arg, $m ) ) { + $arg = $m[1] . str_replace( '\\', '\\\\', $m[2] ); + } + + // Add surrounding quotes + $retVal .= '"' . $arg . '"'; } else { $retVal .= escapeshellarg( $arg ); } @@ -1035,6 +1072,64 @@ function wfHttpError( $code, $label, $desc ) { "