}
}
-# UTF-8 substr function based on a PHP manual comment
if ( !function_exists( 'mb_substr' ) ) {
- function mb_substr( $str, $start ) {
- $ar = array();
- preg_match_all( '/./us', $str, $ar );
-
- if( func_num_args() >= 3 ) {
- $end = func_get_arg( 2 );
- return join( '', array_slice( $ar[0], $start, $end ) );
+ /**
+ * Fallback implementation for mb_substr, hardcoded to UTF-8.
+ * Attempts to be at least _moderately_ efficient; best optimized
+ * for relatively small offset and count values -- about 5x slower
+ * than native mb_string in my testing.
+ *
+ * Larger offsets are still fairly efficient for Latin text, but
+ * can be up to 100x slower than native if the text is heavily
+ * multibyte and we have to slog through a few hundred kb.
+ */
+ function mb_substr( $str, $start, $count='end' ) {
+ if( $start != 0 ) {
+ $split = mb_substr_split_unicode( $str, intval( $start ) );
+ $str = substr( $str, $split );
+ }
+
+ if( $count !== 'end' ) {
+ $split = mb_substr_split_unicode( $str, intval( $count ) );
+ $str = substr( $str, 0, $split );
+ }
+
+ return $str;
+ }
+
+ function mb_substr_split_unicode( $str, $splitPos ) {
+ if( $splitPos == 0 ) {
+ return 0;
+ }
+
+ $byteLen = strlen( $str );
+
+ if( $splitPos > 0 ) {
+ if( $splitPos > 256 ) {
+ // Optimize large string offsets by skipping ahead N bytes.
+ // This will cut out most of our slow time on Latin-based text,
+ // and 1/2 to 1/3 on East European and Asian scripts.
+ $bytePos = $splitPos;
+ while ($bytePos < $byteLen && $str{$bytePos} >= "\x80" && $str{$bytePos} < "\xc0")
+ ++$bytePos;
+ $charPos = mb_strlen( substr( $str, 0, $bytePos ) );
+ } else {
+ $charPos = 0;
+ $bytePos = 0;
+ }
+
+ while( $charPos++ < $splitPos ) {
+ ++$bytePos;
+ // Move past any tail bytes
+ while ($bytePos < $byteLen && $str{$bytePos} >= "\x80" && $str{$bytePos} < "\xc0")
+ ++$bytePos;
+ }
} else {
- return join( '', array_slice( $ar[0], $start ) );
+ $splitPosX = $splitPos + 1;
+ $charPos = 0; // relative to end of string; we don't care about the actual char position here
+ $bytePos = $byteLen;
+ while( $bytePos > 0 && $charPos-- >= $splitPosX ) {
+ --$bytePos;
+ // Move past any tail bytes
+ while ($bytePos > 0 && $str{$bytePos} >= "\x80" && $str{$bytePos} < "\xc0")
+ --$bytePos;
+ }
}
+
+ return $bytePos;
}
}
if ( is_null( $mode ) )
$mode = $wgDirectoryMode;
- return mkdir( $dir, $mode, true ); // PHP5 <3
+ $ok = mkdir( $dir, $mode, true ); // PHP5 <3
+ if( !$ok ) {
+ // PHP doesn't report the path in its warning message, so add our own to aid in diagnosis.
+ trigger_error( __FUNCTION__ . ": failed to mkdir \"$dir\" mode $mode", E_USER_WARNING );
+ }
+ return $ok;
}
/**
}
/**
- * Executes a shell command in the background. Passes back the PID of the operation
+ * Executes a shell command in the background. Returns true if successful.
*
* @param $cmd String
*/
-function wfShellBackgroundExec( $cmd ){
+function wfShellBackgroundExec( $cmd ) {
wfDebug( "wfShellBackgroundExec: $cmd\n" );
-
- if ( ! wfShellExecEnabled() ) {
- return "Unable to run external programs";
+
+ if ( !wfShellExecEnabled() ) {
+ return false;
+ }
+
+ if ( wfIsWindows() ) {
+ shell_exec( "start /b $cmd >nul" );
+ return true;
+ } else {
+ $pid = shell_exec( "nohup $cmd > /dev/null & echo $!" );
+ return (bool)$pid;
}
-
- $pid = shell_exec( "nohup $cmd > /dev/null & echo $!" );
- return $pid;
}
/**
- * Checks if the current instance can execute a shell command
- *
+ * Return true if we can execute a shell command (i.e. not safe mode, etc.)
*/
-function wfShellExecEnabled(){
+function wfShellExecEnabled() {
if( wfIniGetBool( 'safe_mode' ) ) {
wfDebug( "wfShellExec can't run in safe_mode, PHP's exec functions are too broken.\n" );
return false;
}
}
}
-
+
return true;
}
/**
* Find a file.
* Shortcut for RepoGroup::singleton()->findFile()
- * @param $title Title object or string. May be interwiki.
- * @param $time Mixed: requested time for an archived image, or false for the
- * current version. An image object will be returned which was
- * created at the specified time.
- * @param $flags Mixed: FileRepo::FIND_ flags
- * @param $bypass Boolean: bypass the file cache even if it could be used
+ * @param $options Associative array of options:
+ * time: requested time for an archived image, or false for the
+ * current version. An image object will be returned which was
+ * created at the specified time.
+ *
+ * ignoreRedirect: If true, do not follow file redirects
+ *
+ * private: If true, return restricted (deleted) files if the current
+ * user is allowed to view them. Otherwise, such files will not
+ * be found.
+ *
+ * bypassCache: If true, do not use the process-local cache of File objects
+ *
* @return File, or false if the file does not exist
*/
-function wfFindFile( $title, $time = false, $flags = 0, $bypass = false ) {
- if( !$time && !$flags && !$bypass ) {
- return FileCache::singleton()->findFile( $title );
- } else {
- return RepoGroup::singleton()->findFile( $title, $time, $flags );
- }
+function wfFindFile( $title, $options = array() ) {
+ return RepoGroup::singleton()->findFile( $title, $options );
}
/**
}
}
+/**
+ * Send a warning either to the debug log or in a PHP error depending on
+ * $wgDevelopmentWarnings
+ *
+ * @param $msg String: message to send
+ * @param $callerOffset Integer: number of itmes to go back in the backtrace to
+ * find the correct caller (1 = function calling wfWarn, ...)
+ * @param $level Integer: PHP error level; only used when $wgDevelopmentWarnings
+ * is true
+ */
function wfWarn( $msg, $callerOffset = 1, $level = E_USER_NOTICE ) {
$callers = wfDebugBacktrace();
if( isset( $callers[$callerOffset+1] ) ){
* @param $name Mixed: filename to process
*/
function wfStripIllegalFilenameChars( $name ) {
+ global $wgIllegalFileChars;
$name = wfBaseName( $name );
- $name = preg_replace ( "/[^".Title::legalChars()."]|:/", '-', $name );
+ $name = preg_replace("/[^".Title::legalChars()."]".($wgIllegalFileChars ? "|[".$wgIllegalFileChars."]":"")."/",'-',$name);
return $name;
}
return $array;
}
-/* Parse PHP's silly format for memory limits */
-function wfParseMemoryLimit( $memlimit ) {
- $n = intval( $memlimit );
- if( preg_match( '/^([0-9]+)[Mm]$/', trim( $memlimit ), $m ) ) {
- $n = intval( $m[1] * (1024*1024) );
+/**
+ * Set PHP's memory limit to the larger of php.ini or $wgMemoryLimit;
+ * @return Integer value memory was set to.
+ */
+
+function wfMemoryLimit () {
+ global $wgMemoryLimit;
+ $memlimit = wfShorthandToInteger( ini_get( "memory_limit" ) );
+ $conflimit = wfShorthandToInteger( $wgMemoryLimit );
+ if( $memlimit != -1 ) {
+ if( $conflimit == -1 ) {
+ wfDebug( "Removing PHP's memory limit\n" );
+ wfSuppressWarnings();
+ ini_set( "memory_limit", $conflimit );
+ wfRestoreWarnings();
+ return $conflimit;
+ } elseif ( $conflimit > $memlimit ) {
+ wfDebug( "Raising PHP's memory limit to $conflimit bytes\n" );
+ wfSuppressWarnings();
+ ini_set( "memory_limit", $conflimit );
+ wfRestoreWarnings();
+ return $conflimit;
+ }
}
- return $n;
+ return $memlimit;
+}
+
+/**
+ * Converts shorthand byte notation to integer form
+ * @param $string String
+ * @return Integer
+ */
+function wfShorthandToInteger ( $string = '' ) {
+ $string = trim($string);
+ if( empty($string) ) { return -1; }
+ $last = strtolower($string[strlen($string)-1]);
+ $val = intval($string);
+ switch($last) {
+ case 'g':
+ $val *= 1024;
+ case 'm':
+ $val *= 1024;
+ case 'k':
+ $val *= 1024;
+ }
+
+ return $val;
}
/* Get the normalised IETF language tag
$langCode = implode ( '-' , $codeBCP );
return $langCode;
}
-
+class FormatJson{
+ public static function encode($value, $isHtml=false){
+ // Some versions of PHP have a broken json_encode, see PHP bug
+ // 46944. Test encoding an affected character (U+20000) to
+ // avoid this.
+ if (!function_exists('json_encode') || $isHtml || strtolower(json_encode("\xf0\xa0\x80\x80")) != '\ud840\udc00') {
+ $json = new Services_JSON();
+ return $json->encode($value, $isHtml) ;
+ } else {
+ return json_encode($value);
+ }
+ }
+ public static function decode($value, $assoc=false){
+ if (!function_exists('json_decode') ) {
+ $json = new Services_JSON();
+ $jsonDec = $json->decode($value);
+ if($assoc)
+ $jsonDec = (array) $jsonDec;
+ return $jsonDec;
+ } else {
+ return json_decode($value, $assoc);
+ }
+ }
+}
\ No newline at end of file