Comments and whitespace fixes only.
[lhc/web/wiklou.git] / includes / GlobalFunctions.php
index b66589a..8efa1f2 100644 (file)
@@ -33,18 +33,71 @@ if( !function_exists('iconv') ) {
        }
 }
 
-# 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;
        }
 }
 
@@ -2074,7 +2127,12 @@ function wfMkdirParents( $dir, $mode = null, $caller = null ) {
        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;
 }
 
 /**
@@ -2288,26 +2346,30 @@ function wfShellExec( $cmd, &$retval=null ) {
 }
 
 /**
- * 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;
@@ -2746,7 +2808,7 @@ function wfHttpOnlySafe() {
                        }
                }
        }
-       
+
        return true;
 }
 
@@ -2916,20 +2978,23 @@ function &wfGetLBFactory() {
 /**
  * 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 );
 }
 
 /**
@@ -3050,6 +3115,16 @@ function wfDeprecated( $function ) {
        }
 }
 
+/**
+ * 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] ) ){
@@ -3152,8 +3227,9 @@ function wfGenerateToken( $salt = '' ) {
  * @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;
 }
 
@@ -3267,3 +3343,27 @@ function wfBCP47( $code ) {
        $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