Various performance and initialisation issues:
authorTim Starling <tstarling@users.mediawiki.org>
Sun, 2 Jul 2006 15:57:59 +0000 (15:57 +0000)
committerTim Starling <tstarling@users.mediawiki.org>
Sun, 2 Jul 2006 15:57:59 +0000 (15:57 +0000)
* Made autoloader work for unserialize()
* Made XmlFunctions.php and HttpFunctions.php autoloadable modules, via Http:: and Xml::
* Made Image class autoloadable, global functions moved to ImageFunctions.php where they can be loaded on every invocation.
* Removed some unnecessary require_once() calls
* Deferred $wgValidSkinNames initialisation
* Fixed a couple of silly construct/initialise splits. My idea from C++ experience, bad practice in PHP.
* Deferred skin initialisation in ParserOptions
* Removed $wgMwRedir during an attempt to make MagicWord autoloadable. Didn't complete that, but removing the global is still the right direction.

17 files changed:
includes/AutoLoader.php
includes/Database.php
includes/DefaultSettings.php
includes/GlobalFunctions.php
includes/HttpFunctions.php
includes/Image.php
includes/ImageFunctions.php [new file with mode: 0644]
includes/MessageCache.php
includes/Parser.php
includes/Setup.php
includes/Skin.php
includes/SpecialPage.php
includes/SpecialPreferences.php
includes/Title.php
includes/Xml.php [new file with mode: 0644]
includes/XmlFunctions.php
maintenance/parserTests.inc

index 6bfbd30..3cf9396 100644 (file)
@@ -1,6 +1,9 @@
 <?php
 
 /* This defines autoloading handler for whole MediaWiki framework */
+
+ini_set('unserialize_callback_func', '__autoload' );
+
 function __autoload($className) {
        global $wgAutoloadClasses;
 
@@ -83,6 +86,7 @@ function __autoload($className) {
                'HistoryBlobCurStub' => 'includes/HistoryBlob.php',
                'HTMLCacheUpdate' => 'includes/HTMLCacheUpdate.php',
                'HTMLCacheUpdateJob' => 'includes/HTMLCacheUpdate.php',
+               'Http' => 'includes/HttpFunctions.php',
                'Image' => 'includes/Image.php',
                'ThumbnailImage' => 'includes/Image.php',
                'ImageGallery' => 'includes/ImageGallery.php',
@@ -215,6 +219,7 @@ function __autoload($className) {
                'WikiError' => 'includes/WikiError.php',
                'WikiErrorMsg' => 'includes/WikiError.php',
                'WikiXmlError' => 'includes/WikiError.php',
+               'Xml' => 'includes/Xml.php',
                'ZhClient' => 'includes/ZhClient.php',
                'memcached' => 'includes/memcached-client.php',
                'UtfNormal' => 'includes/normal/UtfNormal.php'
@@ -224,7 +229,19 @@ function __autoload($className) {
        } elseif ( isset( $wgAutoloadClasses[$className] ) ) {
                $filename = $wgAutoloadClasses[$className];
        } else {
-               return;
+               # Try a different capitalisation
+               # The case can sometimes be wrong when unserializing PHP 4 objects
+               $filename = false;
+               $lowerClass = strtolower( $className );
+               foreach ( $localClasses as $class2 => $file2 ) {
+                       if ( strtolower( $class2 ) == $lowerClass ) {
+                               $filename = $file2;
+                       }
+               }
+               if ( !$filename ) {
+                       # Give up
+                       return;
+               }
        }
 
        # Make an absolute path, this improves performance by avoiding some stat calls
index 3704ee2..65ccd58 100644 (file)
@@ -5,11 +5,6 @@
  * @package MediaWiki
  */
 
-/**
- * Depends on the CacheManager
- */
-require_once( 'CacheManager.php' );
-
 /** See Database::makeList() */
 define( 'LIST_COMMA', 0 );
 define( 'LIST_AND', 1 );
index c907c48..979fc31 100644 (file)
@@ -1564,6 +1564,13 @@ $wgExtensionFunctions = array();
  */
 $wgSkinExtensionFunctions = array();
 
+/**
+ * List of valid skin names.
+ * The key should be the name in all lower case, the value should be a display name.
+ * The default skins will be added later, by Skin::getSkinNames(). Use 
+ * Skin::getSkinNames() as an accessor if you wish to have access to the full list.
+ */
+$wgValidSkinNames = array();
 
 /**
  * Special page list.
index 661b8a6..0abdda7 100644 (file)
@@ -1964,4 +1964,14 @@ function wfCreateObject( $name, $p ){
        }
 }
 
+/**
+ * Aliases for modularized functions
+ */
+function wfGetHTTP( $url, $timeout = 'default' ) { 
+       return Http::get( $url, $timeout ); 
+}
+function wfIsLocalURL( $url ) { 
+       return Http::isLocalURL( $url ); 
+}
+
 ?>
index fd2e87e..a9fb13c 100644 (file)
@@ -1,90 +1,91 @@
 <?php
-/**
- * Various HTTP related functions
- */
 
 /**
- * Get the contents of a file by HTTP
- *
- * if $timeout is 'default', $wgHTTPTimeout is used
+ * Various HTTP related functions
  */
-function wfGetHTTP( $url, $timeout = 'default' ) {
-       global $wgHTTPTimeout, $wgHTTPProxy, $wgVersion, $wgTitle;
+class Http {
+       /**
+        * Get the contents of a file by HTTP
+        *
+        * if $timeout is 'default', $wgHTTPTimeout is used
+        */
+       static function get( $url, $timeout = 'default' ) {
+               global $wgHTTPTimeout, $wgHTTPProxy, $wgVersion, $wgTitle;
 
-       # Use curl if available
-       if ( function_exists( 'curl_init' ) ) {
-               $c = curl_init( $url );
-               if ( wfIsLocalURL( $url ) ) {
-                       curl_setopt( $c, CURLOPT_PROXY, 'localhost:80' );
-               } else if ($wgHTTPProxy) {
-                       curl_setopt($c, CURLOPT_PROXY, $wgHTTPProxy);
-               }
+               # Use curl if available
+               if ( function_exists( 'curl_init' ) ) {
+                       $c = curl_init( $url );
+                       if ( wfIsLocalURL( $url ) ) {
+                               curl_setopt( $c, CURLOPT_PROXY, 'localhost:80' );
+                       } else if ($wgHTTPProxy) {
+                               curl_setopt($c, CURLOPT_PROXY, $wgHTTPProxy);
+                       }
 
-               if ( $timeout == 'default' ) {
-                       $timeout = $wgHTTPTimeout;
-               }
-               curl_setopt( $c, CURLOPT_TIMEOUT, $timeout );
-               curl_setopt( $c, CURLOPT_USERAGENT, "MediaWiki/$wgVersion" );
+                       if ( $timeout == 'default' ) {
+                               $timeout = $wgHTTPTimeout;
+                       }
+                       curl_setopt( $c, CURLOPT_TIMEOUT, $timeout );
+                       curl_setopt( $c, CURLOPT_USERAGENT, "MediaWiki/$wgVersion" );
 
-               # Set the referer to $wgTitle, even in command-line mode
-               # This is useful for interwiki transclusion, where the foreign
-               # server wants to know what the referring page is.
-               # $_SERVER['REQUEST_URI'] gives a less reliable indication of the
-               # referring page.
-               if ( is_object( $wgTitle ) ) {
-                       curl_setopt( $c, CURLOPT_REFERER, $wgTitle->getFullURL() );
-               }
+                       # Set the referer to $wgTitle, even in command-line mode
+                       # This is useful for interwiki transclusion, where the foreign
+                       # server wants to know what the referring page is.
+                       # $_SERVER['REQUEST_URI'] gives a less reliable indication of the
+                       # referring page.
+                       if ( is_object( $wgTitle ) ) {
+                               curl_setopt( $c, CURLOPT_REFERER, $wgTitle->getFullURL() );
+                       }
 
-               ob_start();
-               curl_exec( $c );
-               $text = ob_get_contents();
-               ob_end_clean();
+                       ob_start();
+                       curl_exec( $c );
+                       $text = ob_get_contents();
+                       ob_end_clean();
 
-               # Don't return the text of error messages, return false on error
-               if ( curl_getinfo( $c, CURLINFO_HTTP_CODE ) != 200 ) {
-                       $text = false;
+                       # Don't return the text of error messages, return false on error
+                       if ( curl_getinfo( $c, CURLINFO_HTTP_CODE ) != 200 ) {
+                               $text = false;
+                       }
+                       curl_close( $c );
+               } else {
+                       # Otherwise use file_get_contents, or its compatibility function from GlobalFunctions.php
+                       # This may take 3 minutes to time out, and doesn't have local fetch capabilities
+                       $url_fopen = ini_set( 'allow_url_fopen', 1 );
+                       $text = file_get_contents( $url );
+                       ini_set( 'allow_url_fopen', $url_fopen );
                }
-               curl_close( $c );
-       } else {
-               # Otherwise use file_get_contents, or its compatibility function from GlobalFunctions.php
-               # This may take 3 minutes to time out, and doesn't have local fetch capabilities
-               $url_fopen = ini_set( 'allow_url_fopen', 1 );
-               $text = file_get_contents( $url );
-               ini_set( 'allow_url_fopen', $url_fopen );
+               return $text;
        }
-       return $text;
-}
 
-/**
- * Check if the URL can be served by localhost
- */
-function wfIsLocalURL( $url ) {
-       global $wgCommandLineMode, $wgConf;
-       if ( $wgCommandLineMode ) {
-               return false;
-       }
+       /**
       * Check if the URL can be served by localhost
       */
+       static function isLocalURL( $url ) {
+               global $wgCommandLineMode, $wgConf;
+               if ( $wgCommandLineMode ) {
+                       return false;
+               }
 
-       // Extract host part
-       $matches = array();
-       if ( preg_match( '!^http://([\w.-]+)[/:].*$!', $url, $matches ) ) {
-               $host = $matches[1];
-               // Split up dotwise
-               $domainParts = explode( '.', $host );
-               // Check if this domain or any superdomain is listed in $wgConf as a local virtual host
-               $domainParts = array_reverse( $domainParts );
-               for ( $i = 0; $i < count( $domainParts ); $i++ ) {
-                       $domainPart = $domainParts[$i];
-                       if ( $i == 0 ) {
-                               $domain = $domainPart;
-                       } else {
-                               $domain = $domainPart . '.' . $domain;
-                       }
-                       if ( $wgConf->isLocalVHost( $domain ) ) {
-                               return true;
+               // Extract host part
+               $matches = array();
+               if ( preg_match( '!^http://([\w.-]+)[/:].*$!', $url, $matches ) ) {
+                       $host = $matches[1];
+                       // Split up dotwise
+                       $domainParts = explode( '.', $host );
+                       // Check if this domain or any superdomain is listed in $wgConf as a local virtual host
+                       $domainParts = array_reverse( $domainParts );
+                       for ( $i = 0; $i < count( $domainParts ); $i++ ) {
+                               $domainPart = $domainParts[$i];
+                               if ( $i == 0 ) {
+                                       $domain = $domainPart;
+                               } else {
+                                       $domain = $domainPart . '.' . $domain;
+                               }
+                               if ( $wgConf->isLocalVHost( $domain ) ) {
+                                       return true;
+                               }
                        }
                }
+               return false;
        }
-       return false;
 }
-
 ?>
index 16fc55b..ff21c4a 100644 (file)
@@ -2165,242 +2165,6 @@ class Image
        
 } //class
 
-
-/**
- * Returns the image directory of an image
- * If the directory does not exist, it is created.
- * The result is an absolute path.
- *
- * This function is called from thumb.php before Setup.php is included
- *
- * @param $fname String: file name of the image file.
- * @public
- */
-function wfImageDir( $fname ) {
-       global $wgUploadDirectory, $wgHashedUploadDirectory;
-
-       if (!$wgHashedUploadDirectory) { return $wgUploadDirectory; }
-
-       $hash = md5( $fname );
-       $oldumask = umask(0);
-       $dest = $wgUploadDirectory . '/' . $hash{0};
-       if ( ! is_dir( $dest ) ) { mkdir( $dest, 0777 ); }
-       $dest .= '/' . substr( $hash, 0, 2 );
-       if ( ! is_dir( $dest ) ) { mkdir( $dest, 0777 ); }
-
-       umask( $oldumask );
-       return $dest;
-}
-
-/**
- * Returns the image directory of an image's thubnail
- * If the directory does not exist, it is created.
- * The result is an absolute path.
- *
- * This function is called from thumb.php before Setup.php is included
- *
- * @param $fname String: file name of the original image file
- * @param $shared Boolean: (optional) use the shared upload directory (default: 'false').
- * @public
- */
-function wfImageThumbDir( $fname, $shared = false ) {
-       $base = wfImageArchiveDir( $fname, 'thumb', $shared );
-       if ( Image::isHashed( $shared ) ) {
-               $dir =  "$base/$fname";
-
-               if ( !is_dir( $base ) ) {
-                       $oldumask = umask(0);
-                       @mkdir( $base, 0777 );
-                       umask( $oldumask );
-               }
-
-               if ( ! is_dir( $dir ) ) {
-                       if ( is_file( $dir ) ) {
-                               // Old thumbnail in the way of directory creation, kill it
-                               unlink( $dir );
-                       }
-                       $oldumask = umask(0);
-                       @mkdir( $dir, 0777 );
-                       umask( $oldumask );
-               }
-       } else {
-               $dir = $base;
-       }
-
-       return $dir;
-}
-
-/**
- * Old thumbnail directory, kept for conversion
- */
-function wfDeprecatedThumbDir( $thumbName , $subdir='thumb', $shared=false) {
-       return wfImageArchiveDir( $thumbName, $subdir, $shared );
-}
-
-/**
- * Returns the image directory of an image's old version
- * If the directory does not exist, it is created.
- * The result is an absolute path.
- *
- * This function is called from thumb.php before Setup.php is included
- *
- * @param $fname String: file name of the thumbnail file, including file size prefix.
- * @param $subdir String: subdirectory of the image upload directory that should be used for storing the old version. Default is 'archive'.
- * @param $shared Boolean use the shared upload directory (only relevant for other functions which call this one). Default is 'false'.
- * @public
- */
-function wfImageArchiveDir( $fname , $subdir='archive', $shared=false ) {
-       global $wgUploadDirectory, $wgHashedUploadDirectory;
-       global $wgSharedUploadDirectory, $wgHashedSharedUploadDirectory;
-       $dir = $shared ? $wgSharedUploadDirectory : $wgUploadDirectory;
-       $hashdir = $shared ? $wgHashedSharedUploadDirectory : $wgHashedUploadDirectory;
-       if (!$hashdir) { return $dir.'/'.$subdir; }
-       $hash = md5( $fname );
-       $oldumask = umask(0);
-
-       # Suppress warning messages here; if the file itself can't
-       # be written we'll worry about it then.
-       wfSuppressWarnings();
-
-       $archive = $dir.'/'.$subdir;
-       if ( ! is_dir( $archive ) ) { mkdir( $archive, 0777 ); }
-       $archive .= '/' . $hash{0};
-       if ( ! is_dir( $archive ) ) { mkdir( $archive, 0777 ); }
-       $archive .= '/' . substr( $hash, 0, 2 );
-       if ( ! is_dir( $archive ) ) { mkdir( $archive, 0777 ); }
-
-       wfRestoreWarnings();
-       umask( $oldumask );
-       return $archive;
-}
-
-
-/*
- * Return the hash path component of an image path (URL or filesystem),
- * e.g. "/3/3c/", or just "/" if hashing is not used.
- *
- * @param $dbkey The filesystem / database name of the file
- * @param $fromSharedDirectory Use the shared file repository? It may
- *   use different hash settings from the local one.
- */
-function wfGetHashPath ( $dbkey, $fromSharedDirectory = false ) {
-       if( Image::isHashed( $fromSharedDirectory ) ) {
-               $hash = md5($dbkey);
-               return '/' . $hash{0} . '/' . substr( $hash, 0, 2 ) . '/';
-       } else {
-               return '/';
-       }
-}
-
-/**
- * Returns the image URL of an image's old version
- *
- * @param $name String: file name of the image file
- * @param $subdir String: (optional) subdirectory of the image upload directory that is used by the old version. Default is 'archive'
- * @public
- */
-function wfImageArchiveUrl( $name, $subdir='archive' ) {
-       global $wgUploadPath, $wgHashedUploadDirectory;
-
-       if ($wgHashedUploadDirectory) {
-               $hash = md5( substr( $name, 15) );
-               $url = $wgUploadPath.'/'.$subdir.'/' . $hash{0} . '/' .
-                 substr( $hash, 0, 2 ) . '/'.$name;
-       } else {
-               $url = $wgUploadPath.'/'.$subdir.'/'.$name;
-       }
-       return wfUrlencode($url);
-}
-
-/**
- * Return a rounded pixel equivalent for a labeled CSS/SVG length.
- * http://www.w3.org/TR/SVG11/coords.html#UnitIdentifiers
- *
- * @param $length String: CSS/SVG length.
- * @return Integer: length in pixels
- */
-function wfScaleSVGUnit( $length ) {
-       static $unitLength = array(
-               'px' => 1.0,
-               'pt' => 1.25,
-               'pc' => 15.0,
-               'mm' => 3.543307,
-               'cm' => 35.43307,
-               'in' => 90.0,
-               ''   => 1.0, // "User units" pixels by default
-               '%'  => 2.0, // Fake it!
-               );
-       if( preg_match( '/^(\d+(?:\.\d+)?)(em|ex|px|pt|pc|cm|mm|in|%|)$/', $length, $matches ) ) {
-               $length = floatval( $matches[1] );
-               $unit = $matches[2];
-               return round( $length * $unitLength[$unit] );
-       } else {
-               // Assume pixels
-               return round( floatval( $length ) );
-       }
-}
-
-/**
- * Compatible with PHP getimagesize()
- * @todo support gzipped SVGZ
- * @todo check XML more carefully
- * @todo sensible defaults
- *
- * @param $filename String: full name of the file (passed to php fopen()).
- * @return array
- */
-function wfGetSVGsize( $filename ) {
-       $width = 256;
-       $height = 256;
-
-       // Read a chunk of the file
-       $f = fopen( $filename, "rt" );
-       if( !$f ) return false;
-       $chunk = fread( $f, 4096 );
-       fclose( $f );
-
-       // Uber-crappy hack! Run through a real XML parser.
-       if( !preg_match( '/<svg\s*([^>]*)\s*>/s', $chunk, $matches ) ) {
-               return false;
-       }
-       $tag = $matches[1];
-       if( preg_match( '/\bwidth\s*=\s*("[^"]+"|\'[^\']+\')/s', $tag, $matches ) ) {
-               $width = wfScaleSVGUnit( trim( substr( $matches[1], 1, -1 ) ) );
-       }
-       if( preg_match( '/\bheight\s*=\s*("[^"]+"|\'[^\']+\')/s', $tag, $matches ) ) {
-               $height = wfScaleSVGUnit( trim( substr( $matches[1], 1, -1 ) ) );
-       }
-
-       return array( $width, $height, 'SVG',
-               "width=\"$width\" height=\"$height\"" );
-}
-
-/**
- * Determine if an image exists on the 'bad image list'.
- *
- * @param $name String: the image name to check
- * @return bool
- */
-function wfIsBadImage( $name ) {
-       static $titleList = false;
-       
-       if( !$titleList ) {
-               # Build the list now
-               $titleList = array();
-               $lines = explode( "\n", wfMsgForContent( 'bad_image_list' ) );
-               foreach( $lines as $line ) {
-                       if( preg_match( '/^\*\s*\[\[:?(.*?)\]\]/i', $line, $matches ) ) {
-                               $title = Title::newFromText( $matches[1] );
-                               if( is_object( $title ) && $title->getNamespace() == NS_IMAGE )
-                                       $titleList[ $title->getDBkey() ] = true;
-                       }
-               }
-       }
-       return array_key_exists( $name, $titleList );
-}
-
-
-
 /**
  * Wrapper class for thumbnail images
  * @package MediaWiki
@@ -2456,21 +2220,4 @@ class ThumbnailImage {
 
 }
 
-/**
- * Calculate the largest thumbnail width for a given original file size
- * such that the thumbnail's height is at most $maxHeight.
- * @param $boxWidth Integer Width of the thumbnail box.
- * @param $boxHeight Integer Height of the thumbnail box.
- * @param $maxHeight Integer Maximum height expected for the thumbnail.
- * @return Integer.
- */
-function wfFitBoxWidth( $boxWidth, $boxHeight, $maxHeight ) {
-       $idealWidth = $boxWidth * $maxHeight / $boxHeight;
-       $roundedUp = ceil( $idealWidth );
-       if( round( $roundedUp * $boxHeight / $boxWidth ) > $maxHeight )
-               return floor( $idealWidth );
-       else
-               return $roundedUp;
-}
-
 ?>
diff --git a/includes/ImageFunctions.php b/includes/ImageFunctions.php
new file mode 100644 (file)
index 0000000..c031d7e
--- /dev/null
@@ -0,0 +1,254 @@
+<?php\r
+\r
+/**\r
+ * Returns the image directory of an image\r
+ * If the directory does not exist, it is created.\r
+ * The result is an absolute path.\r
+ *\r
+ * This function is called from thumb.php before Setup.php is included\r
+ *\r
+ * @param $fname String: file name of the image file.\r
+ * @public\r
+ */\r
+function wfImageDir( $fname ) {\r
+       global $wgUploadDirectory, $wgHashedUploadDirectory;\r
+\r
+       if (!$wgHashedUploadDirectory) { return $wgUploadDirectory; }\r
+\r
+       $hash = md5( $fname );\r
+       $oldumask = umask(0);\r
+       $dest = $wgUploadDirectory . '/' . $hash{0};\r
+       if ( ! is_dir( $dest ) ) { mkdir( $dest, 0777 ); }\r
+       $dest .= '/' . substr( $hash, 0, 2 );\r
+       if ( ! is_dir( $dest ) ) { mkdir( $dest, 0777 ); }\r
+\r
+       umask( $oldumask );\r
+       return $dest;\r
+}\r
+\r
+/**\r
+ * Returns the image directory of an image's thubnail\r
+ * If the directory does not exist, it is created.\r
+ * The result is an absolute path.\r
+ *\r
+ * This function is called from thumb.php before Setup.php is included\r
+ *\r
+ * @param $fname String: file name of the original image file\r
+ * @param $shared Boolean: (optional) use the shared upload directory (default: 'false').\r
+ * @public\r
+ */\r
+function wfImageThumbDir( $fname, $shared = false ) {\r
+       $base = wfImageArchiveDir( $fname, 'thumb', $shared );\r
+       if ( Image::isHashed( $shared ) ) {\r
+               $dir =  "$base/$fname";\r
+\r
+               if ( !is_dir( $base ) ) {\r
+                       $oldumask = umask(0);\r
+                       @mkdir( $base, 0777 );\r
+                       umask( $oldumask );\r
+               }\r
+\r
+               if ( ! is_dir( $dir ) ) {\r
+                       if ( is_file( $dir ) ) {\r
+                               // Old thumbnail in the way of directory creation, kill it\r
+                               unlink( $dir );\r
+                       }\r
+                       $oldumask = umask(0);\r
+                       @mkdir( $dir, 0777 );\r
+                       umask( $oldumask );\r
+               }\r
+       } else {\r
+               $dir = $base;\r
+       }\r
+\r
+       return $dir;\r
+}\r
+\r
+/**\r
+ * Old thumbnail directory, kept for conversion\r
+ */\r
+function wfDeprecatedThumbDir( $thumbName , $subdir='thumb', $shared=false) {\r
+       return wfImageArchiveDir( $thumbName, $subdir, $shared );\r
+}\r
+\r
+/**\r
+ * Returns the image directory of an image's old version\r
+ * If the directory does not exist, it is created.\r
+ * The result is an absolute path.\r
+ *\r
+ * This function is called from thumb.php before Setup.php is included\r
+ *\r
+ * @param $fname String: file name of the thumbnail file, including file size prefix.\r
+ * @param $subdir String: subdirectory of the image upload directory that should be used for storing the old version. Default is 'archive'.\r
+ * @param $shared Boolean use the shared upload directory (only relevant for other functions which call this one). Default is 'false'.\r
+ * @public\r
+ */\r
+function wfImageArchiveDir( $fname , $subdir='archive', $shared=false ) {\r
+       global $wgUploadDirectory, $wgHashedUploadDirectory;\r
+       global $wgSharedUploadDirectory, $wgHashedSharedUploadDirectory;\r
+       $dir = $shared ? $wgSharedUploadDirectory : $wgUploadDirectory;\r
+       $hashdir = $shared ? $wgHashedSharedUploadDirectory : $wgHashedUploadDirectory;\r
+       if (!$hashdir) { return $dir.'/'.$subdir; }\r
+       $hash = md5( $fname );\r
+       $oldumask = umask(0);\r
+\r
+       # Suppress warning messages here; if the file itself can't\r
+       # be written we'll worry about it then.\r
+       wfSuppressWarnings();\r
+\r
+       $archive = $dir.'/'.$subdir;\r
+       if ( ! is_dir( $archive ) ) { mkdir( $archive, 0777 ); }\r
+       $archive .= '/' . $hash{0};\r
+       if ( ! is_dir( $archive ) ) { mkdir( $archive, 0777 ); }\r
+       $archive .= '/' . substr( $hash, 0, 2 );\r
+       if ( ! is_dir( $archive ) ) { mkdir( $archive, 0777 ); }\r
+\r
+       wfRestoreWarnings();\r
+       umask( $oldumask );\r
+       return $archive;\r
+}\r
+\r
+\r
+/*\r
+ * Return the hash path component of an image path (URL or filesystem),\r
+ * e.g. "/3/3c/", or just "/" if hashing is not used.\r
+ *\r
+ * @param $dbkey The filesystem / database name of the file\r
+ * @param $fromSharedDirectory Use the shared file repository? It may\r
+ *   use different hash settings from the local one.\r
+ */\r
+function wfGetHashPath ( $dbkey, $fromSharedDirectory = false ) {\r
+       if( Image::isHashed( $fromSharedDirectory ) ) {\r
+               $hash = md5($dbkey);\r
+               return '/' . $hash{0} . '/' . substr( $hash, 0, 2 ) . '/';\r
+       } else {\r
+               return '/';\r
+       }\r
+}\r
+\r
+/**\r
+ * Returns the image URL of an image's old version\r
+ *\r
+ * @param $name String: file name of the image file\r
+ * @param $subdir String: (optional) subdirectory of the image upload directory that is used by the old version. Default is 'archive'\r
+ * @public\r
+ */\r
+function wfImageArchiveUrl( $name, $subdir='archive' ) {\r
+       global $wgUploadPath, $wgHashedUploadDirectory;\r
+\r
+       if ($wgHashedUploadDirectory) {\r
+               $hash = md5( substr( $name, 15) );\r
+               $url = $wgUploadPath.'/'.$subdir.'/' . $hash{0} . '/' .\r
+                 substr( $hash, 0, 2 ) . '/'.$name;\r
+       } else {\r
+               $url = $wgUploadPath.'/'.$subdir.'/'.$name;\r
+       }\r
+       return wfUrlencode($url);\r
+}\r
+\r
+/**\r
+ * Return a rounded pixel equivalent for a labeled CSS/SVG length.\r
+ * http://www.w3.org/TR/SVG11/coords.html#UnitIdentifiers\r
+ *\r
+ * @param $length String: CSS/SVG length.\r
+ * @return Integer: length in pixels\r
+ */\r
+function wfScaleSVGUnit( $length ) {\r
+       static $unitLength = array(\r
+               'px' => 1.0,\r
+               'pt' => 1.25,\r
+               'pc' => 15.0,\r
+               'mm' => 3.543307,\r
+               'cm' => 35.43307,\r
+               'in' => 90.0,\r
+               ''   => 1.0, // "User units" pixels by default\r
+               '%'  => 2.0, // Fake it!\r
+               );\r
+       if( preg_match( '/^(\d+(?:\.\d+)?)(em|ex|px|pt|pc|cm|mm|in|%|)$/', $length, $matches ) ) {\r
+               $length = floatval( $matches[1] );\r
+               $unit = $matches[2];\r
+               return round( $length * $unitLength[$unit] );\r
+       } else {\r
+               // Assume pixels\r
+               return round( floatval( $length ) );\r
+       }\r
+}\r
+\r
+/**\r
+ * Compatible with PHP getimagesize()\r
+ * @todo support gzipped SVGZ\r
+ * @todo check XML more carefully\r
+ * @todo sensible defaults\r
+ *\r
+ * @param $filename String: full name of the file (passed to php fopen()).\r
+ * @return array\r
+ */\r
+function wfGetSVGsize( $filename ) {\r
+       $width = 256;\r
+       $height = 256;\r
+\r
+       // Read a chunk of the file\r
+       $f = fopen( $filename, "rt" );\r
+       if( !$f ) return false;\r
+       $chunk = fread( $f, 4096 );\r
+       fclose( $f );\r
+\r
+       // Uber-crappy hack! Run through a real XML parser.\r
+       if( !preg_match( '/<svg\s*([^>]*)\s*>/s', $chunk, $matches ) ) {\r
+               return false;\r
+       }\r
+       $tag = $matches[1];\r
+       if( preg_match( '/\bwidth\s*=\s*("[^"]+"|\'[^\']+\')/s', $tag, $matches ) ) {\r
+               $width = wfScaleSVGUnit( trim( substr( $matches[1], 1, -1 ) ) );\r
+       }\r
+       if( preg_match( '/\bheight\s*=\s*("[^"]+"|\'[^\']+\')/s', $tag, $matches ) ) {\r
+               $height = wfScaleSVGUnit( trim( substr( $matches[1], 1, -1 ) ) );\r
+       }\r
+\r
+       return array( $width, $height, 'SVG',\r
+               "width=\"$width\" height=\"$height\"" );\r
+}\r
+\r
+/**\r
+ * Determine if an image exists on the 'bad image list'.\r
+ *\r
+ * @param $name String: the image name to check\r
+ * @return bool\r
+ */\r
+function wfIsBadImage( $name ) {\r
+       static $titleList = false;\r
+       \r
+       if( !$titleList ) {\r
+               # Build the list now\r
+               $titleList = array();\r
+               $lines = explode( "\n", wfMsgForContent( 'bad_image_list' ) );\r
+               foreach( $lines as $line ) {\r
+                       if( preg_match( '/^\*\s*\[\[:?(.*?)\]\]/i', $line, $matches ) ) {\r
+                               $title = Title::newFromText( $matches[1] );\r
+                               if( is_object( $title ) && $title->getNamespace() == NS_IMAGE )\r
+                                       $titleList[ $title->getDBkey() ] = true;\r
+                       }\r
+               }\r
+       }\r
+       return array_key_exists( $name, $titleList );\r
+}\r
+\r
+/**\r
+ * Calculate the largest thumbnail width for a given original file size\r
+ * such that the thumbnail's height is at most $maxHeight.\r
+ * @param $boxWidth Integer Width of the thumbnail box.\r
+ * @param $boxHeight Integer Height of the thumbnail box.\r
+ * @param $maxHeight Integer Maximum height expected for the thumbnail.\r
+ * @return Integer.\r
+ */\r
+function wfFitBoxWidth( $boxWidth, $boxHeight, $maxHeight ) {\r
+       $idealWidth = $boxWidth * $maxHeight / $boxHeight;\r
+       $roundedUp = ceil( $idealWidth );\r
+       if( round( $roundedUp * $boxHeight / $boxWidth ) > $maxHeight )\r
+               return floor( $idealWidth );\r
+       else\r
+               return $roundedUp;\r
+}\r
+\r
+\r
+?>\r
index e5035c5..1247f3f 100644 (file)
@@ -25,7 +25,7 @@ class MessageCache {
        var $mInitialised = false;
        var $mDeferred = true;
 
-       function initialise( &$memCached, $useDB, $expiry, $memcPrefix) {
+       function __construct( &$memCached, $useDB, $expiry, $memcPrefix) {
                $fname = 'MessageCache::initialise';
                wfProfileIn( $fname );
 
@@ -39,7 +39,7 @@ class MessageCache {
                $this->mInitialised = true;
 
                wfProfileIn( $fname.'-parseropt' );
-               $this->mParserOptions = ParserOptions::newFromUser( $u=NULL );
+               $this->mParserOptions = new ParserOptions( $u=NULL );
                wfProfileOut( $fname.'-parseropt' );
                wfProfileIn( $fname.'-parser' );
                $this->mParser = new Parser;
@@ -558,9 +558,11 @@ class MessageCache {
         * @param string $lang The messages language, English by default
         */
        function addMessages( $messages, $lang = 'en' ) {
+               wfProfileIn( __METHOD__ );
                foreach ( $messages as $key => $value ) {
                        $this->addMessage( $key, $value, $lang );
                }
+               wfProfileOut( __METHOD__ );
        }
 
        /**
index 2fde2df..ec4349b 100644 (file)
@@ -6,10 +6,6 @@
  * @subpackage Parser
  */
 
-/** */
-require_once( 'Sanitizer.php' );
-require_once( 'HttpFunctions.php' );
-
 /**
  * Update this version number when the ParserOutput format
  * changes in an incompatible way, so the parser cache
@@ -3165,7 +3161,7 @@ class Parser
                        }
                }
 
-               $text = wfGetHTTP($url);
+               $text = Http::get($url);
                if (!$text)
                        return wfMsg('scarytranscludefailed', $url);
 
@@ -4605,12 +4601,13 @@ class ParserOptions
        var $mTidy;                      # Ask for tidy cleanup
        var $mInterfaceMessage;          # Which lang to call for PLURAL and GRAMMAR
 
+       var $mUser;                      # Stored user object, just used to initialise the skin
+
        function getUseTeX()                        { return $this->mUseTeX; }
        function getUseDynamicDates()               { return $this->mUseDynamicDates; }
        function getInterwikiMagic()                { return $this->mInterwikiMagic; }
        function getAllowExternalImages()           { return $this->mAllowExternalImages; }
        function getAllowExternalImagesFrom()       { return $this->mAllowExternalImagesFrom; }
-       function &getSkin()                         { return $this->mSkin; }
        function getDateFormat()                    { return $this->mDateFormat; }
        function getEditSection()                   { return $this->mEditSection; }
        function getNumberHeadings()                { return $this->mNumberHeadings; }
@@ -4618,6 +4615,13 @@ class ParserOptions
        function getTidy()                          { return $this->mTidy; }
        function getInterfaceMessage()              { return $this->mInterfaceMessage; }
 
+       function &getSkin() {
+               if ( !isset( $this->mSkin ) ) {
+                       $this->mSkin = $this->mUser->getSkin();
+               }
+               return $this->mSkin;
+       }
+
        function setUseTeX( $x )                    { return wfSetVar( $this->mUseTeX, $x ); }
        function setUseDynamicDates( $x )           { return wfSetVar( $this->mUseDynamicDates, $x ); }
        function setInterwikiMagic( $x )            { return wfSetVar( $this->mInterwikiMagic, $x ); }
@@ -4631,9 +4635,8 @@ class ParserOptions
        function setSkin( &$x ) { $this->mSkin =& $x; }
        function setInterfaceMessage( $x )          { return wfSetVar( $this->mInterfaceMessage, $x); }
 
-       function ParserOptions() {
-               global $wgUser;
-               $this->initialiseFromUser( $wgUser );
+       function ParserOptions( $user = null ) {
+               $this->initialiseFromUser( $user );
        }
 
        /**
@@ -4641,9 +4644,7 @@ class ParserOptions
         * @static
         */
        function newFromUser( &$user ) {
-               $popts = new ParserOptions;
-               $popts->initialiseFromUser( $user );
-               return $popts;
+               return new ParserOptions( $user );
        }
 
        /** Get user options */
@@ -4653,20 +4654,25 @@ class ParserOptions
                $fname = 'ParserOptions::initialiseFromUser';
                wfProfileIn( $fname );
                if ( !$userInput ) {
-                       $user = new User;
-                       $user->setLoaded( true );
+                       global $wgUser;
+                       if ( isset( $wgUser ) ) {
+                               $user = $wgUser;
+                       } else {
+                               $user = new User;
+                               $user->setLoaded( true );
+                       }
                } else {
                        $user =& $userInput;
                }
 
+               $this->mUser = $user;
+
                $this->mUseTeX = $wgUseTeX;
                $this->mUseDynamicDates = $wgUseDynamicDates;
                $this->mInterwikiMagic = $wgInterwikiMagic;
                $this->mAllowExternalImages = $wgAllowExternalImages;
                $this->mAllowExternalImagesFrom = $wgAllowExternalImagesFrom;
-               wfProfileIn( $fname.'-skin' );
-               $this->mSkin =& $user->getSkin();
-               wfProfileOut( $fname.'-skin' );
+               $this->mSkin = null; # Deferred
                $this->mDateFormat = $user->getOption( 'date' );
                $this->mEditSection = true;
                $this->mNumberHeadings = $user->getOption( 'numberheadings' );
index c2e89f2..469a691 100644 (file)
@@ -56,16 +56,14 @@ require_once( "$IP/includes/GlobalFunctions.php" );
 require_once( "$IP/includes/Hooks.php" );
 require_once( "$IP/includes/Namespace.php" );
 require_once( "$IP/includes/User.php" );
-require_once( "$IP/includes/Skin.php" );
 require_once( "$IP/includes/OutputPage.php" );
 require_once( "$IP/includes/MagicWord.php" );
-require_once( "$IP/includes/Block.php" );
 require_once( "$IP/includes/MessageCache.php" );
 require_once( "$IP/includes/Parser.php" );
 require_once( "$IP/includes/LoadBalancer.php" );
-require_once( "$IP/includes/HistoryBlob.php" );
 require_once( "$IP/includes/ProxyTools.php" );
 require_once( "$IP/includes/ObjectCache.php" );
+require_once( "$IP/includes/ImageFunctions.php" );
 
 if ( $wgUseDynamicDates ) {
        require_once( "$IP/includes/DateFormatter.php" );
@@ -254,8 +252,7 @@ if( $wgLangClass == $wgContLangClass ) {
 wfProfileOut( $fname.'-language2' );
 wfProfileIn( $fname.'-MessageCache' );
 
-$wgMessageCache = new MessageCache;
-$wgMessageCache->initialise( $parserMemc, $wgUseDatabaseMessages, $wgMsgCacheExpiry, $wgDBname);
+$wgMessageCache = new MessageCache( $parserMemc, $wgUseDatabaseMessages, $wgMsgCacheExpiry, $wgDBname);
 
 wfProfileOut( $fname.'-MessageCache' );
 
@@ -292,7 +289,6 @@ $wgDeferredUpdateList = array();
 $wgPostCommitUpdateList = array();
 
 $wgMagicWords = array();
-$wgMwRedir =& MagicWord::get( MAG_REDIRECT );
 
 if ( $wgUseXMLparser ) {
        require_once( 'ParserXML.php' );
index 6705fae..8a03f46 100644 (file)
@@ -9,26 +9,6 @@ if ( ! defined( 'MEDIAWIKI' ) )
  */
 
 # See skin.txt
-require_once( 'Linker.php' );
-require_once( 'Image.php' );
-
-# Get a list of available skins
-# Build using the regular expression '^(.*).php$'
-# Array keys are all lower case, array value keep the case used by filename
-#
-
-$skinDir = dir( $wgStyleDirectory );
-
-# while code from www.php.net
-while (false !== ($file = $skinDir->read())) {
-       // Skip non-PHP files, hidden files, and '.dep' includes
-       if(preg_match('/^([^.]*)\.php$/',$file, $matches)) {
-               $aSkin = $matches[1];
-               $wgValidSkinNames[strtolower($aSkin)] = $aSkin;
-       }
-}
-$skinDir->close();
-unset($matches);
 
 /**
  * The main skin class that provide methods and properties for all other skins.
@@ -53,8 +33,30 @@ class Skin extends Linker {
         * @return array of strings
         * @static
         */
-       function getSkinNames() {
+       function &getSkinNames() {
                global $wgValidSkinNames;
+               static $skinsInitialised = false;
+               if ( !$skinsInitialised ) {
+                       # Get a list of available skins
+                       # Build using the regular expression '^(.*).php$'
+                       # Array keys are all lower case, array value keep the case used by filename
+                       #
+                       wfProfileIn( __METHOD__ . '-init' );
+                       global $wgStyleDirectory;
+                       $skinDir = dir( $wgStyleDirectory );
+
+                       # while code from www.php.net
+                       while (false !== ($file = $skinDir->read())) {
+                               // Skip non-PHP files, hidden files, and '.dep' includes
+                               if(preg_match('/^([^.]*)\.php$/',$file, $matches)) {
+                                       $aSkin = $matches[1];
+                                       $wgValidSkinNames[strtolower($aSkin)] = $aSkin;
+                               }
+                       }
+                       $skinDir->close();
+                       $skinsInitialised = true;
+                       wfProfileOut( __METHOD__ . '-init' );
+               }
                return $wgValidSkinNames;
        }
 
index 10beb27..ffcd51f 100644 (file)
@@ -143,8 +143,6 @@ class SpecialPage
                global $wgSpecialPages;
                global $wgDisableCounters, $wgDisableInternalSearch, $wgEmailAuthentication;
 
-               #throw new MWException( __METHOD__ );
-
                if ( self::$mListInitialised ) {
                        return;
                }
index 114901e..5411db4 100644 (file)
@@ -447,7 +447,7 @@ class PreferencesForm {
         * @access private
         */
        function mainPrefsForm( $status , $message = '' ) {
-               global $wgUser, $wgOut, $wgLang, $wgContLang, $wgValidSkinNames;
+               global $wgUser, $wgOut, $wgLang, $wgContLang;
                global $wgAllowRealName, $wgImageLimits, $wgThumbLimits;
                global $wgDisableLangConversion;
                global $wgEnotifWatchlist, $wgEnotifUserTalk,$wgEnotifMinorEdits;
@@ -728,9 +728,10 @@ class PreferencesForm {
                $wgOut->addHTML( "<fieldset>\n<legend>\n" . wfMsg('skin') . "</legend>\n" );
                $mptitle = Title::newMainPage();
                $previewtext = wfMsg('skinpreview');
-               # Only show members of $wgValidSkinNames rather than
+               # Only show members of Skin::getSkinNames() rather than
                # $skinNames (skins is all skin names from Language.php)
-               foreach ($wgValidSkinNames as $skinkey => $skinname ) {
+               $validSkinNames = Skin::getSkinNames();
+               foreach ($validSkinNames as $skinkey => $skinname ) {
                        if ( in_array( $skinkey, $wgSkipSkins ) ) {
                                continue;
                        }
index 535b076..bc8f69a 100644 (file)
@@ -286,9 +286,9 @@ class Title {
         * @access public
         */
        function newFromRedirect( $text ) {
-               global $wgMwRedir;
+               $mwRedir = MagicWord::get( MAG_REDIRECT );
                $rt = NULL;
-               if ( $wgMwRedir->matchStart( $text ) ) {
+               if ( $mwRedir->matchStart( $text ) ) {
                        if ( preg_match( '/\[{2}(.*?)(?:\||\]{2})/', $text, $m ) ) {
                                # categories are escaped using : for example one can enter:
                                # #REDIRECT [[:Category:Music]]. Need to remove it.
@@ -1187,8 +1187,12 @@ class Title {
         * Check that the corresponding skin exists
         */
        function isValidCssJsSubpage() {
-               global $wgValidSkinNames;
-               return( $this->isCssJsSubpage() && array_key_exists( $this->getSkinFromCssJsSubpage(), $wgValidSkinNames ) );
+               if ( $this->isCssJsSubpage() ) {
+                       $skinNames = Skin::getSkinNames();
+                       return array_key_exists( $this->getSkinFromCssJsSubpage(), $skinNames );
+               } else {
+                       return false;
+               }
        }
        /**
         * Trim down a .css or .js subpage title to get the corresponding skin name
@@ -1854,7 +1858,7 @@ class Title {
         * @private
         */
        function moveOverExistingRedirect( &$nt, $reason = '' ) {
-               global $wgUseSquid, $wgMwRedir;
+               global $wgUseSquid;
                $fname = 'Title::moveOverExistingRedirect';
                $comment = wfMsgForContent( '1movedto2', $this->getPrefixedText(), $nt->getPrefixedText() );
 
@@ -1893,7 +1897,8 @@ class Title {
                $linkCache->clearLink( $nt->getPrefixedDBkey() );
 
                # Recreate the redirect, this time in the other direction.
-               $redirectText = $wgMwRedir->getSynonym( 0 ) . ' [[' . $nt->getPrefixedText() . "]]\n";
+               $mwRedir = MagicWord::get( MAG_REDIRECT );
+               $redirectText = $mwRedir->getSynonym( 0 ) . ' [[' . $nt->getPrefixedText() . "]]\n";
                $redirectArticle = new Article( $this );
                $newid = $redirectArticle->insertOn( $dbw );
                $redirectRevision = new Revision( array(
@@ -1933,7 +1938,6 @@ class Title {
         */
        function moveToNewTitle( &$nt, $reason = '' ) {
                global $wgUseSquid;
-               global $wgMwRedir;
                $fname = 'MovePageForm::moveToNewTitle';
                $comment = wfMsgForContent( '1movedto2', $this->getPrefixedText(), $nt->getPrefixedText() );
                if ( $reason ) {
@@ -1966,7 +1970,8 @@ class Title {
                $linkCache->clearLink( $nt->getPrefixedDBkey() );
 
                # Insert redirect
-               $redirectText = $wgMwRedir->getSynonym( 0 ) . ' [[' . $nt->getPrefixedText() . "]]\n";
+               $mwRedir = MagicWord::get( MAG_REDIRECT );
+               $redirectText = $mwRedir->getSynonym( 0 ) . ' [[' . $nt->getPrefixedText() . "]]\n";
                $redirectArticle = new Article( $this );
                $newid = $redirectArticle->insertOn( $dbw );
                $redirectRevision = new Revision( array(
diff --git a/includes/Xml.php b/includes/Xml.php
new file mode 100644 (file)
index 0000000..f911bdc
--- /dev/null
@@ -0,0 +1,279 @@
+<?php\r
+\r
+/**\r
+ * Module of static functions for generating XML\r
+ */\r
+\r
+class Xml {\r
+       /**\r
+        * Format an XML element with given attributes and, optionally, text content.\r
+        * Element and attribute names are assumed to be ready for literal inclusion.\r
+        * Strings are assumed to not contain XML-illegal characters; special\r
+        * characters (<, >, &) are escaped but illegals are not touched.\r
+        *\r
+        * @param $element String:\r
+        * @param $attribs Array: Name=>value pairs. Values will be escaped.\r
+        * @param $contents String: NULL to make an open tag only; '' for a contentless closed tag (default)\r
+        * @return string\r
+        */\r
+       function element( $element, $attribs = null, $contents = '') {\r
+               $out = '<' . $element;\r
+               if( !is_null( $attribs ) ) {\r
+                       foreach( $attribs as $name => $val ) {\r
+                               $out .= ' ' . $name . '="' . htmlspecialchars( $val ) . '"';\r
+                       }\r
+               }\r
+               if( is_null( $contents ) ) {\r
+                       $out .= '>';\r
+               } else {\r
+                       if( $contents === '' ) {\r
+                               $out .= ' />';\r
+                       } else {\r
+                               $out .= '>' . htmlspecialchars( $contents ) . "</$element>";\r
+                       }\r
+               }\r
+               return $out;\r
+       }\r
+\r
+       /**\r
+        * Format an XML element as with self::element(), but run text through the\r
+        * UtfNormal::cleanUp() validator first to ensure that no invalid UTF-8\r
+        * is passed.\r
+        *\r
+        * @param $element String:\r
+        * @param $attribs Array: Name=>value pairs. Values will be escaped.\r
+        * @param $contents String: NULL to make an open tag only; '' for a contentless closed tag (default)\r
+        * @return string\r
+        */\r
+       function elementClean( $element, $attribs = array(), $contents = '') {\r
+               if( $attribs ) {\r
+                       $attribs = array_map( array( 'UtfNormal', 'cleanUp' ), $attribs );\r
+               }\r
+               if( $contents ) {\r
+                       $contents = UtfNormal::cleanUp( $contents );\r
+               }\r
+               return self::element( $element, $attribs, $contents );\r
+       }\r
+\r
+       // Shortcuts\r
+       function openElement( $element, $attribs = null ) { return self::element( $element, $attribs, null ); }\r
+       function closeElement( $element ) { return "</$element>"; }\r
+\r
+       /**\r
+        * Create a namespace selector\r
+        *\r
+        * @param $selected Mixed: the namespace which should be selected, default ''\r
+        * @param $allnamespaces String: value of a special item denoting all namespaces. Null to not include (default)\r
+        * @param $includehidden Bool: include hidden namespaces?\r
+        * @return String: Html string containing the namespace selector\r
+        */\r
+       function &namespaceSelector($selected = '', $allnamespaces = null, $includehidden=false) {\r
+               global $wgContLang;\r
+               if( $selected !== '' ) {\r
+                       if( is_null( $selected ) ) {\r
+                               // No namespace selected; let exact match work without hitting Main\r
+                               $selected = '';\r
+                       } else {\r
+                               // Let input be numeric strings without breaking the empty match.\r
+                               $selected = intval( $selected );\r
+                       }\r
+               }\r
+               $s = "<select id='namespace' name='namespace' class='namespaceselector'>\n\t";\r
+               $arr = $wgContLang->getFormattedNamespaces();\r
+               if( !is_null($allnamespaces) ) {\r
+                       $arr = array($allnamespaces => wfMsg('namespacesall')) + $arr;\r
+               }\r
+               foreach ($arr as $index => $name) {\r
+                       if ($index < NS_MAIN) continue;\r
+\r
+                       $name = $index !== 0 ? $name : wfMsg('blanknamespace');\r
+\r
+                       if ($index === $selected) {\r
+                               $s .= self::element("option",\r
+                                               array("value" => $index, "selected" => "selected"),\r
+                                               $name);\r
+                       } else {\r
+                               $s .= self::element("option", array("value" => $index), $name);\r
+                       }\r
+               }\r
+               $s .= "\n</select>\n";\r
+               return $s;\r
+       }\r
+\r
+       function span( $text, $class, $attribs=array() ) {\r
+               return self::element( 'span', array( 'class' => $class ) + $attribs, $text );\r
+       }\r
+\r
+       /**\r
+        * Convenience function to build an HTML text input field\r
+        * @return string HTML\r
+        */\r
+       function input( $name, $size=false, $value=false, $attribs=array() ) {\r
+               return self::element( 'input', array(\r
+                       'name' => $name,\r
+                       'size' => $size,\r
+                       'value' => $value ) + $attribs );\r
+       }\r
+\r
+       /**\r
+        * Internal function for use in checkboxes and radio buttons and such.\r
+        * @return array\r
+        */\r
+       function attrib( $name, $present = true ) {\r
+               return $present ? array( $name => $name ) : array();\r
+       }\r
+\r
+       /**\r
+        * Convenience function to build an HTML checkbox\r
+        * @return string HTML\r
+        */\r
+       function check( $name, $checked=false, $attribs=array() ) {\r
+               return self::element( 'input', array(\r
+                       'name' => $name,\r
+                       'type' => 'checkbox',\r
+                       'value' => 1 ) + self::attrib( 'checked', $checked ) +  $attribs );\r
+       }\r
+\r
+       /**\r
+        * Convenience function to build an HTML radio button\r
+        * @return string HTML\r
+        */\r
+       function radio( $name, $value, $checked=false, $attribs=array() ) {\r
+               return self::element( 'input', array(\r
+                       'name' => $name,\r
+                       'type' => 'radio',\r
+                       'value' => $value ) + self::attrib( 'checked', $checked ) + $attribs );\r
+       }\r
+\r
+       /**\r
+        * Convenience function to build an HTML form label\r
+        * @return string HTML\r
+        */\r
+       function label( $label, $id ) {\r
+               return self::element( 'label', array( 'for' => $id ), $label );\r
+       }\r
+\r
+       /**\r
+        * Convenience function to build an HTML text input field with a label\r
+        * @return string HTML\r
+        */\r
+       function inputLabel( $label, $name, $id, $size=false, $value=false, $attribs=array() ) {\r
+               return Xml::label( $label, $id ) .\r
+                       '&nbsp;' .\r
+                       self::input( $name, $size, $value, array( 'id' => $id ) + $attribs );\r
+       }\r
+\r
+       /**\r
+        * Convenience function to build an HTML checkbox with a label\r
+        * @return string HTML\r
+        */\r
+       function checkLabel( $label, $name, $id, $checked=false, $attribs=array() ) {\r
+               return self::check( $name, $checked, array( 'id' => $id ) + $attribs ) .\r
+                       '&nbsp;' .\r
+                       self::label( $label, $id );\r
+       }\r
+\r
+       /**\r
+        * Convenience function to build an HTML radio button with a label\r
+        * @return string HTML\r
+        */\r
+       function radioLabel( $label, $name, $value, $id, $checked=false, $attribs=array() ) {\r
+               return self::radio( $name, $value, $checked, array( 'id' => $id ) + $attribs ) .\r
+                       '&nbsp;' .\r
+                       self::label( $label, $id );\r
+       }\r
+\r
+       /**\r
+        * Convenience function to build an HTML submit button\r
+        * @param $value String: label text for the button\r
+        * @param $attribs Array: optional custom attributes\r
+        * @return string HTML\r
+        */\r
+       function submitButton( $value, $attribs=array() ) {\r
+               return self::element( 'input', array( 'type' => 'submit', 'value' => $value ) + $attribs );\r
+       }\r
+\r
+       /**\r
+        * Convenience function to build an HTML hidden form field.\r
+        * @todo Document $name parameter.\r
+        * @param $name FIXME\r
+        * @param $value String: label text for the button\r
+        * @param $attribs Array: optional custom attributes\r
+        * @return string HTML\r
+        */\r
+       function hidden( $name, $value, $attribs=array() ) {\r
+               return self::element( 'input', array(\r
+                       'name' => $name,\r
+                       'type' => 'hidden',\r
+                       'value' => $value ) + $attribs );\r
+       }\r
+\r
+       /**\r
+        * Returns an escaped string suitable for inclusion in a string literal\r
+        * for JavaScript source code.\r
+        * Illegal control characters are assumed not to be present.\r
+        *\r
+        * @param string $string\r
+        * @return string\r
+        */\r
+       function escapeJsString( $string ) {\r
+               // See ECMA 262 section 7.8.4 for string literal format\r
+               $pairs = array(\r
+                       "\\" => "\\\\",\r
+                       "\"" => "\\\"",\r
+                       '\'' => '\\\'',\r
+                       "\n" => "\\n",\r
+                       "\r" => "\\r",\r
+\r
+                       # To avoid closing the element or CDATA section\r
+                       "<" => "\\x3c",\r
+                       ">" => "\\x3e",\r
+               );\r
+               return strtr( $string, $pairs );\r
+       }\r
+\r
+       /**\r
+        * Check if a string is well-formed XML.\r
+        * Must include the surrounding tag.\r
+        *\r
+        * @param $text String: string to test.\r
+        * @return bool\r
+        *\r
+        * @todo Error position reporting return\r
+        */\r
+       function isWellFormed( $text ) {\r
+               $parser = xml_parser_create( "UTF-8" );\r
+\r
+               # case folding violates XML standard, turn it off\r
+               xml_parser_set_option( $parser, XML_OPTION_CASE_FOLDING, false );\r
+\r
+               if( !xml_parse( $parser, $text, true ) ) {\r
+                       $err = xml_error_string( xml_get_error_code( $parser ) );\r
+                       $position = xml_get_current_byte_index( $parser );\r
+                       //$fragment = $this->extractFragment( $html, $position );\r
+                       //$this->mXmlError = "$err at byte $position:\n$fragment";\r
+                       xml_parser_free( $parser );\r
+                       return false;\r
+               }\r
+               xml_parser_free( $parser );\r
+               return true;\r
+       }\r
+\r
+       /**\r
+        * Check if a string is a well-formed XML fragment.\r
+        * Wraps fragment in an \<html\> bit and doctype, so it can be a fragment\r
+        * and can use HTML named entities.\r
+        *\r
+        * @param $text String:\r
+        * @return bool\r
+        */\r
+       function isWellFormedXmlFragment( $text ) {\r
+               $html =\r
+                       Sanitizer::hackDocType() .\r
+                       '<html>' .\r
+                       $text .\r
+                       '</html>';\r
+               return Xml::isWellFormedXml( $html );\r
+       }\r
+}\r
+?>\r
index caec564..7bb2895 100644 (file)
 <?php
 
 /**
- * Format an XML element with given attributes and, optionally, text content.
- * Element and attribute names are assumed to be ready for literal inclusion.
- * Strings are assumed to not contain XML-illegal characters; special
- * characters (<, >, &) are escaped but illegals are not touched.
- *
- * @param $element String:
- * @param $attribs Array: Name=>value pairs. Values will be escaped.
- * @param $contents String: NULL to make an open tag only; '' for a contentless closed tag (default)
- * @return string
+ * Aliases for functions in the Xml module
  */
-function wfElement( $element, $attribs = null, $contents = '') {
-       $out = '<' . $element;
-       if( !is_null( $attribs ) ) {
-               foreach( $attribs as $name => $val ) {
-                       $out .= ' ' . $name . '="' . htmlspecialchars( $val ) . '"';
-               }
-       }
-       if( is_null( $contents ) ) {
-               $out .= '>';
-       } else {
-               if( $contents === '' ) {
-                       $out .= ' />';
-               } else {
-                       $out .= '>' . htmlspecialchars( $contents ) . "</$element>";
-               }
-       }
-       return $out;
+function wfElement( $element, $attribs = null, $contents = '') { 
+       return Xml::element( $element, $attribs, $contents ); 
 }
-
-/**
- * Format an XML element as with wfElement(), but run text through the
- * UtfNormal::cleanUp() validator first to ensure that no invalid UTF-8
- * is passed.
- *
- * @param $element String:
- * @param $attribs Array: Name=>value pairs. Values will be escaped.
- * @param $contents String: NULL to make an open tag only; '' for a contentless closed tag (default)
- * @return string
- */
 function wfElementClean( $element, $attribs = array(), $contents = '') {
-       if( $attribs ) {
-               $attribs = array_map( array( 'UtfNormal', 'cleanUp' ), $attribs );
-       }
-       if( $contents ) {
-               $contents = UtfNormal::cleanUp( $contents );
-       }
-       return wfElement( $element, $attribs, $contents );
+       return Xml::elementClean( $element, $attribs, $contents );
+}
+function wfOpenElement( $element, $attribs = null ) { 
+       return Xml::openElement( $element, $attribs ); 
+}
+function wfCloseElement( $element ) { 
+       return "</$element>"; 
 }
-
-// Shortcuts
-function wfOpenElement( $element, $attribs = null ) { return wfElement( $element, $attribs, null ); }
-function wfCloseElement( $element ) { return "</$element>"; }
-
-/**
- * Create a namespace selector
- *
- * @param $selected Mixed: the namespace which should be selected, default ''
- * @param $allnamespaces String: value of a special item denoting all namespaces. Null to not include (default)
- * @param $includehidden Bool: include hidden namespaces?
- * @return String: Html string containing the namespace selector
- */
 function &HTMLnamespaceselector($selected = '', $allnamespaces = null, $includehidden=false) {
-       global $wgContLang;
-       if( $selected !== '' ) {
-               if( is_null( $selected ) ) {
-                       // No namespace selected; let exact match work without hitting Main
-                       $selected = '';
-               } else {
-                       // Let input be numeric strings without breaking the empty match.
-                       $selected = intval( $selected );
-               }
-       }
-       $s = "<select id='namespace' name='namespace' class='namespaceselector'>\n\t";
-       $arr = $wgContLang->getFormattedNamespaces();
-       if( !is_null($allnamespaces) ) {
-               $arr = array($allnamespaces => wfMsg('namespacesall')) + $arr;
-       }
-       foreach ($arr as $index => $name) {
-               if ($index < NS_MAIN) continue;
-
-               $name = $index !== 0 ? $name : wfMsg('blanknamespace');
-
-               if ($index === $selected) {
-                       $s .= wfElement("option",
-                                       array("value" => $index, "selected" => "selected"),
-                                       $name);
-               } else {
-                       $s .= wfElement("option", array("value" => $index), $name);
-               }
-       }
-       $s .= "\n</select>\n";
-       return $s;
+       return Xml::namespaceSelector( $selected = '', $allnamespaces = null, $includehidden=false );
 }
-
 function wfSpan( $text, $class, $attribs=array() ) {
-       return wfElement( 'span', array( 'class' => $class ) + $attribs, $text );
+       return Xml::span( $text, $class, $attribs );
 }
-
-/**
- * Convenience function to build an HTML text input field
- * @return string HTML
- */
 function wfInput( $name, $size=false, $value=false, $attribs=array() ) {
-       return wfElement( 'input', array(
-               'name' => $name,
-               'size' => $size,
-               'value' => $value ) + $attribs );
+       return Xml::input( $name, $size, $value, $attribs );
 }
-
-/**
- * Internal function for use in checkboxes and radio buttons and such.
- * @return array
- */
 function wfAttrib( $name, $present = true ) {
-       return $present ? array( $name => $name ) : array();
+       return Xml::attrib( $name, $present );
 }
-
-/**
- * Convenience function to build an HTML checkbox
- * @return string HTML
- */
 function wfCheck( $name, $checked=false, $attribs=array() ) {
-       return wfElement( 'input', array(
-               'name' => $name,
-               'type' => 'checkbox',
-               'value' => 1 ) + wfAttrib( 'checked', $checked ) +  $attribs );
+       return Xml::check( $name, $checked, $attribs );
 }
-
-/**
- * Convenience function to build an HTML radio button
- * @return string HTML
- */
 function wfRadio( $name, $value, $checked=false, $attribs=array() ) {
-       return wfElement( 'input', array(
-               'name' => $name,
-               'type' => 'radio',
-               'value' => $value ) + wfAttrib( 'checked', $checked ) + $attribs );
+       return Xml::radio( $name, $value, $checked, $attribs );
 }
-
-/**
- * Convenience function to build an HTML form label
- * @return string HTML
- */
 function wfLabel( $label, $id ) {
-       return wfElement( 'label', array( 'for' => $id ), $label );
+       return Xml::label( $label, $id );
 }
-
-/**
- * Convenience function to build an HTML text input field with a label
- * @return string HTML
- */
 function wfInputLabel( $label, $name, $id, $size=false, $value=false, $attribs=array() ) {
-       return wfLabel( $label, $id ) .
-               '&nbsp;' .
-               wfInput( $name, $size, $value, array( 'id' => $id ) + $attribs );
+       return Xml::inputLabel( $label, $name, $id, $size, $value, $attribs );
 }
-
-/**
- * Convenience function to build an HTML checkbox with a label
- * @return string HTML
- */
 function wfCheckLabel( $label, $name, $id, $checked=false, $attribs=array() ) {
-       return wfCheck( $name, $checked, array( 'id' => $id ) + $attribs ) .
-               '&nbsp;' .
-               wfLabel( $label, $id );
+       return Xml::checkLabel( $label, $name, $id, $checked, $attribs );
 }
-
-/**
- * Convenience function to build an HTML radio button with a label
- * @return string HTML
- */
 function wfRadioLabel( $label, $name, $value, $id, $checked=false, $attribs=array() ) {
-       return wfRadio( $name, $value, $checked, array( 'id' => $id ) + $attribs ) .
-               '&nbsp;' .
-               wfLabel( $label, $id );
+       return Xml::radioLabel( $label, $name, $value, $id, $checked, $attribs );
 }
-
-/**
- * Convenience function to build an HTML submit button
- * @param $value String: label text for the button
- * @param $attribs Array: optional custom attributes
- * @return string HTML
- */
 function wfSubmitButton( $value, $attribs=array() ) {
-       return wfElement( 'input', array( 'type' => 'submit', 'value' => $value ) + $attribs );
+       return Xml::submitButton( $value, $attribs );
 }
-
-/**
- * Convenience function to build an HTML hidden form field.
- * @todo Document $name parameter.
- * @param $name FIXME
- * @param $value String: label text for the button
- * @param $attribs Array: optional custom attributes
- * @return string HTML
- */
 function wfHidden( $name, $value, $attribs=array() ) {
-       return wfElement( 'input', array(
-               'name' => $name,
-               'type' => 'hidden',
-               'value' => $value ) + $attribs );
+       return Xml::hidden( $name, $value, $attribs );
 }
-
-/**
- * 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 );
+       return Xml::escapeJsString( $string );
 }
-
-/**
- * Check if a string is well-formed XML.
- * Must include the surrounding tag.
- *
- * @param $text String: string to test.
- * @return bool
- *
- * @todo Error position reporting return
- */
 function wfIsWellFormedXml( $text ) {
-       $parser = xml_parser_create( "UTF-8" );
-
-       # case folding violates XML standard, turn it off
-       xml_parser_set_option( $parser, XML_OPTION_CASE_FOLDING, false );
-
-       if( !xml_parse( $parser, $text, true ) ) {
-               $err = xml_error_string( xml_get_error_code( $parser ) );
-               $position = xml_get_current_byte_index( $parser );
-               //$fragment = $this->extractFragment( $html, $position );
-               //$this->mXmlError = "$err at byte $position:\n$fragment";
-               xml_parser_free( $parser );
-               return false;
-       }
-       xml_parser_free( $parser );
-       return true;
+       return Xml::isWellFormed( $text );
 }
-
-/**
- * Check if a string is a well-formed XML fragment.
- * Wraps fragment in an \<html\> bit and doctype, so it can be a fragment
- * and can use HTML named entities.
- *
- * @param $text String:
- * @return bool
- */
 function wfIsWellFormedXmlFragment( $text ) {
-       $html =
-               Sanitizer::hackDocType() .
-               '<html>' .
-               $text .
-               '</html>';
-       return wfIsWellFormedXml( $html );
+       return Xml::isWellFormedXmlFragment( $text );
 }
 
 
index 3e1b2fd..9f93c4a 100644 (file)
@@ -360,7 +360,7 @@ class ParserTest {
                $GLOBALS['wgContLang'] = $langObj;
 
                $GLOBALS['wgLoadBalancer']->loadMasterPos();
-               $GLOBALS['wgMessageCache']->initialise( new BagOStuff(), false, 0, $GLOBALS['wgDBname'] );
+               $GLOBALS['wgMessageCache'] = new MessageCache( new BagOStuff(), false, 0, $GLOBALS['wgDBname'] );
                $this->setupDatabase();
 
                global $wgUser;