Fixed time zone calculation issue
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / lib / acp / form / PackageStartInstallForm.class.php
1 <?php
2 namespace wcf\acp\form;
3 use wcf\data\package\installation\queue\PackageInstallationQueue;
4 use wcf\data\package\installation\queue\PackageInstallationQueueEditor;
5 use wcf\data\package\Package;
6 use wcf\form\AbstractForm;
7 use wcf\system\exception\PermissionDeniedException;
8 use wcf\system\exception\SystemException;
9 use wcf\system\exception\UserInputException;
10 use wcf\system\package\PackageArchive;
11 use wcf\system\package\PackageInstallationDispatcher;
12 use wcf\system\WCF;
13 use wcf\system\WCFACP;
14 use wcf\util\FileUtil;
15 use wcf\util\StringUtil;
16
17 /**
18 * Shows the package install and update form.
19 *
20 * @author Marcel Werk
21 * @copyright 2001-2014 WoltLab GmbH
22 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
23 * @package com.woltlab.wcf
24 * @subpackage acp.form
25 * @category Community Framework
26 */
27 class PackageStartInstallForm extends AbstractForm {
28 /**
29 * @see \wcf\page\AbstractPage::$activeMenuItem
30 */
31 public $activeMenuItem = 'wcf.acp.menu.link.package.install';
32
33 /**
34 * updated package object
35 * @var \wcf\system\package\Package
36 */
37 public $package = null;
38
39 /**
40 * url to the package to download
41 * @var string
42 */
43 public $downloadPackage = '';
44
45 /**
46 * data of the uploaded package
47 * @var array<string>
48 */
49 public $uploadPackage = '';
50
51 /**
52 * archive of the installation/update package
53 * @var \wcf\system\package\PackageArchive
54 */
55 public $archive = null;
56
57 /**
58 * package installation/update queue
59 * @var \wcf\data\package\installation\queue\PackageInstallationQueue
60 */
61 public $queue = null;
62
63 /**
64 * @see \wcf\form\IForm::readFormParameters()
65 */
66 public function readFormParameters() {
67 parent::readFormParameters();
68
69 if (isset($_POST['downloadPackage'])) $this->downloadPackage = StringUtil::trim($_POST['downloadPackage']);
70 if (isset($_FILES['uploadPackage'])) $this->uploadPackage = $_FILES['uploadPackage'];
71 }
72
73 /**
74 * @see \wcf\form\IForm::validate()
75 */
76 public function validate() {
77 parent::validate();
78
79 if (!empty($this->uploadPackage['name'])) {
80 $this->validateUploadPackage();
81 }
82 else if (!empty($this->downloadPackage)) {
83 $this->validateDownloadPackage();
84 }
85 else {
86 throw new UserInputException('uploadPackage');
87 }
88 }
89
90 /**
91 * Validates the upload package input.
92 */
93 protected function validateUploadPackage() {
94 $this->activeTabMenuItem = 'upload';
95
96 if (empty($this->uploadPackage['tmp_name'])) {
97 throw new UserInputException('uploadPackage', 'uploadFailed');
98 }
99
100 // get filename
101 $this->uploadPackage['name'] = FileUtil::getTemporaryFilename('package_', preg_replace('!^.*(?=\.(?:tar\.gz|tgz|tar)$)!i', '', basename($this->uploadPackage['name'])));
102
103 if (!@move_uploaded_file($this->uploadPackage['tmp_name'], $this->uploadPackage['name'])) {
104 throw new UserInputException('uploadPackage', 'uploadFailed');
105 }
106
107 $this->archive = new PackageArchive($this->uploadPackage['name'], $this->package);
108 $this->validateArchive('uploadPackage');
109 }
110
111 /**
112 * Validates the download package input.
113 */
114 protected function validateDownloadPackage() {
115 $this->activeTabMenuItem = 'upload';
116
117 if (FileUtil::isURL($this->downloadPackage)) {
118 // download package
119 $this->archive = new PackageArchive($this->downloadPackage, $this->package);
120
121 try {
122 $this->downloadPackage = $this->archive->downloadArchive();
123 }
124 catch (SystemException $e) {
125 throw new UserInputException('downloadPackage', 'downloadFailed');
126 }
127 }
128 else {
129 // probably local path
130 if (!file_exists($this->downloadPackage)) {
131 throw new UserInputException('downloadPackage', 'downloadFailed');
132 }
133
134 $this->archive = new PackageArchive($this->downloadPackage, $this->package);
135 }
136
137 $this->validateArchive('downloadPackage');
138 }
139
140 /**
141 * Validates the package archive.
142 *
143 * @param string $type upload or download package
144 */
145 protected function validateArchive($type) {
146 // try to open the archive
147 try {
148 // TODO: Exceptions thrown within openArchive() are discarded, resulting in
149 // the meaningless message 'not a valid package'
150 $this->archive->openArchive();
151 }
152 catch (SystemException $e) {
153 throw new UserInputException($type, 'noValidPackage');
154 }
155
156 // validate php requirements
157 $errors = PackageInstallationDispatcher::validatePHPRequirements($this->archive->getPhpRequirements());
158 if (!empty($errors)) {
159 WCF::getTPL()->assign('phpRequirements', $errors);
160 throw new UserInputException($type, 'phpRequirements');
161 }
162
163 // try to find existing package
164 $sql = "SELECT *
165 FROM wcf".WCF_N."_package
166 WHERE package = ?";
167 $statement = WCF::getDB()->prepareStatement($sql);
168 $statement->execute(array($this->archive->getPackageInfo('name')));
169 $row = $statement->fetchArray();
170 if ($row !== false) {
171 $this->package = new Package(null, $row);
172 }
173
174 // check update or install support
175 if ($this->package !== null) {
176 WCF::getSession()->checkPermissions(array('admin.system.package.canUpdatePackage'));
177 $this->activeMenuItem = 'wcf.acp.menu.link.package';
178
179 if (!$this->archive->isValidUpdate($this->package)) {
180 throw new UserInputException($type, 'noValidUpdate');
181 }
182 }
183 else {
184 WCF::getSession()->checkPermissions(array('admin.system.package.canInstallPackage'));
185
186 if (!$this->archive->isValidInstall()) {
187 throw new UserInputException($type, 'noValidInstall');
188 }
189 else if ($this->archive->isAlreadyInstalled()) {
190 throw new UserInputException($type, 'uniqueAlreadyInstalled');
191 }
192 else if ($this->archive->getPackageInfo('isApplication') && $this->archive->hasUniqueAbbreviation()) {
193 throw new UserInputException($type, 'noUniqueAbbrevation');
194 }
195 }
196 }
197
198 /**
199 * @see \wcf\form\IForm::save()
200 */
201 public function save() {
202 parent::save();
203
204 // get new process no
205 $processNo = PackageInstallationQueue::getNewProcessNo();
206
207 // obey foreign key
208 $packageID = ($this->package) ? $this->package->packageID : null;
209
210 // insert queue
211 $isApplication = $this->archive->getPackageInfo('isApplication');
212 $this->queue = PackageInstallationQueueEditor::create(array(
213 'processNo' => $processNo,
214 'userID' => WCF::getUser()->userID,
215 'package' => $this->archive->getPackageInfo('name'),
216 'packageName' => $this->archive->getLocalizedPackageInfo('packageName'),
217 'packageID' => $packageID,
218 'archive' => (!empty($this->uploadPackage['tmp_name']) ? $this->uploadPackage['name'] : $this->downloadPackage),
219 'action' => ($this->package != null ? 'update' : 'install'),
220 'isApplication' => (!$isApplication ? '0' : '1')
221 ));
222
223 $this->saved();
224
225 // open queue
226 PackageInstallationDispatcher::openQueue(0, $processNo);
227 }
228
229 /**
230 * @see \wcf\page\IPage::assignVariables()
231 */
232 public function assignVariables() {
233 parent::assignVariables();
234
235 WCF::getTPL()->assign(array(
236 'package' => $this->package
237 ));
238 }
239
240 /**
241 * @see \wcf\page\IPage::show()
242 */
243 public function show() {
244 if (!WCF::getSession()->getPermission('admin.system.package.canInstallPackage') && !WCF::getSession()->getPermission('admin.system.package.canUpdatePackage')) {
245 throw new PermissionDeniedException();
246 }
247
248 // check master password
249 WCFACP::checkMasterPassword();
250
251 parent::show();
252 }
253 }