Rename MWNamespace, MWDebug and MWTidy files to match their class
authorTimo Tijhof <krinklemail@gmail.com>
Tue, 15 Jul 2014 20:58:51 +0000 (22:58 +0200)
committerKrinkle <krinklemail@gmail.com>
Tue, 15 Jul 2014 20:59:39 +0000 (20:59 +0000)
Change-Id: I3e6d13ce366861c865401dde272bc2834a1de670

includes/AutoLoader.php
includes/MWNamespace.php [new file with mode: 0644]
includes/Namespace.php [deleted file]
includes/debug/Debug.php [deleted file]
includes/debug/MWDebug.php [new file with mode: 0644]
includes/parser/MWTidy.php [new file with mode: 0644]
includes/parser/Tidy.php [deleted file]

index ff01674..8b4895a 100644 (file)
@@ -136,7 +136,7 @@ $wgAutoloadLocalClasses = array(
        'MimeMagic' => 'includes/MimeMagic.php',
        'MWHookException' => 'includes/Hooks.php',
        'MWHttpRequest' => 'includes/HttpFunctions.php',
-       'MWNamespace' => 'includes/Namespace.php',
+       'MWNamespace' => 'includes/MWNamespace.php',
        'OutputPage' => 'includes/OutputPage.php',
        'Pager' => 'includes/Pager.php',
        'PasswordError' => 'includes/User.php',
@@ -463,7 +463,7 @@ $wgAutoloadLocalClasses = array(
        'SQLiteField' => 'includes/db/DatabaseSqlite.php',
 
        # includes/debug
-       'MWDebug' => 'includes/debug/Debug.php',
+       'MWDebug' => 'includes/debug/MWDebug.php',
 
        # includes/deferred
        'DataUpdate' => 'includes/deferred/DataUpdate.php',
@@ -798,8 +798,8 @@ $wgAutoloadLocalClasses = array(
        'CoreTagHooks' => 'includes/parser/CoreTagHooks.php',
        'DateFormatter' => 'includes/parser/DateFormatter.php',
        'LinkHolderArray' => 'includes/parser/LinkHolderArray.php',
-       'MWTidy' => 'includes/parser/Tidy.php',
-       'MWTidyWrapper' => 'includes/parser/Tidy.php',
+       'MWTidy' => 'includes/parser/MWTidy.php',
+       'MWTidyWrapper' => 'includes/parser/MWTidy.php',
        'PPCustomFrame_DOM' => 'includes/parser/Preprocessor_DOM.php',
        'PPCustomFrame_Hash' => 'includes/parser/Preprocessor_Hash.php',
        'PPDAccum_Hash' => 'includes/parser/Preprocessor_Hash.php',
diff --git a/includes/MWNamespace.php b/includes/MWNamespace.php
new file mode 100644 (file)
index 0000000..392f558
--- /dev/null
@@ -0,0 +1,496 @@
+<?php
+/**
+ * Provide things related to namespaces.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * This is a utility class with only static functions
+ * for dealing with namespaces that encodes all the
+ * "magic" behaviors of them based on index.  The textual
+ * names of the namespaces are handled by Language.php.
+ *
+ * These are synonyms for the names given in the language file
+ * Users and translators should not change them
+ *
+ */
+class MWNamespace {
+
+       /**
+        * These namespaces should always be first-letter capitalized, now and
+        * forevermore. Historically, they could've probably been lowercased too,
+        * but some things are just too ingrained now. :)
+        */
+       private static $alwaysCapitalizedNamespaces = array( NS_SPECIAL, NS_USER, NS_MEDIAWIKI );
+
+       /**
+        * Throw an exception when trying to get the subject or talk page
+        * for a given namespace where it does not make sense.
+        * Special namespaces are defined in includes/Defines.php and have
+        * a value below 0 (ex: NS_SPECIAL = -1 , NS_MEDIA = -2)
+        *
+        * @param int $index
+        * @param string $method
+        *
+        * @throws MWException
+        * @return bool
+        */
+       private static function isMethodValidFor( $index, $method ) {
+               if ( $index < NS_MAIN ) {
+                       throw new MWException( "$method does not make any sense for given namespace $index" );
+               }
+               return true;
+       }
+
+       /**
+        * Can pages in the given namespace be moved?
+        *
+        * @param int $index Namespace index
+        * @return bool
+        */
+       public static function isMovable( $index ) {
+               global $wgAllowImageMoving;
+
+               $result = !( $index < NS_MAIN || ( $index == NS_FILE && !$wgAllowImageMoving ) );
+
+               /**
+                * @since 1.20
+                */
+               wfRunHooks( 'NamespaceIsMovable', array( $index, &$result ) );
+
+               return $result;
+       }
+
+       /**
+        * Is the given namespace is a subject (non-talk) namespace?
+        *
+        * @param int $index Namespace index
+        * @return bool
+        * @since 1.19
+        */
+       public static function isSubject( $index ) {
+               return !self::isTalk( $index );
+       }
+
+       /**
+        * Is the given namespace a talk namespace?
+        *
+        * @param int $index Namespace index
+        * @return bool
+        */
+       public static function isTalk( $index ) {
+               return $index > NS_MAIN
+                       && $index % 2;
+       }
+
+       /**
+        * Get the talk namespace index for a given namespace
+        *
+        * @param int $index Namespace index
+        * @return int
+        */
+       public static function getTalk( $index ) {
+               self::isMethodValidFor( $index, __METHOD__ );
+               return self::isTalk( $index )
+                       ? $index
+                       : $index + 1;
+       }
+
+       /**
+        * Get the subject namespace index for a given namespace
+        * Special namespaces (NS_MEDIA, NS_SPECIAL) are always the subject.
+        *
+        * @param int $index Namespace index
+        * @return int
+        */
+       public static function getSubject( $index ) {
+               # Handle special namespaces
+               if ( $index < NS_MAIN ) {
+                       return $index;
+               }
+
+               return self::isTalk( $index )
+                       ? $index - 1
+                       : $index;
+       }
+
+       /**
+        * Get the associated namespace.
+        * For talk namespaces, returns the subject (non-talk) namespace
+        * For subject (non-talk) namespaces, returns the talk namespace
+        *
+        * @param int $index Namespace index
+        * @return int|null If no associated namespace could be found
+        */
+       public static function getAssociated( $index ) {
+               self::isMethodValidFor( $index, __METHOD__ );
+
+               if ( self::isSubject( $index ) ) {
+                       return self::getTalk( $index );
+               } elseif ( self::isTalk( $index ) ) {
+                       return self::getSubject( $index );
+               } else {
+                       return null;
+               }
+       }
+
+       /**
+        * Returns whether the specified namespace exists
+        *
+        * @param int $index
+        *
+        * @return bool
+        * @since 1.19
+        */
+       public static function exists( $index ) {
+               $nslist = self::getCanonicalNamespaces();
+               return isset( $nslist[$index] );
+       }
+
+       /**
+        * Returns whether the specified namespaces are the same namespace
+        *
+        * @note It's possible that in the future we may start using something
+        * other than just namespace indexes. Under that circumstance making use
+        * of this function rather than directly doing comparison will make
+        * sure that code will not potentially break.
+        *
+        * @param int $ns1 The first namespace index
+        * @param int $ns2 The second namespace index
+        *
+        * @return bool
+        * @since 1.19
+        */
+       public static function equals( $ns1, $ns2 ) {
+               return $ns1 == $ns2;
+       }
+
+       /**
+        * Returns whether the specified namespaces share the same subject.
+        * eg: NS_USER and NS_USER wil return true, as well
+        *     NS_USER and NS_USER_TALK will return true.
+        *
+        * @param int $ns1 The first namespace index
+        * @param int $ns2 The second namespace index
+        *
+        * @return bool
+        * @since 1.19
+        */
+       public static function subjectEquals( $ns1, $ns2 ) {
+               return self::getSubject( $ns1 ) == self::getSubject( $ns2 );
+       }
+
+       /**
+        * Returns array of all defined namespaces with their canonical
+        * (English) names.
+        *
+        * @param bool $rebuild Rebuild namespace list (default = false). Used for testing.
+        *
+        * @return array
+        * @since 1.17
+        */
+       public static function getCanonicalNamespaces( $rebuild = false ) {
+               static $namespaces = null;
+               if ( $namespaces === null || $rebuild ) {
+                       global $wgExtraNamespaces, $wgCanonicalNamespaceNames;
+                       $namespaces = array( NS_MAIN => '' ) + $wgCanonicalNamespaceNames;
+                       if ( is_array( $wgExtraNamespaces ) ) {
+                               $namespaces += $wgExtraNamespaces;
+                       }
+                       wfRunHooks( 'CanonicalNamespaces', array( &$namespaces ) );
+               }
+               return $namespaces;
+       }
+
+       /**
+        * Returns the canonical (English) name for a given index
+        *
+        * @param int $index Namespace index
+        * @return string|bool If no canonical definition.
+        */
+       public static function getCanonicalName( $index ) {
+               $nslist = self::getCanonicalNamespaces();
+               if ( isset( $nslist[$index] ) ) {
+                       return $nslist[$index];
+               } else {
+                       return false;
+               }
+       }
+
+       /**
+        * Returns the index for a given canonical name, or NULL
+        * The input *must* be converted to lower case first
+        *
+        * @param string $name Namespace name
+        * @return int
+        */
+       public static function getCanonicalIndex( $name ) {
+               static $xNamespaces = false;
+               if ( $xNamespaces === false ) {
+                       $xNamespaces = array();
+                       foreach ( self::getCanonicalNamespaces() as $i => $text ) {
+                               $xNamespaces[strtolower( $text )] = $i;
+                       }
+               }
+               if ( array_key_exists( $name, $xNamespaces ) ) {
+                       return $xNamespaces[$name];
+               } else {
+                       return null;
+               }
+       }
+
+       /**
+        * Returns an array of the namespaces (by integer id) that exist on the
+        * wiki. Used primarily by the api in help documentation.
+        * @return array
+        */
+       public static function getValidNamespaces() {
+               static $mValidNamespaces = null;
+
+               if ( is_null( $mValidNamespaces ) ) {
+                       foreach ( array_keys( self::getCanonicalNamespaces() ) as $ns ) {
+                               if ( $ns >= 0 ) {
+                                       $mValidNamespaces[] = $ns;
+                               }
+                       }
+               }
+
+               return $mValidNamespaces;
+       }
+
+       /**
+        * Can this namespace ever have a talk namespace?
+        *
+        * @param int $index Namespace index
+        * @return bool
+        */
+       public static function canTalk( $index ) {
+               return $index >= NS_MAIN;
+       }
+
+       /**
+        * Does this namespace contain content, for the purposes of calculating
+        * statistics, etc?
+        *
+        * @param int $index Index to check
+        * @return bool
+        */
+       public static function isContent( $index ) {
+               global $wgContentNamespaces;
+               return $index == NS_MAIN || in_array( $index, $wgContentNamespaces );
+       }
+
+       /**
+        * Can pages in a namespace be watched?
+        *
+        * @param int $index
+        * @return bool
+        */
+       public static function isWatchable( $index ) {
+               return $index >= NS_MAIN;
+       }
+
+       /**
+        * Does the namespace allow subpages?
+        *
+        * @param int $index Index to check
+        * @return bool
+        */
+       public static function hasSubpages( $index ) {
+               global $wgNamespacesWithSubpages;
+               return !empty( $wgNamespacesWithSubpages[$index] );
+       }
+
+       /**
+        * Get a list of all namespace indices which are considered to contain content
+        * @return array Array of namespace indices
+        */
+       public static function getContentNamespaces() {
+               global $wgContentNamespaces;
+               if ( !is_array( $wgContentNamespaces ) || $wgContentNamespaces === array() ) {
+                       return array( NS_MAIN );
+               } elseif ( !in_array( NS_MAIN, $wgContentNamespaces ) ) {
+                       // always force NS_MAIN to be part of array (to match the algorithm used by isContent)
+                       return array_merge( array( NS_MAIN ), $wgContentNamespaces );
+               } else {
+                       return $wgContentNamespaces;
+               }
+       }
+
+       /**
+        * List all namespace indices which are considered subject, aka not a talk
+        * or special namespace. See also MWNamespace::isSubject
+        *
+        * @return array Array of namespace indices
+        */
+       public static function getSubjectNamespaces() {
+               return array_filter(
+                       MWNamespace::getValidNamespaces(),
+                       'MWNamespace::isSubject'
+               );
+       }
+
+       /**
+        * List all namespace indices which are considered talks, aka not a subject
+        * or special namespace. See also MWNamespace::isTalk
+        *
+        * @return array Array of namespace indices
+        */
+       public static function getTalkNamespaces() {
+               return array_filter(
+                       MWNamespace::getValidNamespaces(),
+                       'MWNamespace::isTalk'
+               );
+       }
+
+       /**
+        * Is the namespace first-letter capitalized?
+        *
+        * @param int $index Index to check
+        * @return bool
+        */
+       public static function isCapitalized( $index ) {
+               global $wgCapitalLinks, $wgCapitalLinkOverrides;
+               // Turn NS_MEDIA into NS_FILE
+               $index = $index === NS_MEDIA ? NS_FILE : $index;
+
+               // Make sure to get the subject of our namespace
+               $index = self::getSubject( $index );
+
+               // Some namespaces are special and should always be upper case
+               if ( in_array( $index, self::$alwaysCapitalizedNamespaces ) ) {
+                       return true;
+               }
+               if ( isset( $wgCapitalLinkOverrides[$index] ) ) {
+                       // $wgCapitalLinkOverrides is explicitly set
+                       return $wgCapitalLinkOverrides[$index];
+               }
+               // Default to the global setting
+               return $wgCapitalLinks;
+       }
+
+       /**
+        * Does the namespace (potentially) have different aliases for different
+        * genders. Not all languages make a distinction here.
+        *
+        * @since 1.18
+        * @param int $index Index to check
+        * @return bool
+        */
+       public static function hasGenderDistinction( $index ) {
+               return $index == NS_USER || $index == NS_USER_TALK;
+       }
+
+       /**
+        * It is not possible to use pages from this namespace as template?
+        *
+        * @since 1.20
+        * @param int $index Index to check
+        * @return bool
+        */
+       public static function isNonincludable( $index ) {
+               global $wgNonincludableNamespaces;
+               return $wgNonincludableNamespaces && in_array( $index, $wgNonincludableNamespaces );
+       }
+
+       /**
+        * Get the default content model for a namespace
+        * This does not mean that all pages in that namespace have the model
+        *
+        * @since 1.21
+        * @param int $index Index to check
+        * @return null|string Default model name for the given namespace, if set
+        */
+       public static function getNamespaceContentModel( $index ) {
+               global $wgNamespaceContentModels;
+               return isset( $wgNamespaceContentModels[$index] )
+                       ? $wgNamespaceContentModels[$index]
+                       : null;
+       }
+
+       /**
+        * Determine which restriction levels it makes sense to use in a namespace,
+        * optionally filtered by a user's rights.
+        *
+        * @since 1.23
+        * @param int $index Index to check
+        * @param User $user User to check
+        * @return array
+        */
+       public static function getRestrictionLevels( $index, User $user = null ) {
+               global $wgNamespaceProtection, $wgRestrictionLevels;
+
+               if ( !isset( $wgNamespaceProtection[$index] ) ) {
+                       // All levels are valid if there's no namespace restriction.
+                       // But still filter by user, if necessary
+                       $levels = $wgRestrictionLevels;
+                       if ( $user ) {
+                               $levels = array_values( array_filter( $levels, function ( $level ) use ( $user ) {
+                                       $right = $level;
+                                       if ( $right == 'sysop' ) {
+                                               $right = 'editprotected'; // BC
+                                       }
+                                       if ( $right == 'autoconfirmed' ) {
+                                               $right = 'editsemiprotected'; // BC
+                                       }
+                                       return ( $right == '' || $user->isAllowed( $right ) );
+                               } ) );
+                       }
+                       return $levels;
+               }
+
+               // First, get the list of groups that can edit this namespace.
+               $namespaceGroups = array();
+               $combine = 'array_merge';
+               foreach ( (array)$wgNamespaceProtection[$index] as $right ) {
+                       if ( $right == 'sysop' ) {
+                               $right = 'editprotected'; // BC
+                       }
+                       if ( $right == 'autoconfirmed' ) {
+                               $right = 'editsemiprotected'; // BC
+                       }
+                       if ( $right != '' ) {
+                               $namespaceGroups = call_user_func( $combine, $namespaceGroups,
+                                       User::getGroupsWithPermission( $right ) );
+                               $combine = 'array_intersect';
+                       }
+               }
+
+               // Now, keep only those restriction levels where there is at least one
+               // group that can edit the namespace but would be blocked by the
+               // restriction.
+               $usableLevels = array( '' );
+               foreach ( $wgRestrictionLevels as $level ) {
+                       $right = $level;
+                       if ( $right == 'sysop' ) {
+                               $right = 'editprotected'; // BC
+                       }
+                       if ( $right == 'autoconfirmed' ) {
+                               $right = 'editsemiprotected'; // BC
+                       }
+                       if ( $right != '' && ( !$user || $user->isAllowed( $right ) ) &&
+                               array_diff( $namespaceGroups, User::getGroupsWithPermission( $right ) )
+                       ) {
+                               $usableLevels[] = $level;
+                       }
+               }
+
+               return $usableLevels;
+       }
+}
diff --git a/includes/Namespace.php b/includes/Namespace.php
deleted file mode 100644 (file)
index 392f558..0000000
+++ /dev/null
@@ -1,496 +0,0 @@
-<?php
-/**
- * Provide things related to namespaces.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-/**
- * This is a utility class with only static functions
- * for dealing with namespaces that encodes all the
- * "magic" behaviors of them based on index.  The textual
- * names of the namespaces are handled by Language.php.
- *
- * These are synonyms for the names given in the language file
- * Users and translators should not change them
- *
- */
-class MWNamespace {
-
-       /**
-        * These namespaces should always be first-letter capitalized, now and
-        * forevermore. Historically, they could've probably been lowercased too,
-        * but some things are just too ingrained now. :)
-        */
-       private static $alwaysCapitalizedNamespaces = array( NS_SPECIAL, NS_USER, NS_MEDIAWIKI );
-
-       /**
-        * Throw an exception when trying to get the subject or talk page
-        * for a given namespace where it does not make sense.
-        * Special namespaces are defined in includes/Defines.php and have
-        * a value below 0 (ex: NS_SPECIAL = -1 , NS_MEDIA = -2)
-        *
-        * @param int $index
-        * @param string $method
-        *
-        * @throws MWException
-        * @return bool
-        */
-       private static function isMethodValidFor( $index, $method ) {
-               if ( $index < NS_MAIN ) {
-                       throw new MWException( "$method does not make any sense for given namespace $index" );
-               }
-               return true;
-       }
-
-       /**
-        * Can pages in the given namespace be moved?
-        *
-        * @param int $index Namespace index
-        * @return bool
-        */
-       public static function isMovable( $index ) {
-               global $wgAllowImageMoving;
-
-               $result = !( $index < NS_MAIN || ( $index == NS_FILE && !$wgAllowImageMoving ) );
-
-               /**
-                * @since 1.20
-                */
-               wfRunHooks( 'NamespaceIsMovable', array( $index, &$result ) );
-
-               return $result;
-       }
-
-       /**
-        * Is the given namespace is a subject (non-talk) namespace?
-        *
-        * @param int $index Namespace index
-        * @return bool
-        * @since 1.19
-        */
-       public static function isSubject( $index ) {
-               return !self::isTalk( $index );
-       }
-
-       /**
-        * Is the given namespace a talk namespace?
-        *
-        * @param int $index Namespace index
-        * @return bool
-        */
-       public static function isTalk( $index ) {
-               return $index > NS_MAIN
-                       && $index % 2;
-       }
-
-       /**
-        * Get the talk namespace index for a given namespace
-        *
-        * @param int $index Namespace index
-        * @return int
-        */
-       public static function getTalk( $index ) {
-               self::isMethodValidFor( $index, __METHOD__ );
-               return self::isTalk( $index )
-                       ? $index
-                       : $index + 1;
-       }
-
-       /**
-        * Get the subject namespace index for a given namespace
-        * Special namespaces (NS_MEDIA, NS_SPECIAL) are always the subject.
-        *
-        * @param int $index Namespace index
-        * @return int
-        */
-       public static function getSubject( $index ) {
-               # Handle special namespaces
-               if ( $index < NS_MAIN ) {
-                       return $index;
-               }
-
-               return self::isTalk( $index )
-                       ? $index - 1
-                       : $index;
-       }
-
-       /**
-        * Get the associated namespace.
-        * For talk namespaces, returns the subject (non-talk) namespace
-        * For subject (non-talk) namespaces, returns the talk namespace
-        *
-        * @param int $index Namespace index
-        * @return int|null If no associated namespace could be found
-        */
-       public static function getAssociated( $index ) {
-               self::isMethodValidFor( $index, __METHOD__ );
-
-               if ( self::isSubject( $index ) ) {
-                       return self::getTalk( $index );
-               } elseif ( self::isTalk( $index ) ) {
-                       return self::getSubject( $index );
-               } else {
-                       return null;
-               }
-       }
-
-       /**
-        * Returns whether the specified namespace exists
-        *
-        * @param int $index
-        *
-        * @return bool
-        * @since 1.19
-        */
-       public static function exists( $index ) {
-               $nslist = self::getCanonicalNamespaces();
-               return isset( $nslist[$index] );
-       }
-
-       /**
-        * Returns whether the specified namespaces are the same namespace
-        *
-        * @note It's possible that in the future we may start using something
-        * other than just namespace indexes. Under that circumstance making use
-        * of this function rather than directly doing comparison will make
-        * sure that code will not potentially break.
-        *
-        * @param int $ns1 The first namespace index
-        * @param int $ns2 The second namespace index
-        *
-        * @return bool
-        * @since 1.19
-        */
-       public static function equals( $ns1, $ns2 ) {
-               return $ns1 == $ns2;
-       }
-
-       /**
-        * Returns whether the specified namespaces share the same subject.
-        * eg: NS_USER and NS_USER wil return true, as well
-        *     NS_USER and NS_USER_TALK will return true.
-        *
-        * @param int $ns1 The first namespace index
-        * @param int $ns2 The second namespace index
-        *
-        * @return bool
-        * @since 1.19
-        */
-       public static function subjectEquals( $ns1, $ns2 ) {
-               return self::getSubject( $ns1 ) == self::getSubject( $ns2 );
-       }
-
-       /**
-        * Returns array of all defined namespaces with their canonical
-        * (English) names.
-        *
-        * @param bool $rebuild Rebuild namespace list (default = false). Used for testing.
-        *
-        * @return array
-        * @since 1.17
-        */
-       public static function getCanonicalNamespaces( $rebuild = false ) {
-               static $namespaces = null;
-               if ( $namespaces === null || $rebuild ) {
-                       global $wgExtraNamespaces, $wgCanonicalNamespaceNames;
-                       $namespaces = array( NS_MAIN => '' ) + $wgCanonicalNamespaceNames;
-                       if ( is_array( $wgExtraNamespaces ) ) {
-                               $namespaces += $wgExtraNamespaces;
-                       }
-                       wfRunHooks( 'CanonicalNamespaces', array( &$namespaces ) );
-               }
-               return $namespaces;
-       }
-
-       /**
-        * Returns the canonical (English) name for a given index
-        *
-        * @param int $index Namespace index
-        * @return string|bool If no canonical definition.
-        */
-       public static function getCanonicalName( $index ) {
-               $nslist = self::getCanonicalNamespaces();
-               if ( isset( $nslist[$index] ) ) {
-                       return $nslist[$index];
-               } else {
-                       return false;
-               }
-       }
-
-       /**
-        * Returns the index for a given canonical name, or NULL
-        * The input *must* be converted to lower case first
-        *
-        * @param string $name Namespace name
-        * @return int
-        */
-       public static function getCanonicalIndex( $name ) {
-               static $xNamespaces = false;
-               if ( $xNamespaces === false ) {
-                       $xNamespaces = array();
-                       foreach ( self::getCanonicalNamespaces() as $i => $text ) {
-                               $xNamespaces[strtolower( $text )] = $i;
-                       }
-               }
-               if ( array_key_exists( $name, $xNamespaces ) ) {
-                       return $xNamespaces[$name];
-               } else {
-                       return null;
-               }
-       }
-
-       /**
-        * Returns an array of the namespaces (by integer id) that exist on the
-        * wiki. Used primarily by the api in help documentation.
-        * @return array
-        */
-       public static function getValidNamespaces() {
-               static $mValidNamespaces = null;
-
-               if ( is_null( $mValidNamespaces ) ) {
-                       foreach ( array_keys( self::getCanonicalNamespaces() ) as $ns ) {
-                               if ( $ns >= 0 ) {
-                                       $mValidNamespaces[] = $ns;
-                               }
-                       }
-               }
-
-               return $mValidNamespaces;
-       }
-
-       /**
-        * Can this namespace ever have a talk namespace?
-        *
-        * @param int $index Namespace index
-        * @return bool
-        */
-       public static function canTalk( $index ) {
-               return $index >= NS_MAIN;
-       }
-
-       /**
-        * Does this namespace contain content, for the purposes of calculating
-        * statistics, etc?
-        *
-        * @param int $index Index to check
-        * @return bool
-        */
-       public static function isContent( $index ) {
-               global $wgContentNamespaces;
-               return $index == NS_MAIN || in_array( $index, $wgContentNamespaces );
-       }
-
-       /**
-        * Can pages in a namespace be watched?
-        *
-        * @param int $index
-        * @return bool
-        */
-       public static function isWatchable( $index ) {
-               return $index >= NS_MAIN;
-       }
-
-       /**
-        * Does the namespace allow subpages?
-        *
-        * @param int $index Index to check
-        * @return bool
-        */
-       public static function hasSubpages( $index ) {
-               global $wgNamespacesWithSubpages;
-               return !empty( $wgNamespacesWithSubpages[$index] );
-       }
-
-       /**
-        * Get a list of all namespace indices which are considered to contain content
-        * @return array Array of namespace indices
-        */
-       public static function getContentNamespaces() {
-               global $wgContentNamespaces;
-               if ( !is_array( $wgContentNamespaces ) || $wgContentNamespaces === array() ) {
-                       return array( NS_MAIN );
-               } elseif ( !in_array( NS_MAIN, $wgContentNamespaces ) ) {
-                       // always force NS_MAIN to be part of array (to match the algorithm used by isContent)
-                       return array_merge( array( NS_MAIN ), $wgContentNamespaces );
-               } else {
-                       return $wgContentNamespaces;
-               }
-       }
-
-       /**
-        * List all namespace indices which are considered subject, aka not a talk
-        * or special namespace. See also MWNamespace::isSubject
-        *
-        * @return array Array of namespace indices
-        */
-       public static function getSubjectNamespaces() {
-               return array_filter(
-                       MWNamespace::getValidNamespaces(),
-                       'MWNamespace::isSubject'
-               );
-       }
-
-       /**
-        * List all namespace indices which are considered talks, aka not a subject
-        * or special namespace. See also MWNamespace::isTalk
-        *
-        * @return array Array of namespace indices
-        */
-       public static function getTalkNamespaces() {
-               return array_filter(
-                       MWNamespace::getValidNamespaces(),
-                       'MWNamespace::isTalk'
-               );
-       }
-
-       /**
-        * Is the namespace first-letter capitalized?
-        *
-        * @param int $index Index to check
-        * @return bool
-        */
-       public static function isCapitalized( $index ) {
-               global $wgCapitalLinks, $wgCapitalLinkOverrides;
-               // Turn NS_MEDIA into NS_FILE
-               $index = $index === NS_MEDIA ? NS_FILE : $index;
-
-               // Make sure to get the subject of our namespace
-               $index = self::getSubject( $index );
-
-               // Some namespaces are special and should always be upper case
-               if ( in_array( $index, self::$alwaysCapitalizedNamespaces ) ) {
-                       return true;
-               }
-               if ( isset( $wgCapitalLinkOverrides[$index] ) ) {
-                       // $wgCapitalLinkOverrides is explicitly set
-                       return $wgCapitalLinkOverrides[$index];
-               }
-               // Default to the global setting
-               return $wgCapitalLinks;
-       }
-
-       /**
-        * Does the namespace (potentially) have different aliases for different
-        * genders. Not all languages make a distinction here.
-        *
-        * @since 1.18
-        * @param int $index Index to check
-        * @return bool
-        */
-       public static function hasGenderDistinction( $index ) {
-               return $index == NS_USER || $index == NS_USER_TALK;
-       }
-
-       /**
-        * It is not possible to use pages from this namespace as template?
-        *
-        * @since 1.20
-        * @param int $index Index to check
-        * @return bool
-        */
-       public static function isNonincludable( $index ) {
-               global $wgNonincludableNamespaces;
-               return $wgNonincludableNamespaces && in_array( $index, $wgNonincludableNamespaces );
-       }
-
-       /**
-        * Get the default content model for a namespace
-        * This does not mean that all pages in that namespace have the model
-        *
-        * @since 1.21
-        * @param int $index Index to check
-        * @return null|string Default model name for the given namespace, if set
-        */
-       public static function getNamespaceContentModel( $index ) {
-               global $wgNamespaceContentModels;
-               return isset( $wgNamespaceContentModels[$index] )
-                       ? $wgNamespaceContentModels[$index]
-                       : null;
-       }
-
-       /**
-        * Determine which restriction levels it makes sense to use in a namespace,
-        * optionally filtered by a user's rights.
-        *
-        * @since 1.23
-        * @param int $index Index to check
-        * @param User $user User to check
-        * @return array
-        */
-       public static function getRestrictionLevels( $index, User $user = null ) {
-               global $wgNamespaceProtection, $wgRestrictionLevels;
-
-               if ( !isset( $wgNamespaceProtection[$index] ) ) {
-                       // All levels are valid if there's no namespace restriction.
-                       // But still filter by user, if necessary
-                       $levels = $wgRestrictionLevels;
-                       if ( $user ) {
-                               $levels = array_values( array_filter( $levels, function ( $level ) use ( $user ) {
-                                       $right = $level;
-                                       if ( $right == 'sysop' ) {
-                                               $right = 'editprotected'; // BC
-                                       }
-                                       if ( $right == 'autoconfirmed' ) {
-                                               $right = 'editsemiprotected'; // BC
-                                       }
-                                       return ( $right == '' || $user->isAllowed( $right ) );
-                               } ) );
-                       }
-                       return $levels;
-               }
-
-               // First, get the list of groups that can edit this namespace.
-               $namespaceGroups = array();
-               $combine = 'array_merge';
-               foreach ( (array)$wgNamespaceProtection[$index] as $right ) {
-                       if ( $right == 'sysop' ) {
-                               $right = 'editprotected'; // BC
-                       }
-                       if ( $right == 'autoconfirmed' ) {
-                               $right = 'editsemiprotected'; // BC
-                       }
-                       if ( $right != '' ) {
-                               $namespaceGroups = call_user_func( $combine, $namespaceGroups,
-                                       User::getGroupsWithPermission( $right ) );
-                               $combine = 'array_intersect';
-                       }
-               }
-
-               // Now, keep only those restriction levels where there is at least one
-               // group that can edit the namespace but would be blocked by the
-               // restriction.
-               $usableLevels = array( '' );
-               foreach ( $wgRestrictionLevels as $level ) {
-                       $right = $level;
-                       if ( $right == 'sysop' ) {
-                               $right = 'editprotected'; // BC
-                       }
-                       if ( $right == 'autoconfirmed' ) {
-                               $right = 'editsemiprotected'; // BC
-                       }
-                       if ( $right != '' && ( !$user || $user->isAllowed( $right ) ) &&
-                               array_diff( $namespaceGroups, User::getGroupsWithPermission( $right ) )
-                       ) {
-                               $usableLevels[] = $level;
-                       }
-               }
-
-               return $usableLevels;
-       }
-}
diff --git a/includes/debug/Debug.php b/includes/debug/Debug.php
deleted file mode 100644 (file)
index 0cea658..0000000
+++ /dev/null
@@ -1,562 +0,0 @@
-<?php
-/**
- * Debug toolbar related code.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-/**
- * New debugger system that outputs a toolbar on page view.
- *
- * By default, most methods do nothing ( self::$enabled = false ). You have
- * to explicitly call MWDebug::init() to enabled them.
- *
- * @todo Profiler support
- *
- * @since 1.19
- */
-class MWDebug {
-       /**
-        * Log lines
-        *
-        * @var array $log
-        */
-       protected static $log = array();
-
-       /**
-        * Debug messages from wfDebug().
-        *
-        * @var array $debug
-        */
-       protected static $debug = array();
-
-       /**
-        * SQL statements of the databses queries.
-        *
-        * @var array $query
-        */
-       protected static $query = array();
-
-       /**
-        * Is the debugger enabled?
-        *
-        * @var bool $enabled
-        */
-       protected static $enabled = false;
-
-       /**
-        * Array of functions that have already been warned, formatted
-        * function-caller to prevent a buttload of warnings
-        *
-        * @var array $deprecationWarnings
-        */
-       protected static $deprecationWarnings = array();
-
-       /**
-        * Enabled the debugger and load resource module.
-        * This is called by Setup.php when $wgDebugToolbar is true.
-        *
-        * @since 1.19
-        */
-       public static function init() {
-               self::$enabled = true;
-       }
-
-       /**
-        * Add ResourceLoader modules to the OutputPage object if debugging is
-        * enabled.
-        *
-        * @since 1.19
-        * @param OutputPage $out
-        */
-       public static function addModules( OutputPage $out ) {
-               if ( self::$enabled ) {
-                       $out->addModules( 'mediawiki.debug.init' );
-               }
-       }
-
-       /**
-        * Adds a line to the log
-        *
-        * @todo Add support for passing objects
-        *
-        * @since 1.19
-        * @param string $str
-        */
-       public static function log( $str ) {
-               if ( !self::$enabled ) {
-                       return;
-               }
-
-               self::$log[] = array(
-                       'msg' => htmlspecialchars( $str ),
-                       'type' => 'log',
-                       'caller' => wfGetCaller(),
-               );
-       }
-
-       /**
-        * Returns internal log array
-        * @since 1.19
-        * @return array
-        */
-       public static function getLog() {
-               return self::$log;
-       }
-
-       /**
-        * Clears internal log array and deprecation tracking
-        * @since 1.19
-        */
-       public static function clearLog() {
-               self::$log = array();
-               self::$deprecationWarnings = array();
-       }
-
-       /**
-        * Adds a warning entry to the log
-        *
-        * @since 1.19
-        * @param string $msg
-        * @param int $callerOffset
-        * @param int $level A PHP error level. See sendMessage()
-        * @param string $log 'production' will always trigger a php error, 'auto'
-        *    will trigger an error if $wgDevelopmentWarnings is true, and 'debug'
-        *    will only write to the debug log(s).
-        *
-        * @return mixed
-        */
-       public static function warning( $msg, $callerOffset = 1, $level = E_USER_NOTICE, $log = 'auto' ) {
-               global $wgDevelopmentWarnings;
-
-               if ( $log === 'auto' && !$wgDevelopmentWarnings ) {
-                       $log = 'debug';
-               }
-
-               if ( $log === 'debug' ) {
-                       $level = false;
-               }
-
-               $callerDescription = self::getCallerDescription( $callerOffset );
-
-               self::sendMessage( $msg, $callerDescription, 'warning', $level );
-
-               if ( self::$enabled ) {
-                       self::$log[] = array(
-                               'msg' => htmlspecialchars( $msg ),
-                               'type' => 'warn',
-                               'caller' => $callerDescription['func'],
-                       );
-               }
-       }
-
-       /**
-        * Show a warning that $function is deprecated.
-        * This will send it to the following locations:
-        * - Debug toolbar, with one item per function and caller, if $wgDebugToolbar
-        *   is set to true.
-        * - PHP's error log, with level E_USER_DEPRECATED, if $wgDevelopmentWarnings
-        *   is set to true.
-        * - MediaWiki's debug log, if $wgDevelopmentWarnings is set to false.
-        *
-        * @since 1.19
-        * @param string $function Function that is deprecated.
-        * @param string|bool $version Version in which the function was deprecated.
-        * @param string|bool $component Component to which the function belongs.
-        *    If false, it is assumbed the function is in MediaWiki core.
-        * @param int $callerOffset How far up the callstack is the original
-        *    caller. 2 = function that called the function that called
-        *    MWDebug::deprecated() (Added in 1.20).
-        * @return mixed
-        */
-       public static function deprecated( $function, $version = false,
-               $component = false, $callerOffset = 2
-       ) {
-               $callerDescription = self::getCallerDescription( $callerOffset );
-               $callerFunc = $callerDescription['func'];
-
-               $sendToLog = true;
-
-               // Check to see if there already was a warning about this function
-               if ( isset( self::$deprecationWarnings[$function][$callerFunc] ) ) {
-                       return;
-               } elseif ( isset( self::$deprecationWarnings[$function] ) ) {
-                       if ( self::$enabled ) {
-                               $sendToLog = false;
-                       } else {
-                               return;
-                       }
-               }
-
-               self::$deprecationWarnings[$function][$callerFunc] = true;
-
-               if ( $version ) {
-                       global $wgDeprecationReleaseLimit;
-                       if ( $wgDeprecationReleaseLimit && $component === false ) {
-                               # Strip -* off the end of $version so that branches can use the
-                               # format #.##-branchname to avoid issues if the branch is merged into
-                               # a version of MediaWiki later than what it was branched from
-                               $comparableVersion = preg_replace( '/-.*$/', '', $version );
-
-                               # If the comparableVersion is larger than our release limit then
-                               # skip the warning message for the deprecation
-                               if ( version_compare( $wgDeprecationReleaseLimit, $comparableVersion, '<' ) ) {
-                                       $sendToLog = false;
-                               }
-                       }
-
-                       $component = $component === false ? 'MediaWiki' : $component;
-                       $msg = "Use of $function was deprecated in $component $version.";
-               } else {
-                       $msg = "Use of $function is deprecated.";
-               }
-
-               if ( $sendToLog ) {
-                       global $wgDevelopmentWarnings; // we could have a more specific $wgDeprecationWarnings setting.
-                       self::sendMessage(
-                               $msg,
-                               $callerDescription,
-                               'deprecated',
-                               $wgDevelopmentWarnings ? E_USER_DEPRECATED : false
-                       );
-               }
-
-               if ( self::$enabled ) {
-                       $logMsg = htmlspecialchars( $msg ) .
-                               Html::rawElement( 'div', array( 'class' => 'mw-debug-backtrace' ),
-                                       Html::element( 'span', array(), 'Backtrace:' ) . wfBacktrace()
-                               );
-
-                       self::$log[] = array(
-                               'msg' => $logMsg,
-                               'type' => 'deprecated',
-                               'caller' => $callerFunc,
-                       );
-               }
-       }
-
-       /**
-        * Get an array describing the calling function at a specified offset.
-        *
-        * @param int $callerOffset How far up the callstack is the original
-        *    caller. 0 = function that called getCallerDescription()
-        * @return array Array with two keys: 'file' and 'func'
-        */
-       private static function getCallerDescription( $callerOffset ) {
-               $callers = wfDebugBacktrace();
-
-               if ( isset( $callers[$callerOffset] ) ) {
-                       $callerfile = $callers[$callerOffset];
-                       if ( isset( $callerfile['file'] ) && isset( $callerfile['line'] ) ) {
-                               $file = $callerfile['file'] . ' at line ' . $callerfile['line'];
-                       } else {
-                               $file = '(internal function)';
-                       }
-               } else {
-                       $file = '(unknown location)';
-               }
-
-               if ( isset( $callers[$callerOffset + 1] ) ) {
-                       $callerfunc = $callers[$callerOffset + 1];
-                       $func = '';
-                       if ( isset( $callerfunc['class'] ) ) {
-                               $func .= $callerfunc['class'] . '::';
-                       }
-                       if ( isset( $callerfunc['function'] ) ) {
-                               $func .= $callerfunc['function'];
-                       }
-               } else {
-                       $func = 'unknown';
-               }
-
-               return array( 'file' => $file, 'func' => $func );
-       }
-
-       /**
-        * Send a message to the debug log and optionally also trigger a PHP
-        * error, depending on the $level argument.
-        *
-        * @param string $msg Message to send
-        * @param array $caller Caller description get from getCallerDescription()
-        * @param string $group Log group on which to send the message
-        * @param int|bool $level Error level to use; set to false to not trigger an error
-        */
-       private static function sendMessage( $msg, $caller, $group, $level ) {
-               $msg .= ' [Called from ' . $caller['func'] . ' in ' . $caller['file'] . ']';
-
-               if ( $level !== false ) {
-                       trigger_error( $msg, $level );
-               }
-
-               wfDebugLog( $group, $msg, 'log' );
-       }
-
-       /**
-        * This is a method to pass messages from wfDebug to the pretty debugger.
-        * Do NOT use this method, use MWDebug::log or wfDebug()
-        *
-        * @since 1.19
-        * @param string $str
-        */
-       public static function debugMsg( $str ) {
-               global $wgDebugComments, $wgShowDebug;
-
-               if ( self::$enabled || $wgDebugComments || $wgShowDebug ) {
-                       self::$debug[] = rtrim( UtfNormal::cleanUp( $str ) );
-               }
-       }
-
-       /**
-        * Begins profiling on a database query
-        *
-        * @since 1.19
-        * @param string $sql
-        * @param string $function
-        * @param bool $isMaster
-        * @return int ID number of the query to pass to queryTime or -1 if the
-        *  debugger is disabled
-        */
-       public static function query( $sql, $function, $isMaster ) {
-               if ( !self::$enabled ) {
-                       return -1;
-               }
-
-               self::$query[] = array(
-                       'sql' => $sql,
-                       'function' => $function,
-                       'master' => (bool)$isMaster,
-                       'time' => 0.0,
-                       '_start' => microtime( true ),
-               );
-
-               return count( self::$query ) - 1;
-       }
-
-       /**
-        * Calculates how long a query took.
-        *
-        * @since 1.19
-        * @param int $id
-        */
-       public static function queryTime( $id ) {
-               if ( $id === -1 || !self::$enabled ) {
-                       return;
-               }
-
-               self::$query[$id]['time'] = microtime( true ) - self::$query[$id]['_start'];
-               unset( self::$query[$id]['_start'] );
-       }
-
-       /**
-        * Returns a list of files included, along with their size
-        *
-        * @param IContextSource $context
-        * @return array
-        */
-       protected static function getFilesIncluded( IContextSource $context ) {
-               $files = get_included_files();
-               $fileList = array();
-               foreach ( $files as $file ) {
-                       $size = filesize( $file );
-                       $fileList[] = array(
-                               'name' => $file,
-                               'size' => $context->getLanguage()->formatSize( $size ),
-                       );
-               }
-
-               return $fileList;
-       }
-
-       /**
-        * Returns the HTML to add to the page for the toolbar
-        *
-        * @since 1.19
-        * @param IContextSource $context
-        * @return string
-        */
-       public static function getDebugHTML( IContextSource $context ) {
-               global $wgDebugComments;
-
-               $html = '';
-
-               if ( self::$enabled ) {
-                       MWDebug::log( 'MWDebug output complete' );
-                       $debugInfo = self::getDebugInfo( $context );
-
-                       // Cannot use OutputPage::addJsConfigVars because those are already outputted
-                       // by the time this method is called.
-                       $html = Html::inlineScript(
-                               ResourceLoader::makeLoaderConditionalScript(
-                                       ResourceLoader::makeConfigSetScript( array( 'debugInfo' => $debugInfo ) )
-                               )
-                       );
-               }
-
-               if ( $wgDebugComments ) {
-                       $html .= "<!-- Debug output:\n" .
-                               htmlspecialchars( implode( "\n", self::$debug ) ) .
-                               "\n\n-->";
-               }
-
-               return $html;
-       }
-
-       /**
-        * Generate debug log in HTML for displaying at the bottom of the main
-        * content area.
-        * If $wgShowDebug is false, an empty string is always returned.
-        *
-        * @since 1.20
-        * @return string HTML fragment
-        */
-       public static function getHTMLDebugLog() {
-               global $wgDebugTimestamps, $wgShowDebug;
-
-               if ( !$wgShowDebug ) {
-                       return '';
-               }
-
-               $curIdent = 0;
-               $ret = "\n<hr />\n<strong>Debug data:</strong><ul id=\"mw-debug-html\">\n<li>";
-
-               foreach ( self::$debug as $line ) {
-                       $pre = '';
-                       if ( $wgDebugTimestamps ) {
-                               $matches = array();
-                               if ( preg_match( '/^(\d+\.\d+ {1,3}\d+.\dM\s{2})/', $line, $matches ) ) {
-                                       $pre = $matches[1];
-                                       $line = substr( $line, strlen( $pre ) );
-                               }
-                       }
-                       $display = ltrim( $line );
-                       $ident = strlen( $line ) - strlen( $display );
-                       $diff = $ident - $curIdent;
-
-                       $display = $pre . $display;
-                       if ( $display == '' ) {
-                               $display = "\xc2\xa0";
-                       }
-
-                       if ( !$ident
-                               && $diff < 0
-                               && substr( $display, 0, 9 ) != 'Entering '
-                               && substr( $display, 0, 8 ) != 'Exiting '
-                       ) {
-                               $ident = $curIdent;
-                               $diff = 0;
-                               $display = '<span style="background:yellow;">' .
-                                       nl2br( htmlspecialchars( $display ) ) . '</span>';
-                       } else {
-                               $display = nl2br( htmlspecialchars( $display ) );
-                       }
-
-                       if ( $diff < 0 ) {
-                               $ret .= str_repeat( "</li></ul>\n", -$diff ) . "</li><li>\n";
-                       } elseif ( $diff == 0 ) {
-                               $ret .= "</li><li>\n";
-                       } else {
-                               $ret .= str_repeat( "<ul><li>\n", $diff );
-                       }
-                       $ret .= "<code>$display</code>\n";
-
-                       $curIdent = $ident;
-               }
-
-               $ret .= str_repeat( '</li></ul>', $curIdent ) . "</li>\n</ul>\n";
-
-               return $ret;
-       }
-
-       /**
-        * Append the debug info to given ApiResult
-        *
-        * @param IContextSource $context
-        * @param ApiResult $result
-        */
-       public static function appendDebugInfoToApiResult( IContextSource $context, ApiResult $result ) {
-               if ( !self::$enabled ) {
-                       return;
-               }
-
-               // output errors as debug info, when display_errors is on
-               // this is necessary for all non html output of the api, because that clears all errors first
-               $obContents = ob_get_contents();
-               if ( $obContents ) {
-                       $obContentArray = explode( '<br />', $obContents );
-                       foreach ( $obContentArray as $obContent ) {
-                               if ( trim( $obContent ) ) {
-                                       self::debugMsg( Sanitizer::stripAllTags( $obContent ) );
-                               }
-                       }
-               }
-
-               MWDebug::log( 'MWDebug output complete' );
-               $debugInfo = self::getDebugInfo( $context );
-
-               $result->setIndexedTagName( $debugInfo, 'debuginfo' );
-               $result->setIndexedTagName( $debugInfo['log'], 'line' );
-               $result->setIndexedTagName( $debugInfo['debugLog'], 'msg' );
-               $result->setIndexedTagName( $debugInfo['queries'], 'query' );
-               $result->setIndexedTagName( $debugInfo['includes'], 'queries' );
-               $result->setIndexedTagName( $debugInfo['profile'], 'function' );
-               $result->addValue( null, 'debuginfo', $debugInfo );
-       }
-
-       /**
-        * Returns the HTML to add to the page for the toolbar
-        *
-        * @param IContextSource $context
-        * @return array
-        */
-       public static function getDebugInfo( IContextSource $context ) {
-               if ( !self::$enabled ) {
-                       return array();
-               }
-
-               global $wgVersion, $wgRequestTime;
-               $request = $context->getRequest();
-
-               // HHVM's reported memory usage from memory_get_peak_usage()
-               // is not useful when passing false, but we continue passing
-               // false for consistency of historical data in zend.
-               // see: https://github.com/facebook/hhvm/issues/2257#issuecomment-39362246
-               $realMemoryUsage = wfIsHHVM();
-
-               return array(
-                       'mwVersion' => $wgVersion,
-                       'phpVersion' => PHP_VERSION,
-                       'gitRevision' => GitInfo::headSHA1(),
-                       'gitBranch' => GitInfo::currentBranch(),
-                       'gitViewUrl' => GitInfo::headViewUrl(),
-                       'time' => microtime( true ) - $wgRequestTime,
-                       'log' => self::$log,
-                       'debugLog' => self::$debug,
-                       'queries' => self::$query,
-                       'request' => array(
-                               'method' => $request->getMethod(),
-                               'url' => $request->getRequestURL(),
-                               'headers' => $request->getAllHeaders(),
-                               'params' => $request->getValues(),
-                       ),
-                       'memory' => $context->getLanguage()->formatSize( memory_get_usage( $realMemoryUsage ) ),
-                       'memoryPeak' => $context->getLanguage()->formatSize( memory_get_peak_usage( $realMemoryUsage ) ),
-                       'includes' => self::getFilesIncluded( $context ),
-                       'profile' => Profiler::instance()->getRawData(),
-               );
-       }
-}
diff --git a/includes/debug/MWDebug.php b/includes/debug/MWDebug.php
new file mode 100644 (file)
index 0000000..0cea658
--- /dev/null
@@ -0,0 +1,562 @@
+<?php
+/**
+ * Debug toolbar related code.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * New debugger system that outputs a toolbar on page view.
+ *
+ * By default, most methods do nothing ( self::$enabled = false ). You have
+ * to explicitly call MWDebug::init() to enabled them.
+ *
+ * @todo Profiler support
+ *
+ * @since 1.19
+ */
+class MWDebug {
+       /**
+        * Log lines
+        *
+        * @var array $log
+        */
+       protected static $log = array();
+
+       /**
+        * Debug messages from wfDebug().
+        *
+        * @var array $debug
+        */
+       protected static $debug = array();
+
+       /**
+        * SQL statements of the databses queries.
+        *
+        * @var array $query
+        */
+       protected static $query = array();
+
+       /**
+        * Is the debugger enabled?
+        *
+        * @var bool $enabled
+        */
+       protected static $enabled = false;
+
+       /**
+        * Array of functions that have already been warned, formatted
+        * function-caller to prevent a buttload of warnings
+        *
+        * @var array $deprecationWarnings
+        */
+       protected static $deprecationWarnings = array();
+
+       /**
+        * Enabled the debugger and load resource module.
+        * This is called by Setup.php when $wgDebugToolbar is true.
+        *
+        * @since 1.19
+        */
+       public static function init() {
+               self::$enabled = true;
+       }
+
+       /**
+        * Add ResourceLoader modules to the OutputPage object if debugging is
+        * enabled.
+        *
+        * @since 1.19
+        * @param OutputPage $out
+        */
+       public static function addModules( OutputPage $out ) {
+               if ( self::$enabled ) {
+                       $out->addModules( 'mediawiki.debug.init' );
+               }
+       }
+
+       /**
+        * Adds a line to the log
+        *
+        * @todo Add support for passing objects
+        *
+        * @since 1.19
+        * @param string $str
+        */
+       public static function log( $str ) {
+               if ( !self::$enabled ) {
+                       return;
+               }
+
+               self::$log[] = array(
+                       'msg' => htmlspecialchars( $str ),
+                       'type' => 'log',
+                       'caller' => wfGetCaller(),
+               );
+       }
+
+       /**
+        * Returns internal log array
+        * @since 1.19
+        * @return array
+        */
+       public static function getLog() {
+               return self::$log;
+       }
+
+       /**
+        * Clears internal log array and deprecation tracking
+        * @since 1.19
+        */
+       public static function clearLog() {
+               self::$log = array();
+               self::$deprecationWarnings = array();
+       }
+
+       /**
+        * Adds a warning entry to the log
+        *
+        * @since 1.19
+        * @param string $msg
+        * @param int $callerOffset
+        * @param int $level A PHP error level. See sendMessage()
+        * @param string $log 'production' will always trigger a php error, 'auto'
+        *    will trigger an error if $wgDevelopmentWarnings is true, and 'debug'
+        *    will only write to the debug log(s).
+        *
+        * @return mixed
+        */
+       public static function warning( $msg, $callerOffset = 1, $level = E_USER_NOTICE, $log = 'auto' ) {
+               global $wgDevelopmentWarnings;
+
+               if ( $log === 'auto' && !$wgDevelopmentWarnings ) {
+                       $log = 'debug';
+               }
+
+               if ( $log === 'debug' ) {
+                       $level = false;
+               }
+
+               $callerDescription = self::getCallerDescription( $callerOffset );
+
+               self::sendMessage( $msg, $callerDescription, 'warning', $level );
+
+               if ( self::$enabled ) {
+                       self::$log[] = array(
+                               'msg' => htmlspecialchars( $msg ),
+                               'type' => 'warn',
+                               'caller' => $callerDescription['func'],
+                       );
+               }
+       }
+
+       /**
+        * Show a warning that $function is deprecated.
+        * This will send it to the following locations:
+        * - Debug toolbar, with one item per function and caller, if $wgDebugToolbar
+        *   is set to true.
+        * - PHP's error log, with level E_USER_DEPRECATED, if $wgDevelopmentWarnings
+        *   is set to true.
+        * - MediaWiki's debug log, if $wgDevelopmentWarnings is set to false.
+        *
+        * @since 1.19
+        * @param string $function Function that is deprecated.
+        * @param string|bool $version Version in which the function was deprecated.
+        * @param string|bool $component Component to which the function belongs.
+        *    If false, it is assumbed the function is in MediaWiki core.
+        * @param int $callerOffset How far up the callstack is the original
+        *    caller. 2 = function that called the function that called
+        *    MWDebug::deprecated() (Added in 1.20).
+        * @return mixed
+        */
+       public static function deprecated( $function, $version = false,
+               $component = false, $callerOffset = 2
+       ) {
+               $callerDescription = self::getCallerDescription( $callerOffset );
+               $callerFunc = $callerDescription['func'];
+
+               $sendToLog = true;
+
+               // Check to see if there already was a warning about this function
+               if ( isset( self::$deprecationWarnings[$function][$callerFunc] ) ) {
+                       return;
+               } elseif ( isset( self::$deprecationWarnings[$function] ) ) {
+                       if ( self::$enabled ) {
+                               $sendToLog = false;
+                       } else {
+                               return;
+                       }
+               }
+
+               self::$deprecationWarnings[$function][$callerFunc] = true;
+
+               if ( $version ) {
+                       global $wgDeprecationReleaseLimit;
+                       if ( $wgDeprecationReleaseLimit && $component === false ) {
+                               # Strip -* off the end of $version so that branches can use the
+                               # format #.##-branchname to avoid issues if the branch is merged into
+                               # a version of MediaWiki later than what it was branched from
+                               $comparableVersion = preg_replace( '/-.*$/', '', $version );
+
+                               # If the comparableVersion is larger than our release limit then
+                               # skip the warning message for the deprecation
+                               if ( version_compare( $wgDeprecationReleaseLimit, $comparableVersion, '<' ) ) {
+                                       $sendToLog = false;
+                               }
+                       }
+
+                       $component = $component === false ? 'MediaWiki' : $component;
+                       $msg = "Use of $function was deprecated in $component $version.";
+               } else {
+                       $msg = "Use of $function is deprecated.";
+               }
+
+               if ( $sendToLog ) {
+                       global $wgDevelopmentWarnings; // we could have a more specific $wgDeprecationWarnings setting.
+                       self::sendMessage(
+                               $msg,
+                               $callerDescription,
+                               'deprecated',
+                               $wgDevelopmentWarnings ? E_USER_DEPRECATED : false
+                       );
+               }
+
+               if ( self::$enabled ) {
+                       $logMsg = htmlspecialchars( $msg ) .
+                               Html::rawElement( 'div', array( 'class' => 'mw-debug-backtrace' ),
+                                       Html::element( 'span', array(), 'Backtrace:' ) . wfBacktrace()
+                               );
+
+                       self::$log[] = array(
+                               'msg' => $logMsg,
+                               'type' => 'deprecated',
+                               'caller' => $callerFunc,
+                       );
+               }
+       }
+
+       /**
+        * Get an array describing the calling function at a specified offset.
+        *
+        * @param int $callerOffset How far up the callstack is the original
+        *    caller. 0 = function that called getCallerDescription()
+        * @return array Array with two keys: 'file' and 'func'
+        */
+       private static function getCallerDescription( $callerOffset ) {
+               $callers = wfDebugBacktrace();
+
+               if ( isset( $callers[$callerOffset] ) ) {
+                       $callerfile = $callers[$callerOffset];
+                       if ( isset( $callerfile['file'] ) && isset( $callerfile['line'] ) ) {
+                               $file = $callerfile['file'] . ' at line ' . $callerfile['line'];
+                       } else {
+                               $file = '(internal function)';
+                       }
+               } else {
+                       $file = '(unknown location)';
+               }
+
+               if ( isset( $callers[$callerOffset + 1] ) ) {
+                       $callerfunc = $callers[$callerOffset + 1];
+                       $func = '';
+                       if ( isset( $callerfunc['class'] ) ) {
+                               $func .= $callerfunc['class'] . '::';
+                       }
+                       if ( isset( $callerfunc['function'] ) ) {
+                               $func .= $callerfunc['function'];
+                       }
+               } else {
+                       $func = 'unknown';
+               }
+
+               return array( 'file' => $file, 'func' => $func );
+       }
+
+       /**
+        * Send a message to the debug log and optionally also trigger a PHP
+        * error, depending on the $level argument.
+        *
+        * @param string $msg Message to send
+        * @param array $caller Caller description get from getCallerDescription()
+        * @param string $group Log group on which to send the message
+        * @param int|bool $level Error level to use; set to false to not trigger an error
+        */
+       private static function sendMessage( $msg, $caller, $group, $level ) {
+               $msg .= ' [Called from ' . $caller['func'] . ' in ' . $caller['file'] . ']';
+
+               if ( $level !== false ) {
+                       trigger_error( $msg, $level );
+               }
+
+               wfDebugLog( $group, $msg, 'log' );
+       }
+
+       /**
+        * This is a method to pass messages from wfDebug to the pretty debugger.
+        * Do NOT use this method, use MWDebug::log or wfDebug()
+        *
+        * @since 1.19
+        * @param string $str
+        */
+       public static function debugMsg( $str ) {
+               global $wgDebugComments, $wgShowDebug;
+
+               if ( self::$enabled || $wgDebugComments || $wgShowDebug ) {
+                       self::$debug[] = rtrim( UtfNormal::cleanUp( $str ) );
+               }
+       }
+
+       /**
+        * Begins profiling on a database query
+        *
+        * @since 1.19
+        * @param string $sql
+        * @param string $function
+        * @param bool $isMaster
+        * @return int ID number of the query to pass to queryTime or -1 if the
+        *  debugger is disabled
+        */
+       public static function query( $sql, $function, $isMaster ) {
+               if ( !self::$enabled ) {
+                       return -1;
+               }
+
+               self::$query[] = array(
+                       'sql' => $sql,
+                       'function' => $function,
+                       'master' => (bool)$isMaster,
+                       'time' => 0.0,
+                       '_start' => microtime( true ),
+               );
+
+               return count( self::$query ) - 1;
+       }
+
+       /**
+        * Calculates how long a query took.
+        *
+        * @since 1.19
+        * @param int $id
+        */
+       public static function queryTime( $id ) {
+               if ( $id === -1 || !self::$enabled ) {
+                       return;
+               }
+
+               self::$query[$id]['time'] = microtime( true ) - self::$query[$id]['_start'];
+               unset( self::$query[$id]['_start'] );
+       }
+
+       /**
+        * Returns a list of files included, along with their size
+        *
+        * @param IContextSource $context
+        * @return array
+        */
+       protected static function getFilesIncluded( IContextSource $context ) {
+               $files = get_included_files();
+               $fileList = array();
+               foreach ( $files as $file ) {
+                       $size = filesize( $file );
+                       $fileList[] = array(
+                               'name' => $file,
+                               'size' => $context->getLanguage()->formatSize( $size ),
+                       );
+               }
+
+               return $fileList;
+       }
+
+       /**
+        * Returns the HTML to add to the page for the toolbar
+        *
+        * @since 1.19
+        * @param IContextSource $context
+        * @return string
+        */
+       public static function getDebugHTML( IContextSource $context ) {
+               global $wgDebugComments;
+
+               $html = '';
+
+               if ( self::$enabled ) {
+                       MWDebug::log( 'MWDebug output complete' );
+                       $debugInfo = self::getDebugInfo( $context );
+
+                       // Cannot use OutputPage::addJsConfigVars because those are already outputted
+                       // by the time this method is called.
+                       $html = Html::inlineScript(
+                               ResourceLoader::makeLoaderConditionalScript(
+                                       ResourceLoader::makeConfigSetScript( array( 'debugInfo' => $debugInfo ) )
+                               )
+                       );
+               }
+
+               if ( $wgDebugComments ) {
+                       $html .= "<!-- Debug output:\n" .
+                               htmlspecialchars( implode( "\n", self::$debug ) ) .
+                               "\n\n-->";
+               }
+
+               return $html;
+       }
+
+       /**
+        * Generate debug log in HTML for displaying at the bottom of the main
+        * content area.
+        * If $wgShowDebug is false, an empty string is always returned.
+        *
+        * @since 1.20
+        * @return string HTML fragment
+        */
+       public static function getHTMLDebugLog() {
+               global $wgDebugTimestamps, $wgShowDebug;
+
+               if ( !$wgShowDebug ) {
+                       return '';
+               }
+
+               $curIdent = 0;
+               $ret = "\n<hr />\n<strong>Debug data:</strong><ul id=\"mw-debug-html\">\n<li>";
+
+               foreach ( self::$debug as $line ) {
+                       $pre = '';
+                       if ( $wgDebugTimestamps ) {
+                               $matches = array();
+                               if ( preg_match( '/^(\d+\.\d+ {1,3}\d+.\dM\s{2})/', $line, $matches ) ) {
+                                       $pre = $matches[1];
+                                       $line = substr( $line, strlen( $pre ) );
+                               }
+                       }
+                       $display = ltrim( $line );
+                       $ident = strlen( $line ) - strlen( $display );
+                       $diff = $ident - $curIdent;
+
+                       $display = $pre . $display;
+                       if ( $display == '' ) {
+                               $display = "\xc2\xa0";
+                       }
+
+                       if ( !$ident
+                               && $diff < 0
+                               && substr( $display, 0, 9 ) != 'Entering '
+                               && substr( $display, 0, 8 ) != 'Exiting '
+                       ) {
+                               $ident = $curIdent;
+                               $diff = 0;
+                               $display = '<span style="background:yellow;">' .
+                                       nl2br( htmlspecialchars( $display ) ) . '</span>';
+                       } else {
+                               $display = nl2br( htmlspecialchars( $display ) );
+                       }
+
+                       if ( $diff < 0 ) {
+                               $ret .= str_repeat( "</li></ul>\n", -$diff ) . "</li><li>\n";
+                       } elseif ( $diff == 0 ) {
+                               $ret .= "</li><li>\n";
+                       } else {
+                               $ret .= str_repeat( "<ul><li>\n", $diff );
+                       }
+                       $ret .= "<code>$display</code>\n";
+
+                       $curIdent = $ident;
+               }
+
+               $ret .= str_repeat( '</li></ul>', $curIdent ) . "</li>\n</ul>\n";
+
+               return $ret;
+       }
+
+       /**
+        * Append the debug info to given ApiResult
+        *
+        * @param IContextSource $context
+        * @param ApiResult $result
+        */
+       public static function appendDebugInfoToApiResult( IContextSource $context, ApiResult $result ) {
+               if ( !self::$enabled ) {
+                       return;
+               }
+
+               // output errors as debug info, when display_errors is on
+               // this is necessary for all non html output of the api, because that clears all errors first
+               $obContents = ob_get_contents();
+               if ( $obContents ) {
+                       $obContentArray = explode( '<br />', $obContents );
+                       foreach ( $obContentArray as $obContent ) {
+                               if ( trim( $obContent ) ) {
+                                       self::debugMsg( Sanitizer::stripAllTags( $obContent ) );
+                               }
+                       }
+               }
+
+               MWDebug::log( 'MWDebug output complete' );
+               $debugInfo = self::getDebugInfo( $context );
+
+               $result->setIndexedTagName( $debugInfo, 'debuginfo' );
+               $result->setIndexedTagName( $debugInfo['log'], 'line' );
+               $result->setIndexedTagName( $debugInfo['debugLog'], 'msg' );
+               $result->setIndexedTagName( $debugInfo['queries'], 'query' );
+               $result->setIndexedTagName( $debugInfo['includes'], 'queries' );
+               $result->setIndexedTagName( $debugInfo['profile'], 'function' );
+               $result->addValue( null, 'debuginfo', $debugInfo );
+       }
+
+       /**
+        * Returns the HTML to add to the page for the toolbar
+        *
+        * @param IContextSource $context
+        * @return array
+        */
+       public static function getDebugInfo( IContextSource $context ) {
+               if ( !self::$enabled ) {
+                       return array();
+               }
+
+               global $wgVersion, $wgRequestTime;
+               $request = $context->getRequest();
+
+               // HHVM's reported memory usage from memory_get_peak_usage()
+               // is not useful when passing false, but we continue passing
+               // false for consistency of historical data in zend.
+               // see: https://github.com/facebook/hhvm/issues/2257#issuecomment-39362246
+               $realMemoryUsage = wfIsHHVM();
+
+               return array(
+                       'mwVersion' => $wgVersion,
+                       'phpVersion' => PHP_VERSION,
+                       'gitRevision' => GitInfo::headSHA1(),
+                       'gitBranch' => GitInfo::currentBranch(),
+                       'gitViewUrl' => GitInfo::headViewUrl(),
+                       'time' => microtime( true ) - $wgRequestTime,
+                       'log' => self::$log,
+                       'debugLog' => self::$debug,
+                       'queries' => self::$query,
+                       'request' => array(
+                               'method' => $request->getMethod(),
+                               'url' => $request->getRequestURL(),
+                               'headers' => $request->getAllHeaders(),
+                               'params' => $request->getValues(),
+                       ),
+                       'memory' => $context->getLanguage()->formatSize( memory_get_usage( $realMemoryUsage ) ),
+                       'memoryPeak' => $context->getLanguage()->formatSize( memory_get_peak_usage( $realMemoryUsage ) ),
+                       'includes' => self::getFilesIncluded( $context ),
+                       'profile' => Profiler::instance()->getRawData(),
+               );
+       }
+}
diff --git a/includes/parser/MWTidy.php b/includes/parser/MWTidy.php
new file mode 100644 (file)
index 0000000..f7fe5a8
--- /dev/null
@@ -0,0 +1,289 @@
+<?php
+/**
+ * HTML validation and correction
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Parser
+ */
+
+/**
+ * Class used to hide mw:editsection tokens from Tidy so that it doesn't break them
+ * or break on them. This is a bit of a hack for now, but hopefully in the future
+ * we may create a real postprocessor or something that will replace this.
+ * It's called wrapper because for now it basically takes over MWTidy::tidy's task
+ * of wrapping the text in a xhtml block
+ *
+ * This re-uses some of the parser's UNIQ tricks, though some of it is private so it's
+ * duplicated. Perhaps we should create an abstract marker hiding class.
+ *
+ * @ingroup Parser
+ */
+class MWTidyWrapper {
+
+       /**
+        * @var ReplacementArray
+        */
+       protected $mTokens;
+
+       protected $mUniqPrefix;
+
+       protected $mMarkerIndex;
+
+       public function __construct() {
+               $this->mTokens = null;
+               $this->mUniqPrefix = null;
+       }
+
+       /**
+        * @param string $text
+        * @return string
+        */
+       public function getWrapped( $text ) {
+               $this->mTokens = new ReplacementArray;
+               $this->mUniqPrefix = "\x7fUNIQ" .
+                       dechex( mt_rand( 0, 0x7fffffff ) ) . dechex( mt_rand( 0, 0x7fffffff ) );
+               $this->mMarkerIndex = 0;
+
+               // Replace <mw:editsection> elements with placeholders
+               $wrappedtext = preg_replace_callback( ParserOutput::EDITSECTION_REGEX,
+                       array( &$this, 'replaceCallback' ), $text );
+               // ...and <mw:toc> markers
+               $wrappedtext = preg_replace_callback( '/\<\\/?mw:toc\>/',
+                       array( &$this, 'replaceCallback' ), $wrappedtext );
+
+               // Modify inline Microdata <link> and <meta> elements so they say <html-link> and <html-meta> so
+               // we can trick Tidy into not stripping them out by including them in tidy's new-empty-tags config
+               $wrappedtext = preg_replace( '!<(link|meta)([^>]*?)(/{0,1}>)!', '<html-$1$2$3', $wrappedtext );
+
+               // Wrap the whole thing in a doctype and body for Tidy.
+               $wrappedtext = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"' .
+                       ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html>' .
+                       '<head><title>test</title></head><body>' . $wrappedtext . '</body></html>';
+
+               return $wrappedtext;
+       }
+
+       /**
+        * @param array $m
+        *
+        * @return string
+        */
+       function replaceCallback( $m ) {
+               $marker = "{$this->mUniqPrefix}-item-{$this->mMarkerIndex}" . Parser::MARKER_SUFFIX;
+               $this->mMarkerIndex++;
+               $this->mTokens->setPair( $marker, $m[0] );
+               return $marker;
+       }
+
+       /**
+        * @param string $text
+        * @return string
+        */
+       public function postprocess( $text ) {
+               // Revert <html-{link,meta}> back to <{link,meta}>
+               $text = preg_replace( '!<html-(link|meta)([^>]*?)(/{0,1}>)!', '<$1$2$3', $text );
+
+               // Restore the contents of placeholder tokens
+               $text = $this->mTokens->replace( $text );
+
+               return $text;
+       }
+
+}
+
+/**
+ * Class to interact with HTML tidy
+ *
+ * Either the external tidy program or the in-process tidy extension
+ * will be used depending on availability. Override the default
+ * $wgTidyInternal setting to disable the internal if it's not working.
+ *
+ * @ingroup Parser
+ */
+class MWTidy {
+       /**
+        * Interface with html tidy, used if $wgUseTidy = true.
+        * If tidy isn't able to correct the markup, the original will be
+        * returned in all its glory with a warning comment appended.
+        *
+        * @param string $text Hideous HTML input
+        * @return string Corrected HTML output
+        */
+       public static function tidy( $text ) {
+               global $wgTidyInternal;
+
+               $wrapper = new MWTidyWrapper;
+               $wrappedtext = $wrapper->getWrapped( $text );
+
+               $retVal = null;
+               if ( $wgTidyInternal ) {
+                       $correctedtext = self::execInternalTidy( $wrappedtext, false, $retVal );
+               } else {
+                       $correctedtext = self::execExternalTidy( $wrappedtext, false, $retVal );
+               }
+
+               if ( $retVal < 0 ) {
+                       wfDebug( "Possible tidy configuration error!\n" );
+                       return $text . "\n<!-- Tidy was unable to run -->\n";
+               } elseif ( is_null( $correctedtext ) ) {
+                       wfDebug( "Tidy error detected!\n" );
+                       return $text . "\n<!-- Tidy found serious XHTML errors -->\n";
+               }
+
+               $correctedtext = $wrapper->postprocess( $correctedtext ); // restore any hidden tokens
+
+               return $correctedtext;
+       }
+
+       /**
+        * Check HTML for errors, used if $wgValidateAllHtml = true.
+        *
+        * @param string $text
+        * @param string &$errorStr Return the error string
+        * @return bool Whether the HTML is valid
+        */
+       public static function checkErrors( $text, &$errorStr = null ) {
+               global $wgTidyInternal;
+
+               $retval = 0;
+               if ( $wgTidyInternal ) {
+                       $errorStr = self::execInternalTidy( $text, true, $retval );
+               } else {
+                       $errorStr = self::execExternalTidy( $text, true, $retval );
+               }
+
+               return ( $retval < 0 && $errorStr == '' ) || $retval == 0;
+       }
+
+       /**
+        * Spawn an external HTML tidy process and get corrected markup back from it.
+        * Also called in OutputHandler.php for full page validation
+        *
+        * @param string $text HTML to check
+        * @param bool $stderr Whether to read result from STDERR rather than STDOUT
+        * @param int &$retval Exit code (-1 on internal error)
+        * @return string|null
+        */
+       private static function execExternalTidy( $text, $stderr = false, &$retval = null ) {
+               global $wgTidyConf, $wgTidyBin, $wgTidyOpts;
+               wfProfileIn( __METHOD__ );
+
+               $cleansource = '';
+               $opts = ' -utf8';
+
+               if ( $stderr ) {
+                       $descriptorspec = array(
+                               0 => array( 'pipe', 'r' ),
+                               1 => array( 'file', wfGetNull(), 'a' ),
+                               2 => array( 'pipe', 'w' )
+                       );
+               } else {
+                       $descriptorspec = array(
+                               0 => array( 'pipe', 'r' ),
+                               1 => array( 'pipe', 'w' ),
+                               2 => array( 'file', wfGetNull(), 'a' )
+                       );
+               }
+
+               $readpipe = $stderr ? 2 : 1;
+               $pipes = array();
+
+               $process = proc_open(
+                       "$wgTidyBin -config $wgTidyConf $wgTidyOpts$opts", $descriptorspec, $pipes );
+
+               //NOTE: At least on linux, the process will be created even if tidy is not installed.
+               //      This means that missing tidy will be treated as a validation failure.
+
+               if ( is_resource( $process ) ) {
+                       // Theoretically, this style of communication could cause a deadlock
+                       // here. If the stdout buffer fills up, then writes to stdin could
+                       // block. This doesn't appear to happen with tidy, because tidy only
+                       // writes to stdout after it's finished reading from stdin. Search
+                       // for tidyParseStdin and tidySaveStdout in console/tidy.c
+                       fwrite( $pipes[0], $text );
+                       fclose( $pipes[0] );
+                       while ( !feof( $pipes[$readpipe] ) ) {
+                               $cleansource .= fgets( $pipes[$readpipe], 1024 );
+                       }
+                       fclose( $pipes[$readpipe] );
+                       $retval = proc_close( $process );
+               } else {
+                       wfWarn( "Unable to start external tidy process" );
+                       $retval = -1;
+               }
+
+               if ( !$stderr && $cleansource == '' && $text != '' ) {
+                       // Some kind of error happened, so we couldn't get the corrected text.
+                       // Just give up; we'll use the source text and append a warning.
+                       $cleansource = null;
+               }
+
+               wfProfileOut( __METHOD__ );
+               return $cleansource;
+       }
+
+       /**
+        * Use the HTML tidy extension to use the tidy library in-process,
+        * saving the overhead of spawning a new process.
+        *
+        * @param string $text HTML to check
+        * @param bool $stderr Whether to read result from error status instead of output
+        * @param int &$retval Exit code (-1 on internal error)
+        * @return string|null
+        */
+       private static function execInternalTidy( $text, $stderr = false, &$retval = null ) {
+               global $wgTidyConf, $wgDebugTidy;
+               wfProfileIn( __METHOD__ );
+
+               if ( !class_exists( 'tidy' ) ) {
+                       wfWarn( "Unable to load internal tidy class." );
+                       $retval = -1;
+
+                       wfProfileOut( __METHOD__ );
+                       return null;
+               }
+
+               $tidy = new tidy;
+               $tidy->parseString( $text, $wgTidyConf, 'utf8' );
+
+               if ( $stderr ) {
+                       $retval = $tidy->getStatus();
+
+                       wfProfileOut( __METHOD__ );
+                       return $tidy->errorBuffer;
+               }
+
+               $tidy->cleanRepair();
+               $retval = $tidy->getStatus();
+               if ( $retval == 2 ) {
+                       // 2 is magic number for fatal error
+                       // http://www.php.net/manual/en/function.tidy-get-status.php
+                       $cleansource = null;
+               } else {
+                       $cleansource = tidy_get_output( $tidy );
+                       if ( $wgDebugTidy && $retval > 0 ) {
+                               $cleansource .= "<!--\nTidy reports:\n" .
+                                       str_replace( '-->', '--&gt;', $tidy->errorBuffer ) .
+                                       "\n-->";
+                       }
+               }
+
+               wfProfileOut( __METHOD__ );
+               return $cleansource;
+       }
+}
diff --git a/includes/parser/Tidy.php b/includes/parser/Tidy.php
deleted file mode 100644 (file)
index f7fe5a8..0000000
+++ /dev/null
@@ -1,289 +0,0 @@
-<?php
-/**
- * HTML validation and correction
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup Parser
- */
-
-/**
- * Class used to hide mw:editsection tokens from Tidy so that it doesn't break them
- * or break on them. This is a bit of a hack for now, but hopefully in the future
- * we may create a real postprocessor or something that will replace this.
- * It's called wrapper because for now it basically takes over MWTidy::tidy's task
- * of wrapping the text in a xhtml block
- *
- * This re-uses some of the parser's UNIQ tricks, though some of it is private so it's
- * duplicated. Perhaps we should create an abstract marker hiding class.
- *
- * @ingroup Parser
- */
-class MWTidyWrapper {
-
-       /**
-        * @var ReplacementArray
-        */
-       protected $mTokens;
-
-       protected $mUniqPrefix;
-
-       protected $mMarkerIndex;
-
-       public function __construct() {
-               $this->mTokens = null;
-               $this->mUniqPrefix = null;
-       }
-
-       /**
-        * @param string $text
-        * @return string
-        */
-       public function getWrapped( $text ) {
-               $this->mTokens = new ReplacementArray;
-               $this->mUniqPrefix = "\x7fUNIQ" .
-                       dechex( mt_rand( 0, 0x7fffffff ) ) . dechex( mt_rand( 0, 0x7fffffff ) );
-               $this->mMarkerIndex = 0;
-
-               // Replace <mw:editsection> elements with placeholders
-               $wrappedtext = preg_replace_callback( ParserOutput::EDITSECTION_REGEX,
-                       array( &$this, 'replaceCallback' ), $text );
-               // ...and <mw:toc> markers
-               $wrappedtext = preg_replace_callback( '/\<\\/?mw:toc\>/',
-                       array( &$this, 'replaceCallback' ), $wrappedtext );
-
-               // Modify inline Microdata <link> and <meta> elements so they say <html-link> and <html-meta> so
-               // we can trick Tidy into not stripping them out by including them in tidy's new-empty-tags config
-               $wrappedtext = preg_replace( '!<(link|meta)([^>]*?)(/{0,1}>)!', '<html-$1$2$3', $wrappedtext );
-
-               // Wrap the whole thing in a doctype and body for Tidy.
-               $wrappedtext = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"' .
-                       ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html>' .
-                       '<head><title>test</title></head><body>' . $wrappedtext . '</body></html>';
-
-               return $wrappedtext;
-       }
-
-       /**
-        * @param array $m
-        *
-        * @return string
-        */
-       function replaceCallback( $m ) {
-               $marker = "{$this->mUniqPrefix}-item-{$this->mMarkerIndex}" . Parser::MARKER_SUFFIX;
-               $this->mMarkerIndex++;
-               $this->mTokens->setPair( $marker, $m[0] );
-               return $marker;
-       }
-
-       /**
-        * @param string $text
-        * @return string
-        */
-       public function postprocess( $text ) {
-               // Revert <html-{link,meta}> back to <{link,meta}>
-               $text = preg_replace( '!<html-(link|meta)([^>]*?)(/{0,1}>)!', '<$1$2$3', $text );
-
-               // Restore the contents of placeholder tokens
-               $text = $this->mTokens->replace( $text );
-
-               return $text;
-       }
-
-}
-
-/**
- * Class to interact with HTML tidy
- *
- * Either the external tidy program or the in-process tidy extension
- * will be used depending on availability. Override the default
- * $wgTidyInternal setting to disable the internal if it's not working.
- *
- * @ingroup Parser
- */
-class MWTidy {
-       /**
-        * Interface with html tidy, used if $wgUseTidy = true.
-        * If tidy isn't able to correct the markup, the original will be
-        * returned in all its glory with a warning comment appended.
-        *
-        * @param string $text Hideous HTML input
-        * @return string Corrected HTML output
-        */
-       public static function tidy( $text ) {
-               global $wgTidyInternal;
-
-               $wrapper = new MWTidyWrapper;
-               $wrappedtext = $wrapper->getWrapped( $text );
-
-               $retVal = null;
-               if ( $wgTidyInternal ) {
-                       $correctedtext = self::execInternalTidy( $wrappedtext, false, $retVal );
-               } else {
-                       $correctedtext = self::execExternalTidy( $wrappedtext, false, $retVal );
-               }
-
-               if ( $retVal < 0 ) {
-                       wfDebug( "Possible tidy configuration error!\n" );
-                       return $text . "\n<!-- Tidy was unable to run -->\n";
-               } elseif ( is_null( $correctedtext ) ) {
-                       wfDebug( "Tidy error detected!\n" );
-                       return $text . "\n<!-- Tidy found serious XHTML errors -->\n";
-               }
-
-               $correctedtext = $wrapper->postprocess( $correctedtext ); // restore any hidden tokens
-
-               return $correctedtext;
-       }
-
-       /**
-        * Check HTML for errors, used if $wgValidateAllHtml = true.
-        *
-        * @param string $text
-        * @param string &$errorStr Return the error string
-        * @return bool Whether the HTML is valid
-        */
-       public static function checkErrors( $text, &$errorStr = null ) {
-               global $wgTidyInternal;
-
-               $retval = 0;
-               if ( $wgTidyInternal ) {
-                       $errorStr = self::execInternalTidy( $text, true, $retval );
-               } else {
-                       $errorStr = self::execExternalTidy( $text, true, $retval );
-               }
-
-               return ( $retval < 0 && $errorStr == '' ) || $retval == 0;
-       }
-
-       /**
-        * Spawn an external HTML tidy process and get corrected markup back from it.
-        * Also called in OutputHandler.php for full page validation
-        *
-        * @param string $text HTML to check
-        * @param bool $stderr Whether to read result from STDERR rather than STDOUT
-        * @param int &$retval Exit code (-1 on internal error)
-        * @return string|null
-        */
-       private static function execExternalTidy( $text, $stderr = false, &$retval = null ) {
-               global $wgTidyConf, $wgTidyBin, $wgTidyOpts;
-               wfProfileIn( __METHOD__ );
-
-               $cleansource = '';
-               $opts = ' -utf8';
-
-               if ( $stderr ) {
-                       $descriptorspec = array(
-                               0 => array( 'pipe', 'r' ),
-                               1 => array( 'file', wfGetNull(), 'a' ),
-                               2 => array( 'pipe', 'w' )
-                       );
-               } else {
-                       $descriptorspec = array(
-                               0 => array( 'pipe', 'r' ),
-                               1 => array( 'pipe', 'w' ),
-                               2 => array( 'file', wfGetNull(), 'a' )
-                       );
-               }
-
-               $readpipe = $stderr ? 2 : 1;
-               $pipes = array();
-
-               $process = proc_open(
-                       "$wgTidyBin -config $wgTidyConf $wgTidyOpts$opts", $descriptorspec, $pipes );
-
-               //NOTE: At least on linux, the process will be created even if tidy is not installed.
-               //      This means that missing tidy will be treated as a validation failure.
-
-               if ( is_resource( $process ) ) {
-                       // Theoretically, this style of communication could cause a deadlock
-                       // here. If the stdout buffer fills up, then writes to stdin could
-                       // block. This doesn't appear to happen with tidy, because tidy only
-                       // writes to stdout after it's finished reading from stdin. Search
-                       // for tidyParseStdin and tidySaveStdout in console/tidy.c
-                       fwrite( $pipes[0], $text );
-                       fclose( $pipes[0] );
-                       while ( !feof( $pipes[$readpipe] ) ) {
-                               $cleansource .= fgets( $pipes[$readpipe], 1024 );
-                       }
-                       fclose( $pipes[$readpipe] );
-                       $retval = proc_close( $process );
-               } else {
-                       wfWarn( "Unable to start external tidy process" );
-                       $retval = -1;
-               }
-
-               if ( !$stderr && $cleansource == '' && $text != '' ) {
-                       // Some kind of error happened, so we couldn't get the corrected text.
-                       // Just give up; we'll use the source text and append a warning.
-                       $cleansource = null;
-               }
-
-               wfProfileOut( __METHOD__ );
-               return $cleansource;
-       }
-
-       /**
-        * Use the HTML tidy extension to use the tidy library in-process,
-        * saving the overhead of spawning a new process.
-        *
-        * @param string $text HTML to check
-        * @param bool $stderr Whether to read result from error status instead of output
-        * @param int &$retval Exit code (-1 on internal error)
-        * @return string|null
-        */
-       private static function execInternalTidy( $text, $stderr = false, &$retval = null ) {
-               global $wgTidyConf, $wgDebugTidy;
-               wfProfileIn( __METHOD__ );
-
-               if ( !class_exists( 'tidy' ) ) {
-                       wfWarn( "Unable to load internal tidy class." );
-                       $retval = -1;
-
-                       wfProfileOut( __METHOD__ );
-                       return null;
-               }
-
-               $tidy = new tidy;
-               $tidy->parseString( $text, $wgTidyConf, 'utf8' );
-
-               if ( $stderr ) {
-                       $retval = $tidy->getStatus();
-
-                       wfProfileOut( __METHOD__ );
-                       return $tidy->errorBuffer;
-               }
-
-               $tidy->cleanRepair();
-               $retval = $tidy->getStatus();
-               if ( $retval == 2 ) {
-                       // 2 is magic number for fatal error
-                       // http://www.php.net/manual/en/function.tidy-get-status.php
-                       $cleansource = null;
-               } else {
-                       $cleansource = tidy_get_output( $tidy );
-                       if ( $wgDebugTidy && $retval > 0 ) {
-                               $cleansource .= "<!--\nTidy reports:\n" .
-                                       str_replace( '-->', '--&gt;', $tidy->errorBuffer ) .
-                                       "\n-->";
-                       }
-               }
-
-               wfProfileOut( __METHOD__ );
-               return $cleansource;
-       }
-}