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