[TASK] Simulatestatic should not be mentioned as sysext
[Packages/TYPO3.CMS.git] / typo3 / sysext / install / Classes / CoreUpdates / InstallSysExtsUpdate.php
1 <?php
2 namespace TYPO3\CMS\Install\CoreUpdates;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2008-2011 Benjamin Mack <benni@typo3.org>
8 * (c) 2008-2011 Steffen Kamper <info@sk-typo3.de>
9 * (c) 2012 Kai Vogel <kai.vogel@speedprogs.de>
10 * All rights reserved
11 *
12 * This script is part of the TYPO3 project. The TYPO3 project is
13 * free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * The GNU General Public License can be found at
19 * http://www.gnu.org/copyleft/gpl.html.
20 * A copy is found in the textfile GPL.txt and important notices to the license
21 * from the author is found in LICENSE.txt distributed with these scripts.
22 *
23 *
24 * This script is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
28 *
29 * This copyright notice MUST APPEAR in all copies of the script!
30 ***************************************************************/
31 /**
32 * Contains the update class for adding new system extensions.
33 *
34 * @author Benjamin Mack <benni@typo3.org>
35 * @author Steffen Kamper <info@sk-typo3.de>
36 * @author Kai Vogel <kai.vogel@speedprogs.de>
37 */
38 class InstallSysExtsUpdate extends \TYPO3\CMS\Install\Updates\AbstractUpdate {
39
40 /**
41 * @var string
42 */
43 protected $title = 'Install System Extensions';
44
45 /**
46 * @var array
47 */
48 protected $systemExtensions = array(
49 'info',
50 'perm',
51 'func',
52 'filelist',
53 'about',
54 'cshmanual',
55 'feedit',
56 'opendocs',
57 'recycler',
58 't3editor',
59 'reports',
60 'scheduler',
61 );
62
63 /**
64 * @var string
65 */
66 protected $extEmConfPath = 'typo3/sysext/@extensionKey/ext_emconf.php';
67
68 /**
69 * @var string
70 */
71 protected $repositoryUrl = 'http://typo3.org/fileadmin/ter/@filename';
72
73 /**
74 * @var string
75 */
76 protected $informationUrl = 'http://typo3.org/index.php?type=95832&tx_terfe2_pi1%5Baction%5D=show&tx_terfe2_pi1%5Bformat%5D=json&tx_terfe2_pi1%5BextensionKey%5D=@extensionKey';
77
78 /**
79 * @var bool
80 */
81 protected $updateSuccessful = TRUE;
82
83 /**
84 * Checks if an update is needed
85 *
86 * @param string &$description: The description for the update
87 * @return boolean whether an update is needed (TRUE) or not (FALSE)
88 */
89 public function checkForUpdate(&$description) {
90 $description = '
91 <br />
92 Uninstalled system extensions have been found.
93 It is now possible to install them automatically by this upgrade wizard.
94 ';
95
96 if ($this->isWizardDone()) {
97 return FALSE;
98 }
99
100 foreach ($this->systemExtensions as $extensionKey) {
101 if (!\TYPO3\CMS\Core\Extension\ExtensionManager::isLoaded($extensionKey)) {
102 return TRUE;
103 }
104 }
105
106 return FALSE;
107 }
108
109 /**
110 * Second step: Get user input for installing system extensions
111 *
112 * @param string $inputPrefix input prefix, all names of form fields have to start with this. Append custom name in [ ... ]
113 * @return string HTML output
114 */
115 public function getUserInput($inputPrefix) {
116 $list = '
117 <p>
118 Install the following system extensions:
119 </p>
120 <fieldset>
121 <ol class="t3-install-form-label-after">%s</ol>
122 </fieldset>';
123 $item = '
124 <li class="labelAfter">
125 <input type="checkbox" id="%1$s" name="%2$s[sysext][%1$s]" value="1" checked="checked" />
126 <label for="%1$s"><strong>%3$s [%1$s]</strong><br />%4$s</label>
127 </li>';
128 $items = array();
129
130 foreach ($this->systemExtensions as $extensionKey) {
131 if (\TYPO3\CMS\Core\Extension\ExtensionManager::isLoaded($extensionKey)) {
132 continue;
133 }
134 $extension = $this->getExtensionDetails($extensionKey);
135 $items[] = sprintf(
136 $item,
137 $extensionKey,
138 $inputPrefix,
139 htmlspecialchars($extension['title']),
140 htmlspecialchars($extension['description'])
141 );
142 }
143
144 return sprintf($list, implode('', $items));
145 }
146
147 /**
148 * Adds the outsourced extensions to the extList in TYPO3_CONF_VARS
149 *
150 * @param array &$dbQueries: queries done in this update
151 * @param mixed &$customMessages: custom messages
152 * @return boolean whether it worked (TRUE) or not (FALSE)
153 */
154 public function performUpdate(array &$dbQueries, &$customMessages) {
155 // Get extension keys that were submitted by the user to be installed and that are valid for this update wizard
156 if (is_array($this->pObj->INSTALL['update']['installSystemExtensions']['sysext'])) {
157 $extArray = array_intersect(
158 $this->systemExtensions,
159 array_keys($this->pObj->INSTALL['update']['installSystemExtensions']['sysext'])
160 );
161 $this->installExtensions($extArray, $customMessages);
162 }
163
164 // Show this wizard again only if new extension keys have been found
165 $this->markWizardAsDone();
166
167 return $this->updateSuccessful;
168 }
169
170 /**
171 * This method can be called to install extensions following all proper processes
172 * (e.g. installing in extList, respecting priority, etc.)
173 *
174 * @param array $extensionKeys List of keys of extensions to install
175 * @param mixed $customMessages
176 * @return void
177 */
178 protected function installExtensions($extensionKeys, &$customMessages) {
179 /** @var $extensionListUtility \TYPO3\CMS\Extensionmanager\Utility\ListUtility */
180 $extensionListUtility = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
181 'TYPO3\\CMS\\Extensionmanager\\Utility\\ListUtility'
182 );
183
184 /** @var $extensionFileHandlingUtility \TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility */
185 $extensionFileHandlingUtility = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
186 'TYPO3\\CMS\\Extensionmanager\\Utility\\FileHandlingUtility'
187 );
188 /** @var $objectManager \TYPO3\CMS\Extbase\Object\ObjectManager */
189 $objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Object\\ObjectManager');
190
191 /** @var $extensionInstallUtility \TYPO3\CMS\Extensionmanager\Utility\InstallUtility */
192 $extensionInstallUtility = $objectManager->get('TYPO3\\CMS\\Extensionmanager\\Utility\\InstallUtility');
193
194 /** @var $extensionTerUtility \TYPO3\CMS\Extensionmanager\Utility\Connection\TerUtility */
195 $extensionTerUtility = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
196 'TYPO3\\CMS\\Extensionmanager\\Utility\\Connection\\TerUtility'
197 );
198 $availableExtensions = $extensionListUtility->getAvailableExtensions();
199 $availableAndInstalledExtensions = $extensionListUtility->getAvailableAndInstalledExtensions($availableExtensions);
200 foreach ($extensionKeys as $extensionKey) {
201 if (!is_array($availableAndInstalledExtensions[$extensionKey])) {
202 $extensionDetails = $this->getExtensionDetails($extensionKey);
203 $t3xContent = $this->fetchExtension($extensionKey, $extensionDetails['versionString']);
204 if (empty($t3xContent)) {
205 $this->updateSuccessful = FALSE;
206 $customMessages .= 'The extension ' . $extensionKey . ' could not be downloaded.';
207 continue;
208 }
209 $t3xExtracted = $extensionTerUtility->decodeExchangeData($t3xContent);
210 if (empty($t3xExtracted) || !is_array($t3xExtracted) || empty($t3xExtracted['extKey'])) {
211 $this->updateSuccessful = FALSE;
212 $customMessages .= 'The extension ' . $extensionKey . ' could not be extracted.';
213 continue;
214 }
215 $extensionFileHandlingUtility->unpackExtensionFromExtensionDataArray($t3xExtracted);
216 }
217 $extensionInstallUtility->install($extensionKey);
218 }
219 }
220
221 /**
222 * Returns the details of a local or external extension
223 *
224 * @param string $extensionKey Key of the extension to check
225 * @return array Extension details
226 */
227 protected function getExtensionDetails($extensionKey) {
228 // Local extension
229 $extEmConf = PATH_site . str_replace('@extensionKey', $extensionKey, $this->extEmConfPath);
230 if (file_exists($extEmConf)) {
231 $EM_CONF = FALSE;
232 require_once($extEmConf);
233 return reset($EM_CONF);
234 }
235
236 // Repository extension
237 $url = str_replace('@extensionKey', $extensionKey, $this->informationUrl);
238 $jsonResponse = $this->fetchUrl($url);
239 if (!empty($jsonResponse) && is_string($jsonResponse)) {
240 return json_decode($jsonResponse, TRUE);
241 }
242
243 return array();
244 }
245
246 /**
247 * Fetch extension from repository
248 *
249 * @param string $extensionKey The extension key to fetch
250 * @param string $version The version to fetch
251 * @return string T3X file content
252 */
253 protected function fetchExtension($extensionKey, $version) {
254 if (empty($extensionKey) || empty($version)) {
255 return '';
256 }
257
258 $filename = $extensionKey[0] . '/' . $extensionKey[1] . '/' . $extensionKey . '_' . $version . '.t3x';
259 $url = str_replace('@filename', $filename, $this->repositoryUrl);
260 return $this->fetchUrl($url);
261 }
262
263 /**
264 * Open an URL and return the response
265 *
266 * This wrapper method is required to try several download methods if
267 * the configuration is not valid or initially written by the installer.
268 *
269 * @param string $url The URL to file
270 * @throws \Exception
271 * @return string File content
272 */
273 protected function fetchUrl($url) {
274 if (empty($url)) {
275 return NULL;
276 }
277
278 $fileContent = \TYPO3\CMS\Core\Utility\GeneralUtility::getUrl($url, 0, array(TYPO3_user_agent));
279
280 // No content, force cURL if disabled in configuration but found in system
281 if ($fileContent === FALSE && function_exists('curl_init') && empty($GLOBALS['TYPO3_CONF_VARS']['SYS']['curlUse'])) {
282 $GLOBALS['TYPO3_CONF_VARS']['SYS']['curlUse'] = TRUE;
283 $fileContent = \TYPO3\CMS\Core\Utility\GeneralUtility::getUrl($url, 0, array(TYPO3_user_agent));
284 $GLOBALS['TYPO3_CONF_VARS']['SYS']['curlUse'] = FALSE;
285 }
286
287 // Still no content, try file_get_contents if allow_url_fopen is enabled
288 if ($fileContent === FALSE && function_exists('file_get_contents') && ini_get('allow_url_fopen')) {
289 $fileContent = file_get_contents($url);
290 }
291
292 // Can not fetch url, throw an exception
293 if ($fileContent === FALSE) {
294 throw new \Exception(
295 'Can not fetch URL "' . $url . '". Possibile reasons are network problems or misconfiguration.',
296 1344685036
297 );
298 }
299
300 return $fileContent;
301 }
302
303 /**
304 * Marks the wizard as being "seen" so that it not shown again until
305 * no new extension keys have been found.
306 *
307 * Writes the info in LocalConfiguration.php
308 *
309 * @return void
310 */
311 protected function markWizardAsDone() {
312 \TYPO3\CMS\Core\Configuration\ConfigurationManager::setLocalConfigurationValueByPath(
313 'INSTALL/wizardDone/' . get_class($this),
314 json_encode($this->systemExtensions)
315 );
316 }
317
318 /**
319 * Checks if all extensions have been "seen" before
320 *
321 * @return boolean TRUE if wizard has been done before, FALSE otherwise
322 */
323 protected function isWizardDone() {
324 $wizardClassName = get_class($this);
325 if (!empty($GLOBALS['TYPO3_CONF_VARS']['INSTALL']['wizardDone'][$wizardClassName])) {
326 $seenExtensions = json_decode($GLOBALS['TYPO3_CONF_VARS']['INSTALL']['wizardDone'][$wizardClassName], TRUE);
327 return (bool) array_diff($this->systemExtensions, $seenExtensions);
328 }
329 return FALSE;
330 }
331 }
332
333 ?>