- Merged 361049b451066d3d6607afc40a40a7a290a68db6 and 71dab8ee7e779a02483841c41580acd...
authorAlexander Ebert <ebert@woltlab.com>
Thu, 14 Jul 2011 20:46:08 +0000 (22:46 +0200)
committerAlexander Ebert <ebert@woltlab.com>
Thu, 14 Jul 2011 20:46:08 +0000 (22:46 +0200)
wcfsetup/install/files/lib/util/FileUtil.class.php

index 3d255f97e8b4505aee3b5f746682f4bd42a473a0..8fe02fbe04bfe8293f368d2b9dd7cbc65d37cc4b 100644 (file)
-<?php\r
-namespace wcf\util;\r
-use wcf\system\io\File;\r
-use wcf\system\io\ZipFile;\r
-use wcf\system\io\RemoteFile;\r
-use wcf\system\exception\SystemException;\r
-\r
-/**\r
- * Contains file-related functions.\r
- *\r
- * @author     Marcel Werk\r
- * @copyright  2001-2009 WoltLab GmbH\r
- * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>\r
- * @package    com.woltlab.wcf\r
- * @subpackage util\r
- * @category   Community Framework\r
- */\r
-class FileUtil {\r
-       /** \r
-        * Generates a new temporary filename in TMP_DIR.\r
-        *\r
-        * @param       string          $prefix\r
-        * @param       string          $extension\r
-        * @param       string          $dir\r
-        * @return      string                          temporary filename\r
-        */\r
-       public static function getTemporaryFilename($prefix = 'tmpFile_', $extension = '', $dir = TMP_DIR) {\r
-               $dir = self::addTrailingSlash($dir);\r
-               do {\r
-                       $tmpFile = $dir.$prefix.StringUtil::getRandomID().$extension;\r
-               }\r
-               while (file_exists($tmpFile));  \r
-               \r
-               return $tmpFile;\r
-       }\r
-       \r
-       /**\r
-        * Removes a leading slash. \r
-        *\r
-        * @param       string          $path\r
-        * @return      string          $path\r
-        */\r
-       public static function removeLeadingSlash($path) {\r
-               if (substr($path, 0, 1) == '/') {\r
-                       return substr($path, 1);\r
-               }\r
-               else {\r
-                       return $path;   \r
-               }       \r
-       }\r
-\r
-       /**\r
-        * Removes a trailing slash. \r
-        *\r
-        * @param       string          $path\r
-        * @return      string          $path\r
-        */\r
-       public static function removeTrailingSlash($path) {\r
-               if (substr($path, -1) == '/') {\r
-                       return substr($path, 0, -1);\r
-               }\r
-               else {\r
-                       return $path;\r
-               }       \r
-       }\r
-       \r
-       /**\r
-        * Adds a trailing slash. \r
-        *\r
-        * @param       string          $path\r
-        * @return      string          $path\r
-        */\r
-       public static function addTrailingSlash($path) {\r
-               if (substr($path, -1) != '/') {\r
-                       return $path.'/';\r
-               }\r
-               else {\r
-                       return $path;\r
-               }       \r
-       }\r
-\r
-       /**\r
-        * Builds a relative path from two absolute paths.\r
-        *\r
-        * @param       string          $currentDir\r
-        * @param       string          $targetDir\r
-        * @return      string                          relative Path\r
-        */\r
-       public static function getRelativePath($currentDir, $targetDir) {\r
-               // remove trailing slashes\r
-               $currentDir = self::removeTrailingSlash(self::unifyDirSeperator($currentDir));\r
-               $targetDir = self::removeTrailingSlash(self::unifyDirSeperator($targetDir));\r
-               \r
-               if ($currentDir == $targetDir) {\r
-                       return './';    \r
-               }\r
-               \r
-               $current = explode('/', $currentDir);\r
-               $target = explode('/', $targetDir);\r
-               \r
-               $relPath = '';\r
-               //for ($i = max(count($current), count($target)) - 1; $i >= 0; $i--) {\r
-               for ($i = 0, $max = max(count($current), count($target)); $i < $max; $i++) {\r
-                       if (isset($current[$i]) && isset($target[$i])) {\r
-                               if ($current[$i] != $target[$i]) {\r
-                                       for ($j = 0; $j < $i; $j++) {\r
-                                               unset($target[$j]);     \r
-                                       }\r
-                                       $relPath .= str_repeat('../', count($current) - $i).implode('/', $target).'/';  \r
-                                       for ($j = $i + 1; $j < count($current); $j++) {\r
-                                               unset($current[$j]);    \r
-                                       }\r
-                                       break;\r
-                               }\r
-                       }       \r
-                       // go up one level\r
-                       else if (isset($current[$i]) && !isset($target[$i])) {\r
-                               $relPath .= '../';\r
-                       }\r
-                       else if (!isset($current[$i]) && isset($target[$i])) {\r
-                               $relPath .= $target[$i].'/';\r
-                       }\r
-               }\r
-               \r
-               return $relPath;\r
-       }\r
-       \r
-       /**\r
-        * Creates a path on the local filesystem. \r
-        * Parent directories do not need to exists as\r
-        * they will be created if necessary.\r
-        * Return true on success, otherwise false.\r
-        * \r
-        * @param       string          $path\r
-        * @param       integer         $chmod\r
-        * @return      boolean                         success\r
-        */\r
-       public static function makePath($path, $chmod = 0777) {\r
-               // directory already exists, abort\r
-               if (file_exists($path)) {\r
-                       return false;\r
-               }\r
-               \r
-               // check if parent directory exists\r
-               $parent = dirname($path);\r
-               if ($parent != $path) {\r
-                       // parent directory does not exist either\r
-                       // we have to create the parent directory first\r
-                       $parent = self::addTrailingSlash($parent);\r
-                       if (!@file_exists($parent)) {\r
-                               // could not create parent directory either => abort\r
-                               if (!self::makePath($parent, $chmod)) {\r
-                                       return false;   \r
-                               }\r
-                       }\r
-                       \r
-                       // well, the parent directory exists or has been created\r
-                       // lets create this path\r
-                       $oldumask = @umask(0);\r
-                       if (!@mkdir($path, $chmod)) {\r
-                               return false;\r
-                       }\r
-                       @umask($oldumask);\r
-                       /*if (!@chmod($path, $chmod)) {\r
-                               return false;\r
-                       }*/\r
-                       if (self::isApacheModule() || !@is_writable($path)) {\r
-                               @chmod($path, 0777);\r
-                       }\r
-                       \r
-                       return true;\r
-               }\r
-               \r
-               return false;\r
-       }\r
-       \r
-       /**\r
-        * Unifies windows and unix directory seperators.\r
-        *\r
-        * @param       string          $path\r
-        * @return      string          $path\r
-        */\r
-       public static function unifyDirSeperator($path) {\r
-               $path = str_replace('\\\\', '/', $path);\r
-               $path = str_replace('\\', '/', $path);\r
-               return $path;\r
-       }\r
-       \r
-       /**\r
-        * Scans a folder (and subfolder) for a specific file.\r
-        * Returns the filename if found, otherwise false.\r
-        *\r
-        * @param       string          $folder\r
-        * @param       string          $searchfile\r
-        * @param       boolean         $recursive\r
-        * @return      mixed           $found\r
-        */\r
-       public static function scanFolder($folder, $searchfile, $recursive = true) {\r
-               if (!@is_dir($folder)) {\r
-                       return false;\r
-               }\r
-               if (!$searchfile) {\r
-                       return false;\r
-               }\r
-\r
-               $folder = self::addTrailingSlash($folder);\r
-               $dirh = @opendir($folder);\r
-               while ($filename = @readdir($dirh)) {\r
-                       if ($filename == '.' || $filename == '..') {\r
-                               continue;\r
-                       }\r
-                       if ($filename == $searchfile) {\r
-                               @closedir($dirh);\r
-                               return $folder.$filename;\r
-                       }\r
-\r
-                       if ($recursive == true && @is_dir($folder.$filename)) {\r
-                               if ($found = self::scanFolder($folder.$filename, $searchfile, $recursive)) {\r
-                                       @closedir($dirh);\r
-                                       return $found;\r
-                               }\r
-                       }\r
-               }\r
-               @closedir($dirh);\r
-       }\r
-       \r
-       /**\r
-        * Return true, if the given filename is an url (http or ftp).\r
-        * \r
-        * @param       string          $filename\r
-        * @return      boolean\r
-        */\r
-       public static function isURL($filename) {\r
-               return preg_match('!^(https?|ftp)://!', $filename);\r
-       }\r
-       \r
-       /**\r
-        * Returns canonicalized absolute pathname.\r
-        * \r
-        * @param       string          $path\r
-        * @return      string          path\r
-        */\r
-       public static function getRealPath($path) {\r
-               $path = self::unifyDirSeperator($path);\r
-               \r
-               $result = array();\r
-               $pathA = explode('/', $path);\r
-               if ($pathA[0] === '') {\r
-                       $result[] = '';\r
-               }\r
-\r
-               foreach ($pathA as $key => $dir) {\r
-                       if ($dir == '..') {\r
-                               if (end($result) == '..') {\r
-                                       $result[] = '..';\r
-                               } \r
-                               else { \r
-                                       $lastValue = array_pop($result);\r
-                                       if ($lastValue === '' || $lastValue === null) {\r
-                                               $result[] = '..';\r
-                                       }\r
-                               }\r
-                       } \r
-                       else if ($dir !== '' && $dir != '.') {\r
-                               $result[] = $dir;\r
-                       }\r
-               }\r
-               \r
-               $lastValue = end($pathA);\r
-               if ($lastValue === '' || $lastValue === false) {\r
-                       $result[] = '';\r
-               }\r
-               \r
-               return implode('/', $result);\r
-       }\r
-       \r
-       /**\r
-        * formats a filesize\r
-        *\r
-        * @param       integer         $byte\r
-        * @param       integer         $precision\r
-        * @return      string          filesize\r
-        */\r
-       public static function formatFilesize($byte, $precision = 2) {\r
-               $symbol = 'Byte';\r
-               if ($byte >= 1000) {\r
-                       $byte /= 1000;\r
-                       $symbol = 'kB';\r
-               }\r
-               if ($byte >= 1000) {\r
-                       $byte /= 1000;\r
-                       $symbol = 'MB';\r
-               }\r
-               if ($byte >= 1000) {\r
-                       $byte /= 1000;\r
-                       $symbol = 'GB';\r
-               }\r
-               if ($byte >= 1000) {\r
-                       $byte /= 1000;\r
-                       $symbol = 'TB';\r
-               }\r
-               \r
-               return StringUtil::formatNumeric(round($byte, $precision)).' '.$symbol;\r
-       }\r
-       \r
-       /**\r
-        * formats a filesize (binary prefix)\r
-        * \r
-        * For more informations: <http://en.wikipedia.org/wiki/Binary_prefix>\r
-        *\r
-        * @param       integer         $byte\r
-        * @param       integer         $precision\r
-        * @return      string          filesize\r
-        */\r
-       public static function formatFilesizeBinary($byte, $precision = 2) {\r
-               $symbol = 'Byte';\r
-               if ($byte >= 1024) {\r
-                       $byte /= 1024;\r
-                       $symbol = 'KiB';\r
-               }\r
-               if ($byte >= 1024) {\r
-                       $byte /= 1024;\r
-                       $symbol = 'MiB';\r
-               }\r
-               if ($byte >= 1024) {\r
-                       $byte /= 1024;\r
-                       $symbol = 'GiB';\r
-               }\r
-               if ($byte >= 1024) {\r
-                       $byte /= 1024;\r
-                       $symbol = 'TiB';\r
-               }\r
-               \r
-               return StringUtil::formatNumeric(round($byte, $precision)).' '.$symbol;\r
-       }\r
-       \r
-       /**\r
-        * Downloads a package archive from an http URL.\r
-        * \r
-        * @param       string          $httpUrl\r
-        * @param       string          $prefix\r
-        * @return      string          path to the dowloaded file\r
-        */\r
-       public static function downloadFileFromHttp($httpUrl, $prefix = 'package') {\r
-               $extension = strrchr($httpUrl, '.');\r
-               //$newFileName = self::getTemporaryFilename($prefix.'_', $extension);\r
-               $newFileName = self::getTemporaryFilename($prefix.'_');\r
-               $localFile = new File($newFileName); // the file to write.\r
-               \r
-               // get proxy\r
-               $options = array();\r
-               if (PROXY_SERVER_HTTP) {\r
-                       $options['http']['proxy'] = PROXY_SERVER_HTTP;\r
-                       $options['http']['request_fulluri'] = true;\r
-               }\r
-               \r
-               // first look if php's built-in fopen() is available, and if so, use it.\r
-               if (function_exists('fopen') && ini_get('allow_url_fopen')) {\r
-                       $remoteFile = new File($httpUrl, 'rb', $options); // the file to read.\r
-                       // get the content of the remote file and write it to a local file.\r
-                       while (!$remoteFile->eof()) {\r
-                               $buffer = $remoteFile->gets(4096);\r
-                               $localFile->write($buffer);\r
-                       }\r
-               }\r
-               // if allow_url_fopen isn't active, we attempt to use our own http download functionality.\r
-               else {\r
-                       $port = 80;\r
-                       $parsedUrl = parse_url($httpUrl);\r
-                       $host = $parsedUrl['host'];\r
-                       $path = (isset($parsedUrl['path']) ? $parsedUrl['path'] : '/');\r
-                       \r
-                       $remoteFile = new RemoteFile($host, $port, 30, $options); // the file to read.\r
-                       if (!isset($remoteFile)) {\r
-                               $localFile->close();\r
-                               unlink($newFileName);\r
-                               throw new SystemException("cannot connect to http host '".$host."'", 14000);\r
-                       }\r
-                       // build and send the http request.\r
-                       $request = "GET ".$path.(!empty($parsedUrl['query']) ? '?'.$parsedUrl['query'] : '')." HTTP/1.0\r\n";\r
-                       $request .= "User-Agent: HTTP.PHP (FileUtil.class.php; WoltLab Community Framework/".WCF_VERSION."; ".WCF::getLanguage()->getLanguageCode().")\r\n";\r
-                       $request .= "Accept: */*\r\n";\r
-                       $request .= "Accept-Language: ".WCF::getLanguage()->getLanguageCode()."\r\n";\r
-                       $request .= "Host: ".$host."\r\n";\r
-                       $request .= "Connection: Close\r\n\r\n";\r
-                       $remoteFile->puts($request);\r
-                       $waiting = true;\r
-                       $readResponse = array();\r
-                       // read http response.\r
-                       while (!$remoteFile->eof()) {\r
-                               $readResponse[] = $remoteFile->gets();\r
-                               // look if we are done with transferring the requested file.                                     \r
-                               if ($waiting) {\r
-                                       if (rtrim($readResponse[count($readResponse) - 1]) == '') {\r
-                                               $waiting = false;\r
-                                       }                                               \r
-                               }\r
-                               else {\r
-                                       // look if the webserver sent an error http statuscode\r
-                                       // This has still to be checked if really sufficient!\r
-                                       $arrayHeader = array('201', '301', '302', '303', '307', '404');\r
-                                       foreach ($arrayHeader as $code) {\r
-                                               $error = strpos($readResponse[0], $code);\r
-                                       }\r
-                                       if ($error !== false) {\r
-                                               $localFile->close();\r
-                                               unlink($newFileName);                                           \r
-                                               throw new SystemException("file ".$path." not found at host '".$host."'", 14001);\r
-                                       }\r
-                                       // write to the target system.\r
-                                       $localFile->write($readResponse[count($readResponse) - 1]);\r
-                               }\r
-                       }\r
-               }\r
-               \r
-               $remoteFile->close();\r
-               $localFile->close();\r
-               return $newFileName;            \r
-       }\r
-       \r
-       /**\r
-        * Strips supernumerous BOMs from a given bytestream.\r
-        *\r
-        * If we are dealing with bytestreams being pushed from one program or script to another in a UTF-8 \r
-        * environment, we might encounter problems with BOMs (Byte Order Marks). E.g., if there's a script \r
-        * that reads a .tar file via readfile(), and this script is encoded in UTF-8, and being called from another\r
-        * script which wants to handle the bytestream that results from readfile(). But apparently because of the \r
-        * UTF-8 encoding of the called script -- at least in some PHP versions -- readfile() adds a UTF-8 BOM\r
-        * at the beginning of the bytestream. If we do write this bytestream to disk and then try to open the\r
-        * resulting file, we will get an error because it is no more a valid .tar archive. The same thing happens\r
-        * if we handle an .xml file and then try to parse it.\r
-        * So, if bytestreams are being handled in a UTF-8 environment, be sure always to use this function \r
-        * before writing the bytestream to disk or trying to parse it with an xml parser.\r
-        * This works regardless of multibyte string support (mb_strpos and friends) being enabled or not.\r
-        * \r
-        * Btw, if you try to apply the following to a bytestream read from a .tar file, \r
-        * you will end up with a file sized zero bytes:\r
-        * while (($byte = fgetc($fileHandle)) !== false) {\r
-        *      fwrite($fileHandle, $byte);\r
-        * }\r
-        * \r
-        * @param       string          $sourceContent\r
-        * @param       string          $characterEncoding\r
-        * @return      string          destinationContent\r
-        */\r
-       public static function stripBoms($sourceContent = '', $characterEncoding = 'UTF-8') {\r
-               try {\r
-                       // TODO: implement recognition of other BOMs (UTF-7, UTF-16 big endian, UTF-16 little endian etc.)\r
-                       if ($characterEncoding == 'UTF-8') {\r
-                               // get the ASCII codes for the three bytes the UTF-8 BOM is consisting of.\r
-                               $firstByte = intval(0xEF);\r
-                               $secondByte = intval(0xBB);\r
-                               $thirdByte = intval(0xBF);\r
-                       }\r
-                       else {\r
-                               return $sourceContent;\r
-                       }\r
-                       \r
-                       // put the bytestream's first three bytes to an array.\r
-                       $workArray = array();\r
-                       $workArray = unpack('C3', $sourceContent);\r
-                       if (!is_array($workArray)) {\r
-                               throw new SystemException("Unable to process bytestream.");\r
-                       }\r
-                       \r
-                       // detect the UTF-8 BOM.\r
-                       $destinationContent = '';\r
-                       if (($workArray['1'] == $firstByte) && ($workArray['2'] == $secondByte) && ($workArray['3'] == $thirdByte)) {\r
-                               $tmpname = FileUtil::getTemporaryFilename('stripBoms_');\r
-                               $tmpStream = fopen($tmpname, 'w+');\r
-                               fwrite($tmpStream, $sourceContent);\r
-                               rewind($tmpStream);\r
-                               \r
-                               // cut off the BOM.\r
-                               fseek($tmpStream, 3); // compatibility for PHP < 5.1.0\r
-                               $destinationContent = stream_get_contents($tmpStream);\r
-                               fclose($tmpStream);\r
-                               @unlink($tmpname);\r
-                               \r
-                               return $destinationContent;\r
-                       } \r
-                       else {\r
-                               return $sourceContent;\r
-                       }\r
-               }\r
-               catch (SystemException $e) {\r
-                       throw $e;\r
-               }                       \r
-       }\r
-       \r
-       /**\r
-        * Determines whether a file is text or binary by checking the first few bytes in the file.\r
-        * The exact number of bytes is system dependent, but it is typically several thousand.\r
-        * If every byte in that part of the file is non-null, considers the file to be text;\r
-        * otherwise it considers the file to be binary.\r
-        * \r
-        * @param       string          $file\r
-        * @return      boolean\r
-        */\r
-       public static function isBinary($file) {\r
-               // open file\r
-               $file = new File($file, 'rb');\r
-               \r
-               // get block size\r
-               $stat = $file->stat();\r
-               $blockSize = $stat['blksize'];\r
-               if ($blockSize < 0) $blockSize = 1024;\r
-               if ($blockSize > $file->filesize()) $blockSize = $file->filesize();\r
-               if ($blockSize <= 0) return false;\r
-               \r
-               // get bytes\r
-               $block = $file->read($blockSize);\r
-               return (strlen($block) == 0 || preg_match_all('/\x00/', $block, $match) > 0);\r
-       }\r
-       \r
-       /**\r
-        * Uncompresses a gzipped file\r
-        *\r
-        * @param       string          $gzipped\r
-        * @param       string          $destination\r
-        * @return      boolean         result\r
-        */\r
-       public static function uncompressFile($gzipped, $destination) {\r
-               if (!@is_file($gzipped)) {\r
-                       return false;   \r
-               }\r
-               \r
-               $sourceFile = new ZipFile($gzipped, 'rb');\r
-               //$filesize = $sourceFile->getFileSize();\r
-               $targetFile = new File($destination);\r
-               while (!$sourceFile->eof()) {\r
-                       $targetFile->write($sourceFile->read(512), 512);        \r
-               }\r
-               $targetFile->close();\r
-               $sourceFile->close();\r
-               @$targetFile->chmod(0777);\r
-               \r
-               /*if ($filesize != filesize($destination)) {\r
-                       @unlink($destination);\r
-                       return false;\r
-               }*/\r
-               \r
-               return true;            \r
-       }\r
-       \r
-       /**\r
-        * Returns the value of the 'safe_mode' configuration option.\r
-        * \r
-        * @return      boolean\r
-        */\r
-       public static function getSafeMode() {\r
-               $configArray = @ini_get_all();\r
-               if (is_array($configArray) && isset($configArray['safe_mode']['local_value'])) {\r
-                       return intval($configArray['safe_mode']['local_value']);\r
-               }\r
-               return intval(@ini_get('safe_mode'));\r
-       }\r
-       \r
-       /**\r
-        * Returns true, if php is running as apache module.\r
-        * \r
-        * @return boolean\r
-        */\r
-       public static function isApacheModule() {\r
-               return function_exists('apache_get_version');\r
-       }\r
+<?php
+namespace wcf\util;
+use wcf\system\io\File;
+use wcf\system\io\ZipFile;
+use wcf\system\io\RemoteFile;
+use wcf\system\exception\SystemException;
+
+/**
+ * Contains file-related functions.
+ *
+ * @author     Marcel Werk
+ * @copyright  2001-2009 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage util
+ * @category   Community Framework
+ */
+class FileUtil {
+       /** 
+        * Generates a new temporary filename in TMP_DIR.
+        *
+        * @param       string          $prefix
+        * @param       string          $extension
+        * @param       string          $dir
+        * @return      string                          temporary filename
+        */
+       public static function getTemporaryFilename($prefix = 'tmpFile_', $extension = '', $dir = TMP_DIR) {
+               $dir = self::addTrailingSlash($dir);
+               do {
+                       $tmpFile = $dir.$prefix.StringUtil::getRandomID().$extension;
+               }
+               while (file_exists($tmpFile));  
+               
+               return $tmpFile;
+       }
+       
+       /**
+        * Removes a leading slash. 
+        *
+        * @param       string          $path
+        * @return      string          $path
+        */
+       public static function removeLeadingSlash($path) {
+               if (substr($path, 0, 1) == '/') {
+                       return substr($path, 1);
+               }
+               else {
+                       return $path;   
+               }       
+       }
+
+       /**
+        * Removes a trailing slash. 
+        *
+        * @param       string          $path
+        * @return      string          $path
+        */
+       public static function removeTrailingSlash($path) {
+               if (substr($path, -1) == '/') {
+                       return substr($path, 0, -1);
+               }
+               else {
+                       return $path;
+               }       
+       }
+       
+       /**
+        * Adds a trailing slash. 
+        *
+        * @param       string          $path
+        * @return      string          $path
+        */
+       public static function addTrailingSlash($path) {
+               if (substr($path, -1) != '/') {
+                       return $path.'/';
+               }
+               else {
+                       return $path;
+               }       
+       }
+
+       /**
+        * Builds a relative path from two absolute paths.
+        *
+        * @param       string          $currentDir
+        * @param       string          $targetDir
+        * @return      string                          relative Path
+        */
+       public static function getRelativePath($currentDir, $targetDir) {
+               // remove trailing slashes
+               $currentDir = self::removeTrailingSlash(self::unifyDirSeperator($currentDir));
+               $targetDir = self::removeTrailingSlash(self::unifyDirSeperator($targetDir));
+               
+               if ($currentDir == $targetDir) {
+                       return './';    
+               }
+               
+               $current = explode('/', $currentDir);
+               $target = explode('/', $targetDir);
+               
+               $relPath = '';
+               //for ($i = max(count($current), count($target)) - 1; $i >= 0; $i--) {
+               for ($i = 0, $max = max(count($current), count($target)); $i < $max; $i++) {
+                       if (isset($current[$i]) && isset($target[$i])) {
+                               if ($current[$i] != $target[$i]) {
+                                       for ($j = 0; $j < $i; $j++) {
+                                               unset($target[$j]);     
+                                       }
+                                       $relPath .= str_repeat('../', count($current) - $i).implode('/', $target).'/';  
+                                       for ($j = $i + 1; $j < count($current); $j++) {
+                                               unset($current[$j]);    
+                                       }
+                                       break;
+                               }
+                       }       
+                       // go up one level
+                       else if (isset($current[$i]) && !isset($target[$i])) {
+                               $relPath .= '../';
+                       }
+                       else if (!isset($current[$i]) && isset($target[$i])) {
+                               $relPath .= $target[$i].'/';
+                       }
+               }
+               
+               return $relPath;
+       }
+       
+       /**
+        * Creates a path on the local filesystem. 
+        * Parent directories do not need to exists as
+        * they will be created if necessary.
+        * Return true on success, otherwise false.
+        * 
+        * @param       string          $path
+        * @param       integer         $chmod
+        * @return      boolean                         success
+        */
+       public static function makePath($path, $chmod = 0777) {
+               // directory already exists, abort
+               if (file_exists($path)) {
+                       return false;
+               }
+               
+               // check if parent directory exists
+               $parent = dirname($path);
+               if ($parent != $path) {
+                       // parent directory does not exist either
+                       // we have to create the parent directory first
+                       $parent = self::addTrailingSlash($parent);
+                       if (!@file_exists($parent)) {
+                               // could not create parent directory either => abort
+                               if (!self::makePath($parent, $chmod)) {
+                                       return false;   
+                               }
+                       }
+                       
+                       // well, the parent directory exists or has been created
+                       // lets create this path
+                       $oldumask = @umask(0);
+                       if (!@mkdir($path, $chmod)) {
+                               return false;
+                       }
+                       @umask($oldumask);
+                       /*if (!@chmod($path, $chmod)) {
+                               return false;
+                       }*/
+                       if (self::isApacheModule() || !@is_writable($path)) {
+                               @chmod($path, 0777);
+                       }
+                       
+                       return true;
+               }
+               
+               return false;
+       }
+       
+       /**
+        * Unifies windows and unix directory seperators.
+        *
+        * @param       string          $path
+        * @return      string          $path
+        */
+       public static function unifyDirSeperator($path) {
+               $path = str_replace('\\\\', '/', $path);
+               $path = str_replace('\\', '/', $path);
+               return $path;
+       }
+       
+       /**
+        * Scans a folder (and subfolder) for a specific file.
+        * Returns the filename if found, otherwise false.
+        *
+        * @param       string          $folder
+        * @param       string          $searchfile
+        * @param       boolean         $recursive
+        * @return      mixed           $found
+        */
+       public static function scanFolder($folder, $searchfile, $recursive = true) {
+               if (!@is_dir($folder)) {
+                       return false;
+               }
+               if (!$searchfile) {
+                       return false;
+               }
+
+               $folder = self::addTrailingSlash($folder);
+               $dirh = @opendir($folder);
+               while ($filename = @readdir($dirh)) {
+                       if ($filename == '.' || $filename == '..') {
+                               continue;
+                       }
+                       if ($filename == $searchfile) {
+                               @closedir($dirh);
+                               return $folder.$filename;
+                       }
+
+                       if ($recursive == true && @is_dir($folder.$filename)) {
+                               if ($found = self::scanFolder($folder.$filename, $searchfile, $recursive)) {
+                                       @closedir($dirh);
+                                       return $found;
+                               }
+                       }
+               }
+               @closedir($dirh);
+       }
+       
+       /**
+        * Return true, if the given filename is an url (http or ftp).
+        * 
+        * @param       string          $filename
+        * @return      boolean
+        */
+       public static function isURL($filename) {
+               return preg_match('!^(https?|ftp)://!', $filename);
+       }
+       
+       /**
+        * Returns canonicalized absolute pathname.
+        * 
+        * @param       string          $path
+        * @return      string          path
+        */
+       public static function getRealPath($path) {
+               $path = self::unifyDirSeperator($path);
+               
+               $result = array();
+               $pathA = explode('/', $path);
+               if ($pathA[0] === '') {
+                       $result[] = '';
+               }
+
+               foreach ($pathA as $key => $dir) {
+                       if ($dir == '..') {
+                               if (end($result) == '..') {
+                                       $result[] = '..';
+                               } 
+                               else { 
+                                       $lastValue = array_pop($result);
+                                       if ($lastValue === '' || $lastValue === null) {
+                                               $result[] = '..';
+                                       }
+                               }
+                       } 
+                       else if ($dir !== '' && $dir != '.') {
+                               $result[] = $dir;
+                       }
+               }
+               
+               $lastValue = end($pathA);
+               if ($lastValue === '' || $lastValue === false) {
+                       $result[] = '';
+               }
+               
+               return implode('/', $result);
+       }
+       
+       /**
+        * formats a filesize
+        *
+        * @param       integer         $byte
+        * @param       integer         $precision
+        * @return      string          filesize
+        */
+       public static function formatFilesize($byte, $precision = 2) {
+               $symbol = 'Byte';
+               if ($byte >= 1000) {
+                       $byte /= 1000;
+                       $symbol = 'kB';
+               }
+               if ($byte >= 1000) {
+                       $byte /= 1000;
+                       $symbol = 'MB';
+               }
+               if ($byte >= 1000) {
+                       $byte /= 1000;
+                       $symbol = 'GB';
+               }
+               if ($byte >= 1000) {
+                       $byte /= 1000;
+                       $symbol = 'TB';
+               }
+               
+               return StringUtil::formatNumeric(round($byte, $precision)).' '.$symbol;
+       }
+       
+       /**
+        * formats a filesize (binary prefix)
+        * 
+        * For more informations: <http://en.wikipedia.org/wiki/Binary_prefix>
+        *
+        * @param       integer         $byte
+        * @param       integer         $precision
+        * @return      string          filesize
+        */
+       public static function formatFilesizeBinary($byte, $precision = 2) {
+               $symbol = 'Byte';
+               if ($byte >= 1024) {
+                       $byte /= 1024;
+                       $symbol = 'KiB';
+               }
+               if ($byte >= 1024) {
+                       $byte /= 1024;
+                       $symbol = 'MiB';
+               }
+               if ($byte >= 1024) {
+                       $byte /= 1024;
+                       $symbol = 'GiB';
+               }
+               if ($byte >= 1024) {
+                       $byte /= 1024;
+                       $symbol = 'TiB';
+               }
+               
+               return StringUtil::formatNumeric(round($byte, $precision)).' '.$symbol;
+       }
+       
+       /**
+        * Downloads a package archive from an http URL.
+        * 
+        * @param       string          $httpUrl
+        * @param       string          $prefix
+        * @return      string          path to the dowloaded file
+        */
+       public static function downloadFileFromHttp($httpUrl, $prefix = 'package') {
+               $extension = strrchr($httpUrl, '.');
+               //$newFileName = self::getTemporaryFilename($prefix.'_', $extension);
+               $newFileName = self::getTemporaryFilename($prefix.'_');
+               $localFile = new File($newFileName); // the file to write.
+               
+               // get proxy
+               $options = array();
+               if (PROXY_SERVER_HTTP) {
+                       $options['http']['proxy'] = PROXY_SERVER_HTTP;
+                       $options['http']['request_fulluri'] = true;
+               }
+               
+               // first look if php's built-in fopen() is available, and if so, use it.
+               if (function_exists('fopen') && ini_get('allow_url_fopen')) {
+                       $remoteFile = new File($httpUrl, 'rb', $options); // the file to read.
+                       // get the content of the remote file and write it to a local file.
+                       while (!$remoteFile->eof()) {
+                               $buffer = $remoteFile->gets(4096);
+                               $localFile->write($buffer);
+                       }
+               }
+               // if allow_url_fopen isn't active, we attempt to use our own http download functionality.
+               else {
+                       $parsedUrl = parse_url($httpUrl);
+                       $port = ($parsedUrl['scheme'] == 'https' ? 443 : 80);
+                       $host = $parsedUrl['host'];
+                       $path = (isset($parsedUrl['path']) ? $parsedUrl['path'] : '/');
+                       
+                       $remoteFile = new RemoteFile(($parsedUrl['scheme'] == 'https' ? 'ssl://' : '').$host, $port, 30, $options); // the file to read.
+                       if (!isset($remoteFile)) {
+                               $localFile->close();
+                               unlink($newFileName);
+                               throw new SystemException("cannot connect to http host '".$host."'", 14000);
+                       }
+                       // build and send the http request.
+                       $request = "GET ".$path.(!empty($parsedUrl['query']) ? '?'.$parsedUrl['query'] : '')." HTTP/1.0\r\n";
+                       $request .= "User-Agent: HTTP.PHP (FileUtil.class.php; WoltLab Community Framework/".WCF_VERSION."; ".WCF::getLanguage()->getLanguageCode().")\r\n";
+                       $request .= "Accept: */*\r\n";
+                       $request .= "Accept-Language: ".WCF::getLanguage()->getLanguageCode()."\r\n";
+                       $request .= "Host: ".$host."\r\n";
+                       $request .= "Connection: Close\r\n\r\n";
+                       $remoteFile->puts($request);
+                       $waiting = true;
+                       $readResponse = array();
+                       // read http response.
+                       while (!$remoteFile->eof()) {
+                               $readResponse[] = $remoteFile->gets();
+                               // look if we are done with transferring the requested file.                                     
+                               if ($waiting) {
+                                       if (rtrim($readResponse[count($readResponse) - 1]) == '') {
+                                               $waiting = false;
+                                       }                                               
+                               }
+                               else {
+                                       // look if the webserver sent an error http statuscode
+                                       // This has still to be checked if really sufficient!
+                                       $arrayHeader = array('201', '301', '302', '303', '307', '404');
+                                       foreach ($arrayHeader as $code) {
+                                               $error = strpos($readResponse[0], $code);
+                                       }
+                                       if ($error !== false) {
+                                               $localFile->close();
+                                               unlink($newFileName);                                           
+                                               throw new SystemException("file ".$path." not found at host '".$host."'", 14001);
+                                       }
+                                       // write to the target system.
+                                       $localFile->write($readResponse[count($readResponse) - 1]);
+                               }
+                       }
+               }
+               
+               $remoteFile->close();
+               $localFile->close();
+               return $newFileName;            
+       }
+       
+       /**
+        * Strips supernumerous BOMs from a given bytestream.
+        *
+        * If we are dealing with bytestreams being pushed from one program or script to another in a UTF-8 
+        * environment, we might encounter problems with BOMs (Byte Order Marks). E.g., if there's a script 
+        * that reads a .tar file via readfile(), and this script is encoded in UTF-8, and being called from another
+        * script which wants to handle the bytestream that results from readfile(). But apparently because of the 
+        * UTF-8 encoding of the called script -- at least in some PHP versions -- readfile() adds a UTF-8 BOM
+        * at the beginning of the bytestream. If we do write this bytestream to disk and then try to open the
+        * resulting file, we will get an error because it is no more a valid .tar archive. The same thing happens
+        * if we handle an .xml file and then try to parse it.
+        * So, if bytestreams are being handled in a UTF-8 environment, be sure always to use this function 
+        * before writing the bytestream to disk or trying to parse it with an xml parser.
+        * This works regardless of multibyte string support (mb_strpos and friends) being enabled or not.
+        * 
+        * Btw, if you try to apply the following to a bytestream read from a .tar file, 
+        * you will end up with a file sized zero bytes:
+        * while (($byte = fgetc($fileHandle)) !== false) {
+        *      fwrite($fileHandle, $byte);
+        * }
+        * 
+        * @param       string          $sourceContent
+        * @param       string          $characterEncoding
+        * @return      string          destinationContent
+        */
+       public static function stripBoms($sourceContent = '', $characterEncoding = 'UTF-8') {
+               try {
+                       // TODO: implement recognition of other BOMs (UTF-7, UTF-16 big endian, UTF-16 little endian etc.)
+                       if ($characterEncoding == 'UTF-8') {
+                               // get the ASCII codes for the three bytes the UTF-8 BOM is consisting of.
+                               $firstByte = intval(0xEF);
+                               $secondByte = intval(0xBB);
+                               $thirdByte = intval(0xBF);
+                       }
+                       else {
+                               return $sourceContent;
+                       }
+                       
+                       // put the bytestream's first three bytes to an array.
+                       $workArray = array();
+                       $workArray = unpack('C3', $sourceContent);
+                       if (!is_array($workArray)) {
+                               throw new SystemException("Unable to process bytestream.");
+                       }
+                       
+                       // detect the UTF-8 BOM.
+                       $destinationContent = '';
+                       if (($workArray['1'] == $firstByte) && ($workArray['2'] == $secondByte) && ($workArray['3'] == $thirdByte)) {
+                               $tmpname = FileUtil::getTemporaryFilename('stripBoms_');
+                               $tmpStream = fopen($tmpname, 'w+');
+                               fwrite($tmpStream, $sourceContent);
+                               rewind($tmpStream);
+                               
+                               // cut off the BOM.
+                               fseek($tmpStream, 3); // compatibility for PHP < 5.1.0
+                               $destinationContent = stream_get_contents($tmpStream);
+                               fclose($tmpStream);
+                               @unlink($tmpname);
+                               
+                               return $destinationContent;
+                       } 
+                       else {
+                               return $sourceContent;
+                       }
+               }
+               catch (SystemException $e) {
+                       throw $e;
+               }                       
+       }
+       
+       /**
+        * Determines whether a file is text or binary by checking the first few bytes in the file.
+        * The exact number of bytes is system dependent, but it is typically several thousand.
+        * If every byte in that part of the file is non-null, considers the file to be text;
+        * otherwise it considers the file to be binary.
+        * 
+        * @param       string          $file
+        * @return      boolean
+        */
+       public static function isBinary($file) {
+               // open file
+               $file = new File($file, 'rb');
+               
+               // get block size
+               $stat = $file->stat();
+               $blockSize = $stat['blksize'];
+               if ($blockSize < 0) $blockSize = 1024;
+               if ($blockSize > $file->filesize()) $blockSize = $file->filesize();
+               if ($blockSize <= 0) return false;
+               
+               // get bytes
+               $block = $file->read($blockSize);
+               return (strlen($block) == 0 || preg_match_all('/\x00/', $block, $match) > 0);
+       }
+       
+       /**
+        * Uncompresses a gzipped file
+        *
+        * @param       string          $gzipped
+        * @param       string          $destination
+        * @return      boolean         result
+        */
+       public static function uncompressFile($gzipped, $destination) {
+               if (!@is_file($gzipped)) {
+                       return false;   
+               }
+               
+               $sourceFile = new ZipFile($gzipped, 'rb');
+               //$filesize = $sourceFile->getFileSize();
+               $targetFile = new File($destination);
+               while (!$sourceFile->eof()) {
+                       $targetFile->write($sourceFile->read(512), 512);        
+               }
+               $targetFile->close();
+               $sourceFile->close();
+               @$targetFile->chmod(0777);
+               
+               /*if ($filesize != filesize($destination)) {
+                       @unlink($destination);
+                       return false;
+               }*/
+               
+               return true;            
+       }
+       
+       /**
+        * Returns the value of the 'safe_mode' configuration option.
+        * 
+        * @return      boolean
+        */
+       public static function getSafeMode() {
+               $configArray = @ini_get_all();
+               if (is_array($configArray) && isset($configArray['safe_mode']['local_value'])) {
+                       return intval($configArray['safe_mode']['local_value']);
+               }
+               return intval(@ini_get('safe_mode'));
+       }
+       
+       /**
+        * Returns true, if php is running as apache module.
+        * 
+        * @return boolean
+        */
+       public static function isApacheModule() {
+               return function_exists('apache_get_version');
+       }
 }
-?>\r