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