Commit | Line | Data |
---|---|---|
158bd3ca TD |
1 | <?php |
2 | namespace wcf\system\setup; | |
3 | use wcf\system\exception\SystemException; | |
4 | use wcf\system\io\Tar; | |
5 | use wcf\util\FileUtil; | |
158bd3ca TD |
6 | |
7 | /** | |
a17de04e | 8 | * Extracts files and directories from a tar archive. |
9f959ced | 9 | * |
158bd3ca | 10 | * @author Marcel Werk |
c839bd49 | 11 | * @copyright 2001-2018 WoltLab GmbH |
158bd3ca | 12 | * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php> |
e71525e4 | 13 | * @package WoltLabSuite\Core\System\Setup |
158bd3ca TD |
14 | */ |
15 | class Installer { | |
9f959ced MS |
16 | /** |
17 | * directory the files are installed into | |
18 | * @var string | |
19 | */ | |
20 | protected $targetDir; | |
21 | ||
22 | /** | |
23 | * name of the source tar archive | |
24 | * @var string | |
25 | */ | |
26 | protected $source; | |
27 | ||
28 | /** | |
29 | * folder within source that limits the installed files to those within | |
30 | * this folder | |
31 | * @var string | |
32 | */ | |
33 | protected $folder; | |
34 | ||
35 | /** | |
36 | * file handler of the installed files | |
0ad90fc3 | 37 | * @var \wcf\system\setup\IFileHandler |
9f959ced MS |
38 | */ |
39 | protected $fileHandler; | |
158bd3ca TD |
40 | |
41 | /** | |
42 | * Creates a new Installer object. | |
9f959ced | 43 | * |
4e25add7 MS |
44 | * @param string $targetDir |
45 | * @param string $source | |
46 | * @param IFileHandler $fileHandler | |
47 | * @param string $folder | |
158bd3ca TD |
48 | */ |
49 | public function __construct($targetDir, $source, $fileHandler = null, $folder = '') { | |
50 | $this->targetDir = FileUtil::addTrailingSlash($targetDir); | |
51 | $this->source = $source; | |
52 | $this->folder = $folder; | |
53 | $this->fileHandler = $fileHandler; | |
54 | $this->install(); | |
55 | } | |
56 | ||
57 | /** | |
58 | * Creates the target directory if necessary. | |
59 | */ | |
60 | protected function createTargetDir() { | |
61 | if (!@is_dir($this->targetDir)) { | |
4879676b | 62 | if (!FileUtil::makePath($this->targetDir)) { |
4fe0b42b | 63 | throw new SystemException("Could not create dir '".$this->targetDir."'"); |
158bd3ca TD |
64 | } |
65 | } | |
7ef4897f | 66 | if (FileUtil::isApacheModule() || !is_writable($this->targetDir)) { |
158bd3ca TD |
67 | $this->makeWriteable($this->targetDir); |
68 | } | |
69 | } | |
70 | ||
71 | /** | |
72 | * Creates a directory in the target directory. | |
9f959ced | 73 | * |
158bd3ca | 74 | * @param string $dir |
2b770bdd | 75 | * @throws SystemException |
158bd3ca TD |
76 | */ |
77 | protected function createDir($dir) { | |
78 | if (!@is_dir($this->targetDir.$dir)) { | |
79 | $oldumask = umask(0); | |
80 | if (!@mkdir($this->targetDir.$dir, 0755, true)) { | |
4fe0b42b | 81 | throw new SystemException("Could not create dir '".$this->targetDir.$dir."'"); |
158bd3ca TD |
82 | } |
83 | umask($oldumask); | |
84 | } | |
7ef4897f | 85 | if (FileUtil::isApacheModule() || !is_writable($this->targetDir.$dir)) { |
158bd3ca TD |
86 | $this->makeWriteable($this->targetDir.$dir); |
87 | } | |
88 | } | |
89 | ||
90 | /** | |
91 | * Touches a file in the target directory. | |
9f959ced | 92 | * |
158bd3ca TD |
93 | * @param string $file |
94 | */ | |
95 | public function touchFile($file) { | |
96 | @touch($this->targetDir.$file); | |
97 | $this->makeWriteable($this->targetDir.$file); | |
98 | } | |
99 | ||
100 | /** | |
101 | * Creates a file in the target directory. | |
9f959ced | 102 | * |
158bd3ca TD |
103 | * @param string $file |
104 | * @param integer $index | |
105 | * @param Tar $tar | |
106 | */ | |
107 | protected function createFile($file, $index, Tar $tar) { | |
108 | $tar->extract($index, $this->targetDir.$file); | |
7ef4897f | 109 | if (FileUtil::isApacheModule() || !is_writable($this->targetDir.$file)) { |
158bd3ca TD |
110 | $this->makeWriteable($this->targetDir.$file); |
111 | } | |
112 | } | |
113 | ||
114 | /** | |
115 | * Starts the extracting of the files. | |
116 | */ | |
117 | protected function install() { | |
118 | $this->createTargetDir(); | |
119 | ||
120 | // open source archive | |
d4955651 | 121 | $tar = $this->getTar($this->source); |
158bd3ca TD |
122 | |
123 | // distinct directories and files | |
058cbd6a MS |
124 | $directories = []; |
125 | $files = []; | |
158bd3ca | 126 | foreach ($tar->getContentList() as $index => $file) { |
838e315b | 127 | if (empty($this->folder) || mb_strpos($file['filename'], $this->folder) === 0) { |
158bd3ca | 128 | if (!empty($this->folder)) { |
838e315b | 129 | $file['filename'] = str_replace($this->folder, '', $file['filename']); |
158bd3ca TD |
130 | } |
131 | ||
132 | // remove leading slash | |
133 | $file['filename'] = FileUtil::removeLeadingSlash($file['filename']); | |
134 | if ($file['type'] == 'folder') { | |
135 | // remove trailing slash | |
136 | $directories[] = FileUtil::removeTrailingSlash($file['filename']); | |
137 | } | |
138 | else { | |
139 | $files[$index] = $file['filename']; | |
140 | } | |
141 | } | |
142 | } | |
143 | ||
144 | $this->checkFiles($files); | |
9f959ced | 145 | |
158bd3ca | 146 | // now create the directories |
058cbd6a | 147 | $errors = []; |
158bd3ca TD |
148 | foreach ($directories as $dir) { |
149 | try { | |
150 | $this->createDir($dir); | |
151 | } | |
152 | catch (SystemException $e) { | |
7eb6d870 | 153 | $errors[] = $e->getMessage(); |
158bd3ca TD |
154 | } |
155 | } | |
9f959ced | 156 | |
158bd3ca TD |
157 | // now untar all files |
158 | foreach ($files as $index => $file) { | |
159 | try { | |
160 | $this->createFile($file, $index, $tar); | |
161 | } | |
162 | catch (SystemException $e) { | |
7eb6d870 | 163 | $errors[] = $e->getMessage(); |
158bd3ca TD |
164 | } |
165 | } | |
15fa2802 | 166 | if (!empty($errors)) { |
e5f9b56c | 167 | throw new SystemException('error(s) during the installation of the files.', 0, implode("<br>", $errors)); |
158bd3ca TD |
168 | } |
169 | ||
170 | $this->logFiles($files); | |
9f959ced | 171 | |
158bd3ca TD |
172 | // close tar |
173 | $tar->close(); | |
174 | } | |
175 | ||
d4955651 AE |
176 | /** |
177 | * Opens a new tar archive. | |
178 | * | |
179 | * @param string $source | |
180 | * @return Tar | |
181 | */ | |
182 | protected function getTar($source) { | |
183 | return new Tar($source); | |
184 | } | |
185 | ||
158bd3ca | 186 | /** |
1615fc2e | 187 | * Checks whether the given files overwriting locked existing files. |
9f959ced MS |
188 | * |
189 | * @param array $files | |
158bd3ca TD |
190 | */ |
191 | protected function checkFiles(&$files) { | |
192 | if ($this->fileHandler != null && $this->fileHandler instanceof IFileHandler) { | |
193 | $this->fileHandler->checkFiles($files); | |
194 | } | |
195 | } | |
196 | ||
197 | /** | |
a17de04e | 198 | * Logs the given files. |
9f959ced | 199 | * |
a17de04e | 200 | * @param array $files |
158bd3ca TD |
201 | */ |
202 | protected function logFiles(&$files) { | |
203 | if ($this->fileHandler != null && $this->fileHandler instanceof IFileHandler) { | |
204 | $this->fileHandler->logFiles($files); | |
205 | } | |
206 | } | |
207 | ||
208 | /** | |
209 | * Makes a file or directory writeable. | |
9f959ced | 210 | * |
158bd3ca TD |
211 | * @param string $target |
212 | */ | |
213 | protected function makeWriteable($target) { | |
1232bce2 | 214 | FileUtil::makeWritable($target); |
158bd3ca | 215 | } |
dcb3a44c | 216 | } |