PageRenderTime 53ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/typo3/sysext/em/classes/install/class.tx_em_install.php

https://github.com/andreaswolf/typo3-tceforms
PHP | 1584 lines | 1180 code | 144 blank | 260 comment | 278 complexity | 3663f359227084f942c6e15a8bbf1573 MD5 | raw file
Possible License(s): Apache-2.0, BSD-2-Clause, LGPL-3.0

Large files files are truncated, but you can click here to view the full file

  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. class tx_em_Install {
  35. /**
  36. * Parent module object
  37. *
  38. * @var SC_mod_tools_em_index
  39. */
  40. protected $parentObject;
  41. /**
  42. * Instance of EM API
  43. *
  44. * @var tx_em_API
  45. */
  46. protected $api;
  47. /**
  48. *
  49. * @var t3lib_install
  50. */
  51. public $install;
  52. /**
  53. * @var integer
  54. */
  55. protected $systemInstall = 0; // If "1" then installs in the sysext directory is allowed. Default: 0
  56. /**
  57. * @var boolean
  58. */
  59. protected $silentMode;
  60. /**
  61. * Constructor
  62. *
  63. * @param SC_mod_tools_em_index $parentObject
  64. */
  65. public function __construct($parentObject = NULL) {
  66. $GLOBALS['LANG']->includeLLFile(t3lib_extMgm::extPath('em', 'language/locallang.xml'));
  67. $this->parentObject = $parentObject;
  68. $this->api = t3lib_div::makeInstance('tx_em_API');
  69. $this->install = t3lib_div::makeInstance('t3lib_install');
  70. $this->install->INSTALL = t3lib_div::_GP('TYPO3_INSTALL');
  71. $this->systemInstall = isset($GLOBALS['TYPO3_CONF_VARS']['EXT']['allowSystemInstall']) && $GLOBALS['TYPO3_CONF_VARS']['EXT']['allowSystemInstall'];
  72. }
  73. /**
  74. * Set silent mode to prevent flashmessages
  75. *
  76. * @param boolean $silentMode
  77. * @return void
  78. */
  79. public function setSilentMode($silentMode) {
  80. $this->silentMode = $silentMode ? TRUE : FALSE;
  81. }
  82. /**
  83. * Imports the data of an extension from upload
  84. *
  85. * @param $uploadedTempFile
  86. * @param $location
  87. * @param bool $uploadOverwrite
  88. * @return array
  89. */
  90. public function uploadExtensionFile($uploadedTempFile, $location, $uploadOverwrite = FALSE) {
  91. $error = '';
  92. $fileContent = t3lib_div::getUrl($uploadedTempFile);
  93. if (!$fileContent) {
  94. return array(
  95. 'success' => FALSE,
  96. 'error' => $GLOBALS['LANG']->getLL('ext_import_file_empty')
  97. );
  98. }
  99. // Decode file data:
  100. $terConnection = t3lib_div::makeInstance('tx_em_Connection_Ter', $this);
  101. $fetchData = $terConnection->decodeExchangeData($fileContent);
  102. if (is_array($fetchData)) {
  103. $extKey = $fetchData[0]['extKey'];
  104. if ($extKey) {
  105. if (!$uploadOverwrite) {
  106. $comingExtPath = tx_em_Tools::typePath($location) . $extKey . '/';
  107. if (@is_dir($comingExtPath)) {
  108. $error = sprintf($GLOBALS['LANG']->getLL('ext_import_ext_present_no_overwrite'), $comingExtPath) .
  109. '<br />' . $GLOBALS['LANG']->getLL('ext_import_ext_present_nothing_done');
  110. } // ... else go on, install...
  111. } // ... else go on, install...
  112. } else {
  113. $error = $GLOBALS['LANG']->getLL('ext_import_no_key');
  114. }
  115. } else {
  116. $error = sprintf($GLOBALS['LANG']->getLL('ext_import_wrong_file_format'), $fetchData);
  117. }
  118. if ($error) {
  119. return array(FALSE, $error);
  120. } else {
  121. return array(TRUE, $fetchData);
  122. }
  123. }
  124. /**
  125. * Installs an extension.
  126. *
  127. * @param $fetchData
  128. * @param $loc
  129. * @param $version
  130. * @param $uploadedTempFile
  131. * @param $dontDelete
  132. * @return mixed|string
  133. */
  134. public function installExtension($fetchData, $loc, $version, $uploadedTempFile, $dontDelete) {
  135. $xmlHandler =& $this->parentObject->xmlHandler;
  136. $extensionList =& $this->parentObject->extensionList;
  137. $extensionDetails =& $this->parentObject->extensionDetails;
  138. $content = '';
  139. if (tx_em_Tools::importAsType($loc)) {
  140. if (is_array($fetchData)) { // There was some data successfully transferred
  141. if ($fetchData[0]['extKey'] && is_array($fetchData[0]['FILES'])) {
  142. $extKey = $fetchData[0]['extKey'];
  143. if (!isset($fetchData[0]['EM_CONF']['constraints'])) {
  144. $fetchData[0]['EM_CONF']['constraints'] = $xmlHandler->extensionsXML[$extKey]['versions'][$version]['dependencies'];
  145. }
  146. $EM_CONF = tx_em_Tools::fixEMCONF($fetchData[0]['EM_CONF']);
  147. if (!$EM_CONF['lockType'] || !strcmp($EM_CONF['lockType'], $loc)) {
  148. // check dependencies, act accordingly if ext is loaded
  149. list($instExtInfo,) = $extensionList->getInstalledExtensions();
  150. $depStatus = $this->checkDependencies($extKey, $EM_CONF, $instExtInfo);
  151. if (t3lib_extMgm::isLoaded($extKey) && !$depStatus['returnCode']) {
  152. $content .= $depStatus['html'];
  153. if ($uploadedTempFile) {
  154. $content .= '<input type="hidden" name="CMD[alreadyUploaded]" value="' . $uploadedTempFile . '" />';
  155. }
  156. } else {
  157. $res = $this->clearAndMakeExtensionDir($fetchData[0], $loc, $dontDelete);
  158. if (is_array($res)) {
  159. $extDirPath = trim($res[0]);
  160. if ($extDirPath && @is_dir($extDirPath) && substr($extDirPath, -1) == '/') {
  161. $emConfFile = $extensionDetails->construct_ext_emconf_file($extKey, $EM_CONF);
  162. $dirs = tx_em_Tools::extractDirsFromFileList(array_keys($fetchData[0]['FILES']));
  163. $res = tx_em_Tools::createDirsInPath($dirs, $extDirPath);
  164. if (!$res) {
  165. $writeFiles = $fetchData[0]['FILES'];
  166. $writeFiles['ext_emconf.php']['content'] = $emConfFile;
  167. $writeFiles['ext_emconf.php']['content_md5'] = md5($emConfFile);
  168. // Write files:
  169. foreach ($writeFiles as $theFile => $fileData) {
  170. t3lib_div::writeFile($extDirPath . $theFile, $fileData['content']);
  171. if (!@is_file($extDirPath . $theFile)) {
  172. if (!$this->silentMode) {
  173. $flashMessage = t3lib_div::makeInstance(
  174. 't3lib_FlashMessage',
  175. sprintf($GLOBALS['LANG']->getLL('ext_import_file_not_created'),
  176. $extDirPath . $theFile),
  177. '',
  178. t3lib_FlashMessage::ERROR
  179. );
  180. $content .= $flashMessage->render();
  181. } else {
  182. if (!$this->silentMode) {
  183. $flashMessage = t3lib_div::makeInstance(
  184. 't3lib_FlashMessage',
  185. sprintf($GLOBALS['LANG']->getLL('ext_import_file_not_created'), $extDirPath . $theFile),
  186. '',
  187. t3lib_FlashMessage::ERROR
  188. );
  189. $content .= $flashMessage->render();
  190. } else {
  191. $content .= sprintf($GLOBALS['LANG']->getLL('ext_import_file_not_created'),
  192. $extDirPath . $theFile) . '<br />';
  193. }
  194. }
  195. } elseif (md5(t3lib_div::getUrl($extDirPath . $theFile)) != $fileData['content_md5']) {
  196. $content .= sprintf($GLOBALS['LANG']->getLL('ext_import_file_corrupted'),
  197. $extDirPath . $theFile) . '<br />';
  198. }
  199. }
  200. t3lib_div::fixPermissions($extDirPath, TRUE);
  201. // No content, no errors. Create success output here:
  202. if (!$content) {
  203. $messageContent = sprintf($GLOBALS['LANG']->getLL('ext_import_success_folder'), $extDirPath) . '<br />';
  204. $uploadSucceed = true;
  205. // Fix TYPO3_MOD_PATH for backend modules in extension:
  206. $modules = t3lib_div::trimExplode(',', $EM_CONF['module'], 1);
  207. if (count($modules)) {
  208. foreach ($modules as $mD) {
  209. $confFileName = $extDirPath . $mD . '/conf.php';
  210. if (@is_file($confFileName)) {
  211. $messageContent .= tx_em_Tools::writeTYPO3_MOD_PATH($confFileName, $loc, $extKey . '/' . $mD . '/') . '<br />';
  212. } else {
  213. $messageContent .= sprintf($GLOBALS['LANG']->getLL('ext_import_no_conf_file'),
  214. $confFileName) . '<br />';
  215. }
  216. }
  217. }
  218. // 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.
  219. // But this order of the code works.... (using the empty Array with type, EMCONF and files hereunder).
  220. // Writing to ext_emconf.php:
  221. $sEMD5A = $extensionDetails->serverExtensionMD5array($extKey, array('type' => $loc, 'EM_CONF' => array(), 'files' => array()));
  222. $EM_CONF['_md5_values_when_last_written'] = serialize($sEMD5A);
  223. $emConfFile = $extensionDetails->construct_ext_emconf_file($extKey, $EM_CONF);
  224. t3lib_div::writeFile($extDirPath . 'ext_emconf.php', $emConfFile);
  225. $messageContent .= 'ext_emconf.php: ' . $extDirPath . 'ext_emconf.php<br />';
  226. $messageContent .= $GLOBALS['LANG']->getLL('ext_import_ext_type') . ' ';
  227. $messageContent .= $this->api->typeLabels[$loc] . '<br />';
  228. $messageContent .= '<br />';
  229. // Remove cache files:
  230. $updateContent = '';
  231. if (t3lib_extMgm::isLoaded($extKey)) {
  232. if (t3lib_extMgm::removeCacheFiles()) {
  233. $messageContent .= $GLOBALS['LANG']->getLL('ext_import_cache_files_removed') . '<br />';
  234. }
  235. list($new_list) = $this->parentObject->extensionList->getInstalledExtensions();
  236. $updateContent = $this->updatesForm($extKey, $new_list[$extKey], 1, t3lib_div::linkThisScript(array(
  237. 'CMD[showExt]' => $extKey,
  238. 'SET[singleDetails]' => 'info'
  239. )));
  240. }
  241. if (!$this->silentMode) {
  242. $flashMessage = t3lib_div::makeInstance(
  243. 't3lib_FlashMessage',
  244. $messageContent,
  245. $GLOBALS['LANG']->getLL('ext_import_success')
  246. );
  247. $content = $flashMessage->render();
  248. } else {
  249. $content = $updateContent;
  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 />';
  272. if ($this->silentMode || t3lib_div::_GP('nodoc')) {
  273. $content .= '<a id="closewindow" href="javascript:parent.TYPO3.EM.Tools.closeImportWindow();">' . $GLOBALS['LANG']->getLL('ext_import_close') . '</a>';
  274. } else {
  275. $content .= '<a href="javascript:opener.top.list.iframe.document.forms[0].submit();window.close();">' .
  276. $GLOBALS['LANG']->getLL('ext_import_close_check') . '</a>';
  277. }
  278. }
  279. }
  280. } else {
  281. if (!$this->silentMode) {
  282. $flashMessage = t3lib_div::makeInstance(
  283. 't3lib_FlashMessage',
  284. $res,
  285. '',
  286. t3lib_FlashMessage::ERROR
  287. );
  288. $content = $flashMessage->render();
  289. } else {
  290. $content = $res;
  291. }
  292. }
  293. } else {
  294. if (!$this->silentMode) {
  295. $flashMessage = t3lib_div::makeInstance(
  296. 't3lib_FlashMessage',
  297. sprintf($GLOBALS['LANG']->getLL('ext_import_ext_path_different'), $extDirPath),
  298. '',
  299. t3lib_FlashMessage::ERROR
  300. );
  301. $content = $flashMessage->render();
  302. } else {
  303. $content = sprintf($GLOBALS['LANG']->getLL('ext_import_ext_path_different'), $extDirPath);
  304. }
  305. }
  306. } else {
  307. if (!$this->silentMode) {
  308. $flashMessage = t3lib_div::makeInstance(
  309. 't3lib_FlashMessage',
  310. $res,
  311. '',
  312. t3lib_FlashMessage::ERROR
  313. );
  314. $content = $flashMessage->render();
  315. } else {
  316. $content = $res;
  317. }
  318. }
  319. }
  320. } else {
  321. if (!$this->silentMode) {
  322. $flashMessage = t3lib_div::makeInstance(
  323. 't3lib_FlashMessage',
  324. sprintf($GLOBALS['LANG']->getLL('ext_import_ext_only_here'),
  325. $this->typePaths[$EM_CONF['lockType']], $EM_CONF['lockType']),
  326. '',
  327. t3lib_FlashMessage::ERROR
  328. );
  329. $content = $flashMessage->render();
  330. } else {
  331. $content = sprintf($GLOBALS['LANG']->getLL('ext_import_ext_only_here'),
  332. tx_em_Tools::typePath($EM_CONF['lockType']), $EM_CONF['lockType']);
  333. }
  334. }
  335. } else {
  336. if (!$this->silentMode) {
  337. $flashMessage = t3lib_div::makeInstance(
  338. 't3lib_FlashMessage',
  339. $GLOBALS['LANG']->getLL('ext_import_no_ext_key_files'),
  340. '',
  341. t3lib_FlashMessage::ERROR
  342. );
  343. $content = $flashMessage->render();
  344. } else {
  345. $content = $GLOBALS['LANG']->getLL('ext_import_no_ext_key_files');
  346. }
  347. }
  348. } else {
  349. if (!$this->silentMode) {
  350. $flashMessage = t3lib_div::makeInstance(
  351. 't3lib_FlashMessage',
  352. sprintf($GLOBALS['LANG']->getLL('ext_import_data_transfer'), $fetchData),
  353. '',
  354. t3lib_FlashMessage::ERROR
  355. );
  356. $content = $flashMessage->render();
  357. } else {
  358. $content = sprintf($GLOBALS['LANG']->getLL('ext_import_data_transfer'), $fetchData);
  359. }
  360. }
  361. } else {
  362. if (!$this->silentMode) {
  363. $flashMessage = t3lib_div::makeInstance(
  364. 't3lib_FlashMessage',
  365. sprintf($GLOBALS['LANG']->getLL('ext_import_no_install_here'), $this->typePaths[$loc]),
  366. '',
  367. t3lib_FlashMessage::ERROR
  368. );
  369. $content = $flashMessage->render();
  370. } else {
  371. $content = sprintf($GLOBALS['LANG']->getLL('ext_import_no_install_here'), tx_em_Tools::typePath($loc));
  372. }
  373. }
  374. return $content;
  375. }
  376. /**
  377. *Check extension dependencies
  378. *
  379. * @param string $extKey
  380. * @param array $conf
  381. * @param array $instExtInfo
  382. * @return array
  383. */
  384. function checkDependencies($extKey, $conf, $instExtInfo) {
  385. $content = '';
  386. $depError = false;
  387. $depIgnore = false;
  388. $msg = array();
  389. $depsolver = t3lib_div::_POST('depsolver');
  390. if (isset($conf['constraints']['depends']) && is_array($conf['constraints']['depends'])) {
  391. foreach ($conf['constraints']['depends'] as $depK => $depV) {
  392. if ($depsolver['ignore'][$depK]) {
  393. $msg[] = '<br />' . sprintf($GLOBALS['LANG']->getLL('checkDependencies_ignored'),
  394. $depK) . '
  395. <input type="hidden" value="1" name="depsolver[ignore][' . $depK . ']" />';
  396. $depIgnore = true;
  397. continue;
  398. }
  399. if ($depK == 'php') {
  400. if (!$depV) {
  401. continue;
  402. }
  403. $versionRange = tx_em_Tools::splitVersionRange($depV);
  404. $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!
  405. if ($versionRange[0] != '0.0.0' && version_compare($phpv, $versionRange[0], '<')) {
  406. $msg[] = '<br />' . sprintf($GLOBALS['LANG']->getLL('checkDependencies_php_too_low'),
  407. $phpv, $versionRange[0]);
  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. } elseif ($versionRange[1] != '0.0.0' && version_compare($phpv, $versionRange[1], '>')) {
  413. $msg[] = '<br />' . sprintf($GLOBALS['LANG']->getLL('checkDependencies_php_too_high'),
  414. $phpv, $versionRange[1]);
  415. $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" value="1" name="depsolver[ignore][' . $depK . ']" id="checkIgnore_' . $depK . '" />
  416. <label for="checkIgnore_' . $depK . '">' . $GLOBALS['LANG']->getLL('checkDependencies_ignore_requirement') . '</label>';
  417. $depError = true;
  418. continue;
  419. }
  420. } elseif ($depK == 'typo3') {
  421. if (!$depV) {
  422. continue;
  423. }
  424. // if the current TYPO3 version is a development version (like TYPO3 4.4-dev),
  425. // then it should behave like TYPO3 4.4.0
  426. $t3version = TYPO3_version;
  427. if (stripos($t3version, '-dev')
  428. || stripos($t3version, '-alpha')
  429. || stripos($t3version, '-beta')
  430. || stripos($t3version, '-RC')) {
  431. // find the last occurence of "-" and replace that part with a ".0"
  432. $t3version = substr($t3version, 0, strrpos($t3version, '-')) . '.0';
  433. }
  434. $versionRange = tx_em_Tools::splitVersionRange($depV);
  435. if ($versionRange[0] != '0.0.0' && version_compare($t3version, $versionRange[0], '<')) {
  436. $msg[] = '<br />' . sprintf($GLOBALS['LANG']->getLL('checkDependencies_typo3_too_low'),
  437. $t3version, $versionRange[0]);
  438. $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" value="1" name="depsolver[ignore][' . $depK . ']" id="checkIgnore_' . $depK . '" />
  439. <label for="checkIgnore_' . $depK . '">' . $GLOBALS['LANG']->getLL('checkDependencies_ignore_requirement') . '</label>';
  440. $depError = true;
  441. continue;
  442. } elseif ($versionRange[1] != '0.0.0' && version_compare($t3version, $versionRange[1], '>')) {
  443. $msg[] = '<br />' . sprintf($GLOBALS['LANG']->getLL('checkDependencies_typo3_too_high'),
  444. $t3version, $versionRange[1]);
  445. $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" value="1" name="depsolver[ignore][' . $depK . ']" id="checkIgnore_' . $depK . '" />
  446. <label for="checkIgnore_' . $depK . '">' . $GLOBALS['LANG']->getLL('checkDependencies_ignore_requirement') . '</label>';
  447. $depError = true;
  448. continue;
  449. }
  450. } elseif (strlen($depK) && !t3lib_extMgm::isLoaded($depK)) { // strlen check for braindead empty dependencies coming from extensions...
  451. if (!isset($instExtInfo[$depK])) {
  452. $msg[] = '<br />' . sprintf($GLOBALS['LANG']->getLL('checkDependencies_ext_not_available'),
  453. $depK);
  454. $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;' . t3lib_iconWorks::getSpriteIcon('actions-system-extension-import', array('title' => $GLOBALS['LANG']->getLL('checkDependencies_import_ext'))) . '&nbsp;
  455. <a href="' . t3lib_div::linkThisUrl($this->parentObject->script, array(
  456. 'CMD[importExt]' => $depK,
  457. 'CMD[loc]' => 'L',
  458. 'CMD[standAlone]' => 1
  459. )) . '" target="_blank">' . $GLOBALS['LANG']->getLL('checkDependencies_import_now') . '</a>';
  460. $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" value="1" name="depsolver[ignore][' . $depK . ']" id="checkIgnore_' . $depK . '" />
  461. <label for="checkIgnore_' . $depK . '">' . $GLOBALS['LANG']->getLL('checkDependencies_ignore_ext_requirement') . '</label>';
  462. } else {
  463. $msg[] = '<br />' . sprintf($GLOBALS['LANG']->getLL('checkDependencies_ext_not_installed'),
  464. $depK, $instExtInfo[$depK]['EM_CONF']['title']);
  465. $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;' . tx_em_Tools::installButton() . '&nbsp;
  466. <a href="' . t3lib_div::linkThisUrl($this->parentObject->script, array(
  467. 'CMD[showExt]' => $depK,
  468. 'CMD[load]' => 1,
  469. 'CMD[clrCmd]' => 1,
  470. 'CMD[standAlone]' => 1,
  471. 'SET[singleDetails]' => 'info'
  472. )) .
  473. '" target="_blank">' . $GLOBALS['LANG']->getLL('checkDependencies_install_now') . '</a>';
  474. $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" value="1" name="depsolver[ignore][' . $depK . ']" id="checkIgnore_' . $depK . '" />
  475. <label for="checkIgnore_' . $depK . '">' . $GLOBALS['LANG']->getLL('checkDependencies_ignore_ext_requirement') . '</label>';
  476. }
  477. $depError = true;
  478. } else {
  479. $versionRange = tx_em_Tools::splitVersionRange($depV);
  480. if ($versionRange[0] != '0.0.0' && version_compare($instExtInfo[$depK]['EM_CONF']['version'], $versionRange[0], '<')) {
  481. $msg[] = '<br />' . sprintf($GLOBALS['LANG']->getLL('checkDependencies_ext_too_low'),
  482. $depK, $instExtInfo[$depK]['EM_CONF']['version'], $versionRange[0]);
  483. $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" value="1" name="depsolver[ignore][' . $depK . ']" id="checkIgnore_' . $depK . '" />
  484. <label for="checkIgnore_' . $depK . '">' . $GLOBALS['LANG']->getLL('checkDependencies_ignore_requirement') . '</label>';
  485. $depError = true;
  486. continue;
  487. } elseif ($versionRange[1] != '0.0.0' && version_compare($instExtInfo[$depK]['EM_CONF']['version'], $versionRange[1], '>')) {
  488. $msg[] = '<br />' . sprintf($GLOBALS['LANG']->getLL('checkDependencies_ext_too_high'),
  489. $depK, $instExtInfo[$depK]['EM_CONF']['version'], $versionRange[1]);
  490. $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" value="1" name="depsolver[ignore][' . $depK . ']" id="checkIgnore_' . $depK . '" />
  491. <label for="checkIgnore_' . $depK . '">' . $GLOBALS['LANG']->getLL('checkDependencies_ignore_requirement') . '</label>';
  492. $depError = true;
  493. continue;
  494. }
  495. }
  496. }
  497. }
  498. if (($depError || $depIgnore) && $this->parentObject instanceof SC_mod_tools_em_index) {
  499. $content .= $this->parentObject->doc->section(
  500. $GLOBALS['LANG']->getLL('removeExtFromList_dependency_error'),
  501. implode('<br />', $msg), 0, 1, 2
  502. );
  503. }
  504. // Check conflicts with other extensions:
  505. $conflictError = false;
  506. $conflictIgnore = false;
  507. $msg = array();
  508. if (isset($conf['constraints']['conflicts']) && is_array($conf['constraints']['conflicts'])) {
  509. foreach ((array) $conf['constraints']['conflicts'] as $conflictK => $conflictV) {
  510. if ($depsolver['ignore'][$conflictK]) {
  511. $msg[] = '<br />' . sprintf($GLOBALS['LANG']->getLL('checkDependencies_conflict_ignored'),
  512. $conflictK) . '
  513. <input type="hidden" value="1" name="depsolver[ignore][' . $conflictK . ']" />';
  514. $conflictIgnore = true;
  515. continue;
  516. }
  517. if (t3lib_extMgm::isLoaded($conflictK)) {
  518. $versionRange = tx_em_Tools::splitVersionRange($conflictV);
  519. if ($versionRange[0] != '0.0.0' && version_compare($instExtInfo[$conflictK]['EM_CONF']['version'], $versionRange[0], '<')) {
  520. continue;
  521. }
  522. elseif ($versionRange[1] != '0.0.0' && version_compare($instExtInfo[$conflictK]['EM_CONF']['version'], $versionRange[1], '>')) {
  523. continue;
  524. }
  525. $msg[] = sprintf($GLOBALS['LANG']->getLL('checkDependencies_conflict_remove'),
  526. $extKey, $conflictK, $instExtInfo[$conflictK]['EM_CONF']['title'], $conflictK, $extKey);
  527. $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;' . tx_em_Tools::removeButton() . '&nbsp;
  528. <a href="' . htmlspecialchars(t3lib_div::linkThisScript(array(
  529. 'CMD[showExt]' => $conflictK,
  530. 'CMD[remove]' => 1,
  531. 'CMD[clrCmd]' => 1,
  532. 'CMD[standAlone]' => 1,
  533. 'SET[singleDetails]' => 'info'
  534. ))) .
  535. '" target="_blank">' . $GLOBALS['LANG']->getLL('checkDependencies_remove_now') . '</a>';
  536. $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" value="1" name="depsolver[ignore][' . $conflictK . ']" id="checkIgnore_' . $conflictK . '" />
  537. <label for="checkIgnore_' . $conflictK . '">' . $GLOBALS['LANG']->getLL('checkDependencies_ignore_conflict') . '</label>';
  538. $conflictError = true;
  539. }
  540. }
  541. }
  542. if ($conflictError || $conflictIgnore) {
  543. $content .= $this->parentObject->doc->section(
  544. $GLOBALS['LANG']->getLL('checkDependencies_conflict_error'), implode('<br />', $msg), 0, 1, 2
  545. );
  546. }
  547. // Check suggests on other extensions:
  548. if (isset($conf['constraints']['suggests']) && is_array($conf['constraints']['suggests'])) {
  549. $suggestion = false;
  550. $suggestionIgnore = false;
  551. $msg = array();
  552. foreach ($conf['constraints']['suggests'] as $suggestK => $suggestV) {
  553. if ($depsolver['ignore'][$suggestK]) {
  554. $msg[] = '<br />' . sprintf($GLOBALS['LANG']->getLL('checkDependencies_suggestion_ignored'),
  555. $suggestK) . '
  556. <input type="hidden" value="1" name="depsolver[ignore][' . $suggestK . ']" />';
  557. $suggestionIgnore = true;
  558. continue;
  559. }
  560. if (!t3lib_extMgm::isLoaded($suggestK)) {
  561. if (!isset($instExtInfo[$suggestK])) {
  562. $msg[] = sprintf($GLOBALS['LANG']->getLL('checkDependencies_suggest_import'),
  563. $suggestK);
  564. $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;' . t3lib_iconWorks::getSpriteIcon('actions-system-extension-import', array('title' => $GLOBALS['LANG']->getLL('checkDependencies_import_ext'))) . '&nbsp;
  565. <a href="' . t3lib_div::linkThisScript(array(
  566. 'CMD[importExt]' => $suggestK,
  567. 'CMD[loc]' => 'L',
  568. 'CMD[standAlone]' => 1
  569. )) . '" target="_blank">' . $GLOBALS['LANG']->getLL('checkDependencies_import_now') . '</a>';
  570. $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" value="1" name="depsolver[ignore][' . $suggestK . ']" id="checkIgnore_' . $suggestK . '" />
  571. <label for="checkIgnore_' . $suggestK . '">' . $GLOBALS['LANG']->getLL('checkDependencies_ignore_suggestion') . '</label>';
  572. } else {
  573. $msg[] = sprintf($GLOBALS['LANG']->getLL('checkDependencies_suggest_installation'),
  574. $suggestK, $instExtInfo[$suggestK]['EM_CONF']['title']);
  575. $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;' . tx_em_Tools::installButton() . '&nbsp;
  576. <a href="' . htmlspecialchars(t3lib_div::linkThisScript(array(
  577. 'CMD[showExt]' => $suggestK,
  578. 'CMD[load]' => 1,
  579. 'CMD[clrCmd]' => 1,
  580. 'CMD[standAlone]' => 1,
  581. 'SET[singleDetails]' => 'info'
  582. ))) .
  583. '" target="_blank">' . $GLOBALS['LANG']->getLL('checkDependencies_install_now') . '</a>';
  584. $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" value="1" name="depsolver[ignore][' . $suggestK . ']" id="checkIgnore_' . $suggestK . '" />
  585. <label for="checkIgnore_' . $suggestK . '">' . $GLOBALS['LANG']->getLL('checkDependencies_ignore_suggestion') . '</label>';
  586. }
  587. $suggestion = true;
  588. }
  589. }
  590. if ($suggestion || $suggestionIgnore) {
  591. $content .= $this->parentObject->doc->section(
  592. sprintf($GLOBALS['LANG']->getLL('checkDependencies_exts_suggested_by_ext'), $extKey),
  593. implode('<br />', $msg), 0, 1, 1
  594. );
  595. }
  596. }
  597. if ($depError || $conflictError || $suggestion) {
  598. foreach ($this->parentObject->CMD as $k => $v) {
  599. $content .= '<input type="hidden" name="CMD[' . $k . ']" value="' . $v . '" />';
  600. }
  601. $content .= '<br /><br /><input type="submit" value="' . $GLOBALS['LANG']->getLL('checkDependencies_try_again') . '" />';
  602. if (t3lib_div::_GP('nodoc')) {
  603. $content .= '<input type="hidden" name="nodoc" value="1" />';
  604. }
  605. return array(
  606. 'returnCode' => FALSE,
  607. 'html' => '<form action="' . $this->parentObject->script . '" method="post" name="depform">' . $content . '</form>');
  608. }
  609. return array(
  610. 'returnCode' => TRUE
  611. );
  612. }
  613. /**
  614. * Delete extension from the file system
  615. *
  616. * @param string Extension key
  617. * @param array Extension info array
  618. * @return string Returns message string about the status of the operation
  619. */
  620. function extDelete($extKey, $extInfo, $command) {
  621. $content = '';
  622. $absPath = tx_em_Tools::getExtPath($extKey, $extInfo['type']);
  623. if (t3lib_extMgm::isLoaded($extKey)) {
  624. return $GLOBALS['LANG']->getLL('extDelete_ext_active');
  625. } elseif (!tx_em_Tools::deleteAsType($extInfo['type'])) {
  626. return sprintf($GLOBALS['LANG']->getLL('extDelete_wrong_scope'),
  627. $this->api->typeLabels[$extInfo['type']]
  628. );
  629. } elseif (t3lib_div::inList('G,L', $extInfo['type'])) {
  630. if ($command['doDelete'] && !strcmp($absPath, urldecode($command['absPath']))) {
  631. $res = $this->removeExtDirectory($absPath);
  632. if ($res) {
  633. if (!$this->silentMode) {
  634. $flashMessage = t3lib_div::makeInstance(
  635. 't3lib_FlashMessage',
  636. nl2br($res),
  637. sprintf($GLOBALS['LANG']->getLL('extDelete_remove_dir_failed'), $absPath),
  638. t3lib_FlashMessage::ERROR
  639. );
  640. return $flashMessage->render();
  641. }
  642. return '';
  643. } else {
  644. if (!$this->silentMode) {
  645. $flashMessage = t3lib_div::makeInstance(
  646. 't3lib_FlashMessage',
  647. sprintf($GLOBALS['LANG']->getLL('extDelete_removed'), $absPath),
  648. $GLOBALS['LANG']->getLL('extDelete_removed_header'),
  649. t3lib_FlashMessage::OK
  650. );
  651. return $flashMessage->render();
  652. }
  653. return '';
  654. }
  655. } else {
  656. $areYouSure = $GLOBALS['LANG']->getLL('extDelete_sure');
  657. $deleteFromServer = $GLOBALS['LANG']->getLL('extDelete_from_server');
  658. $onClick = "if (confirm('$areYouSure')) {window.location.href='" . t3lib_div::linkThisScript(array(
  659. 'CMD[showExt]' => $extKey,
  660. 'CMD[doDelete]' => 1,
  661. 'CMD[absPath]' => rawurlencode($absPath)
  662. )) . "';}";
  663. $content .= '<a class="t3-link deleteLink" href="#" onclick="' . htmlspecialchars($onClick) .
  664. ' return false;"><strong>' . $deleteFromServer . '</strong> ' .
  665. sprintf($GLOBALS['LANG']->getLL('extDelete_from_location'),
  666. $this->api->typeLabels[$extInfo['type']],
  667. substr($absPath, strlen(PATH_site))
  668. ) . '</a>';
  669. $content .= '<br /><br />' . $GLOBALS['LANG']->getLL('extDelete_backup');
  670. return $content;
  671. }
  672. } else {
  673. return $GLOBALS['LANG']->getLL('extDelete_neither_global_nor_local');
  674. }
  675. }
  676. /**
  677. * Removes the extension directory (including content)
  678. *
  679. * @param string Extension directory to remove (with trailing slash)
  680. * @param boolean If set, will leave the extension directory
  681. * @return boolean False on success, otherwise error string.
  682. */
  683. function removeExtDirectory($removePath, $removeContentOnly = 0) {
  684. $errors = array();
  685. if (@is_dir($removePath) && substr($removePath, -1) == '/' && (
  686. t3lib_div::isFirstPartOfStr($removePath, tx_em_Tools::typePath('G')) ||
  687. t3lib_div::isFirstPartOfStr($removePath, tx_em_Tools::typePath('L')) ||
  688. (t3lib_div::isFirstPartOfStr($removePath, tx_em_Tools::typePath('S')) && $this->systemInstall) ||
  689. t3lib_div::isFirstPartOfStr($removePath, PATH_site . $GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'] . '_temp_/')) // Playing-around directory...
  690. ) {
  691. // All files in extension directory:
  692. $fileArr = t3lib_div::getAllFilesAndFoldersInPath(array(), $removePath, '', 1);
  693. if (is_array($fileArr)) {
  694. // Remove files in dirs:
  695. foreach ($fileArr as $removeFile) {
  696. if (!@is_dir($removeFile)) {
  697. 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!
  698. @unlink($removeFile);
  699. clearstatcache();
  700. if (@is_file($removeFile)) {
  701. $errors[] = sprintf($GLOBALS['LANG']->getLL('rmExtDir_could_not_be_deleted'),
  702. $removeFile
  703. );
  704. }
  705. } else {
  706. $errors[] = sprintf($GLOBALS['LANG']->getLL('rmExtDir_error_file'),
  707. $removeFile, $removePath
  708. );
  709. }
  710. }
  711. }
  712. // Remove directories:
  713. $remDirs = tx_em_Tools::extractDirsFromFileList(t3lib_div::removePrefixPathFromList($fileArr, $removePath));
  714. $remDirs = array_reverse($remDirs); // Must delete outer directories first...
  715. foreach ($remDirs as $removeRelDir) {
  716. $removeDir = $removePath . $removeRelDir;
  717. if (@is_dir($removeDir)) {
  718. @rmdir($removeDir);
  719. clearstatcache();
  720. if (@is_dir($removeDir)) {
  721. $errors[] = sprintf($GLOBALS['LANG']->getLL('rmExtDir_error_files_left'),
  722. $removeDir
  723. );
  724. }
  725. } else {
  726. $errors[] = sprintf($GLOBALS['LANG']->getLL('rmExtDir_error_no_dir'),
  727. $removeDir
  728. );
  729. }
  730. }
  731. // If extension dir should also be removed:
  732. if (!$removeContentOnly) {
  733. @rmdir($removePath);
  734. clearstatcache();
  735. if (@is_dir($removePath)) {
  736. $errors[] = sprintf($GLOBALS['LANG']->getLL('rmExtDir_error_folders_left'),
  737. $removePath
  738. );
  739. }
  740. }
  741. } else {
  742. $errors[] = $GLOBALS['LANG']->getLL('rmExtDir_error') . ' ' . $fileArr;
  743. }
  744. } else {
  745. $errors[] = $GLOBALS['LANG']->getLL('rmExtDir_error_unallowed_path') . ' ' . $removePath;
  746. }
  747. // Return errors if any:
  748. return implode(LF, $errors);
  749. }
  750. /**
  751. * Validates the database according to extension requirements
  752. * Prints form for changes if any. If none, returns blank. If an update is ordered, empty is returned as well.
  753. * DBAL compliant (based on Install Tool code)
  754. *
  755. * @param string Extension key
  756. * @param array Extension information array
  757. * @param boolean If true, returns array with info.
  758. * @return mixed If $infoOnly, returns array with information. Otherwise performs update.
  759. */
  760. function checkDBupdates($extKey, $extInfo, $infoOnly = 0) {
  761. $dbStatus = array();
  762. $content = '';
  763. // Updating tables and fields?
  764. if (is_array($extInfo['files']) && in_array('ext_tables.sql', $extInfo['files'])) {
  765. $path = tx_em_Tools::getExtPath($extKey, $extInfo['type']);
  766. $fileContent = t3lib_div::getUrl($path . 'ext_tables.sql');
  767. $FDfile = $this->install->getFieldDefinitions_fileContent($fileContent);
  768. if (count($FDfile)) {
  769. $FDdb = $this->install->getFieldDefinitions_database(TYPO3_db);
  770. $diff = $this->install->getDatabaseExtra($FDfile, $FDdb);
  771. $update_statements = $this->install->getUpdateSuggestions($diff);
  772. $dbStatus['structure']['tables_fields'] = $FDfile;
  773. $dbStatus['structure']['diff'] = $diff;
  774. // Updating database...
  775. if (!$infoOnly && is_array($this->install->INSTALL['database_update'])) {
  776. $this->install->performUpdateQueries($update_statements['add'], $this->install->INSTALL['database_update']);
  777. $this->install->performUpdateQueries($update_statements['change'], $this->install->INSTALL['database_update']);
  778. $this->install->performUpdateQueries($update_statements['create_table'], $this->install->INSTALL['database_update']);
  779. } else {
  780. $content .= $this->install->generateUpdateDatabaseForm_checkboxes(
  781. $update_statements['add'], $GLOBALS['LANG']->getLL('checkDBupdates_add_fields'));
  782. $content .= $this->install->generateUpdateDatabaseForm_checkboxes(
  783. $update_statements['change'], $GLOBALS['LANG']->getLL('checkDBupdates_changing_fields'), 1, 0, $update_statements['change_currentValue']);
  784. $content .= $this->install->generateUpdateDatabaseForm_checkboxes(
  785. $update_statements['create_table'], $GLOBALS['LANG']->getLL('checkDBupdates_add_tables'));
  786. }
  787. }
  788. }
  789. // Importing static tables?
  790. if (is_array($extInfo['files']) && in_array('ext_tables_static+adt.sql', $extInfo['files'])) {
  791. $fileContent = t3lib_div::getUrl(tx_em_Tools::getExtPath($extKey, $extInfo['type']) . 'ext_tables_static+adt.sql');
  792. $statements = $this->install->getStatementarray($fileContent, 1);
  793. list($statements_table, $insertCount) = $this->install->getCreateTables($statements, 1);
  794. // Execute import of static table content:
  795. if (!$infoOnly && is_array($this->install->INSTALL['database_import'])) {
  796. // Traverse the tables
  797. foreach ($this->install->INSTALL['database_import'] as $table => $md5str) {
  798. if ($md5str == md5($statements_table[$table])) {
  799. $GLOBALS['TYPO3_DB']->admin_query('DROP TABLE IF EXISTS ' . $table);
  800. $GLOBALS['TYPO3_DB']->admin_query($statements_table[$table]);
  801. if ($insertCount[$table]) {
  802. $statements_insert = $this->install->getTableInsertStatements($statements, $table);
  803. foreach ($statements_insert as $v) {
  804. $GLOBALS['TYPO3_DB']->admin_query($v);
  805. }
  806. }
  807. }
  808. }
  809. } else {
  810. $whichTables = $this->install->getListOfTables();
  811. if (count($statements_table)) {
  812. $out = '';
  813. foreach ($statements_table as $table => $definition) {
  814. $exist = isset($whichTables[$table]);
  815. $dbStatus['static'][$table]['exists'] = $exist;
  816. $dbStatus['static'][$table]['count'] = $insertCount[$table];
  817. $out .= '<tr>
  818. <td><input type="checkbox" name="TYPO3_INSTALL[database_import][' . $table . ']" checked="checked" value="' . md5($definition) . '" /></td>
  819. <td><strong>' . $table . '</strong></td>
  820. <td><img src="clear.gif" width="10" height="1" alt="" /></td>
  821. <td nowrap="nowrap">' .
  822. ($insertCount[$table] ?
  823. $GLOBALS['LANG']->getLL('checkDBupdates_rows') . ' ' . $insertCount[$table]
  824. : '') .
  825. '</td>
  826. <td><img src="clear.gif" width="10" height="1" alt="" /></td>
  827. <td nowrap="nowrap">' .
  828. ($exist ?
  829. t3lib_iconWorks::getSpriteIcon('status-dialog-warning') .
  830. $GLOBALS['LANG']->getLL('checkDBupdates_table_exists')
  831. : '') .
  832. '</td>
  833. </tr>';
  834. }
  835. $content .= '
  836. <br />
  837. <h3>' . $GLOBALS['LANG']->getLL('checkDBupdates_import_static_data') . '</h3>
  838. <table border="0" cellpadding="0" cellspacing="0">' . $out . '</table>
  839. ';
  840. }
  841. }
  842. }
  843. // Return array of information if $infoOnly, otherwise content.
  844. return $infoOnly ? $dbStatus : $content;
  845. }
  846. /**
  847. * Removes the current extension of $type and creates the base folder for the new one (which is going to be imported)
  848. *
  849. * @param array Data for imported extension
  850. * @param string Extension installation scope (L,G,S)
  851. * @param boolean If set, nothing will be deleted (neither directory nor files)
  852. * @return mixed Returns array on success (with extension directory), otherwise an error string.
  853. */
  854. function clearAndMakeExtensionDir($importedData, $type, $dontDelete = 0) {
  855. if (!$importedData['extKey']) {
  856. return $GLOBALS['LANG']->getLL('clearMakeExtDir_no_ext_key');
  857. }
  858. // Setting install path (L, G, S or fileadmin/_temp_/)
  859. $path = '';
  860. switch ((string) $type) {
  861. case 'G':
  862. case 'L':
  863. $path = tx_em_Tools::typePath($type);
  864. $suffix = '';
  865. // Creates the typo3conf/ext/ directory if it does NOT already exist:
  866. if ((string) $type == 'L' && !@is_dir($path)) {
  867. t3lib_div::mkdir($path);
  868. }
  869. break;
  870. default:
  871. if ($this->systemInstall && (string) $type == 'S') {
  872. $path = tx_em_Tools::typePath($type);
  873. $suffix = '';
  874. } else {
  875. $path = PATH_site . $GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'] . '_temp_/';
  876. $suffix = '_' . date('dmy-His');
  877. }
  878. break;
  879. }
  880. // If the install path is OK...
  881. if ($path && @is_dir($path)) {
  882. // Set extension directory:
  883. $extDirPath = $path . $importedData['extKey'] . $suffix . '/';
  884. // Install dir was found, remove it then:
  885. if (@is_dir($extDirPath)) {
  886. if ($dontDelete) {
  887. return array($extDirPath);
  888. }
  889. $res = $this->removeExtDirectory($extDirPath);
  890. if ($res) {
  891. if (!$this->silentMode) {
  892. $flashMessage = t3lib_div::makeInstance(
  893. 't3lib_FlashMessage',
  894. nl2br($res),
  895. sprintf($GLOBALS['LANG']->getLL('clearMakeExtDir_could_not_remove_dir'), $extDirPath),
  896. t3lib_FlashMessage::ERROR
  897. );
  898. return $flashMessage->render();
  899. }
  900. return '';
  901. }
  902. }
  903. // We go create...
  904. t3lib_div::mkdir($extDirPath);
  905. if (!is_dir($extDirPath)) {
  906. return sprintf($GLOBALS['LANG']->getLL('clearMakeExtDir_could_not_create_dir'),
  907. $extDirPath);
  908. }
  909. return array($extDirPath);
  910. } else {
  911. return sprintf($GLOBALS['LANG']->getLL('clearMakeExtDir_no_dir'),
  912. $path);
  913. }
  914. }
  915. /*******************************
  916. *
  917. * Extension analyzing (detailed information)
  918. *
  919. ******************************/
  920. /**
  921. * Perform a detailed, technical analysis of the available extension on server!
  922. * Includes all kinds of verifications
  923. * Takes some time to process, therfore use with care, in particular in listings.
  924. *
  925. * @param string Extension key
  926. * @param array Extension information
  927. * @param boolean If set, checks for validity of classes etc.
  928. * @return array Information in an array.
  929. */
  930. function makeDetailedExtensionAnalysis($extKey, $extInfo, $validity = 0) {
  931. // Get absolute path of the extension
  932. $absPath = tx_em_Tools::getExtPath($extKey, $extInfo['type']);
  933. $extensionDetails = t3lib_div::makeInstance('tx_em_Extensions_Details', $this);
  934. $infoArray = array();
  935. $table_class_prefix = substr($extKey, 0, 5) == 'user_' ? 'user_' : 'tx_' . str_replace('_', '', $extKey) . '_';
  936. $module_prefix = substr($extKey, 0, 5) == 'user_' ? 'u' : 'tx' . str_replace('_', '', $extKey);
  937. // Database status:
  938. $dbInfo = $this->checkDBupdates($extKey, $extInfo, 1);
  939. // Database structure required:
  940. if (is_array($dbInfo['structure']['tables_fields'])) {
  941. $modify_tables = t3lib_div::trimExplode(',', $extInfo['EM_CONF']['modify_tables'], 1);
  942. $infoArray['dump_tf'] = array();
  943. foreach ($dbInfo['structure']['tables_fields'] as $tN => $d) {
  944. if (in_array($tN, $modify_tables)) {
  945. $infoArray['fields'][] = $tN . ': <i>' .
  946. (is_array($d['fields']) ? implode(', ', array_keys($d['fields'])) : '') .
  947. (is_array($d['keys']) ?
  948. ' + ' . count($d['keys']) . ' ' . $GLOBALS['LANG']->getLL('detailedExtAnalysis_keys') : '') .
  949. '</i>';
  950. if (is_array($d['fields'])) {
  951. foreach ($d['fields'] as $fN => $value) {
  952. $infoArray['dump_tf'][] = $tN . '.' . $fN;
  953. if (!t3lib_div::isFirstPartOfStr($fN, $table_class_prefix)) {
  954. $infoArray['NSerrors']['fields'][$fN] = $fN;
  955. } else {
  956. $infoArray['NSok']['fields'][$fN] = $fN;
  957. }
  958. }
  959. }
  960. if (is_array($d['keys'])) {
  961. foreach ($d['keys'] as $fN => $value) {
  962. $infoArray['dump_tf'][] = $tN . '.KEY:' . $fN;
  963. }
  964. }
  965. } else {
  966. $infoArray['dump_tf'][] = $tN;
  967. $infoArray['tables'][] = $tN;
  968. if (!t3lib_div::isFirstPartOfStr($tN, $table_class_prefix)) {
  969. $infoArray['NSerrors']['tables'][$tN] = $tN;
  970. } else {
  971. $infoArray['NSok']['tables'][$tN] = $tN;
  972. }
  973. }
  974. }
  975. if (count($dbInfo['structure']['diff']['diff']) || count($dbInfo['structure']['diff']['extra'])) {
  976. $msg = array();
  977. if (count($dbInfo['structure']['diff']['diff'])) {
  978. $msg[] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_tables_are_missing');
  979. }
  980. if (count($dbInfo['structure']['diff']['extra'])) {
  981. $msg[] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_tables_are_of_wrong_type');
  982. }
  983. $infoArray['tables_error'] = 1;
  984. if (t3lib_extMgm::isLoaded($extKey)) {
  985. $infoArray['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_tables_are'),
  986. implode(' ' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:and') . ' ', $msg)
  987. );
  988. }
  989. }
  990. }
  991. // Static tables?
  992. if (is_array($dbInfo['static'])) {
  993. $infoArray['static'] = array_keys($dbInfo['static']);
  994. foreach ($dbInfo['static'] as $tN => $d) {
  995. if (!$d['exists']) {
  996. $infoArray['static_error'] = 1;
  997. if (t3lib_extMgm::isLoaded($extKey)) {
  998. $infoArray['errors'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_static_tables_missing');
  999. }
  1000. if (!t3lib_div::isFirstPartOfStr($tN, $table_class_prefix)) {
  1001. $infoArray['NSerrors']['tables'][$tN] = $tN;
  1002. } else {
  1003. $infoArray['NSok']['tables'][$tN] = $tN;
  1004. }
  1005. }
  1006. }
  1007. }
  1008. // Backend Module-check:
  1009. $knownModuleList = t3lib_div::trimExplode(',', $extInfo['EM_CONF']['module'], 1);
  1010. foreach ($knownModuleList as $mod) {
  1011. if (@is_dir($absPath . $mod)) {
  1012. if (@is_file($absPath . $mod . '/conf.php')) {
  1013. $confFileInfo = $extensionDetails->modConfFileAnalysis($absPath . $mod . '/conf.php');
  1014. if (is_array($confFileInfo['TYPO3_MOD_PATH'])) {
  1015. $shouldBePath = tx_em_Tools::typeRelPath($extInfo['type']) . $extKey . '/' . $mod . '/';
  1016. if (strcmp($confFileInfo['TYPO3_MOD_PATH'][1][1], $shouldBePath)) {
  1017. $infoArray['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_wrong_mod_path'),
  1018. $confFileInfo['TYPO3_MOD_PATH'][1][1],
  1019. $shouldBePath
  1020. );
  1021. }
  1022. } else {
  1023. // It seems like TYPO3_MOD_PATH and therefore also this warning is no longer needed.
  1024. // $infoArray['errors'][] = 'No definition of TYPO3_MOD_PATH constant found inside!';
  1025. }
  1026. if (is_array($confFileInfo['MCONF_name'])) {
  1027. $mName = $confFileInfo['MCONF_name'][1][1];
  1028. $mNameParts = explode('_', $mName);
  1029. $infoArray['moduleNames'][] = $mName;
  1030. if (!t3lib_div::isFirstPartOfStr($mNameParts[0], $module_prefix) &&
  1031. (!$mNameParts[1] || !t3lib_div::isFirstPartOfStr($mNameParts[1], $module_prefix))) {
  1032. $infoArray['NSerrors']['modname'][] = $mName;
  1033. } else {
  1034. $infoArray['NSok']['modname'][] = $mName;
  1035. }
  1036. } else {
  1037. $infoArray['errors'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_mconf_missing');
  1038. }
  1039. } else {
  1040. $infoArray['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_be_module_conf_missing'),
  1041. $mod . '/conf.php'
  1042. );
  1043. }
  1044. } else {
  1045. $infoArray['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_module_folder_missing'),
  1046. $mod . '/'
  1047. );
  1048. }
  1049. }
  1050. $dirs = t3lib_div::get_dirs($absPath);
  1051. if (is_array($dirs)) {
  1052. reset($dirs);
  1053. while (list(, $mod) = each($dirs)) {
  1054. if (!in_array($mod, $knownModuleList) && @is_file($absPath . $mod . '/conf.php')) {
  1055. $confFileInfo = $extensionDetails->modConfFileAnalysis($absPath . $mod . '/conf.php');
  1056. if (is_array($confFileInfo)) {
  1057. $infoArray['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_unconfigured_module'),
  1058. $mod . '/conf.php'
  1059. );
  1060. }
  1061. }
  1062. }
  1063. }
  1064. // ext_tables.php:
  1065. if (@is_file($absPath . 'ext_tables.php')) {
  1066. $content = t3lib_div::getUrl($absPath . 'ext_tables.php');
  1067. if (stristr($content, 't3lib_extMgm::addModule')) {
  1068. $infoArray['flags'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_module');
  1069. }
  1070. if (stristr($content, 't3lib_extMgm::insertModuleFunction')) {
  1071. $infoArray['flags'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_module_and_more');
  1072. }
  1073. if (stristr($content, 't3lib_div::loadTCA')) {
  1074. $infoArray['flags'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_loadTCA');
  1075. }
  1076. if (stristr($content, '$TCA[')) {
  1077. $infoArray['flags'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_TCA');
  1078. }
  1079. if (stristr($content, 't3lib_extMgm::addPlugin')) {
  1080. $infoArray['flags'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_plugin');
  1081. }
  1082. }
  1083. // ext_localconf.php:
  1084. if (@is_file($absPath . 'ext_localconf.php')) {
  1085. $content = t3lib_div::getUrl($absPath . 'ext_localconf.php');
  1086. if (stristr($content, 't3lib_extMgm::addPItoST43')) {
  1087. $infoArray['flags'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_plugin_st43');
  1088. }
  1089. if (stristr($content, 't3lib_extMgm::addPageTSConfig')) {
  1090. $infoArray['flags'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_page_ts');
  1091. }
  1092. if (stristr($content, 't3lib_extMgm::addUserTSConfig')) {
  1093. $infoArray['flags'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_user_ts');
  1094. }
  1095. if (stristr($content, 't3lib_extMgm::addTypoScriptSetup')) {
  1096. $infoArray['flags'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_ts_setup');
  1097. }
  1098. if (stristr($content, 't3lib_extMgm::addTypoScriptConstants')) {
  1099. $infoArray['flags'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_ts_constants');
  1100. }
  1101. }
  1102. if (@is_file($absPath . 'ext_typoscript_constants.txt')) {
  1103. $infoArray['TSfiles'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_constants');
  1104. }
  1105. if (@is_file($absPath . 'ext_typoscript_setup.txt')) {
  1106. $infoArray['TSfiles'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_setup');
  1107. }
  1108. if (@is_file($absPath . 'ext_conf_template.txt')) {
  1109. $infoArray['conf'] = 1;
  1110. }
  1111. // Classes:
  1112. if ($validity) {
  1113. $filesInside = tx_em_Tools::getClassIndexLocallangFiles($absPath, $table_class_prefix, $extKey);
  1114. if (is_array($filesInside['errors'])) {
  1115. $infoArray['errors'] = array_merge((array) $infoArray['errors'], $filesInside['errors']);
  1116. }
  1117. if (is_array($filesInside['NSerrors'])) {
  1118. $infoArray['NSerrors'] = array_merge((array) $infoArray['NSerrors'], $filesInside['NSerrors']);
  1119. }
  1120. if (is_array($filesInside['NSok'])) {
  1121. $infoArray['NSok'] = array_merge((array) $infoArray['NSok'], $filesInside['NSok']);
  1122. }
  1123. $infoArray['locallang'] = $filesInside['locallang'];
  1124. $infoArray['classes'] = $filesInside['classes'];
  1125. }
  1126. // Upload folders
  1127. if ($extInfo['EM_CONF']['uploadfolder']) {
  1128. $infoArray['uploadfolder'] = tx_em_Tools::uploadFolder($extKey);
  1129. if (!@is_dir(PATH_site . $infoArray['uploadfolder'])) {
  1130. $infoArray['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_no_upload_folder'),
  1131. $infoArray['uploadfolder']
  1132. );
  1133. $infoArray['uploadfolder'] = '';
  1134. }
  1135. }
  1136. // Create directories:
  1137. if ($extInfo['EM_CONF']['createDirs']) {
  1138. $infoArray['createDirs'] = array_unique(t3lib_div::trimExplode(',', $extInfo['EM_CONF']['createDirs'], 1));
  1139. foreach ($infoArray['createDirs'] as $crDir) {
  1140. if (!@is_dir(PATH_site . $crDir)) {
  1141. $infoArray['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_no_upload_folder'),
  1142. $crDir
  1143. );
  1144. }
  1145. }
  1146. }
  1147. // Return result array:
  1148. return $infoArray;

Large files files are truncated, but you can click here to view the full file