Commit | Line | Data |
---|---|---|
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 | |
10 | define('INSTALL_SCRIPT_DIR', dirname(__FILE__).'/'); | |
11 | define('SETUP_FILE', INSTALL_SCRIPT_DIR . 'WCFSetup.tar.gz'); | |
12 | define('NO_IMPORTS', 1); | |
13 | ||
14 | // set exception handler | |
15 | set_exception_handler('handleException'); | |
16 | // set php error handler | |
17 | set_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 | */ | |
39 | interface 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 | */ | |
52 | class 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 | */ | |
160 | function __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 | */ | |
177 | function 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 | */ | |
186 | function 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 | */ | |
203 | function 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 | */ | |
223 | class BasicFileUtil { | |
224 | /** | |
225 | * Tries to find the temp folder. | |
226 | * | |
227 | * @return string | |
228 | */ | |
229 | public static function getTempFolder() { | |
230 | $tmpDirName = TMP_FILE_PREFIX.'/'; | |
231 | ||
232 | // use tmp folder in document root by default | |
233 | if (!empty($_SERVER['DOCUMENT_ROOT'])) { | |
234 | if (!@file_exists($_SERVER['DOCUMENT_ROOT'].'/tmp/'.$tmpDirName)) { | |
235 | @mkdir($_SERVER['DOCUMENT_ROOT'].'/tmp/'.$tmpDirName, 0777, true); | |
1232bce2 | 236 | self::makeWritable($_SERVER['DOCUMENT_ROOT'].'/tmp/'.$tmpDirName); |
158bd3ca TD |
237 | } |
238 | ||
239 | if (@file_exists($_SERVER['DOCUMENT_ROOT'].'/tmp/'.$tmpDirName) && @is_writable($_SERVER['DOCUMENT_ROOT'].'/tmp/'.$tmpDirName)) { | |
240 | return $_SERVER['DOCUMENT_ROOT'].'/tmp/'.$tmpDirName; | |
241 | } | |
242 | } | |
243 | ||
244 | foreach (array('TMP', 'TEMP', 'TMPDIR') as $tmpDir) { | |
245 | if (isset($_ENV[$tmpDir]) && @is_writable($_ENV[$tmpDir])) { | |
246 | $dir = $_ENV[$tmpDir] . '/' . $tmpDirName; | |
247 | @mkdir($dir, 0777); | |
1232bce2 | 248 | self::makeWritable($dir); |
158bd3ca TD |
249 | |
250 | if (@file_exists($dir) && @is_writable($dir)) { | |
251 | return $dir; | |
252 | } | |
253 | } | |
254 | } | |
255 | ||
256 | $dir = INSTALL_SCRIPT_DIR . 'tmp/' . $tmpDirName; | |
257 | @mkdir($dir, 0777); | |
1232bce2 | 258 | self::makeWritable($dir); |
158bd3ca TD |
259 | |
260 | if (!@file_exists($dir) || !@is_writable($dir)) { | |
261 | $tmpDir = explode('/', $dir); | |
262 | array_pop($tmpDir); | |
263 | $dir = implode('/', $tmpDir); | |
264 | ||
4fe0b42b | 265 | 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.'); |
158bd3ca TD |
266 | } |
267 | ||
268 | return $dir; | |
269 | } | |
1232bce2 AE |
270 | |
271 | /** | |
272 | * Tries to make a file or directory writable. It starts of with the least | |
273 | * permissions and goes up until 0777. | |
274 | * | |
275 | * @param string $filename | |
276 | */ | |
277 | public static function makeWritable($filename) { | |
278 | if (is_writable($filename)) { | |
279 | return; | |
280 | } | |
281 | ||
282 | $chmods = array('0644', '0755', '0775', '0777'); | |
283 | ||
284 | $startIndex = 0; | |
285 | if (is_dir($filename)) { | |
286 | $startIndex = 1; | |
287 | } | |
288 | ||
289 | for ($i = $startIndex; $i < 4; $i++) { | |
290 | @chmod($filename, octdec($chmods[$i])); | |
291 | ||
292 | if (is_writable($filename)) { | |
293 | break; | |
294 | } | |
295 | else if ($i == 3) { | |
296 | // does not work with 0777 | |
297 | throw new SystemException("Unable to make '".$filename."' writable. This is a misconfiguration of your server, please contact your system administrator or hosting provider."); | |
298 | } | |
299 | } | |
300 | } | |
158bd3ca TD |
301 | } |
302 | ||
303 | /** | |
304 | * Opens tar or tar.gz archives. | |
305 | * | |
306 | * Usage: | |
307 | * ------ | |
308 | * $tar = new Tar('archive.tar'); | |
309 | * $contentList = $tar->getContentList(); | |
310 | * foreach ($contentList as $key => $val) { | |
311 | * $tar->extract($key, DESTINATION); | |
312 | * } | |
313 | */ | |
314 | class Tar { | |
315 | protected $archiveName = ''; | |
316 | protected $contentList = array(); | |
317 | protected $opened = false; | |
318 | protected $read = false; | |
319 | protected $file = null; | |
320 | protected $isZipped = false; | |
321 | protected $mode = 'rb'; | |
322 | ||
323 | /** | |
324 | * Creates a new Tar object. | |
325 | * archiveName must be tarball or gzipped tarball | |
326 | * | |
39bea7dd | 327 | * @param string $archiveName |
158bd3ca TD |
328 | */ |
329 | public function __construct($archiveName) { | |
158bd3ca | 330 | if (!is_file($archiveName)) { |
4fe0b42b | 331 | throw new SystemException("unable to find tar archive '".$archiveName."'"); |
158bd3ca TD |
332 | } |
333 | ||
334 | $this->archiveName = $archiveName; | |
335 | $this->open(); | |
336 | $this->readContent(); | |
337 | } | |
338 | ||
339 | /** | |
340 | * Destructor of this class, closes tar archive. | |
341 | */ | |
342 | public function __destruct() { | |
343 | $this->close(); | |
344 | } | |
345 | ||
346 | /** | |
347 | * Opens the tar archive and stores filehandle. | |
348 | */ | |
349 | public function open() { | |
350 | if (!$this->opened) { | |
351 | if ($this->isZipped) $this->file = new ZipFile($this->archiveName, $this->mode); | |
352 | else { | |
353 | // test compression | |
354 | $this->file = new File($this->archiveName, $this->mode); | |
355 | if ($this->file->read(2) == "\37\213") { | |
356 | $this->file->close(); | |
357 | $this->isZipped = true; | |
358 | $this->file = new ZipFile($this->archiveName, $this->mode); | |
359 | } | |
360 | else { | |
361 | $this->file->seek(0); | |
362 | } | |
363 | } | |
364 | $this->opened = true; | |
365 | } | |
366 | } | |
367 | ||
368 | /** | |
369 | * Closes the opened file. | |
370 | */ | |
371 | public function close() { | |
372 | if ($this->opened) { | |
373 | $this->file->close(); | |
374 | $this->opened = false; | |
375 | } | |
376 | } | |
377 | ||
378 | /** | |
379 | * Returns the table of contents (TOC) list for this tar archive. | |
380 | * | |
39bea7dd | 381 | * @return array list of content |
158bd3ca TD |
382 | */ |
383 | public function getContentList() { | |
384 | if (!$this->read) { | |
385 | $this->open(); | |
386 | $this->readContent(); | |
387 | } | |
388 | return $this->contentList; | |
389 | } | |
390 | ||
391 | /** | |
392 | * Returns an associative array with information | |
393 | * about a specific file in the archive. | |
394 | * | |
39bea7dd MS |
395 | * @param mixed $fileindex index or name of the requested file |
396 | * @return array $fileInfo | |
158bd3ca TD |
397 | */ |
398 | public function getFileInfo($fileIndex) { | |
399 | if (!is_int($fileIndex)) { | |
400 | $fileIndex = $this->getIndexByFilename($fileIndex); | |
401 | } | |
402 | ||
403 | if (!isset($this->contentList[$fileIndex])) { | |
6286572b | 404 | throw new SystemException("Tar: could find file '".$fileIndex."' in archive"); |
158bd3ca TD |
405 | } |
406 | return $this->contentList[$fileIndex]; | |
407 | } | |
408 | ||
409 | /** | |
410 | * Searchs a file in the tar archive | |
411 | * and returns the numeric fileindex. | |
412 | * Returns false if not found. | |
413 | * | |
39bea7dd MS |
414 | * @param string $filename |
415 | * @return integer index of the requested file | |
158bd3ca TD |
416 | */ |
417 | public function getIndexByFilename($filename) { | |
418 | foreach ($this->contentList as $index => $file) { | |
419 | if ($file['filename'] == $filename) { | |
420 | return $index; | |
421 | } | |
422 | } | |
423 | return false; | |
424 | } | |
425 | ||
426 | /** | |
427 | * Extracts a specific file and returns the content as string. | |
428 | * Returns false if extraction failed. | |
429 | * | |
39bea7dd MS |
430 | * @param mixed $index index or name of the requested file |
431 | * @return string content of the requested file | |
158bd3ca TD |
432 | */ |
433 | public function extractToString($index) { | |
434 | if (!$this->read) { | |
435 | $this->open(); | |
436 | $this->readContent(); | |
437 | } | |
438 | $header = $this->getFileInfo($index); | |
439 | ||
440 | // can not extract a folder | |
441 | if ($header['type'] != 'file') { | |
442 | return false; | |
443 | } | |
444 | ||
445 | // seek to offset | |
446 | $this->file->seek($header['offset']); | |
447 | ||
448 | // read data | |
449 | $content = ''; | |
450 | $n = floor($header['size'] / 512); | |
451 | for($i = 0; $i < $n; $i++) { | |
452 | $content .= $this->file->read(512); | |
453 | } | |
454 | if(($header['size'] % 512) != 0) { | |
455 | $buffer = $this->file->read(512); | |
456 | $content .= substr($buffer, 0, ($header['size'] % 512)); | |
457 | } | |
458 | ||
459 | return $content; | |
460 | } | |
461 | ||
462 | /** | |
463 | * Extracts a specific file and writes it's content | |
464 | * to the file specified with $destination. | |
465 | * | |
39bea7dd MS |
466 | * @param mixed $index index or name of the requested file |
467 | * @param string $destination | |
468 | * @return boolean $success | |
158bd3ca TD |
469 | */ |
470 | public function extract($index, $destination) { | |
471 | if (!$this->read) { | |
472 | $this->open(); | |
473 | $this->readContent(); | |
474 | } | |
475 | $header = $this->getFileInfo($index); | |
476 | ||
477 | // can not extract a folder | |
478 | if ($header['type'] != 'file') { | |
479 | return false; | |
480 | } | |
481 | ||
482 | // seek to offset | |
483 | $this->file->seek($header['offset']); | |
484 | ||
485 | $targetFile = new File($destination); | |
486 | ||
487 | // read data | |
488 | $n = floor($header['size'] / 512); | |
489 | for ($i = 0; $i < $n; $i++) { | |
490 | $content = $this->file->read(512); | |
491 | $targetFile->write($content, 512); | |
492 | } | |
493 | if (($header['size'] % 512) != 0) { | |
494 | $content = $this->file->read(512); | |
495 | $targetFile->write($content, ($header['size'] % 512)); | |
496 | } | |
497 | ||
498 | $targetFile->close(); | |
1232bce2 | 499 | BasicFileUtil::makeWritable($destination); |
158bd3ca TD |
500 | |
501 | if ($header['mtime']) { | |
502 | @$targetFile->touch($header['mtime']); | |
503 | } | |
504 | ||
505 | // check filesize | |
506 | if (filesize($destination) != $header['size']) { | |
4fe0b42b | 507 | throw new SystemException("Could not untar file '".$header['filename']."' to '".$destination."'. Maybe disk quota exceeded in folder '".dirname($destination)."'."); |
158bd3ca TD |
508 | } |
509 | ||
510 | return true; | |
511 | } | |
512 | ||
513 | /** | |
514 | * Reads table of contents (TOC) from tar archive. | |
515 | * This does not get the entire to memory but only parts of it. | |
516 | */ | |
517 | protected function readContent() { | |
518 | $this->contentList = array(); | |
519 | $this->read = true; | |
520 | $i = 0; | |
521 | ||
522 | // Read the 512 bytes header | |
523 | while (strlen($binaryData = $this->file->read(512)) != 0) { | |
524 | // read header | |
525 | $header = $this->readHeader($binaryData); | |
526 | if ($header === false) { | |
527 | continue; | |
528 | } | |
529 | $this->contentList[$i] = $header; | |
530 | $this->contentList[$i]['index'] = $i; | |
531 | $i++; | |
532 | ||
533 | $this->file->seek($this->file->tell() + (512 * ceil(($header['size'] / 512)))); | |
534 | } | |
535 | } | |
536 | ||
537 | /** | |
538 | * Unpacks file header for one file entry. | |
539 | * | |
39bea7dd MS |
540 | * @param string $binaryData |
541 | * @return array $fileheader | |
158bd3ca TD |
542 | */ |
543 | protected function readHeader($binaryData) { | |
544 | if (strlen($binaryData) != 512) { | |
545 | return false; | |
546 | } | |
547 | ||
548 | $header = array(); | |
549 | $checksum = 0; | |
550 | // First part of the header | |
551 | for ($i = 0; $i < 148; $i++) { | |
552 | $checksum += ord(substr($binaryData, $i, 1)); | |
553 | } | |
554 | // Calculate the checksum | |
555 | // Ignore the checksum value and replace it by ' ' (space) | |
556 | for ($i = 148; $i < 156; $i++) { | |
557 | $checksum += ord(' '); | |
558 | } | |
559 | // Last part of the header | |
560 | for ($i = 156; $i < 512; $i++) { | |
561 | $checksum += ord(substr($binaryData, $i, 1)); | |
562 | } | |
563 | ||
564 | // Extract the values | |
565 | //$data = unpack("a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/a8checksum/a1typeflag/a100link/a6magic/a2version/a32uname/a32gname/a8devmajor/a8devminor", $binaryData); | |
566 | $data = unpack("a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/a8checksum/a1typeflag/a100link/a6magic/a2version/a32uname/a32gname/a8devmajor/a8devminor/a155prefix", $binaryData); | |
567 | ||
568 | // Extract the properties | |
569 | $header['checksum'] = octDec(trim($data['checksum'])); | |
570 | if ($header['checksum'] == $checksum) { | |
571 | $header['filename'] = trim($data['filename']); | |
572 | $header['mode'] = octDec(trim($data['mode'])); | |
573 | $header['uid'] = octDec(trim($data['uid'])); | |
574 | $header['gid'] = octDec(trim($data['gid'])); | |
575 | $header['size'] = octDec(trim($data['size'])); | |
576 | $header['mtime'] = octDec(trim($data['mtime'])); | |
577 | $header['prefix'] = trim($data['prefix']); | |
578 | if ($header['prefix']) { | |
579 | $header['filename'] = $header['prefix'].'/'.$header['filename']; | |
580 | } | |
581 | if (($header['typeflag'] = $data['typeflag']) == '5') { | |
582 | $header['size'] = 0; | |
583 | $header['type'] = 'folder'; | |
584 | } | |
585 | else { | |
586 | $header['type'] = 'file'; | |
587 | } | |
588 | $header['offset'] = $this->file->tell(); | |
589 | ||
590 | return $header; | |
591 | } | |
592 | else { | |
593 | return false; | |
594 | } | |
595 | } | |
596 | } | |
597 | ||
598 | /** | |
599 | * The File class handles all file operations. | |
600 | * | |
601 | * Example: | |
602 | * using php functions: | |
603 | * $fp = fopen('filename', 'wb'); | |
604 | * fwrite($fp, '...'); | |
605 | * fclose($fp); | |
606 | * | |
607 | * using this class: | |
608 | * $file = new File('filename'); | |
609 | * $file->write('...'); | |
610 | * $file->close(); | |
611 | * | |
612 | * @author Marcel Werk | |
613 | */ | |
614 | class File { | |
615 | protected $resource = null; | |
616 | protected $filename; | |
617 | ||
618 | /** | |
619 | * Opens a new file. | |
620 | * | |
39bea7dd MS |
621 | * @param string $filename |
622 | * @param string $mode | |
158bd3ca TD |
623 | */ |
624 | public function __construct($filename, $mode = 'wb') { | |
625 | $this->filename = $filename; | |
626 | $this->resource = fopen($filename, $mode); | |
627 | if ($this->resource === false) { | |
4fe0b42b | 628 | throw new SystemException('Can not open file ' . $filename); |
158bd3ca TD |
629 | } |
630 | } | |
631 | ||
632 | /** | |
633 | * Calls the specified function on the open file. | |
634 | * Do not call this function directly. Use $file->write('') instead. | |
635 | * | |
39bea7dd MS |
636 | * @param string $function |
637 | * @param array $arguments | |
158bd3ca TD |
638 | */ |
639 | public function __call($function, $arguments) { | |
640 | if (function_exists('f' . $function)) { | |
641 | array_unshift($arguments, $this->resource); | |
39bea7dd | 642 | return call_user_func_array('f' . $function, $arguments); |
158bd3ca TD |
643 | } |
644 | else if (function_exists($function)) { | |
645 | array_unshift($arguments, $this->filename); | |
39bea7dd | 646 | return call_user_func_array($function, $arguments); |
158bd3ca TD |
647 | } |
648 | else { | |
4fe0b42b | 649 | throw new SystemException('Can not call file method ' . $function); |
158bd3ca TD |
650 | } |
651 | } | |
652 | } | |
653 | ||
654 | /** | |
655 | * The File class handles all file operations on a zipped file. | |
656 | * | |
657 | * @author Marcel Werk | |
658 | */ | |
659 | class ZipFile extends File { | |
660 | /** | |
661 | * Opens a new zipped file. | |
662 | * | |
39bea7dd MS |
663 | * @param string $filename |
664 | * @param string $mode | |
158bd3ca TD |
665 | */ |
666 | public function __construct($filename, $mode = 'wb') { | |
667 | $this->filename = $filename; | |
668 | if (!function_exists('gzopen')) { | |
4fe0b42b | 669 | throw new SystemException('Can not find functions of the zlib extension'); |
158bd3ca TD |
670 | } |
671 | $this->resource = @gzopen($filename, $mode); | |
672 | if ($this->resource === false) { | |
4fe0b42b | 673 | throw new SystemException('Can not open file ' . $filename); |
158bd3ca TD |
674 | } |
675 | } | |
676 | ||
677 | /** | |
678 | * Calls the specified function on the open file. | |
679 | * | |
39bea7dd MS |
680 | * @param string $function |
681 | * @param array $arguments | |
158bd3ca TD |
682 | */ |
683 | public function __call($function, $arguments) { | |
684 | if (function_exists('gz' . $function)) { | |
685 | array_unshift($arguments, $this->resource); | |
39bea7dd | 686 | return call_user_func_array('gz' . $function, $arguments); |
158bd3ca TD |
687 | } |
688 | else if (function_exists($function)) { | |
689 | array_unshift($arguments, $this->filename); | |
39bea7dd | 690 | return call_user_func_array($function, $arguments); |
158bd3ca TD |
691 | } |
692 | else { | |
4fe0b42b | 693 | throw new SystemException('Can not call method ' . $function); |
158bd3ca TD |
694 | } |
695 | } | |
696 | ||
697 | /** | |
698 | * Returns the filesize of the unzipped file | |
699 | */ | |
700 | public function getFileSize() { | |
701 | $byteBlock = 1<<14; | |
702 | $eof = $byteBlock; | |
703 | ||
704 | // the correction is for zip files that are too small | |
705 | // to get in the first while loop | |
706 | $correction = 1; | |
707 | while ($this->seek($eof) == 0) { | |
708 | $eof += $byteBlock; | |
709 | $correction = 0; | |
710 | } | |
711 | ||
712 | while ($byteBlock > 1) { | |
713 | $byteBlock >>= 1; | |
714 | $eof += $byteBlock * ($this->seek($eof) ? -1 : 1); | |
715 | } | |
716 | ||
717 | if ($this->seek($eof) == -1) $eof -= 1; | |
718 | ||
719 | $this->rewind(); | |
720 | return $eof - $correction; | |
721 | } | |
722 | } | |
723 | ||
724 | // let's go | |
725 | // get temp file prefix | |
726 | if (isset($_REQUEST['tmpFilePrefix'])) { | |
727 | $prefix = preg_replace('/[^a-f0-9_]+/', '', $_REQUEST['tmpFilePrefix']); | |
728 | } | |
729 | else { | |
730 | $prefix = substr(sha1(uniqid(microtime())), 0, 8); | |
731 | } | |
732 | define('TMP_FILE_PREFIX', $prefix); | |
733 | ||
734 | // try to find the temp folder | |
735 | define('TMP_DIR', BasicFileUtil::getTempFolder()); | |
736 | ||
7da7f7cc AE |
737 | /** |
738 | * Reads a file resource from temp folder. | |
739 | * | |
740 | * @param string $key | |
741 | * @param string $directory | |
742 | */ | |
743 | function readFileResource($key, $directory) { | |
ec6e78b9 | 744 | if (preg_match('~[\w\-]+\.(css|jpg|png|svg|eot|woff|ttf)~', $_GET[$key], $match)) { |
7da7f7cc AE |
745 | switch ($match[1]) { |
746 | case 'css': | |
747 | header('Content-Type: text/css'); | |
748 | break; | |
749 | ||
750 | case 'jpg': | |
751 | header('Content-Type: image/jpg'); | |
752 | break; | |
753 | ||
754 | case 'png': | |
755 | header('Content-Type: image/png'); | |
756 | break; | |
757 | ||
758 | case 'svg': | |
759 | header('Content-Type: image/svg+xml'); | |
760 | break; | |
ec6e78b9 MW |
761 | |
762 | case 'eot': | |
763 | header('Content-Type: application/vnd.ms-fontobject'); | |
764 | break; | |
765 | ||
766 | case 'woff': | |
767 | header('Content-Type: application/font-woff'); | |
768 | break; | |
769 | ||
770 | case 'ttf': | |
771 | header('Content-Type: application/octet-stream'); | |
772 | break; | |
7da7f7cc AE |
773 | } |
774 | ||
2d9861cd AE |
775 | header('Expires: '.gmdate('D, d M Y H:i:s', time() + 3600).' GMT'); |
776 | header('Last-Modified: Mon, 26 Jul 1997 05:00:00 GMT'); | |
777 | header('Cache-Control: public, max-age=3600'); | |
778 | ||
7da7f7cc | 779 | readfile($directory . $_GET[$key]); |
158bd3ca TD |
780 | } |
781 | exit; | |
782 | } | |
783 | ||
7da7f7cc AE |
784 | // show image from temp folder |
785 | if (isset($_GET['showImage'])) { | |
786 | readFileResource('showImage', TMP_DIR . 'install/files/acp/images/'); | |
787 | } | |
788 | // show icon from temp folder | |
789 | if (isset($_GET['showIcon'])) { | |
790 | readFileResource('showIcon', TMP_DIR . 'install/files/icon/'); | |
791 | } | |
792 | // show css from temp folder | |
793 | if (isset($_GET['showCSS'])) { | |
e94c3830 | 794 | readFileResource('showCSS', TMP_DIR . 'install/files/acp/style/setup/'); |
7da7f7cc | 795 | } |
ec6e78b9 MW |
796 | // show fonts from temp folder |
797 | if (isset($_GET['showFont'])) { | |
798 | readFileResource('showFont', TMP_DIR . 'install/files/font/'); | |
799 | } | |
7da7f7cc | 800 | |
53e00c6b | 801 | // check whether setup files are already unzipped |
158bd3ca TD |
802 | if (!file_exists(TMP_DIR . 'install/files/lib/system/WCFSetup.class.php')) { |
803 | // try to unzip all setup files into temp folder | |
804 | $tar = new Tar(SETUP_FILE); | |
805 | $contentList = $tar->getContentList(); | |
15fa2802 | 806 | if (empty($contentList)) { |
4fe0b42b | 807 | throw new SystemException("Can not unpack 'WCFSetup.tar.gz'. File is probably broken."); |
158bd3ca TD |
808 | } |
809 | ||
810 | foreach ($contentList as $file) { | |
811 | foreach ($neededFilesPattern as $pattern) { | |
812 | if (preg_match($pattern, $file['filename'])) { | |
813 | // create directory if not exists | |
814 | $dir = TMP_DIR . dirname($file['filename']); | |
815 | if (!@is_dir($dir)) { | |
816 | @mkdir($dir, 0777, true); | |
1232bce2 | 817 | BasicFileUtil::makeWritable($dir); |
158bd3ca TD |
818 | } |
819 | ||
820 | $tar->extract($file['index'], TMP_DIR . $file['filename']); | |
821 | } | |
822 | } | |
823 | } | |
824 | $tar->close(); | |
825 | ||
826 | // create cache folders | |
827 | @mkdir(TMP_DIR . 'setup/lang/cache/', 0777); | |
1232bce2 | 828 | BasicFileUtil::makeWritable(TMP_DIR . 'setup/lang/cache/'); |
158bd3ca TD |
829 | |
830 | @mkdir(TMP_DIR . 'setup/template/compiled/', 0777); | |
1232bce2 | 831 | BasicFileUtil::makeWritable(TMP_DIR . 'setup/template/compiled/'); |
158bd3ca TD |
832 | } |
833 | ||
834 | if (!class_exists('wcf\system\WCFSetup')) { | |
4fe0b42b | 835 | throw new SystemException("Can not find class 'WCFSetup'"); |
158bd3ca TD |
836 | } |
837 | ||
838 | // start setup | |
dcb3a44c | 839 | new \wcf\system\WCFSetup(); |