Fixed bug #16645: EM - Install extension with dependency
[Packages/TYPO3.CMS.git] / typo3 / sysext / em / classes / install / class.tx_em_install.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2010 Steffen Kamper (info@sk-typo3.de)
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
18 *
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27 /**
28 * Module: Extension manager, (un-)install extensions
29 *
30 * $Id: class.tx_em_install.php 2073 2010-03-19 10:42:38Z steffenk $
31 *
32 * @author Steffen Kamper <info@sk-typo3.de>
33 */
34
35
36 class tx_em_Install {
37
38 /**
39 * Parent module object
40 *
41 * @var SC_mod_tools_em_index
42 */
43 protected $parentObject;
44
45 /**
46 * Instance of EM API
47 *
48 * @var tx_em_API
49 */
50 protected $api;
51
52 /**
53 *
54 * @var t3lib_install
55 */
56 protected $install;
57
58
59 protected $systemInstall = 0; // If "1" then installs in the sysext directory is allowed. Default: 0
60
61 /**
62 * Constructor
63 *
64 * @param SC_mod_tools_em_index $parentObject
65 */
66 public function __construct($parentObject = NULL) {
67 $GLOBALS['LANG']->includeLLFile(t3lib_extMgm::extPath('em', 'language/locallang.xml'));
68 $this->parentObject = $parentObject;
69 $this->api = t3lib_div::makeInstance('tx_em_API');
70 $this->install = t3lib_div::makeInstance('t3lib_install');
71 $this->install->INSTALL = t3lib_div::_GP('TYPO3_INSTALL');
72 $this->systemInstall = isset($GLOBALS['TYPO3_CONF_VARS']['EXT']['allowSystemInstall']) && $GLOBALS['TYPO3_CONF_VARS']['EXT']['allowSystemInstall'];
73 }
74
75 /**
76 * Imports the data of an extension from upload
77 *
78 * @param $uploadedTempFile
79 * @param $location
80 * @param bool $uploadOverwrite
81 * @return array
82 */
83 public function uploadExtensionFile($uploadedTempFile, $location, $uploadOverwrite = FALSE) {
84 $error = '';
85 $fileContent = t3lib_div::getUrl($uploadedTempFile);
86 if (!$fileContent) {
87 return array(
88 'success' => FALSE,
89 'error' => $GLOBALS['LANG']->getLL('ext_import_file_empty')
90 );
91 }
92
93 // Decode file data:
94 $terConnection = t3lib_div::makeInstance('tx_em_Connection_Ter', $this);
95 $fetchData = $terConnection->decodeExchangeData($fileContent);
96 if (is_array($fetchData)) {
97 $extKey = $fetchData[0]['extKey'];
98 if ($extKey) {
99 if (!$uploadOverwrite) {
100 $comingExtPath = tx_em_Tools::typePath($location) . $extKey . '/';
101 if (@is_dir($comingExtPath)) {
102 $error = sprintf($GLOBALS['LANG']->getLL('ext_import_ext_present_no_overwrite'), $comingExtPath) .
103 '<br />' . $GLOBALS['LANG']->getLL('ext_import_ext_present_nothing_done');
104
105 } // ... else go on, install...
106 } // ... else go on, install...
107 } else {
108 $error = $GLOBALS['LANG']->getLL('ext_import_no_key');
109 }
110 } else {
111 $error = sprintf($GLOBALS['LANG']->getLL('ext_import_wrong_file_format'), $fetchData);
112 }
113
114 if ($error) {
115 return array(FALSE, $error);
116 } else {
117 return array(TRUE, $fetchData);
118 }
119
120 }
121
122 /**
123 * Installs an extension.
124 *
125 * @param $fetchData
126 * @param $loc
127 * @param $version
128 * @param $uploadedTempFile
129 * @param $dontDelete
130 * @return mixed|string
131 */
132 public function installExtension($fetchData, $loc, $version, $uploadedTempFile, $dontDelete) {
133 $xmlhandler =& $this->parentObject->xmlhandler;
134 $extensionList =& $this->parentObject->extensionList;
135 $extensionDetails =& $this->parentObject->extensionDetails;
136 $content = '';
137
138 if (tx_em_Tools::importAsType($loc)) {
139 if (is_array($fetchData)) { // There was some data successfully transferred
140 if ($fetchData[0]['extKey'] && is_array($fetchData[0]['FILES'])) {
141 $extKey = $fetchData[0]['extKey'];
142 if (!isset($fetchData[0]['EM_CONF']['constraints'])) {
143 $fetchData[0]['EM_CONF']['constraints'] = $xmlhandler->extensionsXML[$extKey]['versions'][$version]['dependencies'];
144 }
145 $EM_CONF = tx_em_Tools::fixEMCONF($fetchData[0]['EM_CONF']);
146 if (!$EM_CONF['lockType'] || !strcmp($EM_CONF['lockType'], $loc)) {
147 // check dependencies, act accordingly if ext is loaded
148 list($instExtInfo,) = $extensionList->getInstalledExtensions();
149 $depStatus = $this->checkDependencies($extKey, $EM_CONF, $instExtInfo);
150 if (t3lib_extMgm::isLoaded($extKey) && !$depStatus['returnCode']) {
151 $content .= $depStatus['html'];
152 if ($uploadedTempFile) {
153 $content .= '<input type="hidden" name="CMD[alreadyUploaded]" value="' . $uploadedTempFile . '" />';
154 }
155 } else {
156 $res = $this->clearAndMakeExtensionDir($fetchData[0], $loc, $dontDelete);
157 if (is_array($res)) {
158 $extDirPath = trim($res[0]);
159 if ($extDirPath && @is_dir($extDirPath) && substr($extDirPath, -1) == '/') {
160
161 $emConfFile = $extensionDetails->construct_ext_emconf_file($extKey, $EM_CONF);
162 $dirs = tx_em_Tools::extractDirsFromFileList(array_keys($fetchData[0]['FILES']));
163
164 $res = tx_em_Tools::createDirsInPath($dirs, $extDirPath);
165 if (!$res) {
166 $writeFiles = $fetchData[0]['FILES'];
167 $writeFiles['ext_emconf.php']['content'] = $emConfFile;
168 $writeFiles['ext_emconf.php']['content_md5'] = md5($emConfFile);
169
170 // Write files:
171 foreach ($writeFiles as $theFile => $fileData) {
172 t3lib_div::writeFile($extDirPath . $theFile, $fileData['content']);
173 if (!@is_file($extDirPath . $theFile)) {
174 $content .= sprintf($GLOBALS['LANG']->getLL('ext_import_file_not_created'),
175 $extDirPath . $theFile) . '<br />';
176 } elseif (md5(t3lib_div::getUrl($extDirPath . $theFile)) != $fileData['content_md5']) {
177 $content .= sprintf($GLOBALS['LANG']->getLL('ext_import_file_corrupted'),
178 $extDirPath . $theFile) . '<br />';
179 }
180 }
181
182 t3lib_div::fixPermissions($extDirPath, TRUE);
183
184 // No content, no errors. Create success output here:
185 if (!$content) {
186 $messageContent = sprintf($GLOBALS['LANG']->getLL('ext_import_success_folder'), $extDirPath) . '<br />';
187
188 $uploadSucceed = true;
189
190 // Fix TYPO3_MOD_PATH for backend modules in extension:
191 $modules = t3lib_div::trimExplode(',', $EM_CONF['module'], 1);
192 if (count($modules)) {
193 foreach ($modules as $mD) {
194 $confFileName = $extDirPath . $mD . '/conf.php';
195 if (@is_file($confFileName)) {
196 $messageContent .= tx_em_Tools::writeTYPO3_MOD_PATH($confFileName, $loc, $extKey . '/' . $mD . '/') . '<br />';
197 } else {
198 $messageContent .= sprintf($GLOBALS['LANG']->getLL('ext_import_no_conf_file'),
199 $confFileName) . '<br />';
200 }
201 }
202 }
203 // NOTICE: I used two hours trying to find out why a script, ext_emconf.php, written twice and in between included by PHP did not update correct the second time. Probably something with PHP-A cache and mtime-stamps.
204 // But this order of the code works.... (using the empty Array with type, EMCONF and files hereunder).
205
206 // Writing to ext_emconf.php:
207 $sEMD5A = $extensionDetails->serverExtensionMD5array($extKey, array('type' => $loc, 'EM_CONF' => array(), 'files' => array()));
208 $EM_CONF['_md5_values_when_last_written'] = serialize($sEMD5A);
209 $emConfFile = $extensionDetails->construct_ext_emconf_file($extKey, $EM_CONF);
210 t3lib_div::writeFile($extDirPath . 'ext_emconf.php', $emConfFile);
211
212 $messageContent .= 'ext_emconf.php: ' . $extDirPath . 'ext_emconf.php<br />';
213 $messageContent .= $GLOBALS['LANG']->getLL('ext_import_ext_type') . ' ';
214 $messageContent .= $this->api->typeLabels[$loc] . '<br />';
215 $messageContent .= '<br />';
216
217 // Remove cache files:
218 $updateContent = '';
219 if (t3lib_extMgm::isLoaded($extKey)) {
220 if (t3lib_extMgm::removeCacheFiles()) {
221 $messageContent .= $GLOBALS['LANG']->getLL('ext_import_cache_files_removed') . '<br />';
222 }
223
224 list($new_list) = $this->parentObject->extensionList->getInstalledExtensions();
225 $updateContent = $this->updatesForm($extKey, $new_list[$extKey], 1, t3lib_div::linkThisScript(array(
226 'CMD[showExt]' => $extKey,
227 'SET[singleDetails]' => 'info'
228 )));
229 }
230
231 $flashMessage = t3lib_div::makeInstance(
232 't3lib_FlashMessage',
233 $messageContent,
234 $GLOBALS['LANG']->getLL('ext_import_success')
235 );
236 $content = $flashMessage->render() . $updateContent;
237
238
239 // Install / Uninstall:
240 if (!$this->parentObject->CMD['standAlone']) {
241 $content .= '<h3>' . $GLOBALS['LANG']->getLL('ext_import_install_uninstall') . '</h3>';
242 $content .= $new_list[$extKey] ?
243 '<a href="' . htmlspecialchars(t3lib_div::linkThisScript(array(
244 'CMD[showExt]' => $extKey,
245 'CMD[remove]' => 1,
246 'CMD[clrCmd]' => 1,
247 'SET[singleDetails]' => 'info'
248 ))) . '">' .
249 tx_em_Tools::removeButton() . ' ' . $GLOBALS['LANG']->getLL('ext_import_uninstall') . '</a>' :
250 '<a href="' . htmlspecialchars(t3lib_div::linkThisScript(array(
251 'CMD[showExt]' => $extKey,
252 'CMD[load]' => 1,
253 'CMD[clrCmd]' => 1,
254 'SET[singleDetails]' => 'info'
255 ))) . '">' .
256 tx_em_Tools::installButton() . ' ' . $GLOBALS['LANG']->getLL('ext_import_install') . '</a>';
257 } else {
258 $content = $GLOBALS['LANG']->getLL('ext_import_imported') .
259 '<br /><br /><a href="javascript:opener.top.list.iframe.document.forms[0].submit();window.close();">' .
260 $GLOBALS['LANG']->getLL('ext_import_close_check') . '</a>';
261 }
262 }
263 } else {
264 $content = $res;
265 }
266 } else {
267 $content = sprintf($GLOBALS['LANG']->getLL('ext_import_ext_path_different'), $extDirPath);
268 }
269 } else {
270 $content = $res;
271 }
272 }
273 } else {
274 $content = sprintf($GLOBALS['LANG']->getLL('ext_import_ext_only_here'),
275 tx_em_Tools::typePath($EM_CONF['lockType']), $EM_CONF['lockType']);
276 }
277 } else {
278 $content = $GLOBALS['LANG']->getLL('ext_import_no_ext_key_files');
279 }
280 } else {
281 $content = sprintf($GLOBALS['LANG']->getLL('ext_import_data_transfer'), $fetchData);
282 }
283 } else {
284 $content = sprintf($GLOBALS['LANG']->getLL('ext_import_no_install_here'), tx_em_Tools::typePath($loc));
285 }
286
287 return $content;
288 }
289
290 /**
291 *Check extension dependencies
292 *
293 * @param string $extKey
294 * @param array $conf
295 * @param array $instExtInfo
296 * @return array
297 */
298 function checkDependencies($extKey, $conf, $instExtInfo) {
299 $content = '';
300 $depError = false;
301 $depIgnore = false;
302 $msg = array();
303 $depsolver = t3lib_div::_POST('depsolver');
304
305 if (isset($conf['constraints']['depends']) && is_array($conf['constraints']['depends'])) {
306 foreach ($conf['constraints']['depends'] as $depK => $depV) {
307 if ($depsolver['ignore'][$depK]) {
308 $msg[] = '<br />' . sprintf($GLOBALS['LANG']->getLL('checkDependencies_ignored'),
309 $depK) . '
310 <input type="hidden" value="1" name="depsolver[ignore][' . $depK . ']" />';
311 $depIgnore = true;
312 continue;
313 }
314 if ($depK == 'php') {
315 if (!$depV) {
316 continue;
317 }
318 $versionRange = tx_em_Tools::splitVersionRange($depV);
319 $phpv = strstr(PHP_VERSION, '-') ? substr(PHP_VERSION, 0, strpos(PHP_VERSION, '-')) : PHP_VERSION; // Linux distributors like to add suffixes, like in 5.1.2-1. Those must be ignored!
320 if ($versionRange[0] != '0.0.0' && version_compare($phpv, $versionRange[0], '<')) {
321 $msg[] = '<br />' . sprintf($GLOBALS['LANG']->getLL('checkDependencies_php_too_low'),
322 $phpv, $versionRange[0]);
323 $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" value="1" name="depsolver[ignore][' . $depK . ']" id="checkIgnore_' . $depK . '" />
324 <label for="checkIgnore_' . $depK . '">' . $GLOBALS['LANG']->getLL('checkDependencies_ignore_requirement') . '</label>';
325 $depError = true;
326 continue;
327 } elseif ($versionRange[1] != '0.0.0' && version_compare($phpv, $versionRange[1], '>')) {
328 $msg[] = '<br />' . sprintf($GLOBALS['LANG']->getLL('checkDependencies_php_too_high'),
329 $phpv, $versionRange[1]);
330 $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" value="1" name="depsolver[ignore][' . $depK . ']" id="checkIgnore_' . $depK . '" />
331 <label for="checkIgnore_' . $depK . '">' . $GLOBALS['LANG']->getLL('checkDependencies_ignore_requirement') . '</label>';
332 $depError = true;
333 continue;
334 }
335
336 } elseif ($depK == 'typo3') {
337 if (!$depV) {
338 continue;
339 }
340
341 // if the current TYPO3 version is a development version (like TYPO3 4.4-dev),
342 // then it should behave like TYPO3 4.4.0
343 $t3version = TYPO3_version;
344 if (stripos($t3version, '-dev')
345 || stripos($t3version, '-alpha')
346 || stripos($t3version, '-beta')
347 || stripos($t3version, '-RC')) {
348 // find the last occurence of "-" and replace that part with a ".0"
349 $t3version = substr($t3version, 0, strrpos($t3version, '-')) . '.0';
350 }
351
352 $versionRange = tx_em_Tools::splitVersionRange($depV);
353 if ($versionRange[0] != '0.0.0' && version_compare($t3version, $versionRange[0], '<')) {
354 $msg[] = '<br />' . sprintf($GLOBALS['LANG']->getLL('checkDependencies_typo3_too_low'),
355 $t3version, $versionRange[0]);
356 $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" value="1" name="depsolver[ignore][' . $depK . ']" id="checkIgnore_' . $depK . '" />
357 <label for="checkIgnore_' . $depK . '">' . $GLOBALS['LANG']->getLL('checkDependencies_ignore_requirement') . '</label>';
358 $depError = true;
359 continue;
360 } elseif ($versionRange[1] != '0.0.0' && version_compare($t3version, $versionRange[1], '>')) {
361 $msg[] = '<br />' . sprintf($GLOBALS['LANG']->getLL('checkDependencies_typo3_too_high'),
362 $t3version, $versionRange[1]);
363 $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" value="1" name="depsolver[ignore][' . $depK . ']" id="checkIgnore_' . $depK . '" />
364 <label for="checkIgnore_' . $depK . '">' . $GLOBALS['LANG']->getLL('checkDependencies_ignore_requirement') . '</label>';
365 $depError = true;
366 continue;
367 }
368 } elseif (strlen($depK) && !t3lib_extMgm::isLoaded($depK)) { // strlen check for braindead empty dependencies coming from extensions...
369 if (!isset($instExtInfo[$depK])) {
370 $msg[] = '<br />' . sprintf($GLOBALS['LANG']->getLL('checkDependencies_ext_not_available'),
371 $depK);
372 $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;' . t3lib_iconWorks::getSpriteIcon('actions-system-extension-import', array('title' => $GLOBALS['LANG']->getLL('checkDependencies_import_ext'))) . '&nbsp;
373 <a href="' . t3lib_div::linkThisUrl($this->parentObject->script, array(
374 'CMD[importExt]' => $depK,
375 'CMD[loc]' => 'L',
376 'CMD[standAlone]' => 1
377 )) . '" target="_blank">' . $GLOBALS['LANG']->getLL('checkDependencies_import_now') . '</a>';
378 $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" value="1" name="depsolver[ignore][' . $depK . ']" id="checkIgnore_' . $depK . '" />
379 <label for="checkIgnore_' . $depK . '">' . $GLOBALS['LANG']->getLL('checkDependencies_ignore_ext_requirement') . '</label>';
380 } else {
381 $msg[] = '<br />' . sprintf($GLOBALS['LANG']->getLL('checkDependencies_ext_not_installed'),
382 $depK, $instExtInfo[$depK]['EM_CONF']['title']);
383 $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;' . tx_em_Tools::installButton() . '&nbsp;
384 <a href="' . t3lib_div::linkThisUrl($this->parentObject->script, array(
385 'CMD[showExt]' => $depK,
386 'CMD[load]' => 1,
387 'CMD[clrCmd]' => 1,
388 'CMD[standAlone]' => 1,
389 'SET[singleDetails]' => 'info'
390 )) .
391 '" target="_blank">' . $GLOBALS['LANG']->getLL('checkDependencies_install_now') . '</a>';
392 $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" value="1" name="depsolver[ignore][' . $depK . ']" id="checkIgnore_' . $depK . '" />
393 <label for="checkIgnore_' . $depK . '">' . $GLOBALS['LANG']->getLL('checkDependencies_ignore_ext_requirement') . '</label>';
394 }
395 $depError = true;
396 } else {
397 $versionRange = tx_em_Tools::splitVersionRange($depV);
398 if ($versionRange[0] != '0.0.0' && version_compare($instExtInfo[$depK]['EM_CONF']['version'], $versionRange[0], '<')) {
399 $msg[] = '<br />' . sprintf($GLOBALS['LANG']->getLL('checkDependencies_ext_too_low'),
400 $depK, $instExtInfo[$depK]['EM_CONF']['version'], $versionRange[0]);
401 $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" value="1" name="depsolver[ignore][' . $depK . ']" id="checkIgnore_' . $depK . '" />
402 <label for="checkIgnore_' . $depK . '">' . $GLOBALS['LANG']->getLL('checkDependencies_ignore_requirement') . '</label>';
403 $depError = true;
404 continue;
405 } elseif ($versionRange[1] != '0.0.0' && version_compare($instExtInfo[$depK]['EM_CONF']['version'], $versionRange[1], '>')) {
406 $msg[] = '<br />' . sprintf($GLOBALS['LANG']->getLL('checkDependencies_ext_too_high'),
407 $depK, $instExtInfo[$depK]['EM_CONF']['version'], $versionRange[1]);
408 $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" value="1" name="depsolver[ignore][' . $depK . ']" id="checkIgnore_' . $depK . '" />
409 <label for="checkIgnore_' . $depK . '">' . $GLOBALS['LANG']->getLL('checkDependencies_ignore_requirement') . '</label>';
410 $depError = true;
411 continue;
412 }
413 }
414 }
415 }
416
417 if (($depError || $depIgnore) && $this->parentObject instanceof SC_mod_tools_em_index) {
418 $content .= $this->parentObject->doc->section(
419 $GLOBALS['LANG']->getLL('removeExtFromList_dependency_error'),
420 implode('<br />', $msg), 0, 1, 2
421 );
422 }
423
424 // Check conflicts with other extensions:
425 $conflictError = false;
426 $conflictIgnore = false;
427 $msg = array();
428
429 if (isset($conf['constraints']['conflicts']) && is_array($conf['constraints']['conflicts'])) {
430 foreach ((array) $conf['constraints']['conflicts'] as $conflictK => $conflictV) {
431 if ($depsolver['ignore'][$conflictK]) {
432 $msg[] = '<br />' . sprintf($GLOBALS['LANG']->getLL('checkDependencies_conflict_ignored'),
433 $conflictK) . '
434 <input type="hidden" value="1" name="depsolver[ignore][' . $conflictK . ']" />';
435 $conflictIgnore = true;
436 continue;
437 }
438 if (t3lib_extMgm::isLoaded($conflictK)) {
439 $versionRange = tx_em_Tools::splitVersionRange($conflictV);
440 if ($versionRange[0] != '0.0.0' && version_compare($instExtInfo[$conflictK]['EM_CONF']['version'], $versionRange[0], '<')) {
441 continue;
442 }
443 elseif ($versionRange[1] != '0.0.0' && version_compare($instExtInfo[$conflictK]['EM_CONF']['version'], $versionRange[1], '>')) {
444 continue;
445 }
446 $msg[] = sprintf($GLOBALS['LANG']->getLL('checkDependencies_conflict_remove'),
447 $extKey, $conflictK, $instExtInfo[$conflictK]['EM_CONF']['title'], $conflictK, $extKey);
448 $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;' . tx_em_Tools::removeButton() . '&nbsp;
449 <a href="' . htmlspecialchars(t3lib_div::linkThisScript(array(
450 'CMD[showExt]' => $conflictK,
451 'CMD[remove]' => 1,
452 'CMD[clrCmd]' => 1,
453 'CMD[standAlone]' => 1,
454 'SET[singleDetails]' => 'info'
455 ))) .
456 '" target="_blank">' . $GLOBALS['LANG']->getLL('checkDependencies_remove_now') . '</a>';
457 $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" value="1" name="depsolver[ignore][' . $conflictK . ']" id="checkIgnore_' . $conflictK . '" />
458 <label for="checkIgnore_' . $conflictK . '">' . $GLOBALS['LANG']->getLL('checkDependencies_ignore_conflict') . '</label>';
459 $conflictError = true;
460 }
461 }
462 }
463 if ($conflictError || $conflictIgnore) {
464 $content .= $this->parentObject->doc->section(
465 $GLOBALS['LANG']->getLL('checkDependencies_conflict_error'), implode('<br />', $msg), 0, 1, 2
466 );
467 }
468
469 // Check suggests on other extensions:
470 if (isset($conf['constraints']['suggests']) && is_array($conf['constraints']['suggests'])) {
471 $suggestion = false;
472 $suggestionIgnore = false;
473 $msg = array();
474 foreach ($conf['constraints']['suggests'] as $suggestK => $suggestV) {
475 if ($depsolver['ignore'][$suggestK]) {
476 $msg[] = '<br />' . sprintf($GLOBALS['LANG']->getLL('checkDependencies_suggestion_ignored'),
477 $suggestK) . '
478 <input type="hidden" value="1" name="depsolver[ignore][' . $suggestK . ']" />';
479 $suggestionIgnore = true;
480 continue;
481 }
482 if (!t3lib_extMgm::isLoaded($suggestK)) {
483 if (!isset($instExtInfo[$suggestK])) {
484 $msg[] = sprintf($GLOBALS['LANG']->getLL('checkDependencies_suggest_import'),
485 $suggestK);
486 $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;' . t3lib_iconWorks::getSpriteIcon('actions-system-extension-import', array('title' => $GLOBALS['LANG']->getLL('checkDependencies_import_ext'))) . '&nbsp;
487 <a href="' . t3lib_div::linkThisScript(array(
488 'CMD[importExt]' => $suggestK,
489 'CMD[loc]' => 'L',
490 'CMD[standAlone]' => 1
491 )) . '" target="_blank">' . $GLOBALS['LANG']->getLL('checkDependencies_import_now') . '</a>';
492 $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" value="1" name="depsolver[ignore][' . $suggestK . ']" id="checkIgnore_' . $suggestK . '" />
493 <label for="checkIgnore_' . $suggestK . '">' . $GLOBALS['LANG']->getLL('checkDependencies_ignore_suggestion') . '</label>';
494 } else {
495 $msg[] = sprintf($GLOBALS['LANG']->getLL('checkDependencies_suggest_installation'),
496 $suggestK, $instExtInfo[$suggestK]['EM_CONF']['title']);
497 $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;' . tx_em_Tools::installButton() . '&nbsp;
498 <a href="' . htmlspecialchars(t3lib_div::linkThisScript(array(
499 'CMD[showExt]' => $suggestK,
500 'CMD[load]' => 1,
501 'CMD[clrCmd]' => 1,
502 'CMD[standAlone]' => 1,
503 'SET[singleDetails]' => 'info'
504 ))) .
505 '" target="_blank">' . $GLOBALS['LANG']->getLL('checkDependencies_install_now') . '</a>';
506 $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" value="1" name="depsolver[ignore][' . $suggestK . ']" id="checkIgnore_' . $suggestK . '" />
507 <label for="checkIgnore_' . $suggestK . '">' . $GLOBALS['LANG']->getLL('checkDependencies_ignore_suggestion') . '</label>';
508 }
509 $suggestion = true;
510 }
511 }
512 if ($suggestion || $suggestionIgnore) {
513 $content .= $this->parentObject->doc->section(
514 sprintf($GLOBALS['LANG']->getLL('checkDependencies_exts_suggested_by_ext'), $extKey),
515 implode('<br />', $msg), 0, 1, 1
516 );
517 }
518 }
519
520 if ($depError || $conflictError || $suggestion) {
521 foreach ($this->parentObject->CMD as $k => $v) {
522 $content .= '<input type="hidden" name="CMD[' . $k . ']" value="' . $v . '" />';
523 }
524 $content .= '<br /><br /><input type="submit" value="' . $GLOBALS['LANG']->getLL('checkDependencies_try_again') . '" />';
525
526 return array(
527 'returnCode' => FALSE,
528 'html' => '<form action="' . $this->parentObject->script . '" method="post" name="depform">' . $content . '</form>');
529 }
530
531 return array(
532 'returnCode' => TRUE
533 );
534 }
535
536
537 /**
538 * Delete extension from the file system
539 *
540 * @param string Extension key
541 * @param array Extension info array
542 * @return string Returns message string about the status of the operation
543 */
544 function extDelete($extKey, $extInfo, $command) {
545 $absPath = tx_em_Tools::getExtPath($extKey, $extInfo['type']);
546 if (t3lib_extMgm::isLoaded($extKey)) {
547 return $GLOBALS['LANG']->getLL('extDelete_ext_active');
548 } elseif (!tx_em_Tools::deleteAsType($extInfo['type'])) {
549 return sprintf($GLOBALS['LANG']->getLL('extDelete_wrong_scope'),
550 $this->api->typeLabels[$extInfo['type']]
551 );
552 } elseif (t3lib_div::inList('G,L', $extInfo['type'])) {
553 if ($command['doDelete'] && !strcmp($absPath, urldecode($command['absPath']))) {
554 $res = $this->removeExtDirectory($absPath);
555 if ($res) {
556 $flashMessage = t3lib_div::makeInstance(
557 't3lib_FlashMessage',
558 nl2br($res),
559 sprintf($GLOBALS['LANG']->getLL('extDelete_remove_dir_failed'), $absPath),
560 t3lib_FlashMessage::ERROR
561 );
562 return $flashMessage->render();
563 } else {
564 $flashMessage = t3lib_div::makeInstance(
565 't3lib_FlashMessage',
566 sprintf($GLOBALS['LANG']->getLL('extDelete_removed'), $absPath),
567 $GLOBALS['LANG']->getLL('extDelete_removed_header'),
568 t3lib_FlashMessage::OK
569 );
570 return $flashMessage->render();
571 }
572 } else {
573 $areYouSure = $GLOBALS['LANG']->getLL('extDelete_sure');
574 $deleteFromServer = $GLOBALS['LANG']->getLL('extDelete_from_server');
575 $onClick = "if (confirm('$areYouSure')) {window.location.href='" . t3lib_div::linkThisScript(array(
576 'CMD[showExt]' => $extKey,
577 'CMD[doDelete]' => 1,
578 'CMD[absPath]' => rawurlencode($absPath)
579 )) . "';}";
580 $content .= '<a class="t3-link" href="#" onclick="' . htmlspecialchars($onClick) .
581 ' return false;"><strong>' . $deleteFromServer . '</strong> ' .
582 sprintf($GLOBALS['LANG']->getLL('extDelete_from_location'),
583 $this->api->typeLabels[$extInfo['type']],
584 substr($absPath, strlen(PATH_site))
585 ) . '</a>';
586 $content .= '<br /><br />' . $GLOBALS['LANG']->getLL('extDelete_backup');
587 return $content;
588 }
589 } else {
590 return $GLOBALS['LANG']->getLL('extDelete_neither_global_nor_local');
591 }
592 }
593
594 /**
595 * Removes the extension directory (including content)
596 *
597 * @param string Extension directory to remove (with trailing slash)
598 * @param boolean If set, will leave the extension directory
599 * @return boolean False on success, otherwise error string.
600 */
601 function removeExtDirectory($removePath, $removeContentOnly = 0) {
602 $errors = array();
603 if (@is_dir($removePath) && substr($removePath, -1) == '/' && (
604 t3lib_div::isFirstPartOfStr($removePath, tx_em_Tools::typePath('G')) ||
605 t3lib_div::isFirstPartOfStr($removePath, tx_em_Tools::typePath('L')) ||
606 (t3lib_div::isFirstPartOfStr($removePath, tx_em_Tools::typePath('S')) && $this->systemInstall) ||
607 t3lib_div::isFirstPartOfStr($removePath, PATH_site . $GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'] . '_temp_/')) // Playing-around directory...
608 ) {
609
610 // All files in extension directory:
611 $fileArr = t3lib_div::getAllFilesAndFoldersInPath(array(), $removePath, '', 1);
612 if (is_array($fileArr)) {
613
614 // Remove files in dirs:
615 foreach ($fileArr as $removeFile) {
616 if (!@is_dir($removeFile)) {
617 if (@is_file($removeFile) && t3lib_div::isFirstPartOfStr($removeFile, $removePath) && strcmp($removeFile, $removePath)) { // ... we are very paranoid, so we check what cannot go wrong: that the file is in fact within the prefix path!
618 @unlink($removeFile);
619 clearstatcache();
620 if (@is_file($removeFile)) {
621 $errors[] = sprintf($GLOBALS['LANG']->getLL('rmExtDir_could_not_be_deleted'),
622 $removeFile
623 );
624 }
625 } else {
626 $errors[] = sprintf($GLOBALS['LANG']->getLL('rmExtDir_error_file'),
627 $removeFile, $removePath
628 );
629 }
630 }
631 }
632
633 // Remove directories:
634 $remDirs = tx_em_Tools::extractDirsFromFileList(t3lib_div::removePrefixPathFromList($fileArr, $removePath));
635 $remDirs = array_reverse($remDirs); // Must delete outer directories first...
636 foreach ($remDirs as $removeRelDir) {
637 $removeDir = $removePath . $removeRelDir;
638 if (@is_dir($removeDir)) {
639 @rmdir($removeDir);
640 clearstatcache();
641 if (@is_dir($removeDir)) {
642 $errors[] = sprintf($GLOBALS['LANG']->getLL('rmExtDir_error_files_left'),
643 $removeDir
644 );
645 }
646 } else {
647 $errors[] = sprintf($GLOBALS['LANG']->getLL('rmExtDir_error_no_dir'),
648 $removeDir
649 );
650 }
651 }
652
653 // If extension dir should also be removed:
654 if (!$removeContentOnly) {
655 @rmdir($removePath);
656 clearstatcache();
657 if (@is_dir($removePath)) {
658 $errors[] = sprintf($GLOBALS['LANG']->getLL('rmExtDir_error_folders_left'),
659 $removePath
660 );
661 }
662 }
663 } else {
664 $errors[] = $GLOBALS['LANG']->getLL('rmExtDir_error') . ' ' . $fileArr;
665 }
666 } else {
667 $errors[] = $GLOBALS['LANG']->getLL('rmExtDir_error_unallowed_path') . ' ' . $removePath;
668 }
669
670 // Return errors if any:
671 return implode(LF, $errors);
672 }
673
674 /**
675 * Validates the database according to extension requirements
676 * Prints form for changes if any. If none, returns blank. If an update is ordered, empty is returned as well.
677 * DBAL compliant (based on Install Tool code)
678 *
679 * @param string Extension key
680 * @param array Extension information array
681 * @param boolean If true, returns array with info.
682 * @return mixed If $infoOnly, returns array with information. Otherwise performs update.
683 */
684 function checkDBupdates($extKey, $extInfo, $infoOnly = 0) {
685
686
687 $dbStatus = array();
688
689 // Updating tables and fields?
690 if (is_array($extInfo['files']) && in_array('ext_tables.sql', $extInfo['files'])) {
691 $fileContent = t3lib_div::getUrl(tx_em_Tools::getExtPath($extKey, $extInfo['type']) . 'ext_tables.sql');
692
693 $FDfile = $this->install->getFieldDefinitions_fileContent($fileContent);
694 if (count($FDfile)) {
695 $FDdb = $this->install->getFieldDefinitions_database(TYPO3_db);
696 $diff = $this->install->getDatabaseExtra($FDfile, $FDdb);
697 $update_statements = $this->install->getUpdateSuggestions($diff);
698
699 $dbStatus['structure']['tables_fields'] = $FDfile;
700 $dbStatus['structure']['diff'] = $diff;
701
702 // Updating database...
703 if (!$infoOnly && is_array($this->install->INSTALL['database_update'])) {
704 $this->install->performUpdateQueries($update_statements['add'], $this->install->INSTALL['database_update']);
705 $this->install->performUpdateQueries($update_statements['change'], $this->install->INSTALL['database_update']);
706 $this->install->performUpdateQueries($update_statements['create_table'], $this->install->INSTALL['database_update']);
707 } else {
708 $content .= $this->install->generateUpdateDatabaseForm_checkboxes(
709 $update_statements['add'], $GLOBALS['LANG']->getLL('checkDBupdates_add_fields'));
710 $content .= $this->install->generateUpdateDatabaseForm_checkboxes(
711 $update_statements['change'], $GLOBALS['LANG']->getLL('checkDBupdates_changing_fields'), 1, 0, $update_statements['change_currentValue']);
712 $content .= $this->install->generateUpdateDatabaseForm_checkboxes(
713 $update_statements['create_table'], $GLOBALS['LANG']->getLL('checkDBupdates_add_tables'));
714 }
715 }
716 }
717
718 // Importing static tables?
719 if (is_array($extInfo['files']) && in_array('ext_tables_static+adt.sql', $extInfo['files'])) {
720 $fileContent = t3lib_div::getUrl(tx_em_Tools::getExtPath($extKey, $extInfo['type']) . 'ext_tables_static+adt.sql');
721
722 $statements = $this->install->getStatementarray($fileContent, 1);
723 list($statements_table, $insertCount) = $this->install->getCreateTables($statements, 1);
724
725 // Execute import of static table content:
726 if (!$infoOnly && is_array($this->install->INSTALL['database_import'])) {
727
728 // Traverse the tables
729 foreach ($this->install->INSTALL['database_import'] as $table => $md5str) {
730 if ($md5str == md5($statements_table[$table])) {
731 $GLOBALS['TYPO3_DB']->admin_query('DROP TABLE IF EXISTS ' . $table);
732 $GLOBALS['TYPO3_DB']->admin_query($statements_table[$table]);
733
734 if ($insertCount[$table]) {
735 $statements_insert = $this->install->getTableInsertStatements($statements, $table);
736
737 foreach ($statements_insert as $v) {
738 $GLOBALS['TYPO3_DB']->admin_query($v);
739 }
740 }
741 }
742 }
743 } else {
744 $whichTables = $this->install->getListOfTables();
745 if (count($statements_table)) {
746 $out = '';
747 foreach ($statements_table as $table => $definition) {
748 $exist = isset($whichTables[$table]);
749
750 $dbStatus['static'][$table]['exists'] = $exist;
751 $dbStatus['static'][$table]['count'] = $insertCount[$table];
752
753 $out .= '<tr>
754 <td><input type="checkbox" name="TYPO3_INSTALL[database_import][' . $table . ']" checked="checked" value="' . md5($definition) . '" /></td>
755 <td><strong>' . $table . '</strong></td>
756 <td><img src="clear.gif" width="10" height="1" alt="" /></td>
757 <td nowrap="nowrap">' .
758 ($insertCount[$table] ?
759 $GLOBALS['LANG']->getLL('checkDBupdates_rows') . ' ' . $insertCount[$table]
760 : '') .
761 '</td>
762 <td><img src="clear.gif" width="10" height="1" alt="" /></td>
763 <td nowrap="nowrap">' .
764 ($exist ?
765 t3lib_iconWorks::getSpriteIcon('status-dialog-warning') .
766 $GLOBALS['LANG']->getLL('checkDBupdates_table_exists')
767 : '') .
768 '</td>
769 </tr>';
770 }
771 $content .= '
772 <br />
773 <h3>' . $GLOBALS['LANG']->getLL('checkDBupdates_import_static_data') . '</h3>
774 <table border="0" cellpadding="0" cellspacing="0">' . $out . '</table>
775 ';
776 }
777 }
778 }
779
780 // Return array of information if $infoOnly, otherwise content.
781 return $infoOnly ? $dbStatus : $content;
782 }
783
784 /**
785 * Removes the current extension of $type and creates the base folder for the new one (which is going to be imported)
786 *
787 * @param array Data for imported extension
788 * @param string Extension installation scope (L,G,S)
789 * @param boolean If set, nothing will be deleted (neither directory nor files)
790 * @return mixed Returns array on success (with extension directory), otherwise an error string.
791 */
792 function clearAndMakeExtensionDir($importedData, $type, $dontDelete = 0) {
793 if (!$importedData['extKey']) {
794 return $GLOBALS['LANG']->getLL('clearMakeExtDir_no_ext_key');
795 }
796
797 // Setting install path (L, G, S or fileadmin/_temp_/)
798 $path = '';
799 switch ((string) $type) {
800 case 'G':
801 case 'L':
802 $path = tx_em_Tools::typePath($type);
803 $suffix = '';
804
805 // Creates the typo3conf/ext/ directory if it does NOT already exist:
806 if ((string) $type == 'L' && !@is_dir($path)) {
807 t3lib_div::mkdir($path);
808 }
809 break;
810 default:
811 if ($this->systemInstall && (string) $type == 'S') {
812 $path = tx_em_Tools::typePath($type);
813 $suffix = '';
814 } else {
815 $path = PATH_site . $GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'] . '_temp_/';
816 $suffix = '_' . date('dmy-His');
817 }
818 break;
819 }
820
821 // If the install path is OK...
822 if ($path && @is_dir($path)) {
823
824 // Set extension directory:
825 $extDirPath = $path . $importedData['extKey'] . $suffix . '/';
826
827 // Install dir was found, remove it then:
828 if (@is_dir($extDirPath)) {
829 if ($dontDelete) {
830 return array($extDirPath);
831 }
832 $res = $this->removeExtDirectory($extDirPath);
833 if ($res) {
834 $flashMessage = t3lib_div::makeInstance(
835 't3lib_FlashMessage',
836 nl2br($res),
837 sprintf($GLOBALS['LANG']->getLL('clearMakeExtDir_could_not_remove_dir'), $extDirPath),
838 t3lib_FlashMessage::ERROR
839 );
840 return $flashMessage->render();
841 }
842 }
843
844 // We go create...
845 t3lib_div::mkdir($extDirPath);
846 if (!is_dir($extDirPath)) {
847 return sprintf($GLOBALS['LANG']->getLL('clearMakeExtDir_could_not_create_dir'),
848 $extDirPath);
849 }
850 return array($extDirPath);
851 } else {
852 return sprintf($GLOBALS['LANG']->getLL('clearMakeExtDir_no_dir'),
853 $path);
854 }
855 }
856
857
858 /*******************************
859 *
860 * Extension analyzing (detailed information)
861 *
862 ******************************/
863
864 /**
865 * Perform a detailed, technical analysis of the available extension on server!
866 * Includes all kinds of verifications
867 * Takes some time to process, therfore use with care, in particular in listings.
868 *
869 * @param string Extension key
870 * @param array Extension information
871 * @param boolean If set, checks for validity of classes etc.
872 * @return array Information in an array.
873 */
874 function makeDetailedExtensionAnalysis($extKey, $extInfo, $validity = 0) {
875
876 // Get absolute path of the extension
877 $absPath = tx_em_Tools::getExtPath($extKey, $extInfo['type']);
878 $extensionDetails = t3lib_div::makeInstance('tx_em_Extensions_Details', $this);
879 $infoArray = array();
880
881 $table_class_prefix = substr($extKey, 0, 5) == 'user_' ? 'user_' : 'tx_' . str_replace('_', '', $extKey) . '_';
882 $module_prefix = substr($extKey, 0, 5) == 'user_' ? 'u' : 'tx' . str_replace('_', '', $extKey);
883
884 // Database status:
885 $dbInfo = $this->checkDBupdates($extKey, $extInfo, 1);
886
887 // Database structure required:
888 if (is_array($dbInfo['structure']['tables_fields'])) {
889 $modify_tables = t3lib_div::trimExplode(',', $extInfo['EM_CONF']['modify_tables'], 1);
890 $infoArray['dump_tf'] = array();
891
892 foreach ($dbInfo['structure']['tables_fields'] as $tN => $d) {
893 if (in_array($tN, $modify_tables)) {
894 $infoArray['fields'][] = $tN . ': <i>' .
895 (is_array($d['fields']) ? implode(', ', array_keys($d['fields'])) : '') .
896 (is_array($d['keys']) ?
897 ' + ' . count($d['keys']) . ' ' . $GLOBALS['LANG']->getLL('detailedExtAnalysis_keys') : '') .
898 '</i>';
899 if (is_array($d['fields'])) {
900 foreach ($d['fields'] as $fN => $value) {
901 $infoArray['dump_tf'][] = $tN . '.' . $fN;
902 if (!t3lib_div::isFirstPartOfStr($fN, $table_class_prefix)) {
903 $infoArray['NSerrors']['fields'][$fN] = $fN;
904 } else {
905 $infoArray['NSok']['fields'][$fN] = $fN;
906 }
907 }
908 }
909 if (is_array($d['keys'])) {
910 foreach ($d['keys'] as $fN => $value) {
911 $infoArray['dump_tf'][] = $tN . '.KEY:' . $fN;
912 }
913 }
914 } else {
915 $infoArray['dump_tf'][] = $tN;
916 $infoArray['tables'][] = $tN;
917 if (!t3lib_div::isFirstPartOfStr($tN, $table_class_prefix)) {
918 $infoArray['NSerrors']['tables'][$tN] = $tN;
919 } else {
920 $infoArray['NSok']['tables'][$tN] = $tN;
921 }
922 }
923 }
924 if (count($dbInfo['structure']['diff']['diff']) || count($dbInfo['structure']['diff']['extra'])) {
925 $msg = array();
926 if (count($dbInfo['structure']['diff']['diff'])) {
927 $msg[] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_tables_are_missing');
928 }
929 if (count($dbInfo['structure']['diff']['extra'])) {
930 $msg[] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_tables_are_of_wrong_type');
931 }
932 $infoArray['tables_error'] = 1;
933 if (t3lib_extMgm::isLoaded($extKey)) {
934 $infoArray['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_tables_are'),
935 implode(' ' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:and') . ' ', $msg)
936 );
937 }
938 }
939 }
940
941 // Static tables?
942 if (is_array($dbInfo['static'])) {
943 $infoArray['static'] = array_keys($dbInfo['static']);
944
945 foreach ($dbInfo['static'] as $tN => $d) {
946 if (!$d['exists']) {
947 $infoArray['static_error'] = 1;
948 if (t3lib_extMgm::isLoaded($extKey)) {
949 $infoArray['errors'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_static_tables_missing');
950 }
951 if (!t3lib_div::isFirstPartOfStr($tN, $table_class_prefix)) {
952 $infoArray['NSerrors']['tables'][$tN] = $tN;
953 } else {
954 $infoArray['NSok']['tables'][$tN] = $tN;
955 }
956 }
957 }
958 }
959
960 // Backend Module-check:
961 $knownModuleList = t3lib_div::trimExplode(',', $extInfo['EM_CONF']['module'], 1);
962 foreach ($knownModuleList as $mod) {
963 if (@is_dir($absPath . $mod)) {
964 if (@is_file($absPath . $mod . '/conf.php')) {
965 $confFileInfo = $extensionDetails->modConfFileAnalysis($absPath . $mod . '/conf.php');
966 if (is_array($confFileInfo['TYPO3_MOD_PATH'])) {
967 $shouldBePath = tx_em_Tools::typeRelPath($extInfo['type']) . $extKey . '/' . $mod . '/';
968 if (strcmp($confFileInfo['TYPO3_MOD_PATH'][1][1], $shouldBePath)) {
969 $infoArray['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_wrong_mod_path'),
970 $confFileInfo['TYPO3_MOD_PATH'][1][1],
971 $shouldBePath
972 );
973 }
974 } else {
975 // It seems like TYPO3_MOD_PATH and therefore also this warning is no longer needed.
976 // $infoArray['errors'][] = 'No definition of TYPO3_MOD_PATH constant found inside!';
977 }
978 if (is_array($confFileInfo['MCONF_name'])) {
979 $mName = $confFileInfo['MCONF_name'][1][1];
980 $mNameParts = explode('_', $mName);
981 $infoArray['moduleNames'][] = $mName;
982 if (!t3lib_div::isFirstPartOfStr($mNameParts[0], $module_prefix) &&
983 (!$mNameParts[1] || !t3lib_div::isFirstPartOfStr($mNameParts[1], $module_prefix))) {
984 $infoArray['NSerrors']['modname'][] = $mName;
985 } else {
986 $infoArray['NSok']['modname'][] = $mName;
987 }
988 } else {
989 $infoArray['errors'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_mconf_missing');
990 }
991 } else {
992 $infoArray['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_be_module_conf_missing'),
993 $mod . '/conf.php'
994 );
995 }
996 } else {
997 $infoArray['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_module_folder_missing'),
998 $mod . '/'
999 );
1000 }
1001 }
1002 $dirs = t3lib_div::get_dirs($absPath);
1003 if (is_array($dirs)) {
1004 reset($dirs);
1005 while (list(, $mod) = each($dirs)) {
1006 if (!in_array($mod, $knownModuleList) && @is_file($absPath . $mod . '/conf.php')) {
1007 $confFileInfo = $extensionDetails->modConfFileAnalysis($absPath . $mod . '/conf.php');
1008 if (is_array($confFileInfo)) {
1009 $infoArray['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_unconfigured_module'),
1010 $mod . '/conf.php'
1011 );
1012 }
1013 }
1014 }
1015 }
1016
1017 // ext_tables.php:
1018 if (@is_file($absPath . 'ext_tables.php')) {
1019 $content = t3lib_div::getUrl($absPath . 'ext_tables.php');
1020 if (stristr($content, 't3lib_extMgm::addModule')) {
1021 $infoArray['flags'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_module');
1022 }
1023 if (stristr($content, 't3lib_extMgm::insertModuleFunction')) {
1024 $infoArray['flags'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_module_and_more');
1025 }
1026 if (stristr($content, 't3lib_div::loadTCA')) {
1027 $infoArray['flags'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_loadTCA');
1028 }
1029 if (stristr($content, '$TCA[')) {
1030 $infoArray['flags'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_TCA');
1031 }
1032 if (stristr($content, 't3lib_extMgm::addPlugin')) {
1033 $infoArray['flags'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_plugin');
1034 }
1035 }
1036
1037 // ext_localconf.php:
1038 if (@is_file($absPath . 'ext_localconf.php')) {
1039 $content = t3lib_div::getUrl($absPath . 'ext_localconf.php');
1040 if (stristr($content, 't3lib_extMgm::addPItoST43')) {
1041 $infoArray['flags'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_plugin_st43');
1042 }
1043 if (stristr($content, 't3lib_extMgm::addPageTSConfig')) {
1044 $infoArray['flags'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_page_ts');
1045 }
1046 if (stristr($content, 't3lib_extMgm::addUserTSConfig')) {
1047 $infoArray['flags'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_user_ts');
1048 }
1049 if (stristr($content, 't3lib_extMgm::addTypoScriptSetup')) {
1050 $infoArray['flags'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_ts_setup');
1051 }
1052 if (stristr($content, 't3lib_extMgm::addTypoScriptConstants')) {
1053 $infoArray['flags'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_ts_constants');
1054 }
1055 }
1056
1057 if (@is_file($absPath . 'ext_typoscript_constants.txt')) {
1058 $infoArray['TSfiles'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_constants');
1059 }
1060 if (@is_file($absPath . 'ext_typoscript_setup.txt')) {
1061 $infoArray['TSfiles'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_setup');
1062 }
1063 if (@is_file($absPath . 'ext_conf_template.txt')) {
1064 $infoArray['conf'] = 1;
1065 }
1066
1067 // Classes:
1068 if ($validity) {
1069 $filesInside = tx_em_Tools::getClassIndexLocallangFiles($absPath, $table_class_prefix, $extKey);
1070 if (is_array($filesInside['errors'])) {
1071 $infoArray['errors'] = array_merge((array) $infoArray['errors'], $filesInside['errors']);
1072 }
1073 if (is_array($filesInside['NSerrors'])) {
1074 $infoArray['NSerrors'] = array_merge((array) $infoArray['NSerrors'], $filesInside['NSerrors']);
1075 }
1076 if (is_array($filesInside['NSok'])) {
1077 $infoArray['NSok'] = array_merge((array) $infoArray['NSok'], $filesInside['NSok']);
1078 }
1079 $infoArray['locallang'] = $filesInside['locallang'];
1080 $infoArray['classes'] = $filesInside['classes'];
1081 }
1082
1083 // Upload folders
1084 if ($extInfo['EM_CONF']['uploadfolder']) {
1085 $infoArray['uploadfolder'] = tx_em_Tools::uploadFolder($extKey);
1086 if (!@is_dir(PATH_site . $infoArray['uploadfolder'])) {
1087 $infoArray['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_no_upload_folder'),
1088 $infoArray['uploadfolder']
1089 );
1090 $infoArray['uploadfolder'] = '';
1091 }
1092 }
1093
1094 // Create directories:
1095 if ($extInfo['EM_CONF']['createDirs']) {
1096 $infoArray['createDirs'] = array_unique(t3lib_div::trimExplode(',', $extInfo['EM_CONF']['createDirs'], 1));
1097 foreach ($infoArray['createDirs'] as $crDir) {
1098 if (!@is_dir(PATH_site . $crDir)) {
1099 $infoArray['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_no_upload_folder'),
1100 $crDir
1101 );
1102 }
1103 }
1104 }
1105
1106 // Return result array:
1107 return $infoArray;
1108 }
1109
1110
1111 /**
1112 * Produces the config form for an extension (if any template file, ext_conf_template.txt is found)
1113 *
1114 * @param string Extension key
1115 * @param array Extension information array
1116 * @param boolean If true, the form HTML content is returned, otherwise the content is set in $this->content.
1117 * @param string Submit-to URL (supposedly)
1118 * @param string Additional form fields to include.
1119 * @return string Depending on $output. Can return the whole form.
1120 */
1121 function tsStyleConfigForm($extKey, $extInfo, $output = 0, $script = '', $addFields = '') {
1122 global $TYPO3_CONF_VARS;
1123
1124 // Initialize:
1125 $absPath = tx_em_Tools::getExtPath($extKey, $extInfo['type']);
1126 $relPath = tx_em_Tools::typeRelPath($extInfo['type']) . $extKey . '/';
1127
1128 // Look for template file for form:
1129 if (t3lib_extMgm::isLoaded($extKey) && @is_file($absPath . 'ext_conf_template.txt')) {
1130
1131 // Load tsStyleConfig class and parse configuration template:
1132 $tsStyleConfig = t3lib_div::makeInstance('t3lib_tsStyleConfig');
1133 $tsStyleConfig->doNotSortCategoriesBeforeMakingForm = TRUE;
1134 $theConstants = $tsStyleConfig->ext_initTSstyleConfig(
1135 t3lib_div::getUrl($absPath . 'ext_conf_template.txt'),
1136 $relPath,
1137 $absPath,
1138 $GLOBALS['BACK_PATH']
1139 );
1140
1141 // Load the list of resources.
1142 $tsStyleConfig->ext_loadResources($absPath . 'res/');
1143
1144 // Load current value:
1145 $arr = unserialize($TYPO3_CONF_VARS['EXT']['extConf'][$extKey]);
1146 $arr = is_array($arr) ? $arr : array();
1147
1148 // Call processing function for constants config and data before write and form rendering:
1149 if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['typo3/mod/tools/em/index.php']['tsStyleConfigForm'])) {
1150 $_params = array('fields' => &$theConstants, 'data' => &$arr, 'extKey' => $extKey);
1151 foreach ($TYPO3_CONF_VARS['SC_OPTIONS']['typo3/mod/tools/em/index.php']['tsStyleConfigForm'] as $_funcRef) {
1152 t3lib_div::callUserFunction($_funcRef, $_params, $this);
1153 }
1154 unset($_params);
1155 }
1156
1157 // If saving operation is done:
1158 if (t3lib_div::_POST('submit')) {
1159 $tsStyleConfig->ext_procesInput(t3lib_div::_POST(), array(), $theConstants, array());
1160 $arr = $tsStyleConfig->ext_mergeIncomingWithExisting($arr);
1161 $this->writeTsStyleConfig($extKey, $arr);
1162 }
1163
1164 // Setting value array
1165 $tsStyleConfig->ext_setValuearray($theConstants, $arr);
1166
1167 // Getting session data:
1168 $MOD_MENU = array();
1169 $MOD_MENU['constant_editor_cat'] = $tsStyleConfig->ext_getCategoriesForModMenu();
1170 $MOD_SETTINGS = t3lib_BEfunc::getModuleData($MOD_MENU, t3lib_div::_GP('SET'), 'xMod_test');
1171
1172 // Resetting the menu (stop)
1173 if (count($MOD_MENU['constant_editor_cat']) > 1) {
1174 $menu = $GLOBALS['LANG']->getLL('extInfoArray_category') . ' ' .
1175 t3lib_BEfunc::getFuncMenu(0, 'SET[constant_editor_cat]', $MOD_SETTINGS['constant_editor_cat'], $MOD_MENU['constant_editor_cat'], '', '&CMD[showExt]=' . $extKey);
1176 $this->parentObject->content .= $this->parentObject->doc->section('', '<span class="nobr">' . $menu . '</span>');
1177 $this->parentObject->content .= $this->parentObject->doc->spacer(10);
1178 }
1179
1180 // Category and constant editor config:
1181 $form = '
1182 <table border="0" cellpadding="0" cellspacing="0" width="600">
1183 <tr>
1184 <td>' . $tsStyleConfig->ext_getForm($MOD_SETTINGS['constant_editor_cat'], $theConstants, $script, $addFields) . '</form></td>
1185 </tr>
1186 </table>';
1187 } else {
1188 $flashMessage = t3lib_div::makeInstance(
1189 't3lib_FlashMessage',
1190 $GLOBALS['LANG']->getLL('tsStyleConfigForm_additional_config'),
1191 '',
1192 t3lib_FlashMessage::INFO
1193 );
1194
1195 $form = '
1196 <table border="0" cellpadding="0" cellspacing="0" width="600">
1197 <tr>
1198 <td>
1199 <form action="' . htmlspecialchars($script) . '" method="post">' .
1200 $addFields .
1201 $flashMessage->render() .
1202 '<br /><input type="submit" name="write" value="' . $GLOBALS['LANG']->getLL('updatesForm_make_updates') . '" />
1203 </form>
1204 </td>
1205 </tr>
1206 </table>';
1207 }
1208
1209 #if ($output) {
1210 return $form;
1211 #} else {
1212 # $this->content.=$this->doc->section('', $form);
1213 #}
1214
1215
1216 }
1217
1218 /**
1219 * Writes the TSstyleconf values to "localconf.php"
1220 * Removes the temp_CACHED* files before return.
1221 *
1222 * @param string Extension key
1223 * @param array Configuration array to write back
1224 * @return void
1225 */
1226 function writeTsStyleConfig($extKey, $arr) {
1227
1228 // Instance of install tool
1229 $instObj = new t3lib_install;
1230 $instObj->allowUpdateLocalConf = 1;
1231 $instObj->updateIdentity = 'TYPO3 Extension Manager';
1232
1233 // Get lines from localconf file
1234 $lines = $instObj->writeToLocalconf_control();
1235 $instObj->setValueInLocalconfFile($lines, '$TYPO3_CONF_VARS[\'EXT\'][\'extConf\'][\'' . $extKey . '\']', serialize($arr)); // This will be saved only if there are no linebreaks in it !
1236 $instObj->writeToLocalconf_control($lines);
1237
1238 t3lib_extMgm::removeCacheFiles();
1239 }
1240
1241
1242 /**
1243 * Creates a form for an extension which contains all options for configuration, updates of database, clearing of cache etc.
1244 * This form is shown when
1245 *
1246 * @param string Extension key
1247 * @param array Extension information array
1248 * @param boolean If set, the form will ONLY show if fields/tables should be updated (suppressing forms like general configuration and cache clearing).
1249 * @param string Alternative action=""-script
1250 * @param string HTML: Additional form fields
1251 * @return string HTML
1252 */
1253 function updatesForm($extKey, $extInfo, $notSilent = 0, $script = '', $addFields = '', $addForm = TRUE) {
1254 $script = $script ? $script : t3lib_div::linkThisScript();
1255 if ($addForm) {
1256 $formWrap = array('<form action="' . htmlspecialchars($script) . '" method="POST">', '</form>');
1257 } else {
1258 $formWrap = array('', '');
1259 }
1260 $extensionDetails = t3lib_div::makeInstance('tx_em_Extensions_Details', $this);
1261
1262 $updates .= $this->checkDBupdates($extKey, $extInfo);
1263 $uCache = $this->checkClearCache($extInfo);
1264 if ($notSilent) {
1265 $updates .= $uCache;
1266 }
1267 $updates .= $extensionDetails->checkUploadFolder($extKey, $extInfo);
1268
1269 $absPath = tx_em_Tools::getExtPath($extKey, $extInfo['type']);
1270 if ($notSilent && @is_file($absPath . 'ext_conf_template.txt')) {
1271 $configForm = $this->tsStyleConfigForm($extKey, $extInfo, 1, $script, $updates . $addFields . '<br />');
1272 }
1273
1274 if ($updates || $configForm) {
1275 if ($configForm) {
1276 $updates = $configForm;
1277 } else {
1278 $updates = $formWrap[0] . $updates . $addFields . '
1279 <br /><input type="submit" name="write" id="update-submit-' . $extKey . '" value="' . $GLOBALS['LANG']->getLL('updatesForm_make_updates') . '" />
1280 ' . $formWrap[1];
1281 }
1282 }
1283
1284 return $updates;
1285 }
1286
1287
1288 /**
1289 * Check if clear-cache should be performed, otherwise show form (for installation of extension)
1290 * Shown only if the extension has the clearCacheOnLoad flag set.
1291 *
1292 * @param string Extension key
1293 * @param array Extension information array
1294 * @return string HTML output (if form is shown)
1295 */
1296 function checkClearCache($extInfo) {
1297 if ($extInfo['EM_CONF']['clearCacheOnLoad']) {
1298 if (t3lib_div::_POST('_clear_all_cache')) { // Action: Clearing the cache
1299 $tce = t3lib_div::makeInstance('t3lib_TCEmain');
1300 $tce->stripslashes_values = 0;
1301 $tce->start(array(), array());
1302 $tce->clear_cacheCmd('all');
1303 } else { // Show checkbox for clearing cache:
1304 $content .= '
1305 <br />
1306 <h3>' . $GLOBALS['LANG']->getLL('checkUploadFolder_clear_cache') . '</h3>
1307 <p>' . $GLOBALS['LANG']->getLL('checkUploadFolder_clear_cache_requested') . '<br />
1308 <label for="check_clear_all_cache">' . $GLOBALS['LANG']->getLL('checkUploadFolder_clear_all_cache') . '</label>
1309 <input type="checkbox" name="_clear_all_cache" id="check_clear_all_cache" checked="checked" value="1" /><br />
1310 </p>
1311 ';
1312 }
1313 }
1314 return $content;
1315 }
1316
1317 /**
1318 * Writes the extension list to "localconf.php" file
1319 * Removes the temp_CACHED* files before return.
1320 *
1321 * @param string List of extensions
1322 * @return void
1323 */
1324 function writeNewExtensionList($newExtList) {
1325 $strippedExtensionList = $this->stripNonFrontendExtensions($newExtList);
1326
1327 // Instance of install tool
1328 $instObj = new t3lib_install;
1329 $instObj->allowUpdateLocalConf = 1;
1330 $instObj->updateIdentity = 'TYPO3 Extension Manager';
1331
1332 // Get lines from localconf file
1333 $lines = $instObj->writeToLocalconf_control();
1334 $instObj->setValueInLocalconfFile($lines, '$TYPO3_CONF_VARS[\'EXT\'][\'extList\']', $newExtList);
1335 $instObj->setValueInLocalconfFile($lines, '$TYPO3_CONF_VARS[\'EXT\'][\'extList_FE\']', $strippedExtensionList);
1336 $instObj->writeToLocalconf_control($lines);
1337
1338 $GLOBALS['TYPO3_CONF_VARS']['EXT']['extList'] = $newExtList;
1339 $GLOBALS['TYPO3_CONF_VARS']['EXT']['extList_FE'] = $strippedExtensionList;
1340 t3lib_extMgm::removeCacheFiles();
1341 }
1342
1343 /**
1344 * Removes unneeded extensions from the frontend based on
1345 * EMCONF doNotLoadInFE = 1
1346 *
1347 * @param string $extList
1348 * @return string
1349 */
1350 function stripNonFrontendExtensions($extList) {
1351 $fullExtList = $this->parentObject->extensionList->getInstalledExtensions();
1352 $extListArray = t3lib_div::trimExplode(',', $extList);
1353 foreach ($extListArray as $arrayKey => $extKey) {
1354 if ($fullExtList[0][$extKey]['EM_CONF']['doNotLoadInFE'] == 1) {
1355 unset($extListArray[$arrayKey]);
1356 }
1357 }
1358 $nonFEList = implode(',', $extListArray);
1359 return $nonFEList;
1360 }
1361
1362 /**
1363 * Updates the database according to extension requirements
1364 * DBAL compliant (based on Install Tool code)
1365 *
1366 * @param string Extension key
1367 * @param array Extension information array
1368 * @return void
1369 */
1370 function forceDBupdates($extKey, $extInfo) {
1371 $instObj = new t3lib_install;
1372
1373 // Updating tables and fields?
1374 if (is_array($extInfo['files']) && in_array('ext_tables.sql', $extInfo['files'])) {
1375 $fileContent = t3lib_div::getUrl(tx_em_Tools::getExtPath($extKey, $extInfo['type']) . 'ext_tables.sql');
1376
1377 $FDfile = $instObj->getFieldDefinitions_fileContent($fileContent);
1378 if (count($FDfile)) {
1379 $FDdb = $instObj->getFieldDefinitions_database(TYPO3_db);
1380 $diff = $instObj->getDatabaseExtra($FDfile, $FDdb);
1381 $update_statements = $instObj->getUpdateSuggestions($diff);
1382
1383 foreach ((array) $update_statements['add'] as $string) {
1384 $GLOBALS['TYPO3_DB']->admin_query($string);
1385 }
1386 foreach ((array) $update_statements['change'] as $string) {
1387 $GLOBALS['TYPO3_DB']->admin_query($string);
1388 }
1389 foreach ((array) $update_statements['create_table'] as $string) {
1390 $GLOBALS['TYPO3_DB']->admin_query($string);
1391 }
1392 }
1393 }
1394
1395 // Importing static tables?
1396 if (is_array($extInfo['files']) && in_array('ext_tables_static+adt.sql', $extInfo['files'])) {
1397 $fileContent = t3lib_div::getUrl(tx_em_Tools::getExtPath($extKey, $extInfo['type']) . 'ext_tables_static+adt.sql');
1398
1399 $statements = $instObj->getStatementarray($fileContent, 1);
1400 list($statements_table, $insertCount) = $instObj->getCreateTables($statements, 1);
1401
1402 // Traverse the tables
1403 foreach ($statements_table as $table => $query) {
1404 $GLOBALS['TYPO3_DB']->admin_query('DROP TABLE IF EXISTS ' . $table);
1405 $GLOBALS['TYPO3_DB']->admin_query($query);
1406
1407 if ($insertCount[$table]) {
1408 $statements_insert = $instObj->getTableInsertStatements($statements, $table);
1409
1410 foreach ($statements_insert as $v) {
1411 $GLOBALS['TYPO3_DB']->admin_query($v);
1412 }
1413 }
1414 }
1415 }
1416 }
1417
1418 }
1419
1420 ?>