Removed initial checks for writable
[GitHub/WoltLab/WCF.git] / wcfsetup / install.php
CommitLineData
158bd3ca
TD
1<?php
2/**
3 * This script tries to find the temp folder and unzip all setup files into.
4 *
5 * @author Marcel Werk
6 * @copyright 2001-2011 WoltLab GmbH
7 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
8 */
9// define constants
10define('INSTALL_SCRIPT_DIR', dirname(__FILE__).'/');
11define('SETUP_FILE', INSTALL_SCRIPT_DIR . 'WCFSetup.tar.gz');
12define('NO_IMPORTS', 1);
13
14// set exception handler
15set_exception_handler('handleException');
16// set php error handler
17set_error_handler('handleError', E_ALL);
18
19// define list of needed file
20$neededFilesPattern = array(
21 '!^setup/.*!',
7da7f7cc 22 '!^install/files/acp/images/wcfLogo.*!',
e94c3830 23 '!^install/files/acp/style/setup/.*!',
158bd3ca 24 '!^install/files/lib/data/.*!',
7da7f7cc 25 '!^install/files/icon/.*!',
e2a34399 26 '!^install/files/font/.*!',
158bd3ca
TD
27 '!^install/files/lib/system/.*!',
28 '!^install/files/lib/util/.*!',
158bd3ca
TD
29 '!^install/lang/.*!',
30 '!^install/packages/.*!');
31
32// define needed functions and classes
33/**
34 * WCF::handleException() calls the show method on exceptions that implement this interface.
35 *
36 * @package com.woltlab.wcf.system.exception
37 * @author Marcel Werk
38 */
39interface IPrintableException {
40 public function show();
41}
42
43// define needed classes
44// needed are:
45// SystemException, PrintableException, BasicFileUtil, Tar, File, ZipFile
46/**
47 * A SystemException is thrown when an unexpected error occurs.
48 *
49 * @package com.woltlab.wcf.system.exception
50 * @author Marcel Werk
51 */
52class SystemException extends \Exception implements IPrintableException {
53 protected $description;
54 protected $information = '';
55 protected $functions = '';
56
57 /**
58 * Creates a new SystemException.
59 *
60 * @param message string error message
61 * @param code integer error code
62 * @param description string description of the error
63 */
64 public function __construct($message = '', $code = 0, $description = '') {
65 parent::__construct($message, $code);
66 $this->description = $description;
67 }
68
69 /**
70 * Returns the description of this exception.
71 *
39bea7dd 72 * @return string
158bd3ca
TD
73 */
74 public function getDescription() {
75 return $this->description;
76 }
77
78 /**
79 * Prints this exception.
80 * This method is called by WCF::handleException().
81 */
82 public function show() {
83 ?>
84<html>
85<head>
86<title>Fatal error: <?php echo htmlspecialchars($this->getMessage()); ?></title>
158bd3ca 87
53e00c6b
L
88<style type="text/css">
89 body {
90 font-family: Verdana, Helvetica, sans-serif;
91 font-size: 0.8em;
92 }
93 div {
94 border: 1px outset lightgrey;
95 padding: 3px;
96 background-color: lightgrey;
97 }
98
99 div div {
100 border: 1px inset lightgrey;
101 padding: 4px;
102 }
103
104 h1 {
105 background-color: #154268;
106 padding: 4px;
107 color: #fff;
108 margin: 0 0 3px 0;
109 font-size: 1.15em;
110 }
111 h2 {
112 font-size: 1.1em;
113 margin-bottom: 0;
114 }
115
116 pre, p {
117 margin: 0;
118 }
158bd3ca
TD
119</style>
120</head>
53e00c6b 121
158bd3ca
TD
122<body>
123 <div>
124 <h1>Fatal error: <?php echo htmlspecialchars($this->getMessage()); ?></h1>
125
126 <div>
127 <p><?php echo $this->getDescription(); ?></p>
128 <?php if ($this->getCode()) { ?><p>You get more information about the problem in our knowledge base: <a href="http://www.woltlab.com/help/?code=<?php echo intval($this->getCode()); ?>">http://www.woltlab.com/help/?code=<?php echo intval($this->getCode()); ?></a></p><?php } ?>
129
130 <h2>Information:</h2>
131 <p>
132 <b>error message:</b> <?php echo htmlspecialchars($this->getMessage()); ?><br />
133 <b>error code:</b> <?php echo intval($this->getCode()); ?><br />
134 <?php echo $this->information; ?>
135 <b>file:</b> <?php echo htmlspecialchars($this->getFile()); ?> (<?php echo $this->getLine(); ?>)<br />
136 <b>php version:</b> <?php echo htmlspecialchars(phpversion()); ?><br />
137 <b>wcf version:</b> <?php if (defined('WCF_VERSION')) echo WCF_VERSION; ?><br />
138 <b>date:</b> <?php echo gmdate('r'); ?><br />
139 <b>request:</b> <?php if (isset($_SERVER['REQUEST_URI'])) echo htmlspecialchars($_SERVER['REQUEST_URI']); ?><br />
140 <b>referer:</b> <?php if (isset($_SERVER['HTTP_REFERER'])) echo htmlspecialchars($_SERVER['HTTP_REFERER']); ?><br />
141 </p>
142
143 <h2>Stacktrace:</h2>
144 <pre><?php echo htmlspecialchars($this->getTraceAsString()); ?></pre>
145 </div>
146
147 <?php echo $this->functions; ?>
148 </div>
149</body>
150</html>
151
152<?php
153 }
154}
155
156
157/**
158 * Loads the required classes automatically.
159 */
160function __autoload($className) {
161 $namespaces = explode('\\', $className);
162 if (count($namespaces) > 1) {
163 // remove 'wcf' component
164 array_shift($namespaces);
165
166 $className = implode('/', $namespaces);
01bd2eff 167 $classPath = TMP_DIR . 'install/files/lib/' . $className . '.class.php';
158bd3ca
TD
168 if (file_exists($classPath)) {
169 require_once($classPath);
170 }
171 }
172}
173
174/**
175 * Escapes strings for execution in sql queries.
176 */
177function escapeString($string) {
178 return \wcf\system\WCF::getDB()->escapeString($string);
179}
180
181/**
182 * Calls the show method on the given exception.
183 *
184 * @param Exception $e
185 */
186function handleException(\Exception $e) {
187 if ($e instanceof IPrintableException || $e instanceof \wcf\system\exception\IPrintableException) {
188 $e->show();
189 exit;
190 }
191
192 print $e;
193}
194
195/**
196 * Catches php errors and throws instead a system exception.
197 *
198 * @param integer $errorNo
199 * @param string $message
200 * @param string $filename
201 * @param integer $lineNo
202 */
203function handleError($errorNo, $message, $filename, $lineNo) {
204 if (error_reporting() != 0) {
205 $type = 'error';
206 switch ($errorNo) {
207 case 2: $type = 'warning';
208 break;
209 case 8: $type = 'notice';
210 break;
211 }
212
213 throw new SystemException('PHP '.$type.' in file '.$filename.' ('.$lineNo.'): '.$message, 0);
214 }
215}
216
217/**
218 * BasicFileUtil contains file-related functions.
219 *
39bea7dd 220 * @package com.woltlab.wcf.util
158bd3ca
TD
221 * @author Marcel Werk
222 */
223class BasicFileUtil {
d8fa09e0
AE
224 /**
225 * chmod mode
226 * @var integer
227 */
228 protected static $mode = null;
229
158bd3ca
TD
230 /**
231 * Tries to find the temp folder.
232 *
233 * @return string
234 */
235 public static function getTempFolder() {
158bd3ca
TD
236 // use tmp folder in document root by default
237 if (!empty($_SERVER['DOCUMENT_ROOT'])) {
069cd37e
MW
238 if (strpos($_SERVER['DOCUMENT_ROOT'], 'strato') !== false) {
239 // strato bugfix
240 // create tmp folder in document root automatically
241 if (!@file_exists($_SERVER['DOCUMENT_ROOT'].'/tmp')) {
242 @mkdir($_SERVER['DOCUMENT_ROOT'].'/tmp/', 0777);
243 try {
244 self::makeWritable($_SERVER['DOCUMENT_ROOT'].'/tmp/');
245 }
246 catch (SystemException $e) {}
247 }
158bd3ca 248 }
069cd37e
MW
249 if (@file_exists($_SERVER['DOCUMENT_ROOT'].'/tmp') && @is_writable($_SERVER['DOCUMENT_ROOT'].'/tmp')) {
250 return $_SERVER['DOCUMENT_ROOT'].'/tmp/';
158bd3ca
TD
251 }
252 }
069cd37e
MW
253
254 if (isset($_ENV['TMP']) && @is_writable($_ENV['TMP'])) {
255 return $_ENV['TMP'] . '/';
158bd3ca 256 }
069cd37e
MW
257 if (isset($_ENV['TEMP']) && @is_writable($_ENV['TEMP'])) {
258 return $_ENV['TEMP'] . '/';
259 }
260 if (isset($_ENV['TMPDIR']) && @is_writable($_ENV['TMPDIR'])) {
261 return $_ENV['TMPDIR'] . '/';
262 }
263
264 if (($path = ini_get('upload_tmp_dir')) && @is_writable($path)) {
265 return $path . '/';
266 }
267 if (@file_exists('/tmp/') && @is_writable('/tmp/')) {
268 return '/tmp/';
158bd3ca 269 }
069cd37e
MW
270 if (function_exists('session_save_path') && ($path = session_save_path()) && @is_writable($path)) {
271 return $path . '/';
272 }
273
274 $path = WCF_DIR.'tmp/';
275 if (@file_exists($path) && @is_writable($path)) {
276 return $path;
277 }
278 else {
279 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.');
280 }
281 }
282
283 /**
284 * Returns the temp folder for the installation.
285 *
286 * @return string
287 */
288 public static function getInstallTempFolder() {
289 $dir = self::getTempFolder() . TMP_FILE_PREFIX . '/';
290 @mkdir($dir);
291 self::makeWritable($dir);
158bd3ca
TD
292
293 return $dir;
294 }
1232bce2
AE
295
296 /**
297 * Tries to make a file or directory writable. It starts of with the least
d8fa09e0 298 * permissions and goes up until 0666 for files and 0777 for directories.
1232bce2
AE
299 *
300 * @param string $filename
301 */
302 public static function makeWritable($filename) {
043b049d 303 if (!file_exists($filename)) {
1232bce2
AE
304 return;
305 }
306
d8fa09e0
AE
307 // determine mode
308 if (self::$mode === null) {
309 // do not use PHP_OS here, as this represents the system it was built on != running on
310 if (strpos(php_uname(), 'Windows') !== false) {
311 self::$mode = 0777;
312 }
313 else {
314 self::$mode = 0666;
315
316 $filename = '__permissions_'.sha1(time()).'.txt';
317 @touch($filename);
318
319 // create a new file and check the file owner, if it is the same
320 // as this file (uploaded through FTP), we can safely grant write
321 // permissions exclusively to the owner rather than everyone
322 if (file_exists($filename)) {
323 $scriptOwner = fileowner(__FILE__);
324 $fileOwner = fileowner($filename);
325
326 if ($scriptOwner === $fileOwner) {
327 self::$mode = 0644;
328 }
329
330 @unlink($filename);
331 }
332 }
333 }
1232bce2
AE
334
335 $startIndex = 0;
336 if (is_dir($filename)) {
d8fa09e0
AE
337 if (self::$mode == 0644) {
338 chmod($filename, 0755);
1232bce2 339 }
d8fa09e0
AE
340 else {
341 chmod($filename, 0777);
1232bce2
AE
342 }
343 }
d8fa09e0
AE
344 else {
345 chmod($filename, self::$mode);
346 }
347
348 if (!is_writable($filename)) {
349 throw new SystemException("Unable to make '".$filename."' writable. This is a misconfiguration of your server, please contact your system administrator or hosting provider.");
350 }
1232bce2 351 }
158bd3ca
TD
352}
353
354/**
355 * Opens tar or tar.gz archives.
356 *
357 * Usage:
358 * ------
359 * $tar = new Tar('archive.tar');
360 * $contentList = $tar->getContentList();
361 * foreach ($contentList as $key => $val) {
362 * $tar->extract($key, DESTINATION);
363 * }
364 */
365class Tar {
366 protected $archiveName = '';
367 protected $contentList = array();
368 protected $opened = false;
369 protected $read = false;
370 protected $file = null;
371 protected $isZipped = false;
372 protected $mode = 'rb';
373
374 /**
375 * Creates a new Tar object.
376 * archiveName must be tarball or gzipped tarball
377 *
39bea7dd 378 * @param string $archiveName
158bd3ca
TD
379 */
380 public function __construct($archiveName) {
158bd3ca 381 if (!is_file($archiveName)) {
4fe0b42b 382 throw new SystemException("unable to find tar archive '".$archiveName."'");
158bd3ca
TD
383 }
384
385 $this->archiveName = $archiveName;
386 $this->open();
387 $this->readContent();
388 }
389
390 /**
391 * Destructor of this class, closes tar archive.
392 */
393 public function __destruct() {
394 $this->close();
395 }
396
397 /**
398 * Opens the tar archive and stores filehandle.
399 */
400 public function open() {
401 if (!$this->opened) {
402 if ($this->isZipped) $this->file = new ZipFile($this->archiveName, $this->mode);
403 else {
404 // test compression
405 $this->file = new File($this->archiveName, $this->mode);
406 if ($this->file->read(2) == "\37\213") {
407 $this->file->close();
408 $this->isZipped = true;
409 $this->file = new ZipFile($this->archiveName, $this->mode);
410 }
411 else {
412 $this->file->seek(0);
413 }
414 }
415 $this->opened = true;
416 }
417 }
418
419 /**
420 * Closes the opened file.
421 */
422 public function close() {
423 if ($this->opened) {
424 $this->file->close();
425 $this->opened = false;
426 }
427 }
428
429 /**
430 * Returns the table of contents (TOC) list for this tar archive.
431 *
39bea7dd 432 * @return array list of content
158bd3ca
TD
433 */
434 public function getContentList() {
435 if (!$this->read) {
436 $this->open();
437 $this->readContent();
438 }
439 return $this->contentList;
440 }
441
442 /**
443 * Returns an associative array with information
444 * about a specific file in the archive.
445 *
39bea7dd
MS
446 * @param mixed $fileindex index or name of the requested file
447 * @return array $fileInfo
158bd3ca
TD
448 */
449 public function getFileInfo($fileIndex) {
450 if (!is_int($fileIndex)) {
451 $fileIndex = $this->getIndexByFilename($fileIndex);
452 }
453
454 if (!isset($this->contentList[$fileIndex])) {
6286572b 455 throw new SystemException("Tar: could find file '".$fileIndex."' in archive");
158bd3ca
TD
456 }
457 return $this->contentList[$fileIndex];
458 }
459
460 /**
461 * Searchs a file in the tar archive
462 * and returns the numeric fileindex.
463 * Returns false if not found.
464 *
39bea7dd
MS
465 * @param string $filename
466 * @return integer index of the requested file
158bd3ca
TD
467 */
468 public function getIndexByFilename($filename) {
469 foreach ($this->contentList as $index => $file) {
470 if ($file['filename'] == $filename) {
471 return $index;
472 }
473 }
474 return false;
475 }
476
477 /**
478 * Extracts a specific file and returns the content as string.
479 * Returns false if extraction failed.
480 *
39bea7dd
MS
481 * @param mixed $index index or name of the requested file
482 * @return string content of the requested file
158bd3ca
TD
483 */
484 public function extractToString($index) {
485 if (!$this->read) {
486 $this->open();
487 $this->readContent();
488 }
489 $header = $this->getFileInfo($index);
490
491 // can not extract a folder
492 if ($header['type'] != 'file') {
493 return false;
494 }
495
496 // seek to offset
497 $this->file->seek($header['offset']);
498
499 // read data
500 $content = '';
501 $n = floor($header['size'] / 512);
502 for($i = 0; $i < $n; $i++) {
503 $content .= $this->file->read(512);
504 }
505 if(($header['size'] % 512) != 0) {
506 $buffer = $this->file->read(512);
507 $content .= substr($buffer, 0, ($header['size'] % 512));
508 }
509
510 return $content;
511 }
512
513 /**
514 * Extracts a specific file and writes it's content
515 * to the file specified with $destination.
516 *
39bea7dd
MS
517 * @param mixed $index index or name of the requested file
518 * @param string $destination
519 * @return boolean $success
158bd3ca
TD
520 */
521 public function extract($index, $destination) {
522 if (!$this->read) {
523 $this->open();
524 $this->readContent();
525 }
526 $header = $this->getFileInfo($index);
527
528 // can not extract a folder
529 if ($header['type'] != 'file') {
530 return false;
531 }
532
533 // seek to offset
534 $this->file->seek($header['offset']);
535
536 $targetFile = new File($destination);
537
538 // read data
539 $n = floor($header['size'] / 512);
540 for ($i = 0; $i < $n; $i++) {
541 $content = $this->file->read(512);
542 $targetFile->write($content, 512);
543 }
544 if (($header['size'] % 512) != 0) {
545 $content = $this->file->read(512);
546 $targetFile->write($content, ($header['size'] % 512));
547 }
548
549 $targetFile->close();
1232bce2 550 BasicFileUtil::makeWritable($destination);
158bd3ca
TD
551
552 if ($header['mtime']) {
553 @$targetFile->touch($header['mtime']);
554 }
555
556 // check filesize
557 if (filesize($destination) != $header['size']) {
4fe0b42b 558 throw new SystemException("Could not untar file '".$header['filename']."' to '".$destination."'. Maybe disk quota exceeded in folder '".dirname($destination)."'.");
158bd3ca
TD
559 }
560
561 return true;
562 }
563
564 /**
565 * Reads table of contents (TOC) from tar archive.
566 * This does not get the entire to memory but only parts of it.
567 */
568 protected function readContent() {
569 $this->contentList = array();
570 $this->read = true;
571 $i = 0;
572
573 // Read the 512 bytes header
574 while (strlen($binaryData = $this->file->read(512)) != 0) {
575 // read header
576 $header = $this->readHeader($binaryData);
577 if ($header === false) {
578 continue;
579 }
580 $this->contentList[$i] = $header;
581 $this->contentList[$i]['index'] = $i;
582 $i++;
583
584 $this->file->seek($this->file->tell() + (512 * ceil(($header['size'] / 512))));
585 }
586 }
587
588 /**
589 * Unpacks file header for one file entry.
590 *
39bea7dd
MS
591 * @param string $binaryData
592 * @return array $fileheader
158bd3ca
TD
593 */
594 protected function readHeader($binaryData) {
595 if (strlen($binaryData) != 512) {
596 return false;
597 }
598
599 $header = array();
600 $checksum = 0;
601 // First part of the header
602 for ($i = 0; $i < 148; $i++) {
603 $checksum += ord(substr($binaryData, $i, 1));
604 }
605 // Calculate the checksum
606 // Ignore the checksum value and replace it by ' ' (space)
607 for ($i = 148; $i < 156; $i++) {
608 $checksum += ord(' ');
609 }
610 // Last part of the header
611 for ($i = 156; $i < 512; $i++) {
612 $checksum += ord(substr($binaryData, $i, 1));
613 }
614
615 // Extract the values
616 //$data = unpack("a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/a8checksum/a1typeflag/a100link/a6magic/a2version/a32uname/a32gname/a8devmajor/a8devminor", $binaryData);
617 $data = unpack("a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/a8checksum/a1typeflag/a100link/a6magic/a2version/a32uname/a32gname/a8devmajor/a8devminor/a155prefix", $binaryData);
618
619 // Extract the properties
620 $header['checksum'] = octDec(trim($data['checksum']));
621 if ($header['checksum'] == $checksum) {
622 $header['filename'] = trim($data['filename']);
623 $header['mode'] = octDec(trim($data['mode']));
624 $header['uid'] = octDec(trim($data['uid']));
625 $header['gid'] = octDec(trim($data['gid']));
626 $header['size'] = octDec(trim($data['size']));
627 $header['mtime'] = octDec(trim($data['mtime']));
628 $header['prefix'] = trim($data['prefix']);
629 if ($header['prefix']) {
630 $header['filename'] = $header['prefix'].'/'.$header['filename'];
631 }
632 if (($header['typeflag'] = $data['typeflag']) == '5') {
633 $header['size'] = 0;
634 $header['type'] = 'folder';
635 }
636 else {
637 $header['type'] = 'file';
638 }
639 $header['offset'] = $this->file->tell();
640
641 return $header;
642 }
643 else {
644 return false;
645 }
646 }
647}
648
649/**
650 * The File class handles all file operations.
651 *
652 * Example:
653 * using php functions:
654 * $fp = fopen('filename', 'wb');
655 * fwrite($fp, '...');
656 * fclose($fp);
657 *
658 * using this class:
659 * $file = new File('filename');
660 * $file->write('...');
661 * $file->close();
662 *
663 * @author Marcel Werk
664 */
665class File {
666 protected $resource = null;
667 protected $filename;
668
669 /**
670 * Opens a new file.
671 *
39bea7dd
MS
672 * @param string $filename
673 * @param string $mode
158bd3ca
TD
674 */
675 public function __construct($filename, $mode = 'wb') {
676 $this->filename = $filename;
677 $this->resource = fopen($filename, $mode);
678 if ($this->resource === false) {
4fe0b42b 679 throw new SystemException('Can not open file ' . $filename);
158bd3ca
TD
680 }
681 }
682
683 /**
684 * Calls the specified function on the open file.
685 * Do not call this function directly. Use $file->write('') instead.
686 *
39bea7dd
MS
687 * @param string $function
688 * @param array $arguments
158bd3ca
TD
689 */
690 public function __call($function, $arguments) {
691 if (function_exists('f' . $function)) {
692 array_unshift($arguments, $this->resource);
39bea7dd 693 return call_user_func_array('f' . $function, $arguments);
158bd3ca
TD
694 }
695 else if (function_exists($function)) {
696 array_unshift($arguments, $this->filename);
39bea7dd 697 return call_user_func_array($function, $arguments);
158bd3ca
TD
698 }
699 else {
4fe0b42b 700 throw new SystemException('Can not call file method ' . $function);
158bd3ca
TD
701 }
702 }
703}
704
705/**
706 * The File class handles all file operations on a zipped file.
707 *
708 * @author Marcel Werk
709 */
710class ZipFile extends File {
711 /**
712 * Opens a new zipped file.
713 *
39bea7dd
MS
714 * @param string $filename
715 * @param string $mode
158bd3ca
TD
716 */
717 public function __construct($filename, $mode = 'wb') {
718 $this->filename = $filename;
719 if (!function_exists('gzopen')) {
4fe0b42b 720 throw new SystemException('Can not find functions of the zlib extension');
158bd3ca
TD
721 }
722 $this->resource = @gzopen($filename, $mode);
723 if ($this->resource === false) {
4fe0b42b 724 throw new SystemException('Can not open file ' . $filename);
158bd3ca
TD
725 }
726 }
727
728 /**
729 * Calls the specified function on the open file.
730 *
39bea7dd
MS
731 * @param string $function
732 * @param array $arguments
158bd3ca
TD
733 */
734 public function __call($function, $arguments) {
735 if (function_exists('gz' . $function)) {
736 array_unshift($arguments, $this->resource);
39bea7dd 737 return call_user_func_array('gz' . $function, $arguments);
158bd3ca
TD
738 }
739 else if (function_exists($function)) {
740 array_unshift($arguments, $this->filename);
39bea7dd 741 return call_user_func_array($function, $arguments);
158bd3ca
TD
742 }
743 else {
4fe0b42b 744 throw new SystemException('Can not call method ' . $function);
158bd3ca
TD
745 }
746 }
747
748 /**
749 * Returns the filesize of the unzipped file
750 */
751 public function getFileSize() {
752 $byteBlock = 1<<14;
753 $eof = $byteBlock;
754
755 // the correction is for zip files that are too small
756 // to get in the first while loop
757 $correction = 1;
758 while ($this->seek($eof) == 0) {
759 $eof += $byteBlock;
760 $correction = 0;
761 }
762
763 while ($byteBlock > 1) {
764 $byteBlock >>= 1;
765 $eof += $byteBlock * ($this->seek($eof) ? -1 : 1);
766 }
767
768 if ($this->seek($eof) == -1) $eof -= 1;
769
770 $this->rewind();
771 return $eof - $correction;
772 }
773}
774
775// let's go
776// get temp file prefix
777if (isset($_REQUEST['tmpFilePrefix'])) {
778 $prefix = preg_replace('/[^a-f0-9_]+/', '', $_REQUEST['tmpFilePrefix']);
779}
780else {
781 $prefix = substr(sha1(uniqid(microtime())), 0, 8);
782}
783define('TMP_FILE_PREFIX', $prefix);
784
785// try to find the temp folder
99be741e 786define('TMP_DIR', BasicFileUtil::getInstallTempFolder());
158bd3ca 787
7da7f7cc
AE
788/**
789 * Reads a file resource from temp folder.
790 *
791 * @param string $key
792 * @param string $directory
793 */
794function readFileResource($key, $directory) {
ec6e78b9 795 if (preg_match('~[\w\-]+\.(css|jpg|png|svg|eot|woff|ttf)~', $_GET[$key], $match)) {
7da7f7cc
AE
796 switch ($match[1]) {
797 case 'css':
798 header('Content-Type: text/css');
799 break;
800
801 case 'jpg':
802 header('Content-Type: image/jpg');
803 break;
804
805 case 'png':
806 header('Content-Type: image/png');
807 break;
808
809 case 'svg':
810 header('Content-Type: image/svg+xml');
811 break;
ec6e78b9
MW
812
813 case 'eot':
814 header('Content-Type: application/vnd.ms-fontobject');
815 break;
816
817 case 'woff':
818 header('Content-Type: application/font-woff');
819 break;
820
821 case 'ttf':
822 header('Content-Type: application/octet-stream');
823 break;
7da7f7cc
AE
824 }
825
2d9861cd
AE
826 header('Expires: '.gmdate('D, d M Y H:i:s', time() + 3600).' GMT');
827 header('Last-Modified: Mon, 26 Jul 1997 05:00:00 GMT');
828 header('Cache-Control: public, max-age=3600');
829
7da7f7cc 830 readfile($directory . $_GET[$key]);
158bd3ca
TD
831 }
832 exit;
833}
834
7da7f7cc
AE
835// show image from temp folder
836if (isset($_GET['showImage'])) {
837 readFileResource('showImage', TMP_DIR . 'install/files/acp/images/');
838}
839// show icon from temp folder
840if (isset($_GET['showIcon'])) {
841 readFileResource('showIcon', TMP_DIR . 'install/files/icon/');
842}
843// show css from temp folder
844if (isset($_GET['showCSS'])) {
e94c3830 845 readFileResource('showCSS', TMP_DIR . 'install/files/acp/style/setup/');
7da7f7cc 846}
ec6e78b9
MW
847// show fonts from temp folder
848if (isset($_GET['showFont'])) {
849 readFileResource('showFont', TMP_DIR . 'install/files/font/');
850}
7da7f7cc 851
53e00c6b 852// check whether setup files are already unzipped
158bd3ca
TD
853if (!file_exists(TMP_DIR . 'install/files/lib/system/WCFSetup.class.php')) {
854 // try to unzip all setup files into temp folder
855 $tar = new Tar(SETUP_FILE);
856 $contentList = $tar->getContentList();
15fa2802 857 if (empty($contentList)) {
4fe0b42b 858 throw new SystemException("Can not unpack 'WCFSetup.tar.gz'. File is probably broken.");
158bd3ca
TD
859 }
860
861 foreach ($contentList as $file) {
862 foreach ($neededFilesPattern as $pattern) {
863 if (preg_match($pattern, $file['filename'])) {
864 // create directory if not exists
865 $dir = TMP_DIR . dirname($file['filename']);
866 if (!@is_dir($dir)) {
867 @mkdir($dir, 0777, true);
1232bce2 868 BasicFileUtil::makeWritable($dir);
158bd3ca
TD
869 }
870
871 $tar->extract($file['index'], TMP_DIR . $file['filename']);
872 }
873 }
874 }
875 $tar->close();
876
877 // create cache folders
878 @mkdir(TMP_DIR . 'setup/lang/cache/', 0777);
1232bce2 879 BasicFileUtil::makeWritable(TMP_DIR . 'setup/lang/cache/');
158bd3ca
TD
880
881 @mkdir(TMP_DIR . 'setup/template/compiled/', 0777);
1232bce2 882 BasicFileUtil::makeWritable(TMP_DIR . 'setup/template/compiled/');
158bd3ca
TD
883}
884
885if (!class_exists('wcf\system\WCFSetup')) {
4fe0b42b 886 throw new SystemException("Can not find class 'WCFSetup'");
158bd3ca
TD
887}
888
889// start setup
dcb3a44c 890new \wcf\system\WCFSetup();