Project

General

Profile

Revision 113

View differences:

tags/eXtplorer-2.0.0-released/preinstall.php
1
<?php
2
/* Password: Make the pass phrase at least 6 characters long */
3
$passPhrase = '';
4

  
5
/*
6
* eXtplorer - a web based file manager
7
*
8
*
9
* This Pre-Installation Script: Copyright (C) 2007 Andy Staudacher <ast@gmx.ch>
10
* All Credits go to the Gallery 2 team!
11
*
12
* This program is free software; you can redistribute it and/or modify
13
* it under the terms of the GNU General Public License as published by
14
* the Free Software Foundation; either version 2 of the License, or (at
15
* your option) any later version.
16
*
17
* This program is distributed in the hope that it will be useful, but
18
* WITHOUT ANY WARRANTY; without even the implied warranty of
19
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20
* General Public License for more details.
21
*
22
* You should have received a copy of the GNU General Public License
23
* along with this program; if not, write to the Free Software
24
* Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA  02110-1301, USA.
25
*/
26
/**
27
 * Script to:
28
 *    - download the extplorer.zip / tar.gz from a known server directly to the
29
 *      server where the script is running.
30
 *    - extract the extplorer.zip / tar.gz archive directly on the server
31
 * @package Preinstaller
32
 * @author: Andy Staudacher <ast@gmx.ch>
33
 * @version $Revision$
34
 * @version  2.0.0
35
 */
36
error_reporting(E_ALL);
37
set_time_limit(900);
38

  
39
/*****************************************************************
40
* C O N F I G U R A T I O N
41
*****************************************************************/
42
/* Download Location */
43
$downloadUrls = array();
44
/* Hardcoded defaults / fallbacks (we try to find out these URLs during runtime) */
45
/*   Latest Release Candidate */
46
//$downloadUrls['rc'] = 'http://prdownloads.sourceforge.net/gallery/gallery-2.2-rc-2-full';
47
/*   Latest stable release */
48
$downloadUrls['stable'] = '';
49
/*   Latest beta version */
50
$downloadUrls['latest']= 'http://joomlacode.org/gf/download/frsrelease/8187/29823/com_eXtplorer_2.0.0.zip';
51
$downloadUrls['beta']= 'http://downloads.sourceforge.net/extplorer/extplorer_2.0.0_RC4.zip';
52

  
53
/* The page on GMC that lists the latest versions */
54
/* FOR GR, we request pages from sf.net which then redirects to GMC, e.g. to /release, /beta, .. */
55
$versionCheckUrl = 'http://virtuemart.net/index2.php?option=com_versions&catid=5&task=feed';
56

  
57
/* Local name of the extplorer archive (without extension )*/
58
$archiveBaseName = 'extplorer';
59
/* A list of folder permissions that are available for chmodding */
60
$folderPermissionList = array('777', '755', '555');
61
/* Archive extensions available for download */
62
$availableExtensions = array('zip', 'tar.gz');
63
/* Available versions of extplorer */
64
//$availableVersions = array('stable', 'rc', 'beta');
65
$availableVersions = array('stable');
66

  
67
/*****************************************************************
68
* M A I N
69
*****************************************************************/
70
compatiblityFunctions();
71
$preInstaller = new PreInstaller();
72
$preInstaller->main();
73

  
74
/*****************************************************************
75
* C L A S S E S
76
*****************************************************************/
77
class PreInstaller {
78

  
79
	function main() {
80
		/* Authentication */
81
		$this->authenticate();
82

  
83
		/* Register all extract / download methods */
84
		$this->_extractMethods =  array(new UnzipExtractor(),
85
		new PhpUnzipExtractor(),
86
		new TarGzExtractor(),
87
		new PhpTarGzExtractor());
88
		$this->_downloadMethods = array(
89
			new CurlDownloader(),
90
			new WgetDownloader(),
91
			new FopenDownloader(),
92
			new FsockopenDownloader()
93
		);
94

  
95
		/* Make sure we can write to the current working directory */
96
		if (!Platform::isDirectoryWritable()) {
97
			render('results', array('failure' => 'Local working directory' . dirname(__FILE__) .
98
			' is not writeable!',
99
			'fix' => 'ftp> chmod 777 ' . basename(dirname(__FILE__))));
100
			exit;
101
		}
102

  
103
		/* Handle the request */
104
		if (empty($_POST['command'])) $command = '';
105
		else $command = trim($_POST['command']);
106
		switch ($command) {
107
			case 'extract':
108
				/* Input validation / sanitation */
109
				if (empty($_POST['method'])) $method = '';
110
				else $method = trim($_POST['method']);
111
				if (!preg_match('/^[a-z]+extractor$/', $method)) $method = '';
112
				/* Handle the request */
113
				if (class_exists($method)) {
114
					global $archiveBaseName;
115
					$extractor = new $method;
116
					if ($extractor->isSupported()) {
117
						$archiveName = dirname(__FILE__) . '/' .
118
						$archiveBaseName .  '.' . $extractor->getSupportedExtension();
119
						if (file_exists($archiveName)) {
120
							$results = $extractor->extract($archiveName);
121
							if ($results === true) {
122
								/* Make sure the dirs and files were extracted successfully */
123
								if (!$this->integrityCheck()) {
124
									render('results', array('failure' => 'Extraction was successful, but coarse integrity check failed'));
125
								} else {
126
									render('results', array('success' => 'Archive successfully extracted'));
127

  
128
									/*
129
									* Set the permissions in the extplorer dir may be such that
130
									* the user can modify login.txt
131
									*/
132
									@chmod(dirname(__FILE__) . '/extplorer', 0777);
133
								}
134
							} else {
135
								render('results', array('failure' => $results));
136
							}
137
						} else {
138
							render('results', array('failure' => "Archive $archiveName does not exist in the current working directory"));
139
						}
140
					} else {
141
						render('results', array('failure' => "Method $method is not supported by this platform!"));
142
					}
143
				} else {
144
					render('results', array('failure' => 'Extract method is not defined or does not exist!'));
145
				}
146
				break;
147
			case 'download':
148
				/* Input validation / sanitation */
149
				/* The download method */
150
				if (empty($_POST['method'])) $method = '';
151
				else $method = trim($_POST['method']);
152
				if (!preg_match('/^[a-z]+downloader$/', $method)) $method = '';
153
				/* ... archive extension */
154
				if (empty($_POST['extension'])) $extension = '';
155
				else $extension = trim($_POST['extension']);
156
				if (!preg_match('/^([a-z]{2,4}\.)?[a-z]{2,4}$/', $extension)) {
157
					render('results', array('failure' => 'Filetype for download not defined, please retry'));
158
					exit;
159
				}
160
				global $availableExtensions, $availableVersions;
161
				if (!in_array($extension, $availableExtensions)) $extension = 'zip';
162
				/* eXtplorer version (stable, rc, beta, nightly snapshot) */
163
				if (empty($_POST['version'])) $version = '';
164
				else $version = trim($_POST['version']);
165
				//if (!in_array($version, $availableVersions)) $version = 'latest';
166
				if (class_exists($method)) {
167
					$downloader = new $method;
168
					if ($downloader->isSupported()) {
169
						global $archiveBaseName;
170
						$archiveName = dirname(__FILE__) . '/' . $archiveBaseName . '.' . $extension;
171
						/* Assemble the downlod URL */
172
						$url = $this->getDownloadUrl($version, $extension, $downloader);
173
						$results = $downloader->download($url, $archiveName);
174
						if ($results === true) {
175
							if (file_exists($archiveName)) {
176
								@chmod($archiveName, 0777);
177
								render('results', array('success' => 'File successfully downloaded'));
178
							} else {
179
								render('results', array('failure' => "Download failed, local file $archiveName does not exist"));
180
							}
181
						} else {
182
							render('results', array('failure' => $results));
183
						}
184
					} else {
185
						render('results', array('failure' => "Method $method is not supported by this platform!"));
186
					}
187
				} else {
188
					render('results', array('failure' => 'Method is not defined or does not exist!'));
189
				}
190
				break;
191
			default:
192
				/* Discover the capabilities of this PHP installation / platform */
193
				$capabilities = $this->discoverCapabilities();
194
				$capabilities['extplorerFolderName'] = $this->findExtplorerFolder();
195
				if (file_exists(dirname(__FILE__).'/'.$capabilities['extplorerFolderName'].'/index.php')) {
196
					$statusMessage  = '<a href="index.php" title="Go to eXtplorer now!">Ready for usage</a> (<span style="color:green;font-weight:bold;">eXtplorer seems to be installed!</span>)';
197
				} else if (!empty($capabilities['anyArchiveExists'])) {
198
					$statusMessage = 'Archive ready for extraction';
199
				} else {
200
					$statusMessage =
201
					'No archive in current working directory, please start with step 1';
202
				}
203
				$capabilities['statusMessage'] = $statusMessage;
204
				/* Are we in RC stage?*/
205
				if (!empty($capabilities['downloadMethods'])) {
206
					foreach ($capabilities['downloadMethods'] as $dMethod) {
207
						if ($dMethod['isSupported']) {
208
							$capabilities['showRcVersion'] =
209
							$this->shouldShowRcVersion(new $dMethod['command']);
210
							break;
211
						}
212
					}
213
				}
214
				render('options', $capabilities);
215
		}
216
	}
217

  
218
	function authenticate() {
219
		global $passPhrase;
220

  
221
		/* Check authentication */
222
		if (empty($passPhrase)) {
223
			render('missingPassword');
224
			exit;
225
		} else if (strlen($passPhrase) < 6) {
226
			render('passwordTooShort');
227
			exit;
228
		} else if (!empty($_COOKIE['EXTPREINSTALLER']) &&
229
		trim($_COOKIE['EXTPREINSTALLER']) == md5($passPhrase)) {
230
			/* Already logged in, got a cookie */
231
			return true;
232
		} else if (!empty($_POST['ext_password'])) {
233
			/* Login attempt */
234
			if ($_POST['ext_password'] == $passPhrase) {
235
				setcookie("EXTPREINSTALLER",md5($passPhrase),0);
236
				return true;
237
			} else {
238
				render('passwordForm', array('incorrectPassword' => 1));
239
				exit;
240
			}
241
		} else {
242
			render('passwordForm');
243
			exit;
244
		}
245
	}
246

  
247
	function discoverCapabilities() {
248
		global $archiveBaseName;
249
		$capabilities = array();
250

  
251
		$extractMethods = array();
252
		$extensions = array();
253
		$anyExtensionSupported = 0;
254
		$anyArchiveExists = 0;
255
		foreach	($this->_extractMethods as $method) {
256
			$archiveName = $archiveBaseName . '.' . $method->getSupportedExtension();
257
			$archiveExists = file_exists(dirname(__FILE__) . '/' . $archiveName) && filesize(dirname(__FILE__) . '/' . $archiveName) > 0;
258
			$isSupported = $method->isSupported();
259
			$extractMethods[] = array('isSupported' => $isSupported,
260
			'name' => $method->getName(),
261
			'command' => strtolower(get_class($method)),
262
			'archiveExists' => $archiveExists,
263
			'archiveName' => $archiveName);
264
			if (empty($extensions[$method->getSupportedExtension()])) {
265
				$extensions[$method->getSupportedExtension()] = (int)$isSupported;
266
			}
267
			if ($isSupported) {
268
				$anyExtensionSupported = 1;
269
			}
270
			if ($archiveExists) {
271
				$anyArchiveExists = 1;
272
			}
273
		}
274
		$capabilities['extractMethods'] = $extractMethods;
275
		$capabilities['extensions'] = $extensions;
276
		$capabilities['anyExtensionSupported'] = $anyExtensionSupported;
277
		$capabilities['anyArchiveExists'] = $anyArchiveExists;
278

  
279
		$downloadMethods = array();
280
		foreach	($this->_downloadMethods as $method) {
281
			$downloadMethods[] = array('isSupported' => $method->isSupported(),
282
			'name' => $method->getName(),
283
			'command' => strtolower(get_class($method)));
284
		}
285
		$capabilities['downloadMethods'] = $downloadMethods;
286

  
287
		return $capabilities;
288
	}
289

  
290
	function findExtplorerFolder() {
291
		/* Search in the current folder for a extplorer folder */
292
		$basePath = dirname(__FILE__) . '/';
293
		if (file_exists($basePath . 'extplorer') &&
294
		file_exists($basePath . 'extplorer/index.php')) {
295
			return 'extplorer';
296
		}
297

  
298
		if (!Platform::isPhpFunctionSupported('opendir') ||
299
		!Platform::isPhpFunctionSupported('readdir')) {
300
			return false;
301
		}
302

  
303
		$handle = opendir($basePath);
304
		if (!$handle) {
305
			return false;
306
		}
307
		while (($fileName = readdir($handle)) !== false) {
308
			if ($fileName == '.' || $fileName == '..') {
309
				continue;
310
			}
311
			if (file_exists($basePath . $fileName . '/index.php')) {
312
				return $fileName;
313
			}
314
		}
315
		closedir($handle);
316

  
317
		return false;
318
	}
319

  
320
	function integrityCheck() {
321
		/* TODO, check for the existence of modules, lib, themes, main.php */
322
		return true;
323
	}
324

  
325
	function getDownloadUrl($version, $extension, $downloader) {
326
		global $downloadUrls;
327

  
328
		/* Default to the last known good version */
329
		$url = $downloadUrls['latest'];
330

  
331
		/* Try to get the latest version string */
332
		$currentDownloadUrls = $this->getLatestVersions($downloader);
333
		if (!empty($currentDownloadUrls[$version])) {
334
			$url = $currentDownloadUrls[$version];
335
		}
336

  
337
		return $url;
338
	}
339

  
340
	function getLatestVersions($downloader) {
341
		global $versionCheckUrl, $availableVersions;
342

  
343
		$tempFile = dirname(__FILE__) . '/availableVersions.txt';
344
		$currentVersions = array();
345
		/*
346
		* Fetch the version information from a remote server and if we already have it,
347
		* update it if it's older than an hour
348
		*/
349
		if (!file_exists($tempFile) || !(($stat = @stat($tempFile)) &&
350
		isset($stat['mtime']) && $stat['mtime'] > time() - 3600)) {
351
			$downloader->download($versionCheckUrl, $tempFile);
352
		}
353
		/* Parse the fetched version information file */
354
		if (file_exists($tempFile)) {
355
			$contents = @file_get_contents($tempFile);
356
			if($contents) {
357
				preg_match_all("/<comments>(.*?)<\/comments>/si", $contents, $versions );
358
				if( $versions ) {
359
					foreach($versions[1] as $version ) {
360
						$versionArr = explode('|', $version );
361
						$currentVersions[$versionArr[0]] = $versionArr[1];
362
					}
363

  
364
				}
365

  
366
			}
367
		}
368

  
369
		return $currentVersions;
370
	}
371

  
372
	function shouldShowRcVersion($downloader) {
373
		/*
374
		* Only show the rc version (along with the stable and beta) if we're in a
375
		* release candidate stage
376
		*/
377

  
378
		$currentDownloadUrls = $this->getLatestVersions($downloader);
379
		return isset($currentDownloadUrls['rc']);
380
	}
381
}
382

  
383
class Platform {
384
	/* Check if a specific php function is available */
385
	function isPhpFunctionSupported($functionName) {
386
		if (in_array($functionName, split(',\s*', ini_get('disable_functions'))) || !function_exists($functionName)) {
387
			return false;
388
		} else {
389
			return true;
390
		}
391
	}
392

  
393
	/* Check if a specific command line tool is available */
394
	function isBinaryAvailable($binaryName) {
395
		$binaryPath = Platform::getBinaryPath($binaryName);
396
		return !empty($binaryPath);
397
	}
398

  
399
	/* Return the path to a binary or false if it's not available */
400
	function getBinaryPath($binaryName) {
401
		if (!Platform::isPhpFunctionSupported('exec')) {
402
			return false;
403
		}
404

  
405
		/* First try 'which' */
406
		$ret = array();
407
		exec('which ' . $binaryName, $ret);
408
		if (strpos(join(' ',$ret), $binaryName) !== false && @is_executable(join('',$ret))) {
409
			return $binaryName; // it's in the path
410
		}
411

  
412
		/* Try a bunch of likely seeming paths to see if any of them work. */
413
		$paths = array();
414
		if (!strncasecmp(PHP_OS, 'win', 3)) {
415
			$separator = ';';
416
			$slash = "\\";
417
			$extension = '.exe';
418
			$paths[] = "C:\\Program Files\\$binaryName\\";
419
			$paths[] = "C:\\apps\$binaryName\\";
420
			$paths[] = "C:\\$binaryName\\";
421
		} else {
422
			$separator = ':';
423
			$slash = "/";
424
			$extension = '';
425
			$paths[] = '/usr/bin/';
426
			$paths[] = '/usr/local/bin/';
427
			$paths[] = '/bin/';
428
			$paths[] = '/sw/bin/';
429
		}
430
		$paths[] = './';
431

  
432
		foreach (explode($separator, getenv('PATH')) as $path) {
433
			$path = trim($path);
434
			if (empty($path)) {
435
				continue;
436
			}
437
			if ($path{strlen($path)-1} != $slash) {
438
				$path .= $slash;
439
			}
440
			$paths[] = $path;
441
		}
442

  
443
		/* Now try each path in turn to see which ones work */
444
		foreach ($paths as $path) {
445
			$execPath = $path . $binaryName . $extension;
446
			if (@file_exists($execPath) && @is_executable($execPath)) {
447
				/* We have a winner */
448
				return $execPath;
449
			}
450
		}
451

  
452
		return false;
453
	}
454

  
455
	/* Check if we can write to this directory (download, extract) */
456
	function isDirectoryWritable() {
457
		return is_writable(dirname(__FILE__));
458
	}
459

  
460
	function extendTimeLimit() {
461
		if (function_exists('apache_reset_timeout')) {
462
			@apache_reset_timeout();
463
		}
464
		@set_time_limit(600);
465
	}
466
}
467

  
468
class DownloadMethod {
469
	function download($url, $outputFile) {
470
		return false;
471
	}
472

  
473
	function isSupported() {
474
		return false;
475
	}
476

  
477
	function getName() {
478
		return '';
479
	}
480
}
481

  
482
class WgetDownloader extends DownloadMethod {
483
	function download($url, $outputFile) {
484
		$status = 0;
485
		$output = array();
486
		$wget = Platform::getBinaryPath('wget');
487
		exec("$wget -O$outputFile $url ", $output, $status);
488
		if ($status) {
489
			$msg = 'exec returned an error status ';
490
			$msg .= is_array($output) ? implode('<br>', $output) : '';
491
			return $msg;
492
		}
493
		return true;
494
	}
495

  
496
	function isSupported() {
497
		return Platform::isBinaryAvailable('wget');
498
	}
499

  
500
	function getName() {
501
		return 'Download with Wget';
502
	}
503
}
504

  
505
class FopenDownloader extends DownloadMethod {
506
	function download($url, $outputFile) {
507
		if (!Platform::isDirectoryWritable()) {
508
			return 'Unable to write to current working directory';
509
		}
510
		$start =time();
511

  
512
		Platform::extendTimeLimit();
513

  
514
		$fh = fopen($url, 'rb');
515
		if (empty($fh)) {
516
			return 'Unable to open url';
517
		}
518
		$ofh = fopen($outputFile, 'wb');
519
		if (!$ofh) {
520
			fclose($fh);
521
			return 'Unable to open output file in writing mode';
522
		}
523

  
524
		$failed = $results = false;
525
		while (!feof($fh) && !$failed) {
526
			$buf = fread($fh, 4096);
527
			if (!$buf) {
528
				$results = 'Error during download';
529
				$failed = true;
530
				break;
531
			}
532
			if (fwrite($ofh, $buf) != strlen($buf)) {
533
				$failed = true;
534
				$results = 'Error during writing';
535
				break;
536
			}
537
			if (time() - $start > 55) {
538
				Platform::extendTimeLimit();
539
				$start = time();
540
			}
541
		}
542
		fclose($ofh);
543
		fclose($fh);
544
		if ($failed) {
545
			return $results;
546
		}
547

  
548
		return true;
549
	}
550

  
551
	function isSupported() {
552
		$actual = ini_get('allow_url_fopen');
553
		if (in_array($actual, array(1, 'On', 'on')) && Platform::isPhpFunctionSupported('fopen')) {
554
			return true;
555
		}
556

  
557
		return false;
558
	}
559

  
560
	function getName() {
561
		return 'Download with PHP fopen()';
562
	}
563
}
564

  
565
class FsockopenDownloader extends DownloadMethod {
566
	function download($url, $outputFile, $maxRedirects=10) {
567
		/* Code from WebHelper_simple.class */
568

  
569
		if ($maxRedirects < 0) {
570
			return "Error too many redirects. Last URL: $url";
571
		}
572

  
573
		$components = parse_url($url);
574
		$port = empty($components['port']) ? 80 : $components['port'];
575

  
576
		$errno = $errstr = null;
577
		$fd = @fsockopen($components['host'], $port, $errno, $errstr, 2);
578
		if (empty($fd)) {
579
			return "Error $errno: '$errstr' retrieving $url";
580
		}
581

  
582
		$get = $components['path'];
583
		if (!empty($components['query'])) {
584
			$get .= '?' . $components['query'];
585
		}
586

  
587
		$start = time();
588

  
589
		/* Read the web file into a buffer */
590
		$ok = fwrite($fd, sprintf("GET %s HTTP/1.0\r\n" .
591
		"Host: %s\r\n" .
592
		"\r\n",
593
		$get,
594
		$components['host']));
595
		if (!$ok) {
596
			return 'Download request failed (fwrite)';
597
		}
598
		$ok = fflush($fd);
599
		if (!$ok) {
600
			return 'Download request failed (fflush)';
601
		}
602

  
603
		/*
604
		* Read the response code. fgets stops after newlines.
605
		* The first line contains only the status code (200, 404, etc.).
606
		*/
607
		$headers = array();
608
		$response = trim(fgets($fd, 4096));
609

  
610
		/* Jump over the headers but follow redirects */
611
		while (!feof($fd)) {
612
			$line = trim(fgets($fd, 4096));
613
			if (empty($line)) {
614
				break;
615
			}
616

  
617
			/* Normalize the line endings */
618
			$line = str_replace("\r", '', $line);
619
			list ($key, $value) = explode(':', $line, 2);
620
			if (trim($key) == 'Location') {
621
				fclose($fd);
622
				return $this->download(trim($value), $outputFile, --$maxRedirects);
623
			}
624
		}
625

  
626
		$success = false;
627
		$ofd = fopen($outputFile, 'wb');
628
		if ($ofd) {
629
			/* Read the body */
630
			$failed = false;
631
			while (!feof($fd) && !$failed) {
632
				$buf = fread($fd, 4096);
633
				if (fwrite($ofd, $buf) != strlen($buf)) {
634
					$failed = true;
635
					break;
636
				}
637
				if (time() - $start > 55) {
638
					Platform::extendTimeLimit();
639
					$start = time();
640
				}
641
			}
642
			fclose($ofd);
643
			if (!$failed) {
644
				$success = true;
645
			}
646
		} else {
647
			return "Could not open $outputFile in write mode";
648
		}
649
		fclose($fd);
650

  
651
		/* if the HTTP response code did not begin with a 2 this request was not successful */
652
		if (!preg_match("/^HTTP\/\d+\.\d+\s2\d{2}/", $response)) {
653
			return "Download failed with HTTP status: $response";
654
		}
655

  
656
		return true;
657
	}
658

  
659
	function isSupported() {
660
		return Platform::isPhpFunctionSupported('fsockopen');
661
	}
662

  
663
	function getName() {
664
		return 'Download with PHP fsockopen()';
665
	}
666
}
667

  
668
class CurlDownloader extends DownloadMethod {
669
	function download($url, $outputFile) {
670
		$ch = curl_init();
671
		$ofh = fopen($outputFile, 'wb');
672
		if (!$ofh) {
673
			fclose($ch);
674
			return 'Unable to open output file in writing mode';
675
		}
676

  
677
		curl_setopt($ch, CURLOPT_URL, $url);
678
		curl_setopt($ch, CURLOPT_FILE, $ofh);
679
		curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
680
		curl_setopt($ch, CURLOPT_FAILONERROR, true);
681
		curl_setopt($ch, CURLOPT_HEADER, false);
682
		curl_setopt($ch, CURLOPT_TIMEOUT, 20 * 60);
683
		curl_setopt($ch, CURLOPT_MAXREDIRS, 10);
684
		curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
685

  
686
		curl_exec($ch);
687

  
688
		$errorString = curl_error($ch);
689
		$errorNumber = curl_errno($ch);
690
		curl_close($ch);
691

  
692
		if ($errorNumber != 0) {
693
			if (!empty($errorString)) {
694
				return $errorString;
695
			} else {
696
				return 'CURL download failed';
697
			}
698
		}
699

  
700
		return true;
701
	}
702

  
703
	function isSupported() {
704
		foreach (array('curl_init', 'curl_setopt', 'curl_exec', 'curl_close', 'curl_error') as $functionName) {
705
			if (!Platform::isPhpFunctionSupported($functionName)) {
706
				return false;
707
			}
708
		}
709
		if( ini_get('open_basedir') != '' || strtolower(ini_get('safe_mode')) == 'on') {
710
			return false;
711
		}
712
		return true;
713
	}
714

  
715
	function getName() {
716
		return 'Download with PHP cURL()';
717
	}
718
}
719

  
720
class ExtractMethod {
721
	/* Extract the archive, add the file_exists() in the calling function */
722
	function extract() {
723
		return false;
724
	}
725

  
726
	/* What archive types can we extract */
727
	function getSupportedExtension() {
728
		return null;
729
	}
730

  
731
	/* Check if we can use this method (e.g. if exec is available) */
732
	function isSupported() {
733
		return false;
734
	}
735

  
736
	function getName() {
737
		return '';
738
	}
739
}
740

  
741
class UnzipExtractor extends ExtractMethod {
742
	function extract($fileName) {
743
		$output = array();
744
		$status = 0;
745
		$unzip = Platform::getBinaryPath('unzip');
746
		exec($unzip . ' ' . $fileName, $output, $status);
747
		if ($status) {
748
			$msg = 'exec returned an error status ';
749
			$msg .= is_array($output) ? implode('<br>', $output) : '';
750
			return $msg;
751
		}
752
		return true;
753
	}
754

  
755
	function getSupportedExtension() {
756
		return 'zip';
757
	}
758

  
759
	function isSupported() {
760
		return Platform::isBinaryAvailable('unzip');
761
	}
762

  
763
	function getName() {
764
		return 'Extract .zip with unzip';
765
	}
766
}
767

  
768
class TargzExtractor extends ExtractMethod {
769
	function extract($fileName) {
770
		$output = array();
771
		$status = 0;
772
		$tar = Platform::getBinaryPath('tar');
773
		exec($tar . ' -xzf' . $fileName, $output, $status);
774
		if ($status) {
775
			$msg = 'exec returned an error status ';
776
			$msg .= is_array($output) ? implode('<br>', $output) : '';
777
			return $msg;
778
		}
779
		return true;
780
	}
781

  
782
	function getSupportedExtension() {
783
		return 'tar.gz';
784
	}
785

  
786
	function isSupported() {
787
		return Platform::isBinaryAvailable('tar');
788
	}
789

  
790
	function getName() {
791
		return 'Extract .tar.gz with tar';
792
	}
793
}
794

  
795
class PhpTargzExtractor extends ExtractMethod {
796
	function extract($fileName) {
797
		return PclTarExtract($fileName);
798
	}
799

  
800
	function getSupportedExtension() {
801
		return 'tar.gz';
802
	}
803

  
804
	function isSupported() {
805
		foreach (array('gzopen', 'gzclose', 'gzseek', 'gzread',
806
		'touch', 'gzeof') as $functionName) {
807
			if (!Platform::isPhpFunctionSupported($functionName)) {
808
				return false;
809
			}
810
		}
811

  
812
		return true;
813
	}
814

  
815
	function getName() {
816
		return 'Extract .tar.gz with PHP functions';
817
	}
818
}
819

  
820
class PhpUnzipExtractor extends ExtractMethod {
821
	function extract($fileName) {
822
		$baseFolder = dirname($fileName);
823
		if (!($zip = zip_open($fileName))) {
824
			return "Could not open the zip archive $fileName";
825
		}
826
		$start = time();
827
		while ($zip_entry = zip_read($zip)) {
828
			if (zip_entry_open($zip, $zip_entry, 'r')) {
829
				$buf = zip_entry_read($zip_entry, zip_entry_filesize($zip_entry));
830
				$dir_name = dirname(zip_entry_name($zip_entry));
831
				if ($dir_name != ".") {
832
					$dir = $baseFolder . '/';
833
					foreach ( explode('/', $dir_name) as $folderName) {
834
						$dir .= $folderName;
835
						if (is_file($dir)) unlink($dir);
836
						if (!is_dir($dir)) mkdir($dir);
837
						$dir .=  '/';
838
					}
839
				}
840
				$fp = fopen($baseFolder . '/' . zip_entry_name($zip_entry), 'w');
841
				if (!$fp) {
842
					return 'Error during php unzip: trying to open a file for writing';
843
				}
844
				if (fwrite($fp,$buf) != strlen($buf)) {
845
					return 'Error during php unzip: could not write the whole buffer length';
846
				}
847
				zip_entry_close($zip_entry);
848

  
849
				if (time() - $start > 55) {
850
					Platform::extendTimeLimit();
851
					$start = time();
852
				}
853
			} else {
854
				return false;
855
			}
856
		}
857
		zip_close($zip);
858

  
859
		return true;
860
	}
861

  
862
	function getSupportedExtension() {
863
		return 'zip';
864
	}
865

  
866
	function isSupported() {
867
		foreach (array('mkdir', 'zip_open', 'zip_entry_name', 'zip_read', 'zip_entry_read',
868
		'zip_entry_filesize', 'zip_entry_close', 'zip_close', 'zip_entry_close')
869
		as $functionName) {
870
			if (!Platform::isPhpFunctionSupported($functionName)) {
871
				return false;
872
			}
873
		}
874
		return true;
875
	}
876

  
877
	function getName() {
878
		return 'Extract .zip with PHP functions';
879
	}
880
}
881

  
882
function render($renderType, $args=array()) {
883
	global $archiveBaseName, $folderPermissionList;
884
	$self = basename(__FILE__);
885
?>
886
<?php print '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" ' .
887
		'"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'; ?>
888
<html>
889
  <head>
890
    <title>eXtplorer Pre-Installer</title>
891
    <?php printHtmlStyle(); ?>
892
    <?php printJs(); ?>
893
  </head>
894
  <body>
895
     <h1>eXtplorer Pre-Installer</h1>
896

  
897
     <div class="box important">
898
       <p>
899
	 Do not forget to <b>delete this <?php print $self; ?> file once you are done!</b> If other
900
	 users guess the password, they can seriously harm your installation with this script!
901
       <p>
902
     </div>
903

  
904
     <div class="box">
905
     <h2>Instructions</h2>
906
     <span id="instructions-toggle" class="blockToggle"
907
	  onclick="BlockToggle('instructions', 'instructions-toggle', 'instructions')">
908
	  Show instructions
909
     </span>
910
     <div id="instructions" style="display: none;">
911
       <p>
912
	 eXtplorer is a web application with hundreds of files and folders.
913
	 Uploading these files and folders with an FTP program can take more than an hour and
914
	 is error-prone depending on the quality of your connection to your webhost and the
915
	 quality of the server itself.
916
       </p>
917
       <p>
918
	 In short, <b>this pre-installer gets the eXtplorer software on your server</b>. It is an
919
	 alternative to uploading all files via FTP or extracting the archive yourself if you
920
	 have ssh access. In detail, this pre-installer does for you the following:
921
       </p>
922
       <ol>
923
	 <li>
924
	   <b>Download/transfer</b> the archived eXtplorer.tar.gz or eXtplorer.zip from the official
925
	   download server directly to your webserver. No need to download / upload the file
926
	   yourself.
927
	 </li>
928
	 <li>
929
	   <b>Extract</b> the archive directly on your server. No
930
	   need to upload thousands of files.
931
	 </li>
932
       </ol>
933
       <p>
934
	 Once eXtplorer is extracted, you can also use these convenience functions:
935
       </p>
936
       <ul>
937
	 <li>
938
	   <b>Change permissions</b>: Since the eXtplorer files have been extracted by the webserver
939
	    and not by yourself, these files and folders are not owned by you. That means that you
940
	    are not allowed to rename the eXtplorer folder or to do much else with it unless you use
941
	    this script to change the permissions.
942
	 </li>
943
	 <li>
944
	   <b>Rename</b> the eXtplorer folder if you want it to be rather &quot;filemanager/&quot; or
945
	   &quot;fileadmin/&quot;, etc. than the default folder name which is &quot;extplorer/&quot;.
946
	 </li>
947
       </ul>
948
       <p>
949
	 <b>Upgrade notes:</b> If you need to upgrade an eXtplorer installation that was extracted
950
	 with this script (the eXtplorer folder is owned by the webserver in this case) you need
951
	 just to make sure the eXtplorer folder is named &quot;extplorer&quot; and that it has
952
	 permissions 755 or 777. Then download the latest release and extract it. It will just
953
	 extract the new files over the existing installation.
954
       </p>
955
     </div>
956
     </div>
957

  
958
     <?php if (!empty($args['statusMessage'])): ?>
959
     <div class="box"><b>Status:</b> <?php print $args['statusMessage']; ?></div>
960
     <?php endif; ?>
961

  
962

  
963
     <?php if ($renderType == 'missingPassword' || $renderType == 'passwordForm'): ?>
964
     <h2>
965
	You are attempting to access a secure section. You can't
966
	proceed until you pass the security check.
967
     </h2>
968
     <?php endif; ?>
969

  
970
     <?php if ($renderType == 'missingPassword'): ?>
971
     <div class="error">
972
       You must enter a setup password in your <?php print $self; ?> file in order
973
       to be able to access this script.
974
     </div>
975
     <?php elseif ($renderType == 'passwordTooShort'): ?>
976
     <div class="error">
977
       The setup password in your <?php print $self; ?> file is too short. It must be at least
978
       6 characters long.
979
     </div>
980
     <?php elseif ($renderType == 'passwordForm'): ?>
981
     <div class="password_form">
982
       <div class="box">
983
	 <span class="message">
984
	   In order to verify you, we require you to enter your pre-install setup password.  This is
985
	   the password that is stored in the config section at the top of this script.
986
	 </span>
987
	 <form id="loginForm" method="post">
988
	   Password:
989
	   <input type="password" name="ext_password"/>
990
	   <script type="text/javascript">document.getElementById('loginForm')['ext_password'].focus();</script>
991
	   <input type="submit" value="Verify Me" onclick="this.disabled=true;this.form.submit();"/>
992
	 </form>
993
	 <?php if (!empty($args['incorrectPassword'])): ?>
994
	 <div class="error">
995
	   Password incorrect!
996
	 </div>
997
	 <?php endif; ?>
998
       </div>
999
     </div>
1000

  
1001
     <?php elseif ($renderType == 'options'): ?>
1002
       <!-- Show available and unavailable options -->
1003
       <?php if (empty($args['anyExtensionSupported'])): ?>
1004
       <div class="error">
1005
	   <h2>This platform has not the ability to extract any of our archive types!</h2>
1006
       <span>
1007
	  <?php $first = true; foreach ($args['extensions'] as $ext => $supported): ?>
1008
	    <?php if (!$supported): ?><span class="disabled"><?php endif; ?>
1009
	    <?php if (!$first) print ', '; else $first = false; ?>
1010
	    <?php print $ext; ?>
1011
	    <?php if (!$supported): ?></span><?php endif; ?>
1012
	  <?php endforeach; ?>
1013
       </span>
1014
       </div>
1015
       <?php endif; ?>
1016

  
1017
       <!-- DOWNLOAD SECTION -->
1018
       <?php
1019
       $label = empty($args['anyArchiveExists']) && empty($args['extplorerFolderName']) ? 'Hide ' : 'Show ';
1020
       $display = empty($args['anyArchiveExists']) && empty($args['extplorerFolderName']) ? '' : 'style="display: none;"';
1021
       ?>
1022
       <div class="box">
1023
       <h2>[1] Download / Transfer Methods (download eXtplorer from another server directly to this server)</h2>
1024
       <span id="download-toggle" class="blockToggle"
1025
	    onclick="BlockToggle('download', 'download-toggle', 'download methods')">
1026
	    <?php print $label . 'download methods'; ?>
1027
       </span>
1028
       <div id="download" <?php print $display; ?>>
1029
	 <br/>
1030
	 <?php if (!empty($args['downloadMethods']) && !empty($args['anyExtensionSupported'])): ?>
1031
	 <form id="downloadForm" method="post">
1032
	 <span class="subtitle">Select the eXtplorer version:</span>
1033
	 <table class="choice">
1034
	   <tr><td><select name="version">
1035
	   <?php
1036
	   foreach ($args['downloadMethods'] as $method) {
1037
	   	if( !empty($method['isSupported']) ) {
1038
	   		$downloader = new $method['command']();
1039
	   		break;
1040
	   	}
1041
	   }
1042
	   $versions = PreInstaller::getLatestVersions( $downloader );
1043
	   $isfirst = true;
1044
	   foreach ( $versions as $versionName => $versionDownload ) {
1045
	   	if( $isfirst ) {
1046
	   		$selected = 'selected="selected"';
1047
	   		$isfirst = false;
1048
	   	} else {
1049
	   		$selected = '';
1050
	   	}
1051
	   	echo '<option value="'.$versionName.'">'.$versionName."</option>\n";
1052
	   } ?>
1053
	   </select></td></tr>
1054
	 </table>
1055
	 <span class="subtitle">Select a download method:</span>
1056
	 <table class="choice">
1057
	 <?php 
1058
	 $first = true; $i = 0;
1059
	 foreach ($args['downloadMethods'] as $method):
1060
	 $disabled = empty($method['isSupported']) ? 'disabled="disabled"' : '';
1061
	 $notSupported = empty($method['isSupported']) ? '<strong>not supported by this platform</strong>' : '&nbsp;';
1062
	 $checked = '';
1063
	 if ($first && !empty($method['isSupported'])) {
1064
	 	$checked = 'checked="checked"'; $first = false;
1065
	 }
1066
	 printf('<tr><td><input type="radio" id="method'.$i.'" name="method" %s value="%s" %s/></td><td><label for="method'.$i.'">%s</label></td><td>%s</td></tr>',
1067
	 $disabled, $method['command'], $checked, $method['name'], $notSupported);
1068
	 $i++;
1069
	 endforeach;
1070
	 	?>
1071
	 </table>
1072
	 <input type="hidden" name="extension" value="zip"/>
1073
	 <input type="hidden" name="command" value="download"/>
1074
	 <input type="submit" value="Download"
1075
		onclick="this.disabled=true;this.form.submit();"/>
1076
	 </form>
1077
	 <?php elseif (!empty($args['anyExtensionSupported'])): ?>
1078
	 <div class="warning">
1079
	   This platform does not support any of our download / transfer methods. You can upload
1080
	   the extplorer.zip archive via FTP and extract it then with this tool.
1081
	 </div>
1082
	 <?php elseif (!empty($args['downloadMethods'])): ?>
1083
	 <div class="warning">
1084
	   This platform cannot extract archives, therefore downloading is also disabled.
1085
	 </div>
1086
	 <?php else: ?>
1087
	 <div class="warning">
1088
	   This platform does not support any of our download / transfer methods.
1089
	 </div>
1090
	 <?php endif; ?>
1091
       </div>
1092
       </div>
1093

  
1094
       <!-- EXTRACTION METHODS -->
1095
       <?php
1096
       $label = !empty($args['anyArchiveExists']) && empty($args['extplorerFolderName']) ? 'Hide ' : 'Show ';
1097
       $display = !empty($args['anyArchiveExists']) && empty($args['extplorerFolderName']) ? '' : 'style="display: none;"';
1098
       ?>
1099
       <div class="box">
1100
       <h2>[2] Extract Methods (extract a extplorer.zip file in the current working directory)</h2>
1101
       <span id="extract-toggle" class="blockToggle"
1102
	    onclick="BlockToggle('extract', 'extract-toggle', 'extraction methods')">
1103
	    <?php print $label .  'extraction methods'; ?>
1104
       </span>
1105
       <div id="extract" <?php print $display; ?>>
1106
       <?php if (!empty($args['anyExtensionSupported'])): ?>
1107
       <form id="extractForm" method="post">
1108
	 <table class="choice">
1109
	 <?php $first = true; foreach ($args['extractMethods'] as $method):
1110
	 $disabled = 'disabled="true"';
1111
	 if (empty($method['isSupported'])) {
1112
	 	$message = 'not supported by this platform';
1113
	 } else if (!$method['archiveExists']){
1114
	 	$message = '<span class="warning">first download the ' . $method['archiveName'] .
1115
	 	' archive</span>';
1116
	 } else {
1117
	 	$message = '<span class="success">ready for extraction!</span>';
1118
	 	$disabled = '';
1119
	 }
1120
	 $checked = '';
1121
	 if ($first && empty($disabled) && !empty($method['isSupported'])) {
1122
	 	$checked = 'checked'; $first = false;
1123
	 }
1124
	 printf('<tr><td><input type="radio" name="method" %s value="%s" %s/></td><td>%s</td><td>%s</td></tr>',
1125
	 $disabled, $method['command'], $checked, $method['name'], $message);
1126
	 endforeach; ?>
1127
	 </table>
1128
	 <input type="hidden" name="command" value="extract"/>
1129
	 <input type="submit" value="Extract"
1130
		 onclick="this.disabled=true;this.form.submit();"/>
1131
       </form>
1132
       <?php else: ?>
1133
	 <div class="warning">
1134
	   This platform cannot extract archives. Ask your webhost to extract the archive for you
1135
	   or if that is not an option you will have to extract the archive on your
1136
	   computer and upload the hundreds of files and folders via FTP.
1137
	 </div>
1138
       <?php endif; ?>
1139
       </div>
1140
       </div>
1141

  
1142
     <?php elseif ($renderType == 'results'): ?>
1143
     <h2> Results </h2>
1144
     <?php if (!empty($args['failure'])): ?>
1145
     <div class="error">
1146
       <?php print $args['failure']; ?>
1147
       <?php if (!empty($args['fix'])): ?>
1148
       <div class="suggested_fix">
1149
	 <h2> Suggested fix: </h2>
1150
	 <?php print $args['fix']; ?>
1151
       </div>
1152
     </div>
1153
     <?php endif; ?>
1154
     <?php endif; ?>
1155
     <?php if (!empty($args['success'])): ?>
1156
     <div class="success">
1157
       <?php print $args['success']; ?>
1158
     </div>
1159
     <?php endif; ?>
1160
     <div>
1161
       <a href="<?php print $self; ?>">Go back to the overview</a>
1162
     </div>
1163
     <?php endif; ?>
1164

  
1165
     <div class="box important">
1166
       <p>
1167
	 Do not forget to <b>delete this <?php print $self; ?> file once you are done!</b> If other
1168
	 users guess the password, they can seriously harm your installation with this script!
1169
       <p>
1170
     </div>
1171
  </body>
1172
</html>
1173
<?php
1174
}
1175

  
1176
function printHtmlStyle() {
1177
    ?>
1178
    <style type="text/css">
1179
	html {
1180
		font-family: "Lucida Grande", Verdana, Arial, sans-serif;
1181
		font-size: 62.5%;
1182
	}
1183

  
1184
	body {
1185
		font-size: 1.2em;
1186
		margin: 16px 16px 0px 16px;
1187
		background: white;
1188
	}
1189

  
1190
	h1, h2 {
1191
		font-family: "Gill Sans", Verdana, Arial, sans-serif;
1192
		color: #333;
1193
		margin: 0;
1194
		padding: 1.0em 0 0.15em 0;
1195
	}
1196

  
1197
	h1 { font-size: 1.5em; border-bottom: 1px solid #ddd; }
1198
	h2 { font-size: 1.3em; padding: 2px;}
1199

  
1200
	span.subtext {
1201
		font-size: 0.9em;
1202
	}
1203

  
1204
	span.disabled, td.disabled {
1205
		color: #ddd;
1206
	}
1207

  
1208
	span.subtitle {
1209
		font-size: 1.2em;
1210
	}
1211

  
1212
	div.error {
1213
		border: solid red 1px;
1214
		margin: 20px;
1215
		padding: 10px;
1216
	}
1217

  
1218
	div.suggested_fix {
1219
		background: #eee;
1220
		margin: 20px;
1221
		padding: 10px;
1222
	}
1223

  
1224
	div.success {
1225
		border: solid green 1px;
1226
		margin: 20px;
1227
		padding: 10px;
1228
	}
1229

  
1230
	div.warning {
1231
		border: solid orange 1px;
1232
		margin: 20px;
1233
		padding: 10px;
1234
	}
1235

  
1236
	.blockToggle {
1237
		padding: 0 0.4em 0.1em;
1238
		background-color: #eee;
1239
		border-width: 1px;
1240
		border: 1px solid #888;
1241
		line-height: 2;
1242
	}
1243

  
1244
	.blockToggle:hover {
1245
		cursor: pointer;
1246
	}
1247

  
1248
	span.warning {
1249
		color: orange;
1250
	}
1251

  
1252
	span.success {
1253
		color: green;
1254
	}
1255

  
1256
	div.box {
1257
		border: solid #ddd 1px;
1258
		margin: 15px;
1259
		padding: 10px;
1260
	}
1261

  
1262
	div.important {
1263
		background: #fdc;
1264
	}
1265

  
1266
	div.status {
1267
		border: solid #d8d 1px;
1268
		margin: 20px;
1269
		padding: 10px;
1270
	}
1271

  
1272
	div.status span.line_error {
1273
		display: block;
1274
		color: #C00;
1275
	}
1276

  
1277
	div.status span.line_info {
1278
		display: block;
1279
		color: #0C0;
1280
	}
1281

  
1282
	table.choice {
1283
		position: relative;
1284
		left: 20px;
1285
	}
1286

  
1287
	pre {
1288
		font-size: 1.2em;
1289
	}
1290
	</style>
1291
<?php
1292
}
1293

  
1294
/**
1295
 * If necessary, define some functions for backwards compatibility.
1296
 */
1297
function compatiblityFunctions() {
1298
	/* On MS Windows, function is_executable() was introduced in PHP 5.0.0. */
1299
	if (!function_exists('is_executable')) {
1300
		function is_executable($file) {
1301
			$stats = stat($file);
1302
			/*
1303
			* If stat doesn't work for some reason, assume it's executable.
1304
			* 0000100 is the is_executable bit. Windows returns true for .exe files.
1305
			*/
1306
			return empty($stats['mode']) || $stats['mode'] & 0000100;
1307
		}
1308
	}
1309
}
1310

  
1311

  
1312
function printJs() {
1313
?>
1314
<script type="text/javascript">
1315
function BlockToggle(objId, togId, text) {
1316
	var o = document.getElementById(objId), t = document.getElementById(togId);
1317
	if (o.style.display == 'none') {
1318
		o.style.display = 'block';
1319
		t.innerHTML = 'Hide ' + text;
1320
	} else {
1321
		o.style.display = 'none';
1322
		t.innerHTML = 'Show ' + text;
1323
	}
1324
}
1325
</script>
1326
<?php
1327
}
1328

  
1329
/* ---------- START 3rd Party code for tar.gz extraction --------------------- */
1330

  
1331
// --------------------------------------------------------------------------------
1332
// PhpConcept Library - Tar Module 1.3
1333
// --------------------------------------------------------------------------------
1334
// License GNU/GPL - Vincent Blavet - August 2001
1335
// http://www.phpconcept.net
1336
// --------------------------------------------------------------------------------
1337
// Note:
1338
//    Small changes have been made by Andy Staudacher <ast@gmx.ch> to incorporate
1339
//    the code in this script. Code to create new archives has been removed,
1340
//    we only need to extract archives. Date: 2006/02/03
1341
// --------------------------------------------------------------------------------
1342
// ----- Global variables
1343
$g_pcltar_version = "1.3";
1344

  
1345
// --------------------------------------------------------------------------------
1346
// Function : PclTarExtract()
1347
// Description :
1348
//   Extract all the files present in the archive $p_tarname, in the directory
1349
//   $p_path. The relative path of the archived files are keep and become
1350
//   relative to $p_path.
1351
//   If a file with the same name already exists it will be replaced.
1352
//   If the path to the file does not exist, it will be created.
1353
//   Depending on the $p_tarname extension (.tar, .tar.gz or .tgz) the
1354
//   function will determine the type of the archive.
1355
// Parameters :
1356
//   $p_tarname : Name of an existing tar file.
1357
//   $p_path : Path where the files will be extracted. The files will use
1358
//             their memorized path from $p_path.
1359
//             If $p_path is "", files will be extracted in "./".
1360
//   $p_remove_path : Path to remove (from the file memorized path) while writing the
1361
//                    extracted files. If the path does not match the file path,
1362
//                    the file is extracted with its memorized path.
1363
//                    $p_path and $p_remove_path are commulative.
1364
//   $p_mode : 'tar' or 'tgz', if not set, will be determined by $p_tarname extension
1365
// Return Values :
1366
//   Same as PclTarList()
1367
// --------------------------------------------------------------------------------
1368
function PclTarExtract($p_tarname, $p_path="./", $p_remove_path="", $p_mode="")
1369
{
1370
	$v_result=1;
1371

  
1372
	// ----- Extract the tar format from the extension
1373
	if (($p_mode == "") || (($p_mode!="tar") && ($p_mode!="tgz")))
1374
	{
1375
		if (($p_mode = PclTarHandleExtension($p_tarname)) == "")
1376
		{
1377
			return 'Extracting tar/gz failed, cannot handle extension';
1378
		}
1379
	}
1380

  
1381
	// ----- Call the extracting fct
1382
	$p_list = array();
1383
	if (($v_result = PclTarHandleExtract($p_tarname, 0, $p_list, "complete", $p_path, $p_mode, $p_remove_path)) != 1)
1384
	{
1385
		return 'Extracting Tar.gz failed';
1386
	}
1387

  
1388
	return true;
1389
}
1390
// --------------------------------------------------------------------------------
1391

  
1392
// --------------------------------------------------------------------------------
1393
// ***** UNDER THIS LINE ARE DEFINED PRIVATE INTERNAL FUNCTIONS *****
1394
// *****                                                        *****
1395
// *****       THESES FUNCTIONS MUST NOT BE USED DIRECTLY       *****
1396
// --------------------------------------------------------------------------------
1397

  
1398
// --------------------------------------------------------------------------------
1399
// Function : PclTarHandleExtract()
1400
// Description :
1401
// Parameters :
1402
//   $p_tarname : Filename of the tar (or tgz) archive
1403
//   $p_file_list : An array which contains the list of files to extract, this
1404
//                  array may be empty when $p_mode is 'complete'
1405
//   $p_list_detail : An array where will be placed the properties of  each extracted/listed file
1406
//   $p_mode : 'complete' will extract all files from the archive,
1407
//             'partial' will look for files in $p_file_list
1408
//             'list' will only list the files from the archive without any extract
1409
//   $p_path : Path to add while writing the extracted files
1410
//   $p_tar_mode : 'tar' for GNU TAR archive, 'tgz' for compressed archive
1411
//   $p_remove_path : Path to remove (from the file memorized path) while writing the
1412
//                    extracted files. If the path does not match the file path,
1413
//                    the file is extracted with its memorized path.
1414
//                    $p_remove_path does not apply to 'list' mode.
1415
//                    $p_path and $p_remove_path are commulative.
1416
// Return Values :
1417
// --------------------------------------------------------------------------------
1418
function PclTarHandleExtract($p_tarname, $p_file_list, &$p_list_detail, $p_mode, $p_path, $p_tar_mode, $p_remove_path)
1419
{
1420
	$v_result=1;
1421
	$v_nb = 0;
1422
	$v_extract_all = TRUE;
1423
	$v_listing = FALSE;
1424

  
1425
	// ----- Check the path
1426
	/*
1427
	if (($p_path == "") || ((substr($p_path, 0, 1) != "/") && (substr($p_path, 0, 3) != "../")))
1428
	$p_path = "./".$p_path;
1429
	*/
1430

  
1431
	$isWin = (substr(PHP_OS, 0, 3) == 'WIN');
1432

  
1433
	if(!$isWin)
1434
	{
1435
		if (($p_path == "") || ((substr($p_path, 0, 1) != "/") && (substr($p_path, 0, 3) != "../")))
1436
		$p_path = "./".$p_path;
1437
	}
1438
	// ----- Look for path to remove format (should end by /)
1439
	if (($p_remove_path != "") && (substr($p_remove_path, -1) != '/'))
1440
	{
1441
		$p_remove_path .= '/';
1442
	}
1443
	$p_remove_path_size = strlen($p_remove_path);
1444

  
1445
	// ----- Study the mode
1446
	switch ($p_mode) {
1447
		case "complete" :
1448
			// ----- Flag extract of all files
1449
			$v_extract_all = TRUE;
1450
			$v_listing = FALSE;
1451
			break;
1452
		case "partial" :
1453
			// ----- Flag extract of specific files
1454
			$v_extract_all = FALSE;
1455
			$v_listing = FALSE;
1456
			break;
1457
		case "list" :
1458
			// ----- Flag list of all files
1459
			$v_extract_all = FALSE;
1460
			$v_listing = TRUE;
1461
			break;
1462
		default :
1463
			return false;
1464
	}
1465

  
1466
	// ----- Open the tar file
1467
	if ($p_tar_mode == "tar")
1468
	{
1469
		$v_tar = fopen($p_tarname, "rb");
1470
	}
1471
	else
1472
	{
1473
		$v_tar = @gzopen($p_tarname, "rb");
1474
	}
1475

  
1476
	// ----- Check that the archive is open
1477
	if ($v_tar == 0)
1478
	{
1479
		return false;
1480
	}
1481

  
1482
	$start = time();
1483

  
1484
	// ----- Read the blocks
1485
	while (!($v_end_of_file = ($p_tar_mode == "tar"?feof($v_tar):gzeof($v_tar))))
1486
	{
1487
		// ----- Clear cache of file infos
1488
		clearstatcache();
1489

  
1490
		if (time() - $start > 55) {
1491
			Platform::extendTimeLimit();
1492
			$start = time();
1493
		}
1494

  
1495
		// ----- Reset extract tag
1496
		$v_extract_file = FALSE;
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff