-<?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