Merge branch '3.0'
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / lib / system / setup / Installer.class.php
CommitLineData
158bd3ca
TD
1<?php
2namespace wcf\system\setup;
3use wcf\system\exception\SystemException;
4use wcf\system\io\Tar;
5use 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 */
15class 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}