* Global functions used everywhere
*/
-require_once dirname(__FILE__) . '/LogPage.php';
require_once dirname(__FILE__) . '/normal/UtfNormalUtil.php';
require_once dirname(__FILE__) . '/XmlFunctions.php';
}
}
+// Support for Wietse Venema's taint feature
+if ( !function_exists( 'istainted' ) ) {
+ function istainted( $var ) {
+ return 0;
+ }
+ function taint( $var, $level = 0 ) {}
+ function untaint( $var, $level = 0 ) {}
+ define( 'TC_HTML', 1 );
+ define( 'TC_SHELL', 1 );
+ define( 'TC_MYSQL', 1 );
+ define( 'TC_PCRE', 1 );
+ define( 'TC_SELF', 1 );
+}
/// @endcond
*/
function wfDebug( $text, $logonly = false ) {
global $wgOut, $wgDebugLogFile, $wgDebugComments, $wgProfileOnly, $wgDebugRawPage;
+ global $wgDebugLogPrefix;
static $recursion = 0;
static $cache = array(); // Cache of unoutputted messages
# Strip unprintables; they can switch terminal modes when binary data
# gets dumped, which is pretty annoying.
$text = preg_replace( '![\x00-\x08\x0b\x0c\x0e-\x1f]!', ' ', $text );
+ $text = $wgDebugLogPrefix . $text;
wfErrorLog( $text, $wgDebugLogFile );
}
}
*/
function wfDebugLog( $logGroup, $text, $public = true ) {
global $wgDebugLogGroups, $wgShowHostnames;
- if( $text{strlen( $text ) - 1} != "\n" ) $text .= "\n";
+ $text = trim($text)."\n";
if( isset( $wgDebugLogGroups[$logGroup] ) ) {
$time = wfTimestamp( TS_DB );
$wiki = wfWikiID();
return Language::factory( $langcode );
# $langcode is a string, but not a valid language code; use content language.
- wfDebug( 'Invalid language code passed to wfGetLangObj, falling back to content language.' );
+ wfDebug( "Invalid language code passed to wfGetLangObj, falling back to content language.\n" );
return $wgContLang;
}
* Behavior for conflicting options (e.g., parse+parseinline) is undefined.
*/
function wfMsgExt( $key, $options ) {
- global $wgOut, $wgParser;
+ global $wgOut;
$args = func_get_args();
array_shift( $args );
}
}
- if( in_array('content', $options) ) {
+ if( in_array('content', $options, true ) ) {
$forContent = true;
$langCode = true;
} elseif( array_key_exists('language', $options) ) {
$string = wfMsgGetKey( $key, /*DB*/true, $langCode, /*Transform*/false );
- if( !in_array('replaceafter', $options) ) {
+ if( !in_array('replaceafter', $options, true ) ) {
$string = wfMsgReplaceArgs( $string, $args );
}
- if( in_array('parse', $options) ) {
+ if( in_array('parse', $options, true ) ) {
$string = $wgOut->parse( $string, true, !$forContent );
- } elseif ( in_array('parseinline', $options) ) {
+ } elseif ( in_array('parseinline', $options, true ) ) {
$string = $wgOut->parse( $string, true, !$forContent );
$m = array();
if( preg_match( '/^<p>(.*)\n?<\/p>\n?$/sU', $string, $m ) ) {
$string = $m[1];
}
- } elseif ( in_array('parsemag', $options) ) {
+ } elseif ( in_array('parsemag', $options, true ) ) {
global $wgMessageCache;
if ( isset( $wgMessageCache ) ) {
- $string = $wgMessageCache->transform( $string, !$forContent );
+ $string = $wgMessageCache->transform( $string,
+ !$forContent,
+ is_object( $langCode ) ? $langCode : null );
}
}
- if ( in_array('escape', $options) ) {
+ if ( in_array('escape', $options, true ) ) {
$string = htmlspecialchars ( $string );
- } elseif ( in_array( 'escapenoentities', $options ) ) {
+ } elseif ( in_array( 'escapenoentities', $options, true ) ) {
$string = Sanitizer::escapeHtmlAllowEntities( $string );
}
- if( in_array('replaceafter', $options) ) {
+ if( in_array('replaceafter', $options, true ) ) {
$string = wfMsgReplaceArgs( $string, $args );
}
wfDebug("WARNING: Abrupt exit in $file at line $line\n");
}
} else {
- wfDebug('WARNING: Abrupt exit\n');
+ wfDebug("WARNING: Abrupt exit\n");
}
wfLogProfilingData();
}
if( is_array( $uname ) && isset( $uname['nodename'] ) ) {
$host = $uname['nodename'];
+ } elseif ( getenv( 'COMPUTERNAME' ) ) {
+ # Windows computer name
+ $host = getenv( 'COMPUTERNAME' );
} else {
# This may be a virtual server.
$host = $_SERVER['SERVER_NAME'];
} else {
$nlink = '<a href="' . $title->escapeLocalUrl( $q ) . "\" class=\"mw-nextlink\">{$next}</a>";
}
- $nums = wfNumLink( $offset, 20, $title, $query ) . ' | ' .
- wfNumLink( $offset, 50, $title, $query ) . ' | ' .
- wfNumLink( $offset, 100, $title, $query ) . ' | ' .
- wfNumLink( $offset, 250, $title, $query ) . ' | ' .
- wfNumLink( $offset, 500, $title, $query );
+ $nums = $wgLang->pipeList( array( wfNumLink( $offset, 20, $title, $query ),
+ wfNumLink( $offset, 50, $title, $query ),
+ wfNumLink( $offset, 100, $title, $query ),
+ wfNumLink( $offset, 250, $title, $query ),
+ wfNumLink( $offset, 500, $title, $query ) ) );
return wfMsg( 'viewprevnext', $plink, $nlink, $nums );
}
*/
function wfEscapeWikiText( $text ) {
$text = str_replace(
- array( '[', '|', ']', '\'', 'ISBN ', 'RFC ', '://', "\n=", '{{' ),
+ array( '[', '|', ']', '\'', 'ISBN ', 'RFC ', '://', "\n=", '{{' ), # }}
array( '[', '|', ']', ''', 'ISBN ', 'RFC ', '://', "\n=", '{{' ),
htmlspecialchars($text) );
return $text;
# This check may also protect against code injection in
# case of broken installations.
- if(! file_exists( $wgDiff3 ) ){
+ if( !$wgDiff3 || !file_exists( $wgDiff3 ) ) {
wfDebug( "diff3 not found\n" );
return false;
}
}
/**
- * @todo document
+ * A wrapper around the PHP function var_export().
+ * Either print it or add it to the regular output ($wgOut).
+ *
+ * @param $var A PHP variable to dump.
*/
function wfVarDump( $var ) {
global $wgOut;
*/
define('TS_POSTGRES', 7);
+/**
+ * DB2 format time
+ */
+define('TS_DB2', 8);
+
/**
* @param mixed $outputtype A timestamp in one of the supported formats, the
* function will autodetect which format is supplied
# TS_ORACLE
$uts = strtotime(preg_replace('/(\d\d)\.(\d\d)\.(\d\d)(\.(\d+))?/', "$1:$2:$3",
str_replace("+00:00", "UTC", $ts)));
- } elseif (preg_match('/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})Z$/', $ts, $da)) {
+ } elseif (preg_match('/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.*\d*)?Z$/', $ts, $da)) {
# TS_ISO_8601
- } elseif (preg_match('/^(\d{4})\-(\d\d)\-(\d\d) (\d\d):(\d\d):(\d\d)[\+\- ](\d\d)$/',$ts,$da)) {
+ } elseif (preg_match('/^(\d{4})\-(\d\d)\-(\d\d) (\d\d):(\d\d):(\d\d)\.*\d*[\+\- ](\d\d)$/',$ts,$da)) {
# TS_POSTGRES
- } elseif (preg_match('/^(\d{4})\-(\d\d)\-(\d\d) (\d\d):(\d\d):(\d\d) GMT$/',$ts,$da)) {
+ } elseif (preg_match('/^(\d{4})\-(\d\d)\-(\d\d) (\d\d):(\d\d):(\d\d)\.*\d* GMT$/',$ts,$da)) {
# TS_POSTGRES
} else {
# Bogus value; fall back to the epoch...
return gmdate( 'd-M-y h.i.s A', $uts) . ' +00:00';
case TS_POSTGRES:
return gmdate( 'Y-m-d H:i:s', $uts) . ' GMT';
+ case TS_DB2:
+ return gmdate( 'Y-m-d H:i:s', $uts);
default:
throw new MWException( 'wfTimestamp() called with illegal output type.');
}
$parserMemc->set( $key, array( 'html' => $parsed, 'hash' => md5( $notice ) ), 600 );
$notice = $parsed;
} else {
- wfDebug( 'wfGetCachedNotice called for ' . $name . ' with no $wgOut available' );
+ wfDebug( 'wfGetCachedNotice called for ' . $name . ' with no $wgOut available'."\n" );
$notice = '';
}
}
return $namespaceNotice;
}
-/**
- * Gets and returns the site-wide notice
- * @return $siteNotice The site-wide notice as set by $wgSiteNotice or MediaWiki:Sitenotice interface message
- */
function wfGetSiteNotice() {
- global $wgUser, $wgSiteNotice, $wgMajorSiteNoticeID;
+ global $wgUser, $wgSiteNotice;
$fname = 'wfGetSiteNotice';
wfProfileIn( $fname );
$siteNotice = '';
- $loggedIn = false;
-
- if( $wgUser instanceOf User && $wgUser->isLoggedIn() ) {
- $loggedIn = true;
- $siteNotice = wfGetCachedNotice('sitenotice');
- if($siteNotice === false)
- return '';
- } else {
- $siteNotice = wfGetCachedNotice('anonnotice');
- if($siteNotice === false) {
- $siteNotice = wfGetCachedNotice('sitenotice');
- if($siteNotice === false)
- return '';
- }
- }
-
- $encNotice = Xml::escapeJsString($siteNotice);
- $encClose = Xml::escapeJsString( wfMsg( 'sitenotice_close' ) );
- $id = intval( $wgMajorSiteNoticeID ) . "." . intval( wfMsgForContent( 'sitenotice_id' ) );
if( wfRunHooks( 'SiteNoticeBefore', array( &$siteNotice ) ) ) {
- if( $loggedIn ) {
- $siteNotice = <<<EOT
-<script type="text/javascript" language="JavaScript">
-<!--
-var cookieName = "dismissSiteNotice=";
-var cookiePos = document.cookie.indexOf(cookieName);
-var siteNoticeID = "$id";
-var siteNoticeValue = "$encNotice";
-var cookieValue = "";
-var msgClose = "$encClose";
-
-if (cookiePos > -1) {
- cookiePos = cookiePos + cookieName.length;
- var endPos = document.cookie.indexOf(";", cookiePos);
- if (endPos > -1) {
- cookieValue = document.cookie.substring(cookiePos, endPos);
- } else {
- cookieValue = document.cookie.substring(cookiePos);
- }
-}
-if (cookieValue != siteNoticeID) {
- function dismissNotice() {
- var date = new Date();
- date.setTime(date.getTime() + 30*86400*1000);
- document.cookie = cookieName + siteNoticeID + "; expires="+date.toGMTString() + "; path=/";
- var element = document.getElementById('siteNotice');
- element.parentNode.removeChild(element);
- }
- document.writeln('<table width="100%" id="mw-dismissable-notice"><tr><td width="80%">'+siteNoticeValue+'</td>');
- document.writeln('<td width="20%" align="right">[<a href="javascript:dismissNotice();">'+msgClose+'</a>]</td></tr></table>');
-}
--->
-</script>
-EOT;
+ if( is_object( $wgUser ) && $wgUser->isLoggedIn() ) {
+ $siteNotice = wfGetCachedNotice( 'sitenotice' );
} else {
- // Don't allow anons to dismiss the site notice
- $siteNotice = <<<EOT
-<script type="text/javascript" language="JavaScript">
-<!--
-document.writeln("$encNotice");
--->
-</script>
-EOT;
+ $anonNotice = wfGetCachedNotice( 'anonnotice' );
+ if( !$anonNotice ) {
+ $siteNotice = wfGetCachedNotice( 'sitenotice' );
+ } else {
+ $siteNotice = $anonNotice;
+ }
}
if( !$siteNotice ) {
$siteNotice = wfGetCachedNotice( 'default' );
/**
* Make directory, and make all parent directories if they don't exist
*
- * @param string $fullDir Full path to directory to create
+ * @param string $dir Full path to directory to create
* @param int $mode Chmod value to use, default is $wgDirectoryMode
* @return bool
*/
-function wfMkdirParents( $fullDir, $mode = null ) {
+function wfMkdirParents( $dir, $mode = null ) {
global $wgDirectoryMode;
- if( strval( $fullDir ) === '' )
- return true;
- if( file_exists( $fullDir ) )
- return true;
- // If not defined or isn't an int, set to default
- if ( is_null( $mode ) ) {
- $mode = $wgDirectoryMode;
- }
-
-
- # Go back through the paths to find the first directory that exists
- $currentDir = $fullDir;
- $createList = array();
- while ( strval( $currentDir ) !== '' && !file_exists( $currentDir ) ) {
- # Strip trailing slashes
- $currentDir = rtrim( $currentDir, '/\\' );
-
- # Add to create list
- $createList[] = $currentDir;
-
- # Find next delimiter searching from the end
- $p = max( strrpos( $currentDir, '/' ), strrpos( $currentDir, '\\' ) );
- if ( $p === false ) {
- $currentDir = false;
- } else {
- $currentDir = substr( $currentDir, 0, $p );
- }
- }
- if ( count( $createList ) == 0 ) {
- # Directory specified already exists
+ if( strval( $dir ) === '' || file_exists( $dir ) )
return true;
- } elseif ( $currentDir === false ) {
- # Went all the way back to root and it apparently doesn't exist
- wfDebugLog( 'mkdir', "Root doesn't exist?\n" );
- return false;
- }
- # Now go forward creating directories
- $createList = array_reverse( $createList );
- # Is the parent directory writable?
- if ( $currentDir === '' ) {
- $currentDir = '/';
- }
- if ( !is_writable( $currentDir ) ) {
- wfDebugLog( 'mkdir', "Not writable: $currentDir\n" );
- return false;
- }
+ if ( is_null( $mode ) )
+ $mode = $wgDirectoryMode;
- foreach ( $createList as $dir ) {
- # use chmod to override the umask, as suggested by the PHP manual
- if ( !mkdir( $dir, $mode ) || !chmod( $dir, $mode ) ) {
- wfDebugLog( 'mkdir', "Unable to create directory $dir\n" );
- return false;
- }
- }
- return true;
+ return mkdir( $dir, $mode, true ); // PHP5 <3
}
/**
* @return collected stdout as a string (trailing newlines stripped)
*/
function wfShellExec( $cmd, &$retval=null ) {
- global $IP, $wgMaxShellMemory, $wgMaxShellFileSize;
+ global $IP, $wgMaxShellMemory, $wgMaxShellFileSize, $wgMaxShellTime;
- if( wfIniGetBool( 'safe_mode' ) ) {
- wfDebug( "wfShellExec can't run in safe_mode, PHP's exec functions are too broken.\n" );
+ static $disabled;
+ if ( is_null( $disabled ) ) {
+ $disabled = false;
+ if( wfIniGetBool( 'safe_mode' ) ) {
+ wfDebug( "wfShellExec can't run in safe_mode, PHP's exec functions are too broken.\n" );
+ $disabled = true;
+ }
+ $functions = explode( ',', ini_get( 'disable_functions' ) );
+ $functions = array_map( 'trim', $functions );
+ $functions = array_map( 'strtolower', $functions );
+ if ( in_array( 'passthru', $functions ) ) {
+ wfDebug( "passthru is in disabled_functions\n" );
+ $disabled = true;
+ }
+ }
+ if ( $disabled ) {
$retval = 1;
return "Unable to run external programs in safe mode.";
}
+
wfInitShellLocale();
if ( php_uname( 's' ) == 'Linux' ) {
- $time = intval( ini_get( 'max_execution_time' ) );
+ $time = intval( $wgMaxShellTime );
$mem = intval( $wgMaxShellMemory );
$filesize = intval( $wgMaxShellFileSize );
}
/**
- * array_merge() does awful things with "numeric" indexes, including
- * string indexes when happen to look like integers. When we want
- * to merge arrays with arbitrary string indexes, we don't want our
- * arrays to be randomly corrupted just because some of them consist
- * of numbers.
- *
- * Fuck you, PHP. Fuck you in the ear!
+ * Backwards array plus for people who haven't bothered to read the PHP manual
+ * XXX: will not darn your socks for you.
*
* @param array $array1, [$array2, [...]]
* @return array
*/
function wfArrayMerge( $array1/* ... */ ) {
- $out = $array1;
- for( $i = 1; $i < func_num_args(); $i++ ) {
- foreach( func_get_arg( $i ) as $key => $value ) {
- $out[$key] = $value;
- }
+ $args = func_get_args();
+ $args = array_reverse( $args, true );
+ $out = array();
+ foreach ( $args as $arg ) {
+ $out += $arg;
}
return $out;
}
/**
- * Make a URL index, appropriate for the el_index field of externallinks.
+ * Merge arrays in the style of getUserPermissionsErrors, with duplicate removal
+ * e.g.
+ * wfMergeErrorArrays(
+ * array( array( 'x' ) ),
+ * array( array( 'x', '2' ) ),
+ * array( array( 'x' ) ),
+ * array( array( 'y') )
+ * );
+ * returns:
+ * array(
+ * array( 'x', '2' ),
+ * array( 'x' ),
+ * array( 'y' )
+ * )
*/
-function wfMakeUrlIndex( $url ) {
+function wfMergeErrorArrays(/*...*/) {
+ $args = func_get_args();
+ $out = array();
+ foreach ( $args as $errors ) {
+ foreach ( $errors as $params ) {
+ $spec = implode( "\t", $params );
+ $out[$spec] = $params;
+ }
+ }
+ return array_values( $out );
+}
+
+/**
+ * parse_url() work-alike, but non-broken. Differences:
+ *
+ * 1) Does not raise warnings on bad URLs (just returns false)
+ * 2) Handles protocols that don't use :// (e.g., mailto: and news:) correctly
+ * 3) Adds a "delimiter" element to the array, either '://' or ':' (see (2))
+ *
+ * @param string $url A URL to parse
+ * @return array Bits of the URL in an associative array, per PHP docs
+ */
+function wfParseUrl( $url ) {
global $wgUrlProtocols; // Allow all protocols defined in DefaultSettings/LocalSettings.php
wfSuppressWarnings();
$bits = parse_url( $url );
if ( !$bits ) {
return false;
}
+
// most of the protocols are followed by ://, but mailto: and sometimes news: not, check for it
- $delimiter = '';
- if ( in_array( $bits['scheme'] . '://' , $wgUrlProtocols ) ) {
- $delimiter = '://';
- } elseif ( in_array( $bits['scheme'] .':' , $wgUrlProtocols ) ) {
- $delimiter = ':';
+ if ( in_array( $bits['scheme'] . '://', $wgUrlProtocols ) ) {
+ $bits['delimiter'] = '://';
+ } elseif ( in_array( $bits['scheme'] . ':', $wgUrlProtocols ) ) {
+ $bits['delimiter'] = ':';
// parse_url detects for news: and mailto: the host part of an url as path
// We have to correct this wrong detection
if ( isset ( $bits['path'] ) ) {
return false;
}
+ return $bits;
+}
+
+/**
+ * Make a URL index, appropriate for the el_index field of externallinks.
+ */
+function wfMakeUrlIndex( $url ) {
+ $bits = wfParseUrl( $url );
+
// Reverse the labels in the hostname, convert to lower case
// For emails reverse domainpart only
if ( $bits['scheme'] == 'mailto' ) {
}
// Reconstruct the pseudo-URL
$prot = $bits['scheme'];
- $index = "$prot$delimiter$reversedHost";
+ $index = $prot . $bits['delimiter'] . $reversedHost;
// Leave out user and password. Add the port, path, query and fragment
if ( isset( $bits['port'] ) ) $index .= ':' . $bits['port'];
if ( isset( $bits['path'] ) ) {
* current version. An image object will be returned which
* was created at the specified time.
* @param mixed $flags FileRepo::FIND_ flags
+ * @param boolean $bypass Bypass the file cache even if it could be used
* @return File, or false if the file does not exist
*/
-function wfFindFile( $title, $time = false, $flags = 0 ) {
- return RepoGroup::singleton()->findFile( $title, $time, $flags );
+function wfFindFile( $title, $time = false, $flags = 0, $bypass = false ) {
+ if( !$time && !$flags && !$bypass ) {
+ return FileCache::singleton()->findFile( $title );
+ } else {
+ return RepoGroup::singleton()->findFile( $title, $time, $flags );
+ }
}
/**
}
}
+/**
+ * Output some plain text in command-line mode or in the installer (updaters.inc).
+ * Do not use it in any other context, its behaviour is subject to change.
+ */
+function wfOut( $s ) {
+ static $lineStarted = false;
+ global $wgCommandLineMode;
+ if ( $wgCommandLineMode && !defined( 'MEDIAWIKI_INSTALL' ) ) {
+ echo $s;
+ } else {
+ echo htmlspecialchars( $s );
+ }
+ flush();
+}
+
/** Generate a random 32-character hexadecimal token.
* @param mixed $salt Some sort of salt, if necessary, to add to random characters before hashing.
*/