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