Completed
Pull Request — master (#348)
by Victor
04:50
created

ZipExtractor::extract()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 9
ccs 0
cts 9
cp 0
rs 9.6666
cc 3
eloc 6
nc 3
nop 0
crap 12
1
<?php
2
/**
3
 * @author Victor Dubiniuk <[email protected]>
4
 *
5
 * @copyright Copyright (c) 2015, ownCloud, Inc.
6
 * @license AGPL-3.0
7
 *
8
 * This code is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Affero General Public License, version 3,
10
 * as published by the Free Software Foundation.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
 * GNU Affero General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Affero General Public License, version 3,
18
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
19
 *
20
 */
21
22
namespace Owncloud\Updater\Utils;
23
24
use Symfony\Component\Console\Output\OutputInterface;
25
use Symfony\Component\Process\Process;
26
use Symfony\Component\Process\ProcessUtils;
27
use ZipArchive;
28
29
class ZipExtractor {
30
31
	protected $file;
32
	protected $path;
33
	
34
	/** @var  OutputInterface */
35
	protected $output;
36
37
	/**
38
	 * @param string $file
39
	 * @param string $path
40
	 * @param OutputInterface $output
41
	 */
42
	public function __construct($file, $path, OutputInterface $output = null){
43
		$this->file = $file;
44
		$this->path = $path;
45
		if (!is_null($output)){
46
			$this->output = $output;
47
		}
48
	}
49
50
	/**
51
	 * @return bool
52
	 */
53
	public function extract(){
54
		if ($this->extractShell()){
55
			return true;
56
		}
57
		if (!class_exists('ZipArchive')){
58
			throw new \RuntimeException("Could not decompress the archive, enable the PHP zip extension or install unzip.");
59
		}
60
		return $this->extractZipArchive();
61
	}
62
63
	private function extractShell(){
64
		$command = 'unzip ' . ProcessUtils::escapeArgument($this->file) . ' -d ' . ProcessUtils::escapeArgument($this->path) . ' && chmod -R u+w ' . ProcessUtils::escapeArgument($this->path);
65
		$process = new Process($command);
66
		$process->setTimeout(null);
67
		$process->run();
68
		if ($this->output) {
69
			$this->output->writeln($process->getErrorOutput());
70
		}
71
		return $process->isSuccessful();
72
	}
73
74
	/**
75
	 * @return bool
76
	 */
77
	private function extractZipArchive(){
78
		$zipArchive = new ZipArchive();
79
80
		if (true !== ($exitCode = $zipArchive->open($this->file))){
81
			throw new \UnexpectedValueException($this->getErrorMessage($exitCode), $exitCode);
82
		}
83
84
		if (true !== $zipArchive->extractTo($this->path)){
85
			throw new \RuntimeException("There was an error extracting the ZIP file. Corrupt file?");
86
		}
87
88
		$zipArchive->close();
89
		return true;
90
	}
91
92
	/**
93
	 * @param int $exitCode
94
	 * @return string
95
	 */
96
	protected function getErrorMessage($exitCode){
97
		switch ($exitCode){
98
			case ZipArchive::ER_EXISTS:
99
				return sprintf("File '%s' already exists.", $this->file);
100
			case ZipArchive::ER_INCONS:
101
				return sprintf("Zip archive '%s' is inconsistent.", $this->file);
102
			case ZipArchive::ER_INVAL:
103
				return sprintf("Invalid argument (%s)", $this->file);
104
			case ZipArchive::ER_MEMORY:
105
				return sprintf("Malloc failure (%s)", $this->file);
106
			case ZipArchive::ER_NOENT:
107
				return sprintf("No such zip file: '%s'", $this->file);
108
			case ZipArchive::ER_NOZIP:
109
				return sprintf("'%s' is not a zip archive.", $this->file);
110
			case ZipArchive::ER_OPEN:
111
				return sprintf("Can't open zip file: %s", $this->file);
112
			case ZipArchive::ER_READ:
113
				return sprintf("Zip read error (%s)", $this->file);
114
			case ZipArchive::ER_SEEK:
115
				return sprintf("Zip seek error (%s)", $this->file);
116
			default:
117
				return sprintf("'%s' is not a valid zip archive, got error code: %s", $this->file, $exitCode);
118
		}
119
	}
120
}
121