* This script tries to find the temp folder and unzip all setup files into.
*
* @author Marcel Werk
- * @copyright 2001-2011 WoltLab GmbH
+ * @copyright 2001-2013 WoltLab GmbH
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
*/
// define constants
+define('INSTALL_SCRIPT', __FILE__);
define('INSTALL_SCRIPT_DIR', dirname(__FILE__).'/');
define('SETUP_FILE', INSTALL_SCRIPT_DIR . 'WCFSetup.tar.gz');
define('NO_IMPORTS', 1);
$neededFilesPattern = array(
'!^setup/.*!',
'!^install/files/acp/images/wcfLogo.*!',
- '!^install/files/acp/style/.*!',
+ '!^install/files/acp/style/setup/.*!',
'!^install/files/lib/data/.*!',
'!^install/files/icon/.*!',
+ '!^install/files/font/.*!',
'!^install/files/lib/system/.*!',
'!^install/files/lib/util/.*!',
'!^install/lang/.*!',
/**
* WCF::handleException() calls the show method on exceptions that implement this interface.
*
- * @package com.woltlab.wcf.system.exception
+ * @package com.woltlab.wcf
* @author Marcel Werk
*/
interface IPrintableException {
/**
* A SystemException is thrown when an unexpected error occurs.
*
- * @package com.woltlab.wcf.system.exception
+ * @package com.woltlab.wcf
* @author Marcel Werk
*/
class SystemException extends \Exception implements IPrintableException {
/**
* Returns the description of this exception.
*
- * @return string
+ * @return string
*/
public function getDescription() {
return $this->description;
array_shift($namespaces);
$className = implode('/', $namespaces);
- $classPath = TMP_DIR . 'install/files/lib/' . $className . '.class.php';
+ $classPath = TMP_DIR . 'install/files/lib/' . $className . '.class.php';
if (file_exists($classPath)) {
require_once($classPath);
}
/**
* BasicFileUtil contains file-related functions.
*
- * @package com.woltlab.wcf.util
+ * @package com.woltlab.wcf
* @author Marcel Werk
*/
class BasicFileUtil {
+ /**
+ * chmod mode
+ * @var integer
+ */
+ protected static $mode = null;
+
/**
* Tries to find the temp folder.
*
* @return string
*/
public static function getTempFolder() {
- $tmpDirName = TMP_FILE_PREFIX.'/';
-
// use tmp folder in document root by default
if (!empty($_SERVER['DOCUMENT_ROOT'])) {
- if (!@file_exists($_SERVER['DOCUMENT_ROOT'].'/tmp/'.$tmpDirName)) {
- @mkdir($_SERVER['DOCUMENT_ROOT'].'/tmp/'.$tmpDirName, 0777, true);
- @chmod($_SERVER['DOCUMENT_ROOT'].'/tmp/'.$tmpDirName, 0777);
+ if (strpos($_SERVER['DOCUMENT_ROOT'], 'strato') !== false) {
+ // strato bugfix
+ // create tmp folder in document root automatically
+ if (!@file_exists($_SERVER['DOCUMENT_ROOT'].'/tmp')) {
+ @mkdir($_SERVER['DOCUMENT_ROOT'].'/tmp/', 0777);
+ try {
+ self::makeWritable($_SERVER['DOCUMENT_ROOT'].'/tmp/');
+ }
+ catch (SystemException $e) {}
+ }
}
-
- if (@file_exists($_SERVER['DOCUMENT_ROOT'].'/tmp/'.$tmpDirName) && @is_writable($_SERVER['DOCUMENT_ROOT'].'/tmp/'.$tmpDirName)) {
- return $_SERVER['DOCUMENT_ROOT'].'/tmp/'.$tmpDirName;
+ if (@file_exists($_SERVER['DOCUMENT_ROOT'].'/tmp') && @is_writable($_SERVER['DOCUMENT_ROOT'].'/tmp')) {
+ return $_SERVER['DOCUMENT_ROOT'].'/tmp/';
}
}
+
+ if (isset($_ENV['TMP']) && @is_writable($_ENV['TMP'])) {
+ return $_ENV['TMP'] . '/';
+ }
+ if (isset($_ENV['TEMP']) && @is_writable($_ENV['TEMP'])) {
+ return $_ENV['TEMP'] . '/';
+ }
+ if (isset($_ENV['TMPDIR']) && @is_writable($_ENV['TMPDIR'])) {
+ return $_ENV['TMPDIR'] . '/';
+ }
+
+ if (($path = ini_get('upload_tmp_dir')) && @is_writable($path)) {
+ return $path . '/';
+ }
+ if (@file_exists('/tmp/') && @is_writable('/tmp/')) {
+ return '/tmp/';
+ }
+ if (function_exists('session_save_path') && ($path = session_save_path()) && @is_writable($path)) {
+ return $path . '/';
+ }
+
+ $path = INSTALL_SCRIPT_DIR.'tmp/';
+ if (@file_exists($path) && @is_writable($path)) {
+ return $path;
+ }
+ else {
+ throw new SystemException('There is no access to the system temporary folder due to an unknown reason and no user specific temporary folder exists in '.INSTALL_SCRIPT_DIR.'! This is a misconfiguration of your webserver software! Please create a folder called '.$path.' using your favorite ftp program, make it writable and then retry this installation.');
+ }
+ }
+
+ /**
+ * Returns the temp folder for the installation.
+ *
+ * @return string
+ */
+ public static function getInstallTempFolder() {
+ $dir = self::getTempFolder() . TMP_FILE_PREFIX . '/';
+ @mkdir($dir);
+ self::makeWritable($dir);
+
+ return $dir;
+ }
+
+ /**
+ * Tries to make a file or directory writable. It starts of with the least
+ * permissions and goes up until 0666 for files and 0777 for directories.
+ *
+ * @param string $filename
+ */
+ public static function makeWritable($filename) {
+ if (!file_exists($filename)) {
+ return;
+ }
- foreach (array('TMP', 'TEMP', 'TMPDIR') as $tmpDir) {
- if (isset($_ENV[$tmpDir]) && @is_writable($_ENV[$tmpDir])) {
- $dir = $_ENV[$tmpDir] . '/' . $tmpDirName;
- @mkdir($dir, 0777);
- @chmod($dir, 0777);
+ // determine mode
+ if (self::$mode === null) {
+ // do not use PHP_OS here, as this represents the system it was built on != running on
+ if (strpos(php_uname(), 'Windows') !== false) {
+ self::$mode = 0777;
+ }
+ else {
+ clearstatcache();
+
+ self::$mode = 0666;
- if (@file_exists($dir) && @is_writable($dir)) {
- return $dir;
+ $tmpFilename = '__permissions_'.sha1(time()).'.txt';
+ @touch($tmpFilename);
+
+ // create a new file and check the file owner, if it is the same
+ // as this file (uploaded through FTP), we can safely grant write
+ // permissions exclusively to the owner rather than everyone
+ if (file_exists($tmpFilename)) {
+ $scriptOwner = fileowner(__FILE__);
+ $fileOwner = fileowner($tmpFilename);
+
+ if ($scriptOwner === $fileOwner) {
+ self::$mode = 0644;
+ }
+
+ @unlink($tmpFilename);
}
}
}
- $dir = INSTALL_SCRIPT_DIR . 'tmp/' . $tmpDirName;
- @mkdir($dir, 0777);
- @chmod($dir, 0777);
-
- if (!@file_exists($dir) || !@is_writable($dir)) {
- $tmpDir = explode('/', $dir);
- array_pop($tmpDir);
- $dir = implode('/', $tmpDir);
-
- throw new SystemException('There is no access to the system temporary folder due to an unknown reason and no user specific temporary folder exists in '.INSTALL_SCRIPT_DIR.'! This is a misconfiguration of your webserver software! Please create a folder called '.$dir.' using your favorite ftp program, make it writable and then retry this installation.');
+ $startIndex = 0;
+ if (is_dir($filename)) {
+ if (self::$mode == 0644) {
+ @chmod($filename, 0755);
+ }
+ else {
+ @chmod($filename, 0777);
+ }
+ }
+ else {
+ @chmod($filename, self::$mode);
}
- return $dir;
+ if (!is_writable($filename)) {
+ throw new SystemException("Unable to make '".$filename."' writable. This is a misconfiguration of your server, please contact your system administrator or hosting provider.");
+ }
}
}
* Creates a new Tar object.
* archiveName must be tarball or gzipped tarball
*
- * @param string $archiveName
+ * @param string $archiveName
*/
public function __construct($archiveName) {
- $match = array();
if (!is_file($archiveName)) {
throw new SystemException("unable to find tar archive '".$archiveName."'");
}
/**
* Returns the table of contents (TOC) list for this tar archive.
*
- * @return array list of content
+ * @return array list of content
*/
public function getContentList() {
if (!$this->read) {
* Returns an associative array with information
* about a specific file in the archive.
*
- * @param mixed $fileindex index or name of the requested file
- * @return array $fileInfo
+ * @param mixed $fileindex index or name of the requested file
+ * @return array $fileInfo
*/
public function getFileInfo($fileIndex) {
if (!is_int($fileIndex)) {
}
if (!isset($this->contentList[$fileIndex])) {
- throw new SystemException("Tar: could find file '$index' in archive");
+ throw new SystemException("Tar: could find file '".$fileIndex."' in archive");
}
return $this->contentList[$fileIndex];
}
* and returns the numeric fileindex.
* Returns false if not found.
*
- * @param string $filename
- * @return integer index of the requested file
+ * @param string $filename
+ * @return integer index of the requested file
*/
public function getIndexByFilename($filename) {
foreach ($this->contentList as $index => $file) {
* Extracts a specific file and returns the content as string.
* Returns false if extraction failed.
*
- * @param mixed $index index or name of the requested file
- * @return string content of the requested file
+ * @param mixed $index index or name of the requested file
+ * @return string content of the requested file
*/
public function extractToString($index) {
if (!$this->read) {
* Extracts a specific file and writes it's content
* to the file specified with $destination.
*
- * @param mixed $index index or name of the requested file
- * @param string $destination
- * @return boolean $success
+ * @param mixed $index index or name of the requested file
+ * @param string $destination
+ * @return boolean $success
*/
public function extract($index, $destination) {
if (!$this->read) {
}
$targetFile->close();
- if (function_exists('apache_get_version') || !@$targetFile->is_writable()) {
- @$targetFile->chmod(0777);
- }
- else {
- @$targetFile->chmod(0755);
- }
+ BasicFileUtil::makeWritable($destination);
if ($header['mtime']) {
@$targetFile->touch($header['mtime']);
/**
* Unpacks file header for one file entry.
*
- * @param string $binaryData
- * @return array $fileheader
+ * @param string $binaryData
+ * @return array $fileheader
*/
protected function readHeader($binaryData) {
if (strlen($binaryData) != 512) {
// Extract the values
//$data = unpack("a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/a8checksum/a1typeflag/a100link/a6magic/a2version/a32uname/a32gname/a8devmajor/a8devminor", $binaryData);
- $data = unpack("a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/a8checksum/a1typeflag/a100link/a6magic/a2version/a32uname/a32gname/a8devmajor/a8devminor/a155prefix", $binaryData);
+ if (version_compare(PHP_VERSION, '5.5.0-dev', '>=')) {
+ $format = 'Z100filename/Z8mode/Z8uid/Z8gid/Z12size/Z12mtime/Z8checksum/Z1typeflag/Z100link/Z6magic/Z2version/Z32uname/Z32gname/Z8devmajor/Z8devminor/Z155prefix';
+ }
+ else {
+ $format = 'a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/a8checksum/a1typeflag/a100link/a6magic/a2version/a32uname/a32gname/a8devmajor/a8devminor/a155prefix';
+ }
+
+ $data = unpack($format, $binaryData);
// Extract the properties
$header['checksum'] = octDec(trim($data['checksum']));
/**
* Opens a new file.
*
- * @param string $filename
- * @param string $mode
+ * @param string $filename
+ * @param string $mode
*/
public function __construct($filename, $mode = 'wb') {
$this->filename = $filename;
* Calls the specified function on the open file.
* Do not call this function directly. Use $file->write('') instead.
*
- * @param string $function
- * @param array $arguments
+ * @param string $function
+ * @param array $arguments
*/
public function __call($function, $arguments) {
if (function_exists('f' . $function)) {
array_unshift($arguments, $this->resource);
- return call_user_func_array('f' . $function, $arguments);
+ return call_user_func_array('f' . $function, $arguments);
}
else if (function_exists($function)) {
array_unshift($arguments, $this->filename);
- return call_user_func_array($function, $arguments);
+ return call_user_func_array($function, $arguments);
}
else {
throw new SystemException('Can not call file method ' . $function);
/**
* Opens a new zipped file.
*
- * @param string $filename
- * @param string $mode
+ * @param string $filename
+ * @param string $mode
*/
public function __construct($filename, $mode = 'wb') {
$this->filename = $filename;
/**
* Calls the specified function on the open file.
*
- * @param string $function
- * @param array $arguments
+ * @param string $function
+ * @param array $arguments
*/
public function __call($function, $arguments) {
if (function_exists('gz' . $function)) {
array_unshift($arguments, $this->resource);
- return call_user_func_array('gz' . $function, $arguments);
+ return call_user_func_array('gz' . $function, $arguments);
}
else if (function_exists($function)) {
array_unshift($arguments, $this->filename);
- return call_user_func_array($function, $arguments);
+ return call_user_func_array($function, $arguments);
}
else {
throw new SystemException('Can not call method ' . $function);
define('TMP_FILE_PREFIX', $prefix);
// try to find the temp folder
-define('TMP_DIR', BasicFileUtil::getTempFolder());
+define('TMP_DIR', BasicFileUtil::getInstallTempFolder());
/**
* Reads a file resource from temp folder.
* @param string $directory
*/
function readFileResource($key, $directory) {
- if (preg_match('~[\w\-]+\.(css|jpg|png|svg)~', $_GET[$key], $match)) {
+ if (preg_match('~[\w\-]+\.(css|jpg|png|svg|eot|woff|ttf)~', $_GET[$key], $match)) {
switch ($match[1]) {
case 'css':
header('Content-Type: text/css');
case 'svg':
header('Content-Type: image/svg+xml');
break;
+
+ case 'eot':
+ header('Content-Type: application/vnd.ms-fontobject');
+ break;
+
+ case 'woff':
+ header('Content-Type: application/font-woff');
+ break;
+
+ case 'ttf':
+ header('Content-Type: application/octet-stream');
+ break;
}
+ header('Expires: '.gmdate('D, d M Y H:i:s', time() + 3600).' GMT');
+ header('Last-Modified: Mon, 26 Jul 1997 05:00:00 GMT');
+ header('Cache-Control: public, max-age=3600');
+
readfile($directory . $_GET[$key]);
}
exit;
}
// show css from temp folder
if (isset($_GET['showCSS'])) {
- readFileResource('showCSS', TMP_DIR . 'install/files/acp/style/');
+ readFileResource('showCSS', TMP_DIR . 'install/files/acp/style/setup/');
+}
+// show fonts from temp folder
+if (isset($_GET['showFont'])) {
+ readFileResource('showFont', TMP_DIR . 'install/files/font/');
}
// check whether setup files are already unzipped
// try to unzip all setup files into temp folder
$tar = new Tar(SETUP_FILE);
$contentList = $tar->getContentList();
- if (!count($contentList)) {
+ if (empty($contentList)) {
throw new SystemException("Can not unpack 'WCFSetup.tar.gz'. File is probably broken.");
}
$dir = TMP_DIR . dirname($file['filename']);
if (!@is_dir($dir)) {
@mkdir($dir, 0777, true);
- @chmod($dir, 0777);
+ BasicFileUtil::makeWritable($dir);
}
$tar->extract($file['index'], TMP_DIR . $file['filename']);
// create cache folders
@mkdir(TMP_DIR . 'setup/lang/cache/', 0777);
- @chmod(TMP_DIR . 'setup/lang/cache/', 0777);
+ BasicFileUtil::makeWritable(TMP_DIR . 'setup/lang/cache/');
@mkdir(TMP_DIR . 'setup/template/compiled/', 0777);
- @chmod(TMP_DIR . 'setup/template/compiled/', 0777);
+ BasicFileUtil::makeWritable(TMP_DIR . 'setup/template/compiled/');
}
if (!class_exists('wcf\system\WCFSetup')) {