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