summaryrefslogtreecommitdiff
path: root/includes/utils
diff options
context:
space:
mode:
Diffstat (limited to 'includes/utils')
-rw-r--r--includes/utils/ArrayUtils.php187
-rw-r--r--includes/utils/AutoloadGenerator.php296
-rw-r--r--includes/utils/Cdb.php163
-rw-r--r--includes/utils/CdbDBA.php75
-rw-r--r--includes/utils/CdbPHP.php494
-rw-r--r--includes/utils/IP.php23
-rw-r--r--includes/utils/MWCryptHKDF.php11
-rw-r--r--includes/utils/MWCryptRand.php11
-rw-r--r--includes/utils/MWFunction.php37
-rw-r--r--includes/utils/StringUtils.php612
-rw-r--r--includes/utils/UIDGenerator.php6
-rw-r--r--includes/utils/ZipDirectoryReader.php1
12 files changed, 336 insertions, 1580 deletions
diff --git a/includes/utils/ArrayUtils.php b/includes/utils/ArrayUtils.php
deleted file mode 100644
index 1e521cb8..00000000
--- a/includes/utils/ArrayUtils.php
+++ /dev/null
@@ -1,187 +0,0 @@
-<?php
-/**
- * Methods to play with arrays.
- *
- * 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
- */
-
-/**
- * A collection of static methods to play with arrays.
- *
- * @since 1.21
- */
-class ArrayUtils {
- /**
- * Sort the given array in a pseudo-random order which depends only on the
- * given key and each element value. This is typically used for load
- * balancing between servers each with a local cache.
- *
- * Keys are preserved. The input array is modified in place.
- *
- * Note: Benchmarking on PHP 5.3 and 5.4 indicates that for small
- * strings, md5() is only 10% slower than hash('joaat',...) etc.,
- * since the function call overhead dominates. So there's not much
- * justification for breaking compatibility with installations
- * compiled with ./configure --disable-hash.
- *
- * @param array $array Array to sort
- * @param string $key
- * @param string $separator A separator used to delimit the array elements and the
- * key. This can be chosen to provide backwards compatibility with
- * various consistent hash implementations that existed before this
- * function was introduced.
- */
- public static function consistentHashSort( &$array, $key, $separator = "\000" ) {
- $hashes = array();
- foreach ( $array as $elt ) {
- $hashes[$elt] = md5( $elt . $separator . $key );
- }
- uasort( $array, function ( $a, $b ) use ( $hashes ) {
- return strcmp( $hashes[$a], $hashes[$b] );
- } );
- }
-
- /**
- * Given an array of non-normalised probabilities, this function will select
- * an element and return the appropriate key
- *
- * @param array $weights
- * @return bool|int|string
- */
- public static function pickRandom( $weights ) {
- if ( !is_array( $weights ) || count( $weights ) == 0 ) {
- return false;
- }
-
- $sum = array_sum( $weights );
- if ( $sum == 0 ) {
- # No loads on any of them
- # In previous versions, this triggered an unweighted random selection,
- # but this feature has been removed as of April 2006 to allow for strict
- # separation of query groups.
- return false;
- }
- $max = mt_getrandmax();
- $rand = mt_rand( 0, $max ) / $max * $sum;
-
- $sum = 0;
- foreach ( $weights as $i => $w ) {
- $sum += $w;
- # Do not return keys if they have 0 weight.
- # Note that the "all 0 weight" case is handed above
- if ( $w > 0 && $sum >= $rand ) {
- break;
- }
- }
-
- return $i;
- }
-
- /**
- * Do a binary search, and return the index of the largest item that sorts
- * less than or equal to the target value.
- *
- * @since 1.23
- *
- * @param array $valueCallback A function to call to get the value with
- * a given array index.
- * @param int $valueCount The number of items accessible via $valueCallback,
- * indexed from 0 to $valueCount - 1
- * @param array $comparisonCallback A callback to compare two values, returning
- * -1, 0 or 1 in the style of strcmp().
- * @param string $target The target value to find.
- *
- * @return int|bool The item index of the lower bound, or false if the target value
- * sorts before all items.
- */
- public static function findLowerBound( $valueCallback, $valueCount,
- $comparisonCallback, $target
- ) {
- if ( $valueCount === 0 ) {
- return false;
- }
-
- $min = 0;
- $max = $valueCount;
- do {
- $mid = $min + ( ( $max - $min ) >> 1 );
- $item = call_user_func( $valueCallback, $mid );
- $comparison = call_user_func( $comparisonCallback, $target, $item );
- if ( $comparison > 0 ) {
- $min = $mid;
- } elseif ( $comparison == 0 ) {
- $min = $mid;
- break;
- } else {
- $max = $mid;
- }
- } while ( $min < $max - 1 );
-
- if ( $min == 0 ) {
- $item = call_user_func( $valueCallback, $min );
- $comparison = call_user_func( $comparisonCallback, $target, $item );
- if ( $comparison < 0 ) {
- // Before the first item
- return false;
- }
- }
- return $min;
- }
-
- /**
- * Do array_diff_assoc() on multi-dimensional arrays.
- *
- * Note: empty arrays are removed.
- *
- * @since 1.23
- *
- * @param array $array1 The array to compare from
- * @param array $array2,... More arrays to compare against
- * @return array An array containing all the values from array1
- * that are not present in any of the other arrays.
- */
- public static function arrayDiffAssocRecursive( $array1 ) {
- $arrays = func_get_args();
- array_shift( $arrays );
- $ret = array();
-
- foreach ( $array1 as $key => $value ) {
- if ( is_array( $value ) ) {
- $args = array( $value );
- foreach ( $arrays as $array ) {
- if ( isset( $array[$key] ) ) {
- $args[] = $array[$key];
- }
- }
- $valueret = call_user_func_array( __METHOD__, $args );
- if ( count( $valueret ) ) {
- $ret[$key] = $valueret;
- }
- } else {
- foreach ( $arrays as $array ) {
- if ( isset( $array[$key] ) && $array[$key] === $value ) {
- continue 2;
- }
- }
- $ret[$key] = $value;
- }
- }
-
- return $ret;
- }
-}
diff --git a/includes/utils/AutoloadGenerator.php b/includes/utils/AutoloadGenerator.php
new file mode 100644
index 00000000..9cf8cab5
--- /dev/null
+++ b/includes/utils/AutoloadGenerator.php
@@ -0,0 +1,296 @@
+<?php
+
+/**
+ * Accepts a list of files and directories to search for
+ * php files and generates $wgAutoloadLocalClasses or $wgAutoloadClasses
+ * lines for all detected classes. These lines are written out
+ * to an autoload.php file in the projects provided basedir.
+ *
+ * Usage:
+ *
+ * $gen = new AutoloadGenerator( __DIR__ );
+ * $gen->readDir( __DIR__ . '/includes' );
+ * $gen->readFile( __DIR__ . '/foo.php' )
+ * $gen->generateAutoload();
+ */
+class AutoloadGenerator {
+ /**
+ * @var string Root path of the project being scanned for classes
+ */
+ protected $basepath;
+
+ /**
+ * @var ClassCollector Helper class extracts class names from php files
+ */
+ protected $collector;
+
+ /**
+ * @var array Map of file shortpath to list of FQCN detected within file
+ */
+ protected $classes = array();
+
+ /**
+ * @var string The global variable to write output to
+ */
+ protected $variableName = 'wgAutoloadClasses';
+
+ /**
+ * @var array Map of FQCN to relative path(from self::$basepath)
+ */
+ protected $overrides = array();
+
+ /**
+ * @param string $basepath Root path of the project being scanned for classes
+ * @param array|string $flags
+ *
+ * local - If this flag is set $wgAutoloadLocalClasses will be build instead
+ * of $wgAutoloadClasses
+ */
+ public function __construct( $basepath, $flags = array() ) {
+ if ( !is_array( $flags ) ) {
+ $flags = array( $flags );
+ }
+ $this->basepath = self::normalizePathSeparator( realpath( $basepath ) );
+ $this->collector = new ClassCollector;
+ if ( in_array( 'local', $flags ) ) {
+ $this->variableName = 'wgAutoloadLocalClasses';
+ }
+ }
+
+ /**
+ * Force a class to be autoloaded from a specific path, regardless of where
+ * or if it was detected.
+ *
+ * @param string $fqcn FQCN to force the location of
+ * @param string $inputPath Full path to the file containing the class
+ * @throws Exception
+ */
+ public function forceClassPath( $fqcn, $inputPath ) {
+ $path = self::normalizePathSeparator( realpath( $inputPath ) );
+ if ( !$path ) {
+ throw new \Exception( "Invalid path: $inputPath" );
+ }
+ $len = strlen( $this->basepath );
+ if ( substr( $path, 0, $len ) !== $this->basepath ) {
+ throw new \Exception( "Path is not within basepath: $inputPath" );
+ }
+ $shortpath = substr( $path, $len );
+ $this->overrides[$fqcn] = $shortpath;
+ }
+
+ /**
+ * @param string $inputPath Path to a php file to find classes within
+ * @throws Exception
+ */
+ public function readFile( $inputPath ) {
+ // NOTE: do NOT expand $inputPath using realpath(). It is perfectly
+ // reasonable for LocalSettings.php and similiar files to be symlinks
+ // to files that are outside of $this->basepath.
+ $inputPath = self::normalizePathSeparator( $inputPath );
+ $len = strlen( $this->basepath );
+ if ( substr( $inputPath, 0, $len ) !== $this->basepath ) {
+ throw new \Exception( "Path is not within basepath: $inputPath" );
+ }
+ $result = $this->collector->getClasses(
+ file_get_contents( $inputPath )
+ );
+ if ( $result ) {
+ $shortpath = substr( $inputPath, $len );
+ $this->classes[$shortpath] = $result;
+ }
+ }
+
+ /**
+ * @param string $dir Path to a directory to recursively search
+ * for php files with either .php or .inc extensions
+ */
+ public function readDir( $dir ) {
+ $it = new RecursiveDirectoryIterator(
+ self::normalizePathSeparator( realpath( $dir ) ) );
+ $it = new RecursiveIteratorIterator( $it );
+
+ foreach ( $it as $path => $file ) {
+ $ext = pathinfo( $path, PATHINFO_EXTENSION );
+ // some older files in mw use .inc
+ if ( $ext === 'php' || $ext === 'inc' ) {
+ $this->readFile( $path );
+ }
+ }
+ }
+
+ /**
+ * Write out all known classes to autoload.php in
+ * the provided basedir
+ *
+ * @param string $commandName Value used in file comment to direct
+ * developers towards the appropriate way to update the autoload.
+ */
+ public function generateAutoload( $commandName = 'AutoloadGenerator' ) {
+ $content = array();
+
+ // We need to generate a line each rather than exporting the
+ // full array so __DIR__ can be prepended to all the paths
+ $format = "%s => __DIR__ . %s,";
+ foreach ( $this->classes as $path => $contained ) {
+ $exportedPath = var_export( $path, true );
+ foreach ( $contained as $fqcn ) {
+ $content[$fqcn] = sprintf(
+ $format,
+ var_export( $fqcn, true ),
+ $exportedPath
+ );
+ }
+ }
+
+ foreach ( $this->overrides as $fqcn => $path ) {
+ $content[$fqcn] = sprintf(
+ $format,
+ var_export( $fqcn, true ),
+ var_export( $path, true )
+ );
+ }
+
+ // sort for stable output
+ ksort( $content );
+
+ // extensions using this generator are appending to the existing
+ // autoload.
+ if ( $this->variableName === 'wgAutoloadClasses' ) {
+ $op = '+=';
+ } else {
+ $op = '=';
+ }
+
+ $output = implode( "\n\t", $content );
+ file_put_contents(
+ $this->basepath . '/autoload.php',
+ <<<EOD
+<?php
+// This file is generated by $commandName, do not adjust manually
+// @codingStandardsIgnoreFile
+global \${$this->variableName};
+
+\${$this->variableName} {$op} array(
+ {$output}
+);
+
+EOD
+ );
+ }
+
+ /**
+ * Ensure that Unix-style path separators ("/") are used in the path.
+ *
+ * @param string $path
+ * @return string
+ */
+ protected static function normalizePathSeparator( $path ) {
+ return str_replace( '\\', '/', $path );
+ }
+}
+
+/**
+ * Reads PHP code and returns the FQCN of every class defined within it.
+ */
+class ClassCollector {
+
+ /**
+ * @var string Current namespace
+ */
+ protected $namespace = '';
+
+ /**
+ * @var array List of FQCN detected in this pass
+ */
+ protected $classes;
+
+ /**
+ * @var array Token from token_get_all() that started an expect sequence
+ */
+ protected $startToken;
+
+ /**
+ * @var array List of tokens that are members of the current expect sequence
+ */
+ protected $tokens;
+
+ /**
+ * @var string $code PHP code (including <?php) to detect class names from
+ * @return array List of FQCN detected within the tokens
+ */
+ public function getClasses( $code ) {
+ $this->namespace = '';
+ $this->classes = array();
+ $this->startToken = null;
+ $this->tokens = array();
+
+ foreach ( token_get_all( $code ) as $token ) {
+ if ( $this->startToken === null ) {
+ $this->tryBeginExpect( $token );
+ } else {
+ $this->tryEndExpect( $token );
+ }
+ }
+
+ return $this->classes;
+ }
+
+ /**
+ * Determine if $token begins the next expect sequence.
+ *
+ * @param array $token
+ */
+ protected function tryBeginExpect( $token ) {
+ if ( is_string( $token ) ) {
+ return;
+ }
+ switch ( $token[0] ) {
+ case T_NAMESPACE:
+ case T_CLASS:
+ case T_INTERFACE:
+ $this->startToken = $token;
+ }
+ }
+
+ /**
+ * Accepts the next token in an expect sequence
+ *
+ * @param array
+ */
+ protected function tryEndExpect( $token ) {
+ switch ( $this->startToken[0] ) {
+ case T_NAMESPACE:
+ if ( $token === ';' || $token === '{' ) {
+ $this->namespace = $this->implodeTokens() . '\\';
+ } else {
+ $this->tokens[] = $token;
+ }
+ break;
+
+ case T_CLASS:
+ case T_INTERFACE:
+ $this->tokens[] = $token;
+ if ( is_array( $token ) && $token[0] === T_STRING ) {
+ $this->classes[] = $this->namespace . $this->implodeTokens();
+ }
+ }
+ }
+
+ /**
+ * Returns the string representation of the tokens within the
+ * current expect sequence and resets the sequence.
+ *
+ * @return string
+ */
+ protected function implodeTokens() {
+ $content = array();
+ foreach ( $this->tokens as $token ) {
+ $content[] = is_string( $token ) ? $token : $token[1];
+ }
+
+ $this->tokens = array();
+ $this->startToken = null;
+
+ return trim( implode( '', $content ), " \n\t" );
+ }
+}
diff --git a/includes/utils/Cdb.php b/includes/utils/Cdb.php
deleted file mode 100644
index 3ceb620f..00000000
--- a/includes/utils/Cdb.php
+++ /dev/null
@@ -1,163 +0,0 @@
-<?php
-/**
- * Native CDB file reader and writer.
- *
- * 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
- */
-
-/**
- * Read from a CDB file.
- * Native and pure PHP implementations are provided.
- * http://cr.yp.to/cdb.html
- */
-abstract class CdbReader {
- /**
- * The file handle
- */
- protected $handle;
-
- /**
- * Open a file and return a subclass instance
- *
- * @param string $fileName
- *
- * @return CdbReader
- */
- public static function open( $fileName ) {
- return self::haveExtension() ?
- new CdbReaderDBA( $fileName ) :
- new CdbReaderPHP( $fileName );
- }
-
- /**
- * Returns true if the native extension is available
- *
- * @return bool
- */
- public static function haveExtension() {
- if ( !function_exists( 'dba_handlers' ) ) {
- return false;
- }
- $handlers = dba_handlers();
- if ( !in_array( 'cdb', $handlers ) || !in_array( 'cdb_make', $handlers ) ) {
- return false;
- }
-
- return true;
- }
-
- /**
- * Create the object and open the file
- *
- * @param string $fileName
- */
- abstract public function __construct( $fileName );
-
- /**
- * Close the file. Optional, you can just let the variable go out of scope.
- */
- abstract public function close();
-
- /**
- * Get a value with a given key. Only string values are supported.
- *
- * @param string $key
- */
- abstract public function get( $key );
-}
-
-/**
- * Write to a CDB file.
- * Native and pure PHP implementations are provided.
- */
-abstract class CdbWriter {
- /**
- * The file handle
- */
- protected $handle;
-
- /**
- * File we'll be writing to when we're done
- * @var string
- */
- protected $realFileName;
-
- /**
- * File we write to temporarily until we're done
- * @var string
- */
- protected $tmpFileName;
-
- /**
- * Open a writer and return a subclass instance.
- * The user must have write access to the directory, for temporary file creation.
- *
- * @param string $fileName
- *
- * @return CdbWriterDBA|CdbWriterPHP
- */
- public static function open( $fileName ) {
- return CdbReader::haveExtension() ?
- new CdbWriterDBA( $fileName ) :
- new CdbWriterPHP( $fileName );
- }
-
- /**
- * Create the object and open the file
- *
- * @param string $fileName
- */
- abstract public function __construct( $fileName );
-
- /**
- * Set a key to a given value. The value will be converted to string.
- * @param string $key
- * @param string $value
- */
- abstract public function set( $key, $value );
-
- /**
- * Close the writer object. You should call this function before the object
- * goes out of scope, to write out the final hashtables.
- */
- abstract public function close();
-
- /**
- * If the object goes out of scope, close it for sanity
- */
- public function __destruct() {
- if ( isset( $this->handle ) ) {
- $this->close();
- }
- }
-
- /**
- * Are we running on Windows?
- * @return bool
- */
- protected function isWindows() {
- return substr( php_uname(), 0, 7 ) == 'Windows';
- }
-}
-
-/**
- * Exception for Cdb errors.
- * This explicitly doesn't subclass MWException to encourage reuse.
- */
-class CdbException extends Exception {
-}
diff --git a/includes/utils/CdbDBA.php b/includes/utils/CdbDBA.php
deleted file mode 100644
index efcaf21f..00000000
--- a/includes/utils/CdbDBA.php
+++ /dev/null
@@ -1,75 +0,0 @@
-<?php
-/**
- * DBA-based CDB reader/writer
- *
- * 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
- */
-
-/**
- * Reader class which uses the DBA extension
- */
-class CdbReaderDBA extends CdbReader {
- public function __construct( $fileName ) {
- $this->handle = dba_open( $fileName, 'r-', 'cdb' );
- if ( !$this->handle ) {
- throw new CdbException( 'Unable to open CDB file "' . $fileName . '"' );
- }
- }
-
- public function close() {
- if ( isset( $this->handle ) ) {
- dba_close( $this->handle );
- }
- unset( $this->handle );
- }
-
- public function get( $key ) {
- return dba_fetch( $key, $this->handle );
- }
-}
-
-/**
- * Writer class which uses the DBA extension
- */
-class CdbWriterDBA extends CdbWriter {
- public function __construct( $fileName ) {
- $this->realFileName = $fileName;
- $this->tmpFileName = $fileName . '.tmp.' . mt_rand( 0, 0x7fffffff );
- $this->handle = dba_open( $this->tmpFileName, 'n', 'cdb_make' );
- if ( !$this->handle ) {
- throw new CdbException( 'Unable to open CDB file for write "' . $fileName . '"' );
- }
- }
-
- public function set( $key, $value ) {
- return dba_insert( $key, $value, $this->handle );
- }
-
- public function close() {
- if ( isset( $this->handle ) ) {
- dba_close( $this->handle );
- }
- if ( $this->isWindows() ) {
- unlink( $this->realFileName );
- }
- if ( !rename( $this->tmpFileName, $this->realFileName ) ) {
- throw new CdbException( 'Unable to move the new CDB file into place.' );
- }
- unset( $this->handle );
- }
-}
diff --git a/includes/utils/CdbPHP.php b/includes/utils/CdbPHP.php
deleted file mode 100644
index 19d747a7..00000000
--- a/includes/utils/CdbPHP.php
+++ /dev/null
@@ -1,494 +0,0 @@
-<?php
-/**
- * This is a port of D.J. Bernstein's CDB to PHP. It's based on the copy that
- * appears in PHP 5.3. Changes are:
- * * Error returns replaced with exceptions
- * * Exception thrown if sizes or offsets are between 2GB and 4GB
- * * Some variables renamed
- *
- * 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
- */
-
-/**
- * Common functions for readers and writers
- */
-class CdbFunctions {
- /**
- * Take a modulo of a signed integer as if it were an unsigned integer.
- * $b must be less than 0x40000000 and greater than 0
- *
- * @param int $a
- * @param int $b
- *
- * @return int
- */
- public static function unsignedMod( $a, $b ) {
- if ( $a & 0x80000000 ) {
- $m = ( $a & 0x7fffffff ) % $b + 2 * ( 0x40000000 % $b );
-
- return $m % $b;
- } else {
- return $a % $b;
- }
- }
-
- /**
- * Shift a signed integer right as if it were unsigned
- * @param int $a
- * @param int $b
- * @return int
- */
- public static function unsignedShiftRight( $a, $b ) {
- if ( $b == 0 ) {
- return $a;
- }
- if ( $a & 0x80000000 ) {
- return ( ( $a & 0x7fffffff ) >> $b ) | ( 0x40000000 >> ( $b - 1 ) );
- } else {
- return $a >> $b;
- }
- }
-
- /**
- * The CDB hash function.
- *
- * @param string $s
- *
- * @return int
- */
- public static function hash( $s ) {
- $h = 5381;
- $len = strlen( $s );
- for ( $i = 0; $i < $len; $i++ ) {
- $h5 = ( $h << 5 ) & 0xffffffff;
- // Do a 32-bit sum
- // Inlined here for speed
- $sum = ( $h & 0x3fffffff ) + ( $h5 & 0x3fffffff );
- $h =
- (
- ( $sum & 0x40000000 ? 1 : 0 )
- + ( $h & 0x80000000 ? 2 : 0 )
- + ( $h & 0x40000000 ? 1 : 0 )
- + ( $h5 & 0x80000000 ? 2 : 0 )
- + ( $h5 & 0x40000000 ? 1 : 0 )
- ) << 30
- | ( $sum & 0x3fffffff );
- $h ^= ord( $s[$i] );
- $h &= 0xffffffff;
- }
-
- return $h;
- }
-}
-
-/**
- * CDB reader class
- */
-class CdbReaderPHP extends CdbReader {
- /** The filename */
- protected $fileName;
-
- /* number of hash slots searched under this key */
- protected $loop;
-
- /* initialized if loop is nonzero */
- protected $khash;
-
- /* initialized if loop is nonzero */
- protected $kpos;
-
- /* initialized if loop is nonzero */
- protected $hpos;
-
- /* initialized if loop is nonzero */
- protected $hslots;
-
- /* initialized if findNext() returns true */
- protected $dpos;
-
- /* initialized if cdb_findnext() returns 1 */
- protected $dlen;
-
- /**
- * @param string $fileName
- * @throws CdbException
- */
- public function __construct( $fileName ) {
- $this->fileName = $fileName;
- $this->handle = fopen( $fileName, 'rb' );
- if ( !$this->handle ) {
- throw new CdbException( 'Unable to open CDB file "' . $this->fileName . '".' );
- }
- $this->findStart();
- }
-
- public function close() {
- if ( isset( $this->handle ) ) {
- fclose( $this->handle );
- }
- unset( $this->handle );
- }
-
- /**
- * @param mixed $key
- * @return bool|string
- */
- public function get( $key ) {
- // strval is required
- if ( $this->find( strval( $key ) ) ) {
- return $this->read( $this->dlen, $this->dpos );
- } else {
- return false;
- }
- }
-
- /**
- * @param string $key
- * @param int $pos
- * @return bool
- */
- protected function match( $key, $pos ) {
- $buf = $this->read( strlen( $key ), $pos );
-
- return $buf === $key;
- }
-
- protected function findStart() {
- $this->loop = 0;
- }
-
- /**
- * @throws CdbException
- * @param int $length
- * @param int $pos
- * @return string
- */
- protected function read( $length, $pos ) {
- if ( fseek( $this->handle, $pos ) == -1 ) {
- // This can easily happen if the internal pointers are incorrect
- throw new CdbException(
- 'Seek failed, file "' . $this->fileName . '" may be corrupted.' );
- }
-
- if ( $length == 0 ) {
- return '';
- }
-
- $buf = fread( $this->handle, $length );
- if ( $buf === false || strlen( $buf ) !== $length ) {
- throw new CdbException(
- 'Read from CDB file failed, file "' . $this->fileName . '" may be corrupted.' );
- }
-
- return $buf;
- }
-
- /**
- * Unpack an unsigned integer and throw an exception if it needs more than 31 bits
- * @param string $s
- * @throws CdbException
- * @return mixed
- */
- protected function unpack31( $s ) {
- $data = unpack( 'V', $s );
- if ( $data[1] > 0x7fffffff ) {
- throw new CdbException(
- 'Error in CDB file "' . $this->fileName . '", integer too big.' );
- }
-
- return $data[1];
- }
-
- /**
- * Unpack a 32-bit signed integer
- * @param string $s
- * @return int
- */
- protected function unpackSigned( $s ) {
- $data = unpack( 'va/vb', $s );
-
- return $data['a'] | ( $data['b'] << 16 );
- }
-
- /**
- * @param string $key
- * @return bool
- */
- protected function findNext( $key ) {
- if ( !$this->loop ) {
- $u = CdbFunctions::hash( $key );
- $buf = $this->read( 8, ( $u << 3 ) & 2047 );
- $this->hslots = $this->unpack31( substr( $buf, 4 ) );
- if ( !$this->hslots ) {
- return false;
- }
- $this->hpos = $this->unpack31( substr( $buf, 0, 4 ) );
- $this->khash = $u;
- $u = CdbFunctions::unsignedShiftRight( $u, 8 );
- $u = CdbFunctions::unsignedMod( $u, $this->hslots );
- $u <<= 3;
- $this->kpos = $this->hpos + $u;
- }
-
- while ( $this->loop < $this->hslots ) {
- $buf = $this->read( 8, $this->kpos );
- $pos = $this->unpack31( substr( $buf, 4 ) );
- if ( !$pos ) {
- return false;
- }
- $this->loop += 1;
- $this->kpos += 8;
- if ( $this->kpos == $this->hpos + ( $this->hslots << 3 ) ) {
- $this->kpos = $this->hpos;
- }
- $u = $this->unpackSigned( substr( $buf, 0, 4 ) );
- if ( $u === $this->khash ) {
- $buf = $this->read( 8, $pos );
- $keyLen = $this->unpack31( substr( $buf, 0, 4 ) );
- if ( $keyLen == strlen( $key ) && $this->match( $key, $pos + 8 ) ) {
- // Found
- $this->dlen = $this->unpack31( substr( $buf, 4 ) );
- $this->dpos = $pos + 8 + $keyLen;
-
- return true;
- }
- }
- }
-
- return false;
- }
-
- /**
- * @param mixed $key
- * @return bool
- */
- protected function find( $key ) {
- $this->findStart();
-
- return $this->findNext( $key );
- }
-}
-
-/**
- * CDB writer class
- */
-class CdbWriterPHP extends CdbWriter {
- protected $hplist;
-
- protected $numentries;
-
- protected $pos;
-
- /**
- * @param string $fileName
- */
- public function __construct( $fileName ) {
- $this->realFileName = $fileName;
- $this->tmpFileName = $fileName . '.tmp.' . mt_rand( 0, 0x7fffffff );
- $this->handle = fopen( $this->tmpFileName, 'wb' );
- if ( !$this->handle ) {
- $this->throwException(
- 'Unable to open CDB file "' . $this->tmpFileName . '" for write.' );
- }
- $this->hplist = array();
- $this->numentries = 0;
- $this->pos = 2048; // leaving space for the pointer array, 256 * 8
- if ( fseek( $this->handle, $this->pos ) == -1 ) {
- $this->throwException( 'fseek failed in file "' . $this->tmpFileName . '".' );
- }
- }
-
- /**
- * @param string $key
- * @param string $value
- */
- public function set( $key, $value ) {
- if ( strval( $key ) === '' ) {
- // DBA cross-check hack
- return;
- }
- $this->addbegin( strlen( $key ), strlen( $value ) );
- $this->write( $key );
- $this->write( $value );
- $this->addend( strlen( $key ), strlen( $value ), CdbFunctions::hash( $key ) );
- }
-
- /**
- * @throws CdbException
- */
- public function close() {
- $this->finish();
- if ( isset( $this->handle ) ) {
- fclose( $this->handle );
- }
- if ( $this->isWindows() && file_exists( $this->realFileName ) ) {
- unlink( $this->realFileName );
- }
- if ( !rename( $this->tmpFileName, $this->realFileName ) ) {
- $this->throwException( 'Unable to move the new CDB file into place.' );
- }
- unset( $this->handle );
- }
-
- /**
- * @throws CdbException
- * @param string $buf
- */
- protected function write( $buf ) {
- $len = fwrite( $this->handle, $buf );
- if ( $len !== strlen( $buf ) ) {
- $this->throwException( 'Error writing to CDB file "' . $this->tmpFileName . '".' );
- }
- }
-
- /**
- * @throws CdbException
- * @param int $len
- */
- protected function posplus( $len ) {
- $newpos = $this->pos + $len;
- if ( $newpos > 0x7fffffff ) {
- $this->throwException(
- 'A value in the CDB file "' . $this->tmpFileName . '" is too large.' );
- }
- $this->pos = $newpos;
- }
-
- /**
- * @param int $keylen
- * @param int $datalen
- * @param int $h
- */
- protected function addend( $keylen, $datalen, $h ) {
- $this->hplist[] = array(
- 'h' => $h,
- 'p' => $this->pos
- );
-
- $this->numentries++;
- $this->posplus( 8 );
- $this->posplus( $keylen );
- $this->posplus( $datalen );
- }
-
- /**
- * @throws CdbException
- * @param int $keylen
- * @param int $datalen
- */
- protected function addbegin( $keylen, $datalen ) {
- if ( $keylen > 0x7fffffff ) {
- $this->throwException( 'Key length too long in file "' . $this->tmpFileName . '".' );
- }
- if ( $datalen > 0x7fffffff ) {
- $this->throwException( 'Data length too long in file "' . $this->tmpFileName . '".' );
- }
- $buf = pack( 'VV', $keylen, $datalen );
- $this->write( $buf );
- }
-
- /**
- * @throws CdbException
- */
- protected function finish() {
- // Hack for DBA cross-check
- $this->hplist = array_reverse( $this->hplist );
-
- // Calculate the number of items that will be in each hashtable
- $counts = array_fill( 0, 256, 0 );
- foreach ( $this->hplist as $item ) {
- ++$counts[255 & $item['h']];
- }
-
- // Fill in $starts with the *end* indexes
- $starts = array();
- $pos = 0;
- for ( $i = 0; $i < 256; ++$i ) {
- $pos += $counts[$i];
- $starts[$i] = $pos;
- }
-
- // Excessively clever and indulgent code to simultaneously fill $packedTables
- // with the packed hashtables, and adjust the elements of $starts
- // to actually point to the starts instead of the ends.
- $packedTables = array_fill( 0, $this->numentries, false );
- foreach ( $this->hplist as $item ) {
- $packedTables[--$starts[255 & $item['h']]] = $item;
- }
-
- $final = '';
- for ( $i = 0; $i < 256; ++$i ) {
- $count = $counts[$i];
-
- // The size of the hashtable will be double the item count.
- // The rest of the slots will be empty.
- $len = $count + $count;
- $final .= pack( 'VV', $this->pos, $len );
-
- $hashtable = array();
- for ( $u = 0; $u < $len; ++$u ) {
- $hashtable[$u] = array( 'h' => 0, 'p' => 0 );
- }
-
- // Fill the hashtable, using the next empty slot if the hashed slot
- // is taken.
- for ( $u = 0; $u < $count; ++$u ) {
- $hp = $packedTables[$starts[$i] + $u];
- $where = CdbFunctions::unsignedMod(
- CdbFunctions::unsignedShiftRight( $hp['h'], 8 ), $len );
- while ( $hashtable[$where]['p'] ) {
- if ( ++$where == $len ) {
- $where = 0;
- }
- }
- $hashtable[$where] = $hp;
- }
-
- // Write the hashtable
- for ( $u = 0; $u < $len; ++$u ) {
- $buf = pack( 'vvV',
- $hashtable[$u]['h'] & 0xffff,
- CdbFunctions::unsignedShiftRight( $hashtable[$u]['h'], 16 ),
- $hashtable[$u]['p'] );
- $this->write( $buf );
- $this->posplus( 8 );
- }
- }
-
- // Write the pointer array at the start of the file
- rewind( $this->handle );
- if ( ftell( $this->handle ) != 0 ) {
- $this->throwException( 'Error rewinding to start of file "' . $this->tmpFileName . '".' );
- }
- $this->write( $final );
- }
-
- /**
- * Clean up the temp file and throw an exception
- *
- * @param string $msg
- * @throws CdbException
- */
- protected function throwException( $msg ) {
- if ( $this->handle ) {
- fclose( $this->handle );
- unlink( $this->tmpFileName );
- }
- throw new CdbException( $msg );
- }
-}
diff --git a/includes/utils/IP.php b/includes/utils/IP.php
index 0e2db8cc..4441236d 100644
--- a/includes/utils/IP.php
+++ b/includes/utils/IP.php
@@ -629,6 +629,25 @@ class IP {
}
/**
+ * Determines if an IP address is a list of CIDR a.b.c.d/n ranges.
+ *
+ * @since 1.25
+ *
+ * @param string $ip the IP to check
+ * @param array $ranges the IP ranges, each element a range
+ *
+ * @return bool true if the specified adress belongs to the specified range; otherwise, false.
+ */
+ public static function isInRanges( $ip, $ranges ) {
+ foreach ( $ranges as $range ) {
+ if ( self::isInRange( $ip, $range ) ) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
* Convert some unusual representations of IPv4 addresses to their
* canonical dotted quad representation.
*
@@ -698,7 +717,7 @@ class IP {
*/
public static function isTrustedProxy( $ip ) {
$trusted = self::isConfiguredProxy( $ip );
- wfRunHooks( 'IsTrustedProxy', array( &$ip, &$trusted ) );
+ Hooks::run( 'IsTrustedProxy', array( &$ip, &$trusted ) );
return $trusted;
}
@@ -712,7 +731,6 @@ class IP {
public static function isConfiguredProxy( $ip ) {
global $wgSquidServers, $wgSquidServersNoPurge;
- wfProfileIn( __METHOD__ );
// Quick check of known singular proxy servers
$trusted = in_array( $ip, $wgSquidServers );
@@ -723,7 +741,6 @@ class IP {
}
$trusted = self::$proxyIpSet->match( $ip );
}
- wfProfileOut( __METHOD__ );
return $trusted;
}
diff --git a/includes/utils/MWCryptHKDF.php b/includes/utils/MWCryptHKDF.php
index cc136793..950dd846 100644
--- a/includes/utils/MWCryptHKDF.php
+++ b/includes/utils/MWCryptHKDF.php
@@ -103,6 +103,7 @@ class MWCryptHKDF {
* @param string $algorithm Name of hashing algorithm
* @param BagOStuff $cache
* @param string|array $context Context to mix into HKDF context
+ * @throws MWException
*/
public function __construct( $secretKeyMaterial, $algorithm, $cache, $context ) {
if ( strlen( $secretKeyMaterial ) < 16 ) {
@@ -157,6 +158,7 @@ class MWCryptHKDF {
/**
* Return a singleton instance, based on the global configs.
* @return HKDF
+ * @throws MWException
*/
protected static function singleton() {
global $wgHKDFAlgorithm, $wgHKDFSecret, $wgSecretKey;
@@ -271,14 +273,15 @@ class MWCryptHKDF {
*
* @param string $hash Hashing Algorithm
* @param string $prk A pseudorandom key of at least HashLen octets
- * (usually, the output from the extract step)
+ * (usually, the output from the extract step)
* @param string $info Optional context and application specific information
- * (can be a zero-length string)
+ * (can be a zero-length string)
* @param int $bytes Length of output keying material in bytes
- * (<= 255*HashLen)
+ * (<= 255*HashLen)
* @param string &$lastK Set by this function to the last block of the expansion.
- * In MediaWiki, this is used to seed future Extractions.
+ * In MediaWiki, this is used to seed future Extractions.
* @return string Cryptographically secure random string $bytes long
+ * @throws MWException
*/
private static function HKDFExpand( $hash, $prk, $info, $bytes, &$lastK = '' ) {
$hashLen = MWCryptHKDF::$hashLength[$hash];
diff --git a/includes/utils/MWCryptRand.php b/includes/utils/MWCryptRand.php
index b602f78e..e6c0e784 100644
--- a/includes/utils/MWCryptRand.php
+++ b/includes/utils/MWCryptRand.php
@@ -294,7 +294,6 @@ class MWCryptRand {
* @see self::generate()
*/
public function realGenerate( $bytes, $forceStrong = false ) {
- wfProfileIn( __METHOD__ );
wfDebug( __METHOD__ . ": Generating cryptographic random bytes for " .
wfGetAllCallers( 5 ) . "\n" );
@@ -314,7 +313,6 @@ class MWCryptRand {
// entropy so this is also preferable to just trying to read urandom because it may work
// on Windows systems as well.
if ( function_exists( 'mcrypt_create_iv' ) ) {
- wfProfileIn( __METHOD__ . '-mcrypt' );
$rem = $bytes - strlen( $buffer );
$iv = mcrypt_create_iv( $rem, MCRYPT_DEV_URANDOM );
if ( $iv === false ) {
@@ -324,7 +322,6 @@ class MWCryptRand {
wfDebug( __METHOD__ . ": mcrypt_create_iv generated " . strlen( $iv ) .
" bytes of randomness.\n" );
}
- wfProfileOut( __METHOD__ . '-mcrypt' );
}
}
@@ -337,7 +334,6 @@ class MWCryptRand {
if ( function_exists( 'openssl_random_pseudo_bytes' )
&& ( !wfIsWindows() || version_compare( PHP_VERSION, '5.3.4', '>=' ) )
) {
- wfProfileIn( __METHOD__ . '-openssl' );
$rem = $bytes - strlen( $buffer );
$openssl_bytes = openssl_random_pseudo_bytes( $rem, $openssl_strong );
if ( $openssl_bytes === false ) {
@@ -353,7 +349,6 @@ class MWCryptRand {
// using it use it's say on whether the randomness is strong
$this->strong = !!$openssl_strong;
}
- wfProfileOut( __METHOD__ . '-openssl' );
}
}
@@ -361,7 +356,6 @@ class MWCryptRand {
if ( strlen( $buffer ) < $bytes &&
( function_exists( 'stream_set_read_buffer' ) || $forceStrong )
) {
- wfProfileIn( __METHOD__ . '-fopen-urandom' );
$rem = $bytes - strlen( $buffer );
if ( !function_exists( 'stream_set_read_buffer' ) && $forceStrong ) {
wfDebug( __METHOD__ . ": Was forced to read from /dev/urandom " .
@@ -400,7 +394,6 @@ class MWCryptRand {
} else {
wfDebug( __METHOD__ . ": /dev/urandom could not be opened.\n" );
}
- wfProfileOut( __METHOD__ . '-fopen-urandom' );
}
// If we cannot use or generate enough data from a secure source
@@ -414,12 +407,10 @@ class MWCryptRand {
": Falling back to using a pseudo random state to generate randomness.\n" );
}
while ( strlen( $buffer ) < $bytes ) {
- wfProfileIn( __METHOD__ . '-fallback' );
$buffer .= $this->hmac( $this->randomState(), mt_rand() );
// This code is never really cryptographically strong, if we use it
// at all, then set strong to false.
$this->strong = false;
- wfProfileOut( __METHOD__ . '-fallback' );
}
// Once the buffer has been filled up with enough random data to fulfill
@@ -431,8 +422,6 @@ class MWCryptRand {
wfDebug( __METHOD__ . ": " . strlen( $buffer ) .
" bytes of randomness leftover in the buffer.\n" );
- wfProfileOut( __METHOD__ );
-
return $generated;
}
diff --git a/includes/utils/MWFunction.php b/includes/utils/MWFunction.php
index 3a0492dc..fa7eebe8 100644
--- a/includes/utils/MWFunction.php
+++ b/includes/utils/MWFunction.php
@@ -23,41 +23,18 @@
class MWFunction {
/**
- * @deprecated since 1.22; use call_user_func()
- * @param callable $callback
- * @return mixed
- */
- public static function call( $callback ) {
- wfDeprecated( __METHOD__, '1.22' );
- $args = func_get_args();
-
- return call_user_func_array( 'call_user_func', $args );
- }
-
- /**
- * @deprecated since 1.22; use call_user_func_array()
- * @param callable $callback
- * @param array $argsarams
- * @return mixed
- */
- public static function callArray( $callback, $argsarams ) {
- wfDeprecated( __METHOD__, '1.22' );
-
- return call_user_func_array( $callback, $argsarams );
- }
-
- /**
* @param string $class
* @param array $args
* @return object
+ * @deprecated 1.25 Use ObjectFactory::getObjectFromSpec() instead
*/
public static function newObj( $class, $args = array() ) {
- if ( !count( $args ) ) {
- return new $class;
- }
-
- $ref = new ReflectionClass( $class );
+ wfDeprecated( __METHOD__, '1.25' );
- return $ref->newInstanceArgs( $args );
+ return ObjectFactory::getObjectFromSpec( array(
+ 'class' => $class,
+ 'args' => $args,
+ 'closure_expansion' => false,
+ ) );
}
}
diff --git a/includes/utils/StringUtils.php b/includes/utils/StringUtils.php
deleted file mode 100644
index 86f45122..00000000
--- a/includes/utils/StringUtils.php
+++ /dev/null
@@ -1,612 +0,0 @@
-<?php
-/**
- * Methods to play with strings.
- *
- * 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
- */
-
-/**
- * A collection of static methods to play with strings.
- */
-class StringUtils {
- /**
- * Test whether a string is valid UTF-8.
- *
- * The function check for invalid byte sequences, overlong encoding but
- * not for different normalisations.
- *
- * This relies internally on the mbstring function mb_check_encoding()
- * hardcoded to check against UTF-8. Whenever the function is not available
- * we fallback to a pure PHP implementation. Setting $disableMbstring to
- * true will skip the use of mb_check_encoding, this is mostly intended for
- * unit testing our internal implementation.
- *
- * @since 1.21
- * @note In MediaWiki 1.21, this function did not provide proper UTF-8 validation.
- * In particular, the pure PHP code path did not in fact check for overlong forms.
- * Beware of this when backporting code to that version of MediaWiki.
- *
- * @param string $value String to check
- * @param bool $disableMbstring Whether to use the pure PHP
- * implementation instead of trying mb_check_encoding. Intended for unit
- * testing. Default: false
- *
- * @return bool Whether the given $value is a valid UTF-8 encoded string
- */
- static function isUtf8( $value, $disableMbstring = false ) {
- $value = (string)$value;
-
- // If the mbstring extension is loaded, use it. However, before PHP 5.4, values above
- // U+10FFFF are incorrectly allowed, so we have to check for them separately.
- if ( !$disableMbstring && function_exists( 'mb_check_encoding' ) ) {
- static $newPHP;
- if ( $newPHP === null ) {
- $newPHP = !mb_check_encoding( "\xf4\x90\x80\x80", 'UTF-8' );
- }
-
- return mb_check_encoding( $value, 'UTF-8' ) &&
- ( $newPHP || preg_match( "/\xf4[\x90-\xbf]|[\xf5-\xff]/S", $value ) === 0 );
- }
-
- if ( preg_match( "/[\x80-\xff]/S", $value ) === 0 ) {
- // String contains only ASCII characters, has to be valid
- return true;
- }
-
- // PCRE implements repetition using recursion; to avoid a stack overflow (and segfault)
- // for large input, we check for invalid sequences (<= 5 bytes) rather than valid
- // sequences, which can be as long as the input string is. Multiple short regexes are
- // used rather than a single long regex for performance.
- static $regexes;
- if ( $regexes === null ) {
- $cont = "[\x80-\xbf]";
- $after = "(?!$cont)"; // "(?:[^\x80-\xbf]|$)" would work here
- $regexes = array(
- // Continuation byte at the start
- "/^$cont/",
-
- // ASCII byte followed by a continuation byte
- "/[\\x00-\x7f]$cont/S",
-
- // Illegal byte
- "/[\xc0\xc1\xf5-\xff]/S",
-
- // Invalid 2-byte sequence, or valid one then an extra continuation byte
- "/[\xc2-\xdf](?!$cont$after)/S",
-
- // Invalid 3-byte sequence, or valid one then an extra continuation byte
- "/\xe0(?![\xa0-\xbf]$cont$after)/",
- "/[\xe1-\xec\xee\xef](?!$cont{2}$after)/S",
- "/\xed(?![\x80-\x9f]$cont$after)/",
-
- // Invalid 4-byte sequence, or valid one then an extra continuation byte
- "/\xf0(?![\x90-\xbf]$cont{2}$after)/",
- "/[\xf1-\xf3](?!$cont{3}$after)/S",
- "/\xf4(?![\x80-\x8f]$cont{2}$after)/",
- );
- }
-
- foreach ( $regexes as $regex ) {
- if ( preg_match( $regex, $value ) !== 0 ) {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Perform an operation equivalent to
- *
- * preg_replace( "!$startDelim(.*?)$endDelim!", $replace, $subject );
- *
- * except that it's worst-case O(N) instead of O(N^2)
- *
- * Compared to delimiterReplace(), this implementation is fast but memory-
- * hungry and inflexible. The memory requirements are such that I don't
- * recommend using it on anything but guaranteed small chunks of text.
- *
- * @param string $startDelim
- * @param string $endDelim
- * @param string $replace
- * @param string $subject
- *
- * @return string
- */
- static function hungryDelimiterReplace( $startDelim, $endDelim, $replace, $subject ) {
- $segments = explode( $startDelim, $subject );
- $output = array_shift( $segments );
- foreach ( $segments as $s ) {
- $endDelimPos = strpos( $s, $endDelim );
- if ( $endDelimPos === false ) {
- $output .= $startDelim . $s;
- } else {
- $output .= $replace . substr( $s, $endDelimPos + strlen( $endDelim ) );
- }
- }
-
- return $output;
- }
-
- /**
- * Perform an operation equivalent to
- *
- * preg_replace_callback( "!$startDelim(.*)$endDelim!s$flags", $callback, $subject )
- *
- * This implementation is slower than hungryDelimiterReplace but uses far less
- * memory. The delimiters are literal strings, not regular expressions.
- *
- * If the start delimiter ends with an initial substring of the end delimiter,
- * e.g. in the case of C-style comments, the behavior differs from the model
- * regex. In this implementation, the end must share no characters with the
- * start, so e.g. /*\/ is not considered to be both the start and end of a
- * comment. /*\/xy/*\/ is considered to be a single comment with contents /xy/.
- *
- * @param string $startDelim Start delimiter
- * @param string $endDelim End delimiter
- * @param callable $callback Function to call on each match
- * @param string $subject
- * @param string $flags Regular expression flags
- * @throws MWException
- * @return string
- */
- static function delimiterReplaceCallback( $startDelim, $endDelim, $callback,
- $subject, $flags = ''
- ) {
- $inputPos = 0;
- $outputPos = 0;
- $output = '';
- $foundStart = false;
- $encStart = preg_quote( $startDelim, '!' );
- $encEnd = preg_quote( $endDelim, '!' );
- $strcmp = strpos( $flags, 'i' ) === false ? 'strcmp' : 'strcasecmp';
- $endLength = strlen( $endDelim );
- $m = array();
-
- while ( $inputPos < strlen( $subject ) &&
- preg_match( "!($encStart)|($encEnd)!S$flags", $subject, $m, PREG_OFFSET_CAPTURE, $inputPos )
- ) {
- $tokenOffset = $m[0][1];
- if ( $m[1][0] != '' ) {
- if ( $foundStart &&
- $strcmp( $endDelim, substr( $subject, $tokenOffset, $endLength ) ) == 0
- ) {
- # An end match is present at the same location
- $tokenType = 'end';
- $tokenLength = $endLength;
- } else {
- $tokenType = 'start';
- $tokenLength = strlen( $m[0][0] );
- }
- } elseif ( $m[2][0] != '' ) {
- $tokenType = 'end';
- $tokenLength = strlen( $m[0][0] );
- } else {
- throw new MWException( 'Invalid delimiter given to ' . __METHOD__ );
- }
-
- if ( $tokenType == 'start' ) {
- # Only move the start position if we haven't already found a start
- # This means that START START END matches outer pair
- if ( !$foundStart ) {
- # Found start
- $inputPos = $tokenOffset + $tokenLength;
- # Write out the non-matching section
- $output .= substr( $subject, $outputPos, $tokenOffset - $outputPos );
- $outputPos = $tokenOffset;
- $contentPos = $inputPos;
- $foundStart = true;
- } else {
- # Move the input position past the *first character* of START,
- # to protect against missing END when it overlaps with START
- $inputPos = $tokenOffset + 1;
- }
- } elseif ( $tokenType == 'end' ) {
- if ( $foundStart ) {
- # Found match
- $output .= call_user_func( $callback, array(
- substr( $subject, $outputPos, $tokenOffset + $tokenLength - $outputPos ),
- substr( $subject, $contentPos, $tokenOffset - $contentPos )
- ) );
- $foundStart = false;
- } else {
- # Non-matching end, write it out
- $output .= substr( $subject, $inputPos, $tokenOffset + $tokenLength - $outputPos );
- }
- $inputPos = $outputPos = $tokenOffset + $tokenLength;
- } else {
- throw new MWException( 'Invalid delimiter given to ' . __METHOD__ );
- }
- }
- if ( $outputPos < strlen( $subject ) ) {
- $output .= substr( $subject, $outputPos );
- }
-
- return $output;
- }
-
- /**
- * Perform an operation equivalent to
- *
- * preg_replace( "!$startDelim(.*)$endDelim!$flags", $replace, $subject )
- *
- * @param string $startDelim Start delimiter regular expression
- * @param string $endDelim End delimiter regular expression
- * @param string $replace Replacement string. May contain $1, which will be
- * replaced by the text between the delimiters
- * @param string $subject String to search
- * @param string $flags Regular expression flags
- * @return string The string with the matches replaced
- */
- static function delimiterReplace( $startDelim, $endDelim, $replace, $subject, $flags = '' ) {
- $replacer = new RegexlikeReplacer( $replace );
-
- return self::delimiterReplaceCallback( $startDelim, $endDelim,
- $replacer->cb(), $subject, $flags );
- }
-
- /**
- * More or less "markup-safe" explode()
- * Ignores any instances of the separator inside <...>
- * @param string $separator
- * @param string $text
- * @return array
- */
- static function explodeMarkup( $separator, $text ) {
- $placeholder = "\x00";
-
- // Remove placeholder instances
- $text = str_replace( $placeholder, '', $text );
-
- // Replace instances of the separator inside HTML-like tags with the placeholder
- $replacer = new DoubleReplacer( $separator, $placeholder );
- $cleaned = StringUtils::delimiterReplaceCallback( '<', '>', $replacer->cb(), $text );
-
- // Explode, then put the replaced separators back in
- $items = explode( $separator, $cleaned );
- foreach ( $items as $i => $str ) {
- $items[$i] = str_replace( $placeholder, $separator, $str );
- }
-
- return $items;
- }
-
- /**
- * Escape a string to make it suitable for inclusion in a preg_replace()
- * replacement parameter.
- *
- * @param string $string
- * @return string
- */
- static function escapeRegexReplacement( $string ) {
- $string = str_replace( '\\', '\\\\', $string );
- $string = str_replace( '$', '\\$', $string );
-
- return $string;
- }
-
- /**
- * Workalike for explode() with limited memory usage.
- * Returns an Iterator
- * @param string $separator
- * @param string $subject
- * @return ArrayIterator|ExplodeIterator
- */
- static function explode( $separator, $subject ) {
- if ( substr_count( $subject, $separator ) > 1000 ) {
- return new ExplodeIterator( $separator, $subject );
- } else {
- return new ArrayIterator( explode( $separator, $subject ) );
- }
- }
-}
-
-/**
- * Base class for "replacers", objects used in preg_replace_callback() and
- * StringUtils::delimiterReplaceCallback()
- */
-class Replacer {
- /**
- * @return array
- */
- function cb() {
- return array( &$this, 'replace' );
- }
-}
-
-/**
- * Class to replace regex matches with a string similar to that used in preg_replace()
- */
-class RegexlikeReplacer extends Replacer {
- private $r;
-
- /**
- * @param string $r
- */
- function __construct( $r ) {
- $this->r = $r;
- }
-
- /**
- * @param array $matches
- * @return string
- */
- function replace( $matches ) {
- $pairs = array();
- foreach ( $matches as $i => $match ) {
- $pairs["\$$i"] = $match;
- }
-
- return strtr( $this->r, $pairs );
- }
-}
-
-/**
- * Class to perform secondary replacement within each replacement string
- */
-class DoubleReplacer extends Replacer {
- /**
- * @param mixed $from
- * @param mixed $to
- * @param int $index
- */
- function __construct( $from, $to, $index = 0 ) {
- $this->from = $from;
- $this->to = $to;
- $this->index = $index;
- }
-
- /**
- * @param array $matches
- * @return mixed
- */
- function replace( $matches ) {
- return str_replace( $this->from, $this->to, $matches[$this->index] );
- }
-}
-
-/**
- * Class to perform replacement based on a simple hashtable lookup
- */
-class HashtableReplacer extends Replacer {
- private $table, $index;
-
- /**
- * @param array $table
- * @param int $index
- */
- function __construct( $table, $index = 0 ) {
- $this->table = $table;
- $this->index = $index;
- }
-
- /**
- * @param array $matches
- * @return mixed
- */
- function replace( $matches ) {
- return $this->table[$matches[$this->index]];
- }
-}
-
-/**
- * Replacement array for FSS with fallback to strtr()
- * Supports lazy initialisation of FSS resource
- */
-class ReplacementArray {
- private $data = false;
- private $fss = false;
-
- /**
- * Create an object with the specified replacement array
- * The array should have the same form as the replacement array for strtr()
- * @param array $data
- */
- function __construct( $data = array() ) {
- $this->data = $data;
- }
-
- /**
- * @return array
- */
- function __sleep() {
- return array( 'data' );
- }
-
- function __wakeup() {
- $this->fss = false;
- }
-
- /**
- * Set the whole replacement array at once
- * @param array $data
- */
- function setArray( $data ) {
- $this->data = $data;
- $this->fss = false;
- }
-
- /**
- * @return array|bool
- */
- function getArray() {
- return $this->data;
- }
-
- /**
- * Set an element of the replacement array
- * @param string $from
- * @param string $to
- */
- function setPair( $from, $to ) {
- $this->data[$from] = $to;
- $this->fss = false;
- }
-
- /**
- * @param array $data
- */
- function mergeArray( $data ) {
- $this->data = array_merge( $this->data, $data );
- $this->fss = false;
- }
-
- /**
- * @param ReplacementArray $other
- */
- function merge( $other ) {
- $this->data = array_merge( $this->data, $other->data );
- $this->fss = false;
- }
-
- /**
- * @param string $from
- */
- function removePair( $from ) {
- unset( $this->data[$from] );
- $this->fss = false;
- }
-
- /**
- * @param array $data
- */
- function removeArray( $data ) {
- foreach ( $data as $from => $to ) {
- $this->removePair( $from );
- }
- $this->fss = false;
- }
-
- /**
- * @param string $subject
- * @return string
- */
- function replace( $subject ) {
- if ( function_exists( 'fss_prep_replace' ) ) {
- wfProfileIn( __METHOD__ . '-fss' );
- if ( $this->fss === false ) {
- $this->fss = fss_prep_replace( $this->data );
- }
- $result = fss_exec_replace( $this->fss, $subject );
- wfProfileOut( __METHOD__ . '-fss' );
- } else {
- wfProfileIn( __METHOD__ . '-strtr' );
- $result = strtr( $subject, $this->data );
- wfProfileOut( __METHOD__ . '-strtr' );
- }
-
- return $result;
- }
-}
-
-/**
- * An iterator which works exactly like:
- *
- * foreach ( explode( $delim, $s ) as $element ) {
- * ...
- * }
- *
- * Except it doesn't use 193 byte per element
- */
-class ExplodeIterator implements Iterator {
- // The subject string
- private $subject, $subjectLength;
-
- // The delimiter
- private $delim, $delimLength;
-
- // The position of the start of the line
- private $curPos;
-
- // The position after the end of the next delimiter
- private $endPos;
-
- // The current token
- private $current;
-
- /**
- * Construct a DelimIterator
- * @param string $delim
- * @param string $subject
- */
- function __construct( $delim, $subject ) {
- $this->subject = $subject;
- $this->delim = $delim;
-
- // Micro-optimisation (theoretical)
- $this->subjectLength = strlen( $subject );
- $this->delimLength = strlen( $delim );
-
- $this->rewind();
- }
-
- function rewind() {
- $this->curPos = 0;
- $this->endPos = strpos( $this->subject, $this->delim );
- $this->refreshCurrent();
- }
-
- function refreshCurrent() {
- if ( $this->curPos === false ) {
- $this->current = false;
- } elseif ( $this->curPos >= $this->subjectLength ) {
- $this->current = '';
- } elseif ( $this->endPos === false ) {
- $this->current = substr( $this->subject, $this->curPos );
- } else {
- $this->current = substr( $this->subject, $this->curPos, $this->endPos - $this->curPos );
- }
- }
-
- function current() {
- return $this->current;
- }
-
- /**
- * @return int|bool Current position or boolean false if invalid
- */
- function key() {
- return $this->curPos;
- }
-
- /**
- * @return string
- */
- function next() {
- if ( $this->endPos === false ) {
- $this->curPos = false;
- } else {
- $this->curPos = $this->endPos + $this->delimLength;
- if ( $this->curPos >= $this->subjectLength ) {
- $this->endPos = false;
- } else {
- $this->endPos = strpos( $this->subject, $this->delim, $this->curPos );
- }
- }
- $this->refreshCurrent();
-
- return $this->current;
- }
-
- /**
- * @return bool
- */
- function valid() {
- return $this->curPos !== false;
- }
-}
diff --git a/includes/utils/UIDGenerator.php b/includes/utils/UIDGenerator.php
index 5346afa6..92415877 100644
--- a/includes/utils/UIDGenerator.php
+++ b/includes/utils/UIDGenerator.php
@@ -119,6 +119,7 @@ class UIDGenerator {
/**
* @param array $info (UIDGenerator::millitime(), counter, clock sequence)
* @return string 88 bits
+ * @throws MWException
*/
protected function getTimestampedID88( array $info ) {
list( $time, $counter ) = $info;
@@ -163,6 +164,7 @@ class UIDGenerator {
/**
* @param array $info (UIDGenerator::millitime(), counter, clock sequence)
* @return string 128 bits
+ * @throws MWException
*/
protected function getTimestampedID128( array $info ) {
list( $time, $counter, $clkSeq ) = $info;
@@ -260,6 +262,7 @@ class UIDGenerator {
* @param int $count Number of IDs to return (1 to 10000)
* @param int $flags (supports UIDGenerator::QUICK_VOLATILE)
* @return array Ordered list of float integer values
+ * @throws MWException
*/
protected function getSequentialPerNodeIDs( $bucket, $bits, $count, $flags ) {
if ( $count <= 0 ) {
@@ -278,7 +281,7 @@ class UIDGenerator {
if ( ( $flags & self::QUICK_VOLATILE ) && PHP_SAPI !== 'cli' ) {
try {
$cache = ObjectCache::newAccelerator( array() );
- } catch ( MWException $e ) {
+ } catch ( Exception $e ) {
// not supported
}
}
@@ -436,6 +439,7 @@ class UIDGenerator {
/**
* @param array $time Result of UIDGenerator::millitime()
* @return string 46 MSBs of "milliseconds since epoch" in binary (rolls over in 4201)
+ * @throws MWException
*/
protected function millisecondsSinceEpochBinary( array $time ) {
list( $sec, $msec ) = $time;
diff --git a/includes/utils/ZipDirectoryReader.php b/includes/utils/ZipDirectoryReader.php
index bc849766..86960aa1 100644
--- a/includes/utils/ZipDirectoryReader.php
+++ b/includes/utils/ZipDirectoryReader.php
@@ -186,6 +186,7 @@ class ZipDirectoryReader {
* Throw an error, and log a debug message
* @param mixed $code
* @param string $debugMessage
+ * @throws ZipDirectoryReaderError
*/
function error( $code, $debugMessage ) {
wfDebug( __CLASS__ . ": Fatal error: $debugMessage\n" );