PageRenderTime 46ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 1ms

/typo3/mod/tools/em/class.em_index.php

https://bitbucket.org/linxpinx/mercurial
PHP | 6205 lines | 4237 code | 708 blank | 1260 comment | 759 complexity | 63d5a84b510a060cee640d8810107b70 MD5 | raw file
Possible License(s): BSD-3-Clause, GPL-2.0, Unlicense, LGPL-2.1, Apache-2.0
  1. <?php
  2. /***************************************************************
  3. * Copyright notice
  4. *
  5. * (c) 1999-2010 Kasper Skaarhoj (kasperYYYY@typo3.com)
  6. * (c) 2005-2010 Karsten Dambekalns <karsten@typo3.org>
  7. * All rights reserved
  8. *
  9. * This script is part of the TYPO3 project. The TYPO3 project is
  10. * free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * The GNU General Public License can be found at
  16. * http://www.gnu.org/copyleft/gpl.html.
  17. * A copy is found in the textfile GPL.txt and important notices to the license
  18. * from the author is found in LICENSE.txt distributed with these scripts.
  19. *
  20. *
  21. * This script is distributed in the hope that it will be useful,
  22. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  23. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  24. * GNU General Public License for more details.
  25. *
  26. * This copyright notice MUST APPEAR in all copies of the script!
  27. ***************************************************************/
  28. /**
  29. * Module: Extension manager
  30. *
  31. * $Id: class.em_index.php 8429 2010-07-28 09:19:00Z ohader $
  32. *
  33. * @author Kasper Skaarhoj <kasperYYYY@typo3.com>
  34. * @author Karsten Dambekalns <karsten@typo3.org>
  35. */
  36. /**
  37. * [CLASS/FUNCTION INDEX of SCRIPT]
  38. *
  39. *
  40. *
  41. * 194: class SC_mod_tools_em_index extends t3lib_SCbase
  42. *
  43. * SECTION: Standard module initialization
  44. * 337: function init()
  45. * 417: function handleExternalFunctionValue($MM_key='function', $MS_value=NULL)
  46. * 431: function menuConfig()
  47. * 508: function main()
  48. * 584: function printContent()
  49. *
  50. * SECTION: Function Menu Applications
  51. * 609: function extensionList_loaded()
  52. * 664: function extensionList_installed()
  53. * 736: function extensionList_import()
  54. * 903: function alterSettings()
  55. *
  56. * SECTION: Command Applications (triggered by GET var)
  57. * 1005: function importExtInfo($extKey, $version='')
  58. * 1062: function fetchMetaData($metaType)
  59. * 1125: function getMirrorURL()
  60. * 1158: function installExtension($extKey, $version=null, $mode=EM_INSTALL_VERSION_MIN)
  61. * 1279: function importExtFromRep($extKey,$version,$loc,$uploadFlag=0,$dontDelete=0,$directInput='')
  62. * 1425: function showExtDetails($extKey)
  63. *
  64. * SECTION: Application Sub-functions (HTML parts)
  65. * 1737: function updatesForm($extKey,$extInfo,$notSilent=0,$script='',$addFields='')
  66. * 1768: function extDumpTables($extKey,$extInfo)
  67. * 1835: function getFileListOfExtension($extKey,$conf)
  68. * 1889: function extDelete($extKey,$extInfo)
  69. * 1920: function extUpdateEMCONF($extKey,$extInfo)
  70. * 1940: function extBackup($extKey,$extInfo)
  71. * 1987: function extBackup_dumpDataTablesLine($tablesArray,$extKey)
  72. * 2015: function extInformationArray($extKey,$extInfo,$remote=0)
  73. * 2097: function extInformationArray_dbReq($techInfo,$tableHeader=0)
  74. * 2110: function extInformationArray_dbInst($dbInst,$current)
  75. * 2129: function getRepositoryUploadForm($extKey,$extInfo)
  76. *
  77. * SECTION: Extension list rendering
  78. * 2190: function extensionListRowHeader($trAttrib,$cells,$import=0)
  79. * 2251: function extensionListRow($extKey,$extInfo,$cells,$bgColorClass='',$inst_list=array(),$import=0,$altLinkUrl='')
  80. *
  81. * SECTION: Output helper functions
  82. * 2367: function wrapEmail($str,$email)
  83. * 2380: function helpCol($key)
  84. * 2396: function labelInfo($str)
  85. * 2408: function extensionTitleIconHeader($extKey,$extInfo,$align='top')
  86. * 2423: function removeButton()
  87. * 2432: function installButton()
  88. * 2441: function noImportMsg()
  89. * 2454: function depToString($dep,$type='depends')
  90. * 2473: function stringToDep($dep)
  91. *
  92. * SECTION: Read information about all available extensions
  93. * 2503: function getInstalledExtensions()
  94. * 2530: function getInstExtList($path,&$list,&$cat,$type)
  95. * 2561: function fixEMCONF($emConf)
  96. * 2600: function splitVersionRange($ver)
  97. * 2616: function prepareImportExtList()
  98. * 2660: function setCat(&$cat,$listArrayPart,$extKey)
  99. *
  100. * SECTION: Extension analyzing (detailed information)
  101. * 2710: function makeDetailedExtensionAnalysis($extKey,$extInfo,$validity=0)
  102. * 2892: function getClassIndexLocallangFiles($absPath,$table_class_prefix,$extKey)
  103. * 2962: function modConfFileAnalysis($confFilePath)
  104. * 2990: function serverExtensionMD5Array($extKey,$conf)
  105. * 3015: function findMD5ArrayDiff($current,$past)
  106. *
  107. * SECTION: File system operations
  108. * 3047: function createDirsInPath($dirs,$extDirPath)
  109. * 3065: function removeExtDirectory($removePath,$removeContentOnly=0)
  110. * 3128: function clearAndMakeExtensionDir($importedData,$type,$dontDelete=0)
  111. * 3182: function removeCacheFiles()
  112. * 3192: function extractDirsFromFileList($files)
  113. * 3218: function getExtPath($extKey,$type)
  114. *
  115. * SECTION: Writing to "conf.php" and "localconf.php" files
  116. * 3252: function writeTYPO3_MOD_PATH($confFilePath,$type,$mP)
  117. * 3289: function writeNewExtensionList($newExtList)
  118. * 3312: function writeTsStyleConfig($extKey,$arr)
  119. * 3334: function updateLocalEM_CONF($extKey,$extInfo)
  120. *
  121. * SECTION: Compiling upload information, emconf-file etc.
  122. * 3376: function construct_ext_emconf_file($extKey,$EM_CONF)
  123. * 3407: function arrayToCode($array, $level=0)
  124. * 3433: function makeUploadArray($extKey,$conf)
  125. * 3502: function getSerializedLocalLang($file,$content)
  126. *
  127. * SECTION: Managing dependencies, conflicts, priorities, load order of extension keys
  128. * 3538: function addExtToList($extKey,$instExtInfo)
  129. * 3569: function checkDependencies($extKey, $conf, $instExtInfo)
  130. * 3709: function removeExtFromList($extKey,$instExtInfo)
  131. * 3746: function removeRequiredExtFromListArr($listArr)
  132. * 3761: function managesPriorities($listArr,$instExtInfo)
  133. *
  134. * SECTION: System Update functions (based on extension requirements)
  135. * 3813: function checkClearCache($extInfo)
  136. * 3840: function checkUploadFolder($extKey,$extInfo)
  137. * 3925: function checkDBupdates($extKey,$extInfo,$infoOnly=0)
  138. * 4022: function forceDBupdates($extKey, $extInfo)
  139. * 4080: function tsStyleConfigForm($extKey,$extInfo,$output=0,$script='',$addFields='')
  140. *
  141. * SECTION: Dumping database (MySQL compliant)
  142. * 4175: function dumpTableAndFieldStructure($arr)
  143. * 4200: function dumpStaticTables($tableList)
  144. * 4229: function dumpHeader()
  145. * 4246: function dumpTableHeader($table,$fieldKeyInfo,$dropTableIfExists=0)
  146. * 4288: function dumpTableContent($table,$fieldStructure)
  147. * 4323: function getTableAndFieldStructure($parts)
  148. *
  149. * SECTION: TER Communication functions
  150. * 4373: function uploadExtensionToTER($em)
  151. *
  152. * SECTION: Various helper functions
  153. * 4411: function listOrderTitle($listOrder,$key)
  154. * 4436: function makeVersion($v,$mode)
  155. * 4448: function renderVersion($v,$raise='')
  156. * 4485: function ulFolder($extKey)
  157. * 4494: function importAtAll()
  158. * 4505: function importAsType($type,$lockType='')
  159. * 4527: function deleteAsType($type)
  160. * 4548: function versionDifference($v1,$v2,$div=1)
  161. * 4560: function first_in_array($str,$array,$caseInsensitive=FALSE)
  162. * 4578: function includeEMCONF($path,$_EXTKEY)
  163. * 4593: function searchExtension($extKey,$row)
  164. *
  165. * TOTAL FUNCTIONS: 90
  166. * (This index is automatically created/updated by the extension "extdeveval")
  167. *
  168. */
  169. // Include classes needed:
  170. require_once('class.em_xmlhandler.php');
  171. require_once('class.em_terconnection.php');
  172. require_once('class.em_unzip.php');
  173. $GLOBALS['LANG']->includeLLFile('EXT:lang/locallang_mod_tools_em.xml');
  174. // from tx_ter by Robert Lemke
  175. define('TX_TER_RESULT_EXTENSIONSUCCESSFULLYUPLOADED', '10504');
  176. define('EM_INSTALL_VERSION_MIN', 1);
  177. define('EM_INSTALL_VERSION_MAX', 2);
  178. define('EM_INSTALL_VERSION_STRICT', 3);
  179. /**
  180. * Module: Extension manager
  181. *
  182. * @author Kasper Skaarhoj <kasperYYYY@typo3.com>
  183. * @author Karsten Dambekalns <karsten@typo3.org>
  184. * @package TYPO3
  185. * @subpackage core
  186. */
  187. class SC_mod_tools_em_index extends t3lib_SCbase {
  188. // Internal, static:
  189. var $versionDiffFactor = 1; // This means that version difference testing for import is detected for sub-versions only, not dev-versions. Default: 1000
  190. var $systemInstall = 0; // If "1" then installs in the sysext directory is allowed. Default: 0
  191. var $requiredExt = ''; // List of required extension (from TYPO3_CONF_VARS)
  192. var $maxUploadSize = 31457280; // Max size in bytes of extension upload to repository
  193. var $kbMax = 500; // Max size in kilobytes for files to be edited.
  194. var $doPrintContent = true; // If set (default), the function printContent() will echo the content which was collected in $this->content. You can set this to FALSE in order to echo content from elsewhere, fx. when using outbut buffering
  195. var $listingLimit = 500; // List that many extension maximally at one time (fixing memory problems)
  196. var $listingLimitAuthor = 250; // List that many extension maximally at one time (fixing memory problems)
  197. /**
  198. * Internal variable loaded with extension categories (for display/listing). Should reflect $categories above
  199. * Dynamic var.
  200. */
  201. var $defaultCategories = Array(
  202. 'cat' => Array (
  203. 'be' => array(),
  204. 'module' => array(),
  205. 'fe' => array(),
  206. 'plugin' => array(),
  207. 'misc' => array(),
  208. 'services' => array(),
  209. 'templates' => array(),
  210. 'example' => array(),
  211. 'doc' => array()
  212. )
  213. );
  214. var $categories = array(); // Extension Categories (static var); see init()
  215. var $states = array(); // Extension States; see init()
  216. /**
  217. * Colors for extension states
  218. */
  219. var $stateColors = Array (
  220. 'alpha' => '#d12438',
  221. 'beta' => '#97b17e',
  222. 'stable' => '#3bb65c',
  223. 'experimental' => '#007eba',
  224. 'test' => '#979797',
  225. 'obsolete' => '#000000',
  226. 'excludeFromUpdates' => '#cf7307'
  227. );
  228. /**
  229. * "TYPE" information; labels, paths, description etc. See init()
  230. */
  231. var $typeLabels = array();
  232. var $typeDescr = array();
  233. var $typePaths = Array(); // Also static, set in init()
  234. var $typeBackPaths = Array(); // Also static, set in init()
  235. var $typeRelPaths = Array (
  236. 'S' => 'sysext/',
  237. 'G' => 'ext/',
  238. 'L' => '../typo3conf/ext/',
  239. );
  240. var $detailCols = Array (
  241. 0 => 2,
  242. 1 => 5,
  243. 2 => 6,
  244. 3 => 6,
  245. 4 => 4,
  246. 5 => 1
  247. );
  248. var $fe_user = array(
  249. 'username' => '',
  250. 'password' => '',
  251. );
  252. var $privacyNotice; // Set in init()
  253. var $securityHint; // Set in init()
  254. var $editTextExtensions = 'html,htm,txt,css,tmpl,inc,php,sql,conf,cnf,pl,pm,sh,xml,ChangeLog';
  255. var $nameSpaceExceptions = 'beuser_tracking,design_components,impexp,static_file_edit,cms,freesite,quickhelp,classic_welcome,indexed_search,sys_action,sys_workflows,sys_todos,sys_messages,direct_mail,sys_stat,tt_address,tt_board,tt_calender,tt_guest,tt_links,tt_news,tt_poll,tt_rating,tt_products,setup,taskcenter,tsconfig_help,context_help,sys_note,tstemplate,lowlevel,install,belog,beuser,phpmyadmin,aboutmodules,imagelist,setup,taskcenter,sys_notepad,viewpage,adodb';
  256. // Default variables for backend modules
  257. var $MCONF = array(); // Module configuration
  258. var $MOD_MENU = array(); // Module menu items
  259. var $MOD_SETTINGS = array(); // Module session settings
  260. /**
  261. * Document Template Object
  262. *
  263. * @var noDoc
  264. */
  265. var $doc;
  266. var $content; // Accumulated content
  267. var $inst_keys = array(); // Storage of installed extensions
  268. var $gzcompress = 0; // Is set true, if system support compression.
  269. /**
  270. * instance of TER connection handler
  271. *
  272. * @var SC_mod_tools_em_terconnection
  273. */
  274. var $terConnection;
  275. /**
  276. * XML handling class for the TYPO3 Extension Manager
  277. *
  278. * @var SC_mod_tools_em_xmlhandler
  279. */
  280. var $xmlhandler;
  281. var $JScode; // JavaScript code to be forwared to $this->doc->JScode
  282. // GPvars:
  283. var $CMD = array(); // CMD array
  284. var $listRemote; // If set, connects to remote repository
  285. var $lookUpStr; // Search string when listing local extensions
  286. /*********************************
  287. *
  288. * Standard module initialization
  289. *
  290. *********************************/
  291. /**
  292. * Standard init function of a module.
  293. *
  294. * @return void
  295. */
  296. function init() {
  297. global $BE_USER,$LANG,$BACK_PATH,$TYPO3_CONF_VARS;
  298. /**
  299. * Extension Categories (static var)
  300. * Content must be redundant with the same internal variable as in class.tx_extrep.php!
  301. */
  302. $this->categories = array(
  303. 'be' => $GLOBALS['LANG']->getLL('category_BE'),
  304. 'module' => $GLOBALS['LANG']->getLL('category_BE_modules'),
  305. 'fe' => $GLOBALS['LANG']->getLL('category_FE'),
  306. 'plugin' => $GLOBALS['LANG']->getLL('category_FE_plugins'),
  307. 'misc' => $GLOBALS['LANG']->getLL('category_miscellanous'),
  308. 'services' => $GLOBALS['LANG']->getLL('category_services'),
  309. 'templates' => $GLOBALS['LANG']->getLL('category_templates'),
  310. 'example' => $GLOBALS['LANG']->getLL('category_examples'),
  311. 'doc' => $GLOBALS['LANG']->getLL('category_documentation')
  312. );
  313. /**
  314. * Extension States
  315. * Content must be redundant with the same internal variable as in class.tx_extrep.php!
  316. */
  317. $this->states = array(
  318. 'alpha' => $GLOBALS['LANG']->getLL('state_alpha'),
  319. 'beta' => $GLOBALS['LANG']->getLL('state_beta'),
  320. 'stable' => $GLOBALS['LANG']->getLL('state_stable'),
  321. 'experimental' => $GLOBALS['LANG']->getLL('state_experimental'),
  322. 'test' => $GLOBALS['LANG']->getLL('state_test'),
  323. 'obsolete' => $GLOBALS['LANG']->getLL('state_obsolete'),
  324. 'excludeFromUpdates' => $GLOBALS['LANG']->getLL('state_exclude_from_updates')
  325. );
  326. /**
  327. * "TYPE" information; labels, paths, description etc.
  328. */
  329. $this->typeLabels = array(
  330. 'S' => $GLOBALS['LANG']->getLL('type_system'),
  331. 'G' => $GLOBALS['LANG']->getLL('type_global'),
  332. 'L' => $GLOBALS['LANG']->getLL('type_local'),
  333. );
  334. $this->typeDescr = array(
  335. 'S' => $GLOBALS['LANG']->getLL('descr_system'),
  336. 'G' => $GLOBALS['LANG']->getLL('descr_global'),
  337. 'L' => $GLOBALS['LANG']->getLL('descr_local'),
  338. );
  339. // Setting paths of install scopes:
  340. $this->typePaths = Array (
  341. 'S' => TYPO3_mainDir.'sysext/',
  342. 'G' => TYPO3_mainDir.'ext/',
  343. 'L' => 'typo3conf/ext/'
  344. );
  345. $this->typeBackPaths = Array (
  346. 'S' => '../../../',
  347. 'G' => '../../../',
  348. 'L' => '../../../../'.TYPO3_mainDir
  349. );
  350. $this->privacyNotice = $GLOBALS['LANG']->getLL('privacy_notice');
  351. $securityMessage = $GLOBALS['LANG']->getLL('security_warning_extensions') .
  352. '<br /><br />' . sprintf($GLOBALS['LANG']->getLL('security_descr'),
  353. '<a href="http://typo3.org/teams/security/" target="_blank">', '</a>'
  354. );
  355. $flashMessage = t3lib_div::makeInstance(
  356. 't3lib_FlashMessage',
  357. $securityMessage,
  358. $GLOBALS['LANG']->getLL('security_header'),
  359. t3lib_FlashMessage::INFO
  360. );
  361. $this->securityHint = $flashMessage->render();
  362. $this->excludeForPackaging = $GLOBALS['TYPO3_CONF_VARS']['EXT']['excludeForPackaging'];
  363. // Setting module configuration:
  364. $this->MCONF = $GLOBALS['MCONF'];
  365. // Setting GPvars:
  366. $this->CMD = is_array(t3lib_div::_GP('CMD')) ? t3lib_div::_GP('CMD') : array();
  367. $this->lookUpStr = trim(t3lib_div::_GP('lookUp'));
  368. $this->listRemote = t3lib_div::_GP('ter_connect');
  369. $this->listRemote_search = trim(t3lib_div::_GP('ter_search'));
  370. // Configure menu
  371. $this->menuConfig();
  372. // Setting internal static:
  373. if ($TYPO3_CONF_VARS['EXT']['allowSystemInstall']) $this->systemInstall = 1;
  374. $this->requiredExt = t3lib_div::trimExplode(',',$TYPO3_CONF_VARS['EXT']['requiredExt'],1);
  375. // Initialize helper object
  376. $this->terConnection = t3lib_div::makeInstance('SC_mod_tools_em_terconnection');
  377. $this->terConnection->emObj = $this;
  378. $this->terConnection->wsdlURL = $TYPO3_CONF_VARS['EXT']['em_wsdlURL'];
  379. $this->xmlhandler = t3lib_div::makeInstance('SC_mod_tools_em_xmlhandler');
  380. $this->xmlhandler->emObj = $this;
  381. $this->xmlhandler->useObsolete = $this->MOD_SETTINGS['display_obsolete'];
  382. // Initialize Document Template object:
  383. $this->doc = t3lib_div::makeInstance('template');
  384. $this->doc->backPath = $BACK_PATH;
  385. $this->doc->setModuleTemplate('templates/em_index.html');
  386. // JavaScript
  387. $this->doc->JScode = $this->doc->wrapScriptTags('
  388. script_ended = 0;
  389. function jumpToUrl(URL) { //
  390. window.location.href = URL;
  391. }
  392. ');
  393. // Reload left frame menu
  394. if ($this->CMD['refreshMenu']) {
  395. $this->doc->JScode .= $this->doc->wrapScriptTags('
  396. if(top.refreshMenu) {
  397. top.refreshMenu();
  398. } else {
  399. top.TYPO3ModuleMenu.refreshMenu();
  400. }
  401. ');
  402. }
  403. // Descriptions:
  404. $this->descrTable = '_MOD_'.$this->MCONF['name'];
  405. if ($BE_USER->uc['edit_showFieldHelp']) {
  406. $LANG->loadSingleTableDescription($this->descrTable);
  407. }
  408. // Setting username/password etc. for upload-user:
  409. $this->fe_user['username'] = $this->MOD_SETTINGS['fe_u'];
  410. $this->fe_user['password'] = $this->MOD_SETTINGS['fe_p'];
  411. parent::init();
  412. $this->handleExternalFunctionValue('singleDetails');
  413. }
  414. /**
  415. * This function is a copy of the same function in t3lib_SCbase with one modification:
  416. * In contrast to t3lib_SCbase::handleExternalFunctionValue() this function merges the $this->extClassConf array
  417. * instead of overwriting it. That was necessary for including the Kickstarter as a submodule into the 'singleDetails'
  418. * selectorbox as well as in the main 'function' selectorbox.
  419. *
  420. * @param string Mod-setting array key
  421. * @param string Mod setting value, overriding the one in the key
  422. * @return void
  423. * @see t3lib_SCbase::handleExternalFunctionValue()
  424. */
  425. function handleExternalFunctionValue($MM_key='function', $MS_value=NULL) {
  426. $MS_value = is_null($MS_value) ? $this->MOD_SETTINGS[$MM_key] : $MS_value;
  427. $externalItems = $this->getExternalItemConfig($this->MCONF['name'],$MM_key,$MS_value);
  428. if (is_array($externalItems)) $this->extClassConf = array_merge($externalItems,is_array($this->extClassConf)?$this->extClassConf:array());
  429. if (is_array($this->extClassConf) && $this->extClassConf['path']) {
  430. $this->include_once[]=$this->extClassConf['path'];
  431. }
  432. }
  433. /**
  434. * Configuration of which mod-menu items can be used
  435. *
  436. * @return void
  437. */
  438. function menuConfig() {
  439. global $BE_USER, $TYPO3_CONF_VARS;
  440. // MENU-ITEMS:
  441. $this->MOD_MENU = array(
  442. 'function' => array(
  443. 0 => $GLOBALS['LANG']->getLL('menu_loaded_extensions'),
  444. 1 => $GLOBALS['LANG']->getLL('menu_install_extensions'),
  445. 2 => $GLOBALS['LANG']->getLL('menu_import_extensions'),
  446. 4 => $GLOBALS['LANG']->getLL('menu_translation_handling'),
  447. 3 => $GLOBALS['LANG']->getLL('menu_settings'),
  448. 5 => $GLOBALS['LANG']->getLL('menu_extension_updates'),
  449. ),
  450. 'listOrder' => array(
  451. 'cat' => $GLOBALS['LANG']->getLL('list_order_category'),
  452. 'author_company' => $GLOBALS['LANG']->getLL('list_order_author'),
  453. 'state' => $GLOBALS['LANG']->getLL('list_order_state'),
  454. 'type' => $GLOBALS['LANG']->getLL('list_order_type'),
  455. ),
  456. 'display_details' => array(
  457. 1 => $GLOBALS['LANG']->getLL('show_details'),
  458. 0 => $GLOBALS['LANG']->getLL('show_description'),
  459. 2 => $GLOBALS['LANG']->getLL('show_more_details'),
  460. 3 => $GLOBALS['LANG']->getLL('show_technical'),
  461. 4 => $GLOBALS['LANG']->getLL('show_validating'),
  462. 5 => $GLOBALS['LANG']->getLL('show_changed'),
  463. ),
  464. 'display_shy' => '',
  465. 'display_own' => '',
  466. 'display_obsolete' => '',
  467. 'display_installed' => '',
  468. 'display_files' => '',
  469. 'singleDetails' => array(
  470. 'info' => $GLOBALS['LANG']->getLL('details_info'),
  471. 'edit' => $GLOBALS['LANG']->getLL('details_edit'),
  472. 'backup' => $GLOBALS['LANG']->getLL('details_backup_delete'),
  473. 'dump' => $GLOBALS['LANG']->getLL('details_dump_db'),
  474. 'upload' => $GLOBALS['LANG']->getLL('details_upload'),
  475. 'updateModule' => $GLOBALS['LANG']->getLL('details_update'),
  476. ),
  477. 'fe_u' => '',
  478. 'fe_p' => '',
  479. 'mirrorListURL' => '',
  480. 'rep_url' => '',
  481. 'extMirrors' => '',
  482. 'selectedMirror' => '',
  483. 'selectedLanguages' => ''
  484. );
  485. $this->MOD_MENU['singleDetails'] = $this->mergeExternalItems($this->MCONF['name'],'singleDetails',$this->MOD_MENU['singleDetails']);
  486. // page/be_user TSconfig settings and blinding of menu-items
  487. if (!$BE_USER->getTSConfigVal('mod.'.$this->MCONF['name'].'.allowTVlisting')) {
  488. unset($this->MOD_MENU['display_details'][3]);
  489. unset($this->MOD_MENU['display_details'][4]);
  490. unset($this->MOD_MENU['display_details'][5]);
  491. }
  492. // CLEANSE SETTINGS
  493. $this->MOD_SETTINGS = t3lib_BEfunc::getModuleData($this->MOD_MENU, t3lib_div::_GP('SET'), $this->MCONF['name']);
  494. if ($this->MOD_SETTINGS['function']==2) {
  495. // If listing from online repository, certain items are removed though:
  496. unset($this->MOD_MENU['listOrder']['type']);
  497. unset($this->MOD_MENU['display_details'][2]);
  498. unset($this->MOD_MENU['display_details'][3]);
  499. unset($this->MOD_MENU['display_details'][4]);
  500. unset($this->MOD_MENU['display_details'][5]);
  501. $this->MOD_SETTINGS = t3lib_BEfunc::getModuleData($this->MOD_MENU, t3lib_div::_GP('SET'), $this->MCONF['name']);
  502. }
  503. parent::menuConfig();
  504. }
  505. /**
  506. * Main function for Extension Manager module.
  507. *
  508. * @return void
  509. */
  510. function main() {
  511. global $BE_USER,$LANG,$TYPO3_CONF_VARS;
  512. if (empty($this->MOD_SETTINGS['mirrorListURL'])) $this->MOD_SETTINGS['mirrorListURL'] = $TYPO3_CONF_VARS['EXT']['em_mirrorListURL'];
  513. // Starting page:
  514. $this->content.=$this->doc->header($GLOBALS['LANG']->getLL('header'));
  515. $this->content.=$this->doc->spacer(5);
  516. // Command given which is executed regardless of main menu setting:
  517. if ($this->CMD['showExt']) { // Show details for a single extension
  518. $this->showExtDetails($this->CMD['showExt']);
  519. } elseif ($this->CMD['requestInstallExtensions']) { // Show details for a single extension
  520. $this->requestInstallExtensions($this->CMD['requestInstallExtensions']);
  521. } elseif ($this->CMD['importExt'] || $this->CMD['uploadExt']) { // Imports an extension from online rep.
  522. $err = $this->importExtFromRep($this->CMD['importExt'],$this->CMD['extVersion'],$this->CMD['loc'],$this->CMD['uploadExt']);
  523. if ($err) {
  524. $this->content.=$this->doc->section('',$GLOBALS['TBE_TEMPLATE']->rfw($err));
  525. }
  526. if(!$err && $this->CMD['importExt']) {
  527. $this->installTranslationsForExtension($this->CMD['importExt'], $this->getMirrorURL());
  528. }
  529. } elseif ($this->CMD['importExtInfo']) { // Gets detailed information of an extension from online rep.
  530. $this->importExtInfo($this->CMD['importExtInfo'],$this->CMD['extVersion']);
  531. } else { // No command - we show what the menu setting tells us:
  532. if (t3lib_div::inList('0,1,2',$this->MOD_SETTINGS['function'])) {
  533. $menu .= '&nbsp;' . $GLOBALS['LANG']->getLL('group_by') . '&nbsp;' . t3lib_BEfunc::getFuncMenu(0, 'SET[listOrder]', $this->MOD_SETTINGS['listOrder'], $this->MOD_MENU['listOrder']) .
  534. '&nbsp;&nbsp;' . $GLOBALS['LANG']->getLL('show') . '&nbsp;' . t3lib_BEfunc::getFuncMenu(0, 'SET[display_details]', $this->MOD_SETTINGS['display_details'], $this->MOD_MENU['display_details']) . '<br />';
  535. }
  536. if (t3lib_div::inList('0,1,5',$this->MOD_SETTINGS['function'])) {
  537. $menu.='<label for="checkDisplayShy">' . $GLOBALS['LANG']->getLL('display_shy') . '</label>&nbsp;&nbsp;' . t3lib_BEfunc::getFuncCheck(0, 'SET[display_shy]', $this->MOD_SETTINGS['display_shy'], '', '', 'id="checkDisplayShy"');
  538. }
  539. if (t3lib_div::inList('2',$this->MOD_SETTINGS['function']) && strlen($this->fe_user['username'])) {
  540. $menu.='<label for="checkDisplayOwn">' . $GLOBALS['LANG']->getLL('only_my_ext') . '</label>&nbsp;&nbsp;' . t3lib_BEfunc::getFuncCheck(0, 'SET[display_own]', $this->MOD_SETTINGS['display_own'], '', '', 'id="checkDisplayOwn"');
  541. }
  542. if (t3lib_div::inList('0,1,2',$this->MOD_SETTINGS['function'])) {
  543. $menu.='&nbsp;&nbsp;<label for="checkDisplayObsolete">' . $GLOBALS['LANG']->getLL('show_obsolete') . '</label>&nbsp;&nbsp;' . t3lib_BEfunc::getFuncCheck(0, 'SET[display_obsolete]', $this->MOD_SETTINGS['display_obsolete'], '', '', 'id="checkDisplayObsolete"');
  544. }
  545. $this->content.=$this->doc->section('','<form action="index.php" method="post" name="pageform"><span class="nobr">' . ($menu ? $menu : '&nbsp;') . '</span></form>');
  546. $this->content.=$this->doc->spacer(10);
  547. switch((string)$this->MOD_SETTINGS['function']) {
  548. case '0':
  549. // Lists loaded (installed) extensions
  550. $this->extensionList_loaded();
  551. break;
  552. case '1':
  553. // Lists the installed (available) extensions
  554. $this->extensionList_installed();
  555. break;
  556. case '2':
  557. // Lists the extensions available from online rep.
  558. $this->extensionList_import();
  559. break;
  560. case '3':
  561. // Shows the settings screen
  562. $this->alterSettings();
  563. break;
  564. case '4':
  565. // Allows to set the translation preferences and check the status
  566. $this->translationHandling();
  567. break;
  568. case '5':
  569. // Shows a list of extensions with updates in TER
  570. $this->checkForUpdates();
  571. break;
  572. default:
  573. $this->extObjContent();
  574. break;
  575. }
  576. }
  577. // closing any form?
  578. $formTags = substr_count($this->content, '<form') + substr_count($this->content, '</form');
  579. if ($formTags % 2 > 0) {
  580. $this->content .= '</form>';
  581. }
  582. // Setting up the buttons and markers for docheader
  583. $docHeaderButtons = $this->getButtons();
  584. $markers = array(
  585. 'CSH' => $docHeaderButtons['csh'],
  586. 'FUNC_MENU' => $this->getFuncMenu(),
  587. 'CONTENT' => $this->content
  588. );
  589. // Build the <body> for the module
  590. $this->content = $this->doc->startPage('Extension Manager');
  591. $this->content.= $this->doc->moduleBody($this->pageinfo, $docHeaderButtons, $markers);
  592. $this->content.= $this->doc->endPage();
  593. $this->content = $this->doc->insertStylesAndJS($this->content);
  594. }
  595. /**
  596. * Print module content. Called as last thing in the global scope.
  597. *
  598. * @return void
  599. */
  600. function printContent() {
  601. if ($this->doPrintContent) {
  602. echo $this->content;
  603. }
  604. }
  605. /**
  606. * Create the function menu
  607. *
  608. * @return string HTML of the function menu
  609. */
  610. protected function getFuncMenu() {
  611. $funcMenu = '';
  612. if(!$this->CMD['showExt'] && !$this->CMD['requestInstallExtensions'] && !$this->CMD['importExt'] && !$this->CMD['uploadExt'] && !$this->CMD['importExtInfo']) {
  613. $funcMenu = t3lib_BEfunc::getFuncMenu(0, 'SET[function]', $this->MOD_SETTINGS['function'], $this->MOD_MENU['function']);
  614. } elseif($this->CMD['showExt'] && (!$this->CMD['standAlone'] && !t3lib_div::_GP('standAlone'))) {
  615. $funcMenu = t3lib_BEfunc::getFuncMenu(0, 'SET[singleDetails]', $this->MOD_SETTINGS['singleDetails'], $this->MOD_MENU['singleDetails'], '', '&CMD[showExt]=' . $this->CMD['showExt']);
  616. }
  617. return $funcMenu;
  618. }
  619. /**
  620. * Create the panel of buttons for submitting the form or otherwise perform operations.
  621. *
  622. * @return array all available buttons as an assoc. array
  623. */
  624. protected function getButtons() {
  625. $buttons = array(
  626. 'csh' => '',
  627. 'back' => '',
  628. 'shortcut' => ''
  629. );
  630. // CSH
  631. //$buttons['csh'] = t3lib_BEfunc::cshItem('_MOD_web_func', '', $GLOBALS['BACK_PATH']);
  632. // Shortcut
  633. if ($GLOBALS['BE_USER']->mayMakeShortcut()) {
  634. $buttons['shortcut'] = $this->doc->makeShortcutIcon('CMD','function',$this->MCONF['name']);
  635. }
  636. // Back
  637. if(($this->CMD['showExt'] && (!$this->CMD['standAlone'] && !t3lib_div::_GP('standAlone'))) || ($this->CMD['importExt'] || $this->CMD['uploadExt'] && (!$this->CMD['standAlone'])) || $this->CMD['importExtInfo']) {
  638. $buttons['back'] = '<a href="index.php" class="typo3-goBack" title="' . $GLOBALS['LANG']->getLL('go_back') . '">' .
  639. t3lib_iconWorks::getSpriteIcon('actions-view-go-back') .
  640. '</a>';
  641. }
  642. return $buttons;
  643. }
  644. /*********************************
  645. *
  646. * Function Menu Applications
  647. *
  648. *********************************/
  649. /**
  650. * Listing of loaded (installed) extensions
  651. *
  652. * @return void
  653. */
  654. function extensionList_loaded() {
  655. global $TYPO3_LOADED_EXT;
  656. list($list,$cat) = $this->getInstalledExtensions();
  657. // Loaded extensions
  658. $content = '';
  659. $lines = array();
  660. // Available extensions
  661. if (is_array($cat[$this->MOD_SETTINGS['listOrder']])) {
  662. $content='';
  663. $lines=array();
  664. $lines[] = $this->extensionListRowHeader(' class="t3-row-header"',array('<td><img src="clear.gif" width="1" height="1" alt="" /></td>'));
  665. foreach($cat[$this->MOD_SETTINGS['listOrder']] as $catName => $extEkeys) {
  666. natcasesort($extEkeys);
  667. $extensions = array();
  668. foreach ($extEkeys as $extKey => $value) {
  669. if (array_key_exists($extKey,$TYPO3_LOADED_EXT) && ($this->MOD_SETTINGS['display_shy'] || !$list[$extKey]['EM_CONF']['shy']) && $this->searchExtension($extKey,$list[$extKey])) {
  670. if (in_array($extKey, $this->requiredExt)) {
  671. $loadUnloadLink = '<strong>' . $GLOBALS['TBE_TEMPLATE']->rfw($GLOBALS['LANG']->getLL('extension_required_short')) . '</strong>';
  672. } else {
  673. $loadUnloadLink = '<a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[remove]=1').'">'.$this->removeButton().'</a>';
  674. }
  675. $extensions[] = $this->extensionListRow($extKey,$list[$extKey],array('<td class="bgColor">'.$loadUnloadLink.'</td>'));
  676. }
  677. }
  678. if(count($extensions)) {
  679. $lines[]='<tr><td colspan="'.(3+$this->detailCols[$this->MOD_SETTINGS['display_details']]).'"><br /></td></tr>';
  680. $lines[]='<tr><td colspan="'.(3+$this->detailCols[$this->MOD_SETTINGS['display_details']]).'">' . t3lib_iconWorks::getSpriteIcon('apps-filetree-folder-default') . '<strong>'.htmlspecialchars($this->listOrderTitle($this->MOD_SETTINGS['listOrder'],$catName)).'</strong></td></tr>';
  681. $lines[] = implode(LF,$extensions);
  682. }
  683. }
  684. }
  685. $content.= t3lib_BEfunc::cshItem('_MOD_tools_em', 'loaded', $GLOBALS['BACK_PATH'],'');
  686. $content.= '<form action="index.php" method="post" name="lookupform">';
  687. $content.= '<label for="lookUp">' . $GLOBALS['LANG']->getLL('look_up') . '</label> <input type="text" id="lookUp" name="lookUp" value="' . htmlspecialchars($this->lookUpStr) . '" /><input type="submit" value="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:search') . '" /><br /><br />';
  688. $content.= '</form>
  689. <!-- Loaded Extensions List -->
  690. <table border="0" cellpadding="2" cellspacing="1">'.implode('',$lines).'</table>';
  691. $this->content.=$this->doc->section($GLOBALS['LANG']->getLL('loaded_exts'),$content,0,1);
  692. }
  693. /**
  694. * Listing of available (installed) extensions
  695. *
  696. * @return void
  697. */
  698. function extensionList_installed() {
  699. global $TYPO3_LOADED_EXT;
  700. list($list,$cat)=$this->getInstalledExtensions();
  701. // Available extensions
  702. if (is_array($cat[$this->MOD_SETTINGS['listOrder']])) {
  703. $content='';
  704. $lines=array();
  705. $lines[]=$this->extensionListRowHeader(' class="t3-row-header"',array('<td><img src="clear.gif" width="18" height="1" alt="" /></td>'));
  706. $allKeys=array();
  707. foreach($cat[$this->MOD_SETTINGS['listOrder']] as $catName => $extEkeys) {
  708. if(!$this->MOD_SETTINGS['display_obsolete'] && $catName=='obsolete') continue;
  709. $allKeys[]='';
  710. $allKeys[]='TYPE: '.$catName;
  711. natcasesort($extEkeys);
  712. $extensions = array();
  713. foreach ($extEkeys as $extKey => $value) {
  714. $allKeys[]=$extKey;
  715. if ((!$list[$extKey]['EM_CONF']['shy'] || $this->MOD_SETTINGS['display_shy']) &&
  716. ($list[$extKey]['EM_CONF']['state']!='obsolete' || $this->MOD_SETTINGS['display_obsolete'])
  717. && $this->searchExtension($extKey,$list[$extKey])) {
  718. $loadUnloadLink = t3lib_extMgm::isLoaded($extKey)?
  719. '<a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[remove]=1&CMD[clrCmd]=1&SET[singleDetails]=info').'">'.$this->removeButton().'</a>':
  720. '<a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[load]=1&CMD[clrCmd]=1&SET[singleDetails]=info').'">'.$this->installButton().'</a>';
  721. if (in_array($extKey,$this->requiredExt)) {
  722. $loadUnloadLink = '<strong>' . $GLOBALS['TBE_TEMPLATE']->rfw($GLOBALS['LANG']->getLL('extension_required_short')) . '</strong>';
  723. }
  724. $theRowClass = t3lib_extMgm::isLoaded($extKey)? 'em-listbg1' : 'em-listbg2';
  725. $extensions[]=$this->extensionListRow($extKey,$list[$extKey],array('<td class="bgColor">'.$loadUnloadLink.'</td>'),$theRowClass);
  726. }
  727. }
  728. if(count($extensions)) {
  729. $lines[]='<tr><td colspan="'.(3+$this->detailCols[$this->MOD_SETTINGS['display_details']]).'"><br /></td></tr>';
  730. $lines[]='<tr><td colspan="' . (3+$this->detailCols[$this->MOD_SETTINGS['display_details']]) . '">' . t3lib_iconWorks::getSpriteIcon('apps-filetree-folder-default') . '<strong>'. htmlspecialchars($this->listOrderTitle($this->MOD_SETTINGS['listOrder'],$catName)).'</strong></td></tr>';
  731. $lines[] = implode(LF,$extensions);
  732. }
  733. }
  734. $content.='
  735. <!--
  736. EXTENSION KEYS:
  737. '.trim(implode(LF,$allKeys)).'
  738. -->
  739. ';
  740. $content.= t3lib_BEfunc::cshItem('_MOD_tools_em', 'avail', $GLOBALS['BACK_PATH'], '|<br />');
  741. $content.= sprintf($GLOBALS['LANG']->getLL('how_to_install'), $this->installButton()) . ' <br />' .
  742. sprintf($GLOBALS['LANG']->getLL('how_to_uninstall'), $this->removeButton()). ' <br /><br />';
  743. $content .= '<form action="index.php" method="post" name="lookupform">';
  744. $content .= '<label for="lookUp">' . $GLOBALS['LANG']->getLL('look_up') . '</label> <input type="text" id="lookUp" name="lookUp" value="' . htmlspecialchars($this->lookUpStr) . '" /><input type="submit" value="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:search') . '" /></form><br /><br />';
  745. $content.= $this->securityHint.'<br /><br />';
  746. $content.= '<table border="0" cellpadding="2" cellspacing="1">'.implode('',$lines).'</table>';
  747. $this->content.=$this->doc->section(sprintf($GLOBALS['LANG']->getLL('available_extensions'), $this->MOD_MENU['listOrder'][$this->MOD_SETTINGS['listOrder']]),$content,0,1);
  748. }
  749. }
  750. /**
  751. * Listing remote extensions from online repository
  752. *
  753. * @return void
  754. */
  755. function extensionList_import() {
  756. global $TYPO3_LOADED_EXT;
  757. $content='';
  758. // Listing from online repository:
  759. if ($this->listRemote) {
  760. list($inst_list,) = $this->getInstalledExtensions();
  761. $this->inst_keys = array_flip(array_keys($inst_list));
  762. $this->detailCols[1]+=6;
  763. // see if we have an extensionlist at all
  764. $this->extensionCount = $this->xmlhandler->countExtensions();
  765. if (!$this->extensionCount) {
  766. $content .= $this->fetchMetaData('extensions');
  767. }
  768. if($this->MOD_SETTINGS['listOrder']=='author_company') {
  769. $this->listingLimit = $this->listingLimitAuthor;
  770. }
  771. $this->pointer = intval(t3lib_div::_GP('pointer'));
  772. $offset = $this->listingLimit*$this->pointer;
  773. if($this->MOD_SETTINGS['display_own'] && strlen($this->fe_user['username'])) {
  774. $this->xmlhandler->searchExtensionsXML($this->listRemote_search, $this->fe_user['username'], $this->MOD_SETTINGS['listOrder'], TRUE);
  775. } else {
  776. $this->xmlhandler->searchExtensionsXML($this->listRemote_search, '', $this->MOD_SETTINGS['listOrder'], TRUE, FALSE, $offset, $this->listingLimit);
  777. }
  778. if (count($this->xmlhandler->extensionsXML)) {
  779. list($list,$cat) = $this->prepareImportExtList(true);
  780. // Available extensions
  781. if (is_array($cat[$this->MOD_SETTINGS['listOrder']])) {
  782. $lines=array();
  783. $lines[]=$this->extensionListRowHeader(' class="t3-row-header"',array('<td><img src="clear.gif" width="18" height="1" alt="" /></td>'),1);
  784. foreach($cat[$this->MOD_SETTINGS['listOrder']] as $catName => $extEkeys) {
  785. if (count($extEkeys)) {
  786. $lines[]='<tr><td colspan="'.(3+$this->detailCols[$this->MOD_SETTINGS['display_details']]).'"><br /></td></tr>';
  787. $lines[]='<tr><td colspan="'.(3+$this->detailCols[$this->MOD_SETTINGS['display_details']]).'">' . t3lib_iconWorks::getSpriteIcon('apps-filetree-folder-default') . '<strong>'.htmlspecialchars($this->listOrderTitle($this->MOD_SETTINGS['listOrder'],$catName)).'</strong></td></tr>';
  788. natcasesort($extEkeys);
  789. foreach ($extEkeys as $extKey => $value) {
  790. $version = array_keys($list[$extKey]['versions']);
  791. $version = end($version);
  792. $ext = $list[$extKey]['versions'][$version];
  793. $ext['downloadcounter_all'] = $list[$extKey]['downloadcounter'];
  794. $ext['_ICON'] = $list[$extKey]['_ICON'];
  795. $loadUnloadLink='';
  796. if ($inst_list[$extKey]['type']!='S' && (!isset($inst_list[$extKey]) || $this->versionDifference($version,$inst_list[$extKey]['EM_CONF']['version'],$this->versionDiffFactor))) {
  797. if (isset($inst_list[$extKey])) {
  798. // update
  799. if ($inst_list[$extKey]['EM_CONF']['state'] != 'excludeFromUpdates') {
  800. $loc= ($inst_list[$extKey]['type']=='G'?'G':'L');
  801. $aUrl = 'index.php?CMD[importExt]='.$extKey.'&CMD[extVersion]='.$version.'&CMD[loc]='.$loc;
  802. $loadUnloadLink .= '<a href="' . htmlspecialchars($aUrl) . '" title="' . sprintf($GLOBALS['LANG']->getLL('do_update'), ($loc == 'G' ? $GLOBALS['LANG']->getLL('global') : $GLOBALS['LANG']->getLL('local'))) . '">' .
  803. t3lib_iconWorks::getSpriteIcon('actions-system-extension-update') .
  804. '</a>';
  805. } else {
  806. // extension is marked as "excludeFromUpdates"
  807. $loadUnloadLink .= t3lib_iconWorks::getSpriteIcon('status-dialog-warning', $GLOBALS['LANG']->getLL('excluded_from_updates') );
  808. }
  809. } else {
  810. // import
  811. $aUrl = 'index.php?CMD[importExt]='.$extKey.'&CMD[extVersion]='.$version.'&CMD[loc]=L';
  812. $loadUnloadLink .= '<a href="' . htmlspecialchars($aUrl) . '" title="' . $GLOBALS['LANG']->getLL('import_to_local_dir') . '">' . t3lib_iconWorks::getSpriteIcon('actions-system-extension-import') . '</a>';
  813. }
  814. } else {
  815. $loadUnloadLink = '&nbsp;';
  816. }
  817. if (isset($inst_list[$extKey])) {
  818. $theRowClass = t3lib_extMgm::isLoaded($extKey) ? 'em-listbg1' : 'em-listbg2';
  819. } else {
  820. $theRowClass = 'em-listbg3';
  821. }
  822. $lines[]=$this->extensionListRow($extKey,$ext,array('<td class="bgColor">'.$loadUnloadLink.'</td>'),$theRowClass,$inst_list,1,'index.php?CMD[importExtInfo]='.rawurlencode($extKey));
  823. unset($list[$extKey]);
  824. }
  825. }
  826. }
  827. unset($list);
  828. // CSH:
  829. $content .= t3lib_BEfunc::cshItem('_MOD_tools_em', 'import_ter', $GLOBALS['BACK_PATH'], '|<br />');
  830. $onsubmit = "window.location.href='index.php?ter_connect=1&ter_search='+escape(this.elements['lookUp'].value);return false;";
  831. $content .= '<form action="index.php" method="post" onsubmit="' . htmlspecialchars($onsubmit) .
  832. '"><label for="lookUp">' . $GLOBALS['LANG']->getLL('list_or_look_up_extensions') . '</label><br />
  833. <input type="text" id="lookUp" name="lookUp" value="' . htmlspecialchars($this->listRemote_search) .
  834. '" /> <input type="submit" value="' . $GLOBALS['LANG']->getLL('look_up_button') . '" /></form><br /><br />';
  835. $content .= $this->browseLinks();
  836. $content.= '
  837. <!-- TER Extensions list -->
  838. <table border="0" cellpadding="2" cellspacing="1">'.implode(LF,$lines).'</table>';
  839. $content .= '<br />'.$this->browseLinks();
  840. $content.= '<br /><br />'.$this->securityHint;
  841. $content .= '<br /><br /><strong>' . $GLOBALS['LANG']->getLL('privacy_notice_header') .
  842. '</strong><br /> ' . $this->privacyNotice;
  843. $this->content .= $this->doc->section($GLOBALS['LANG']->getLL('extensions_repository_group_by') . ' ' .
  844. $this->MOD_MENU['listOrder'][$this->MOD_SETTINGS['listOrder']], $content, 0, 1);
  845. // Plugins which are NOT uploaded to repository but present on this server.
  846. $content='';
  847. $lines=array();
  848. if (count($this->inst_keys)) {
  849. foreach ($this->inst_keys as $extKey => $value) {
  850. $this->xmlhandler->searchExtensionsXMLExact($extKey, '', '', true);
  851. if((strlen($this->listRemote_search) && !stristr($extKey,$this->listRemote_search)) || isset($this->xmlhandler->extensionsXML[$extKey])) continue;
  852. $loadUnloadLink = t3lib_extMgm::isLoaded($extKey)?
  853. '<a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[remove]=1&CMD[clrCmd]=1&SET[singleDetails]=info').'">'.$this->removeButton().'</a>':
  854. '<a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[load]=1&CMD[clrCmd]=1&SET[singleDetails]=info').'">'.$this->installButton().'</a>';
  855. if (in_array($extKey,$this->requiredExt)) {
  856. $loadUnloadLink = '<strong>' .$GLOBALS['TBE_TEMPLATE']->rfw($GLOBALS['LANG']->getLL('extension_required_short')) . '</strong>';
  857. }
  858. $lines[]=$this->extensionListRow($extKey,$inst_list[$extKey],array('<td class="bgColor">'.$loadUnloadLink.'</td>'),t3lib_extMgm::isLoaded($extKey)?'em-listbg1':'em-listbg2');
  859. }
  860. }
  861. if(count($lines)) {
  862. $content .= $GLOBALS['LANG']->getLL('list_of_local_extensions') .
  863. '<br />' . $GLOBALS['LANG']->getLL('might_be_user_defined') . '<br /><br />';
  864. $content.= '<table border="0" cellpadding="2" cellspacing="1">'.
  865. $this->extensionListRowHeader(' class="t3-row-header"',array('<td><img src="clear.gif" width="18" height="1" alt="" /></td>')).
  866. implode('',$lines).'</table>';
  867. $this->content.=$this->doc->spacer(20);
  868. $this->content.=$this->doc->section($GLOBALS['LANG']->getLL('only_on_this_server'), $content, 0, 1);
  869. }
  870. }
  871. } else {
  872. $content .= t3lib_BEfunc::cshItem('_MOD_tools_em', 'import_ter', $GLOBALS['BACK_PATH'], '|<br />');
  873. $onsubmit = "window.location.href='index.php?ter_connect=1&ter_search='+escape(this.elements['lookUp'].value);return false;";
  874. $content .= '<form action="index.php" method="post" onsubmit="' . htmlspecialchars($onsubmit) .
  875. '"><label for="lookUp">' .
  876. $GLOBALS['LANG']->getLL('list_or_look_up_extensions') . '</label><br />
  877. <input type="text" id="lookUp" name="lookUp" value="' . htmlspecialchars($this->listRemote_search) .
  878. '" /> <input type="submit" value="' . $GLOBALS['LANG']->getLL('look_up_button') . '" /></form><br /><br />';
  879. $content .= '<p><strong>' . $GLOBALS['LANG']->getLL('no_matching_extensions') . '</strong></p>';
  880. $content .= '<br /><br /><strong>' . $GLOBALS['LANG']->getLL('privacy_notice_header') .
  881. '</strong><br /> ' . $this->privacyNotice;
  882. $this->content.=$this->doc->section($GLOBALS['LANG']->getLL('extensions_repository_group_by') . ' ' .
  883. $this->MOD_MENU['listOrder'][$this->MOD_SETTINGS['listOrder']], $content, 0, 1);
  884. }
  885. } else {
  886. // CSH
  887. $content .= t3lib_BEfunc::cshItem('_MOD_tools_em', 'import', $GLOBALS['BACK_PATH'], '|<br />');
  888. $onsubmit = "window.location.href='index.php?ter_connect=1&ter_search='+escape(this.elements['lookUp'].value);return false;";
  889. $content .= '<form action="index.php" method="post" onsubmit="' . htmlspecialchars($onsubmit) .
  890. '"><label for="lookUp">' .
  891. $GLOBALS['LANG']->getLL('list_or_look_up_extensions') . '</label><br />
  892. <input type="text" id="lookUp" name="lookUp" value="" /> <input type="submit" value="' .
  893. $GLOBALS['LANG']->getLL('look_up_button') . '" /><br /><br />';
  894. if ($this->CMD['fetchMetaData']) { // fetches mirror/extension data from online rep.
  895. $content .= $this->fetchMetaData($this->CMD['fetchMetaData']);
  896. } else {
  897. $onCLick = "window.location.href='index.php?CMD[fetchMetaData]=extensions';return false;";
  898. $content .= $GLOBALS['LANG']->getLL('connect_to_ter') . '<br />
  899. <input type="submit" value="' . $GLOBALS['LANG']->getLL('retrieve_update') .
  900. '" onclick="' . htmlspecialchars($onCLick) . '" />';
  901. if (is_file(PATH_site.'typo3temp/extensions.xml.gz')) {
  902. $dateFormat = $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'];
  903. $timeFormat = $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'];
  904. $content .= ' ' . sprintf($GLOBALS['LANG']->getLL('ext_list_last_updated') . ' ',
  905. date(
  906. $dateFormat . ', ' . $timeFormat,
  907. filemtime(PATH_site . 'typo3temp/extensions.xml.gz')
  908. )
  909. );
  910. }
  911. }
  912. $content.= '</form><br /><br />'.$this->securityHint;
  913. $content .= '<br /><br /><strong>' . $GLOBALS['LANG']->getLL('privacy_notice_header') .
  914. '</strong><br />' . $this->privacyNotice;
  915. $this->content.=$this->doc->section($GLOBALS['LANG']->getLL('in_repository'), $content, 0, 1);
  916. }
  917. // Upload:
  918. if ($this->importAtAll()) {
  919. $content= '<form action="index.php" enctype="'.$GLOBALS['TYPO3_CONF_VARS']['SYS']['form_enctype'].'" method="post">
  920. <label for="upload_ext_file">' . $GLOBALS['LANG']->getLL('upload_t3x') . '</label><br />
  921. <input type="file" size="60" id="upload_ext_file" name="upload_ext_file" /><br />' .
  922. $GLOBALS['LANG']->getLL('upload_to_location') . '<br />
  923. <select name="CMD[loc]">';
  924. if ($this->importAsType('L')) $content .= '<option value="L">' . $GLOBALS['LANG']->getLL('local_folder') . '</option>';
  925. if ($this->importAsType('G')) $content .= '<option value="G">' . $GLOBALS['LANG']->getLL('global_folder') . '</option>';
  926. if ($this->importAsType('S')) $content .= '<option value="S">' . $GLOBALS['LANG']->getLL('system_folder') . '</option>';
  927. $content.='</select><br />
  928. <input type="checkbox" value="1" name="CMD[uploadOverwrite]" id="checkUploadOverwrite" /> <label for="checkUploadOverwrite">' .
  929. $GLOBALS['LANG']->getLL('overwrite_ext') . '</label><br />
  930. <input type="submit" name="CMD[uploadExt]" value="' . $GLOBALS['LANG']->getLL('upload_ext_file') . '" /></form><br />
  931. ';
  932. } else $content=$this->noImportMsg();
  933. $this->content.=$this->doc->spacer(20);
  934. $this->content .= $this->doc->section($GLOBALS['LANG']->getLL('upload_ext_directly'), $content, 0, 1);
  935. }
  936. /**
  937. * Generates a link to the next page of extensions
  938. *
  939. * @return void
  940. */
  941. function browseLinks() {
  942. $content = '';
  943. if ($this->pointer) {
  944. $content .= '<a href="' . t3lib_div::linkThisScript(array('pointer' => $this->pointer-1)) .
  945. '" class="typo3-prevPage"><img' . t3lib_iconWorks::skinImg($GLOBALS['BACK_PATH'],
  946. 'gfx/pilleft_n.gif', 'width="14" height="14"') .
  947. ' alt="' . $GLOBALS['LANG']->getLL('previous_page') . '" /> ' .
  948. $GLOBALS['LANG']->getLL('previous_page') . '</a>';
  949. }
  950. if ($content) $content .= '&nbsp;&nbsp;&nbsp;';
  951. if (intval($this->xmlhandler->matchingCount/$this->listingLimit)>$this->pointer) {
  952. $content .= '<a href="' . t3lib_div::linkThisScript(array('pointer' => $this->pointer+1)) .
  953. '" class="typo3-nextPage"><img' . t3lib_iconWorks::skinImg($GLOBALS['BACK_PATH'],
  954. 'gfx/pilright_n.gif', 'width="14" height="14"') .
  955. ' alt="' . $GLOBALS['LANG']->getLL('next_page') . '" /> ' .
  956. $GLOBALS['LANG']->getLL('next_page') . '</a>';
  957. }
  958. $upper = (($this->pointer+1)*$this->listingLimit);
  959. if ($upper>$this->xmlhandler->matchingCount) {
  960. $upper = $this->xmlhandler->matchingCount;
  961. }
  962. if ($content) $content .= '<br /><br />' .
  963. sprintf($GLOBALS['LANG']->getLL('showing_extensions_from_to'),
  964. '<strong>' . ($this->pointer*$this->listingLimit+1) . '</strong>',
  965. '<strong>' . $upper . '</strong>'
  966. );
  967. if ($content) $content .= '<br /><br />';
  968. return $content;
  969. }
  970. /**
  971. * Allows changing of settings
  972. *
  973. * @return void
  974. */
  975. function alterSettings() {
  976. // Prepare the HTML output:
  977. $content.= '
  978. ' . t3lib_BEfunc::cshItem('_MOD_tools_em', 'settings', $GLOBALS['BACK_PATH'], '|<br />') . '
  979. <form action="index.php" method="post" name="altersettings">
  980. <fieldset><legend>' . $GLOBALS['LANG']->getLL('user_settings') . '</legend>
  981. <table border="0" cellpadding="2" cellspacing="2">
  982. <tr class="bgColor4">
  983. <td><label for="set_fe_u">' . $GLOBALS['LANG']->getLL('enter_repository_username') . '</label></td>
  984. <td><input type="text" id="set_fe_u" name="SET[fe_u]" value="'.htmlspecialchars($this->MOD_SETTINGS['fe_u']).'" /></td>
  985. </tr>
  986. <tr class="bgColor4">
  987. <td><label for="set_fe_p">' . $GLOBALS['LANG']->getLL('enter_repository_password') . '</label></td>
  988. <td><input type="password" id="set_fe_p" name="SET[fe_p]" value="'.htmlspecialchars($this->MOD_SETTINGS['fe_p']).'" /></td>
  989. </tr>
  990. </table>
  991. <strong>' . $GLOBALS['LANG']->getLL('notice') . '</strong> ' .
  992. $GLOBALS['LANG']->getLL('repository_password_info') . '
  993. </fieldset>
  994. <br />
  995. <br />
  996. <fieldset><legend>' . $GLOBALS['LANG']->getLL('mirror_selection') . '</legend>
  997. <table border="0" cellpadding="2" cellspacing="2">
  998. <tr class="bgColor4">
  999. <td><label for="set_mirror_list_url">' . $GLOBALS['LANG']->getLL('mirror_list_url') . '</label></td>
  1000. <td><input type="text" size="50" id="set_mirror_list_url" name="SET[mirrorListURL]" value="'.htmlspecialchars($this->MOD_SETTINGS['mirrorListURL']).'" /></td>
  1001. </tr>
  1002. </table>
  1003. </fieldset>
  1004. <br />
  1005. <p>' . $GLOBALS['LANG']->getLL('mirror_select') . '<br /><br /></p>
  1006. <fieldset><legend>' . $GLOBALS['LANG']->getLL('mirror_list') . '</legend>';
  1007. if(!empty($this->MOD_SETTINGS['mirrorListURL'])) {
  1008. if ($this->CMD['fetchMetaData']) { // fetches mirror/extension data from online rep.
  1009. $content .= $this->fetchMetaData($this->CMD['fetchMetaData']);
  1010. } else {
  1011. $content .= '<a href="index.php?CMD[fetchMetaData]=mirrors">' . $GLOBALS['LANG']->getLL('mirror_list_reload') . '</a>';
  1012. }
  1013. }
  1014. $content .= '<br />
  1015. <table cellspacing="4" style="text-align:left; vertical-alignment:top;">
  1016. <tr>
  1017. <td>' . $GLOBALS['LANG']->getLL('mirror_use') . '</td>
  1018. <td>' . $GLOBALS['LANG']->getLL('mirror_name') . '</td>
  1019. <td>' . $GLOBALS['LANG']->getLL('mirror_url') . '</td>
  1020. <td>' . $GLOBALS['LANG']->getLL('mirror_country') . '</td>
  1021. <td>' . $GLOBALS['LANG']->getLL('mirror_sponsored_by') . '</td>
  1022. </tr>
  1023. ';
  1024. if (!strlen($this->MOD_SETTINGS['extMirrors'])) $this->fetchMetaData('mirrors');
  1025. $extMirrors = unserialize($this->MOD_SETTINGS['extMirrors']);
  1026. $extMirrors[''] = array('title'=>$GLOBALS['LANG']->getLL('mirror_use_random'));
  1027. ksort($extMirrors);
  1028. if(is_array($extMirrors)) {
  1029. foreach($extMirrors as $k => $v) {
  1030. if(isset($v['sponsor'])) {
  1031. $sponsor = '<a href="'.htmlspecialchars($v['sponsor']['link']).'" target="_blank"><img src="'.$v['sponsor']['logo'].'" title="'.htmlspecialchars($v['sponsor']['name']).'" alt="'.htmlspecialchars($v['sponsor']['name']).'" /></a>';
  1032. }
  1033. $selected = ($this->MOD_SETTINGS['selectedMirror']==$k) ? 'checked="checked"' : '';
  1034. $content.='<tr class="bgColor4">
  1035. <td><input type="radio" name="SET[selectedMirror]" id="selectedMirror'.$k.'" value="'.$k.'" '.$selected.'/></td><td><label for="selectedMirror'.$k.'">'.htmlspecialchars($v['title']).'</label></td><td>'.htmlspecialchars($v['host'].$v['path']).'</td><td>'.$v['country'].'</td><td>'.$sponsor.'</td></tr>';
  1036. }
  1037. }
  1038. $content.= '
  1039. </table>
  1040. </fieldset>
  1041. <fieldset>
  1042. <br />
  1043. <table border="0" cellpadding="2" cellspacing="2">
  1044. <tr class="bgColor4">
  1045. <td><label for="set_rep_url">' . $GLOBALS['LANG']->getLL('enter_repository_url') . '</label></td>
  1046. <td><input type="text" size="50" id="set_rep_url" name="SET[rep_url]" value="'.htmlspecialchars($this->MOD_SETTINGS['rep_url']).'" /></td>
  1047. </tr>
  1048. </table>
  1049. ' . $GLOBALS['LANG']->getLL('repository_url_hint') . '<br />
  1050. </fieldset>
  1051. <br />
  1052. <input type="submit" value="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_tsfe.xml:update') . '" />
  1053. </form>
  1054. ';
  1055. $this->content .= $this->doc->section($GLOBALS['LANG']->getLL('repository_settings'), $content, 0, 1);
  1056. }
  1057. /**
  1058. * Allows to set the translation preferences and check the status
  1059. *
  1060. * @return void
  1061. */
  1062. function translationHandling() {
  1063. global $LANG, $TYPO3_LOADED_EXT;
  1064. $LANG->includeLLFile('EXT:setup/mod/locallang.xml');
  1065. //prepare docheader
  1066. $docHeaderButtons = $this->getButtons();
  1067. $markers = array(
  1068. 'CSH' => $docHeaderButtons['csh'],
  1069. 'FUNC_MENU' => $this->getFuncMenu(),
  1070. );
  1071. $incoming = t3lib_div::_POST('SET');
  1072. if(isset($incoming['selectedLanguages']) && is_array($incoming['selectedLanguages'])) {
  1073. t3lib_BEfunc::getModuleData($this->MOD_MENU, array('selectedLanguages' => serialize($incoming['selectedLanguages'])), $this->MCONF['name'], '', 'selectedLanguages');
  1074. $this->MOD_SETTINGS['selectedLanguages'] = serialize($incoming['selectedLanguages']);
  1075. }
  1076. $selectedLanguages = unserialize($this->MOD_SETTINGS['selectedLanguages']);
  1077. if(count($selectedLanguages)==1 && empty($selectedLanguages[0])) $selectedLanguages = array();
  1078. $theLanguages = t3lib_div::trimExplode('|',TYPO3_languages);
  1079. foreach($theLanguages as $val) {
  1080. if ($val!='default') {
  1081. $localLabel = ' - ['.htmlspecialchars($GLOBALS['LOCAL_LANG']['default']['lang_'.$val]).']';
  1082. $selected = (is_array($selectedLanguages) && in_array($val, $selectedLanguages)) ? ' selected="selected"' : '';
  1083. $opt[$GLOBALS['LANG']->getLL('lang_' . $val, 1) . '--' . $val] = '
  1084. <option value="'.$val.'"'.$selected.'>'.$LANG->getLL('lang_'.$val,1).$localLabel.'</option>';
  1085. }
  1086. }
  1087. ksort($opt);
  1088. // Prepare the HTML output:
  1089. $content.= '
  1090. ' . t3lib_BEfunc::cshItem('_MOD_tools_em', 'translation', $GLOBALS['BACK_PATH'], '|<br />') . '
  1091. <form action="index.php" method="post" name="translationform">
  1092. <fieldset><legend>' . $GLOBALS['LANG']->getLL('translation_settings') . '</legend>
  1093. <table border="0" cellpadding="2" cellspacing="2">
  1094. <tr class="bgColor4">
  1095. <td>' . $GLOBALS['LANG']->getLL('languages_to_fetch') . '</td>
  1096. <td>
  1097. <select name="SET[selectedLanguages][]" multiple="multiple" size="10">
  1098. <option>&nbsp;</option>'.
  1099. implode('',$opt).'
  1100. </select>
  1101. </td>
  1102. </tr>
  1103. </table>
  1104. <br />
  1105. <p>' . $GLOBALS['LANG']->getLL('translation_info') . '<br />
  1106. <br />' . $GLOBALS['LANG']->getLL('translation_loaded_exts') . '</p>
  1107. </fieldset>
  1108. <br />
  1109. <input type="submit" value="' . $GLOBALS['LANG']->getLL('translation_save_selection') . '" />
  1110. <br />
  1111. </form>';
  1112. $this->content .= $this->doc->section($GLOBALS['LANG']->getLL('translation_settings'), $content, 0, 1);
  1113. if(count($selectedLanguages)>0) {
  1114. $mirrorURL = $this->getMirrorURL();
  1115. $content = '<input type="button" value="' . $GLOBALS['LANG']->getLL('translation_check_status_button') .
  1116. '" onclick="document.location.href=\'' . htmlspecialchars(t3lib_div::linkThisScript(array('l10n'=>'check'))) .
  1117. '\'" />&nbsp;<input type="button" value="' . $GLOBALS['LANG']->getLL('translation_update_button') .
  1118. '" onclick="document.location.href=\'' . htmlspecialchars(t3lib_div::linkThisScript(array('l10n'=>'update'))) .
  1119. '\'" />';
  1120. // as this page loads dynamically, quit output buffering caused by ob_gzhandler
  1121. t3lib_div::cleanOutputBuffers();
  1122. if(t3lib_div::_GET('l10n') == 'check') {
  1123. $loadedExtensions = array_keys($TYPO3_LOADED_EXT);
  1124. $loadedExtensions = array_diff($loadedExtensions,array('_CACHEFILE'));
  1125. // Override content output - we now do that ourselves:
  1126. $this->content .= $this->doc->section($GLOBALS['LANG']->getLL('translation_status'), $content, 0, 1);
  1127. // Setting up the buttons and markers for docheader
  1128. $content = $this->doc->startPage('Extension Manager');
  1129. $content.= $this->doc->moduleBody($this->pageinfo, $docHeaderButtons, $markers);
  1130. $contentParts=explode('###CONTENT###',$content);
  1131. echo $contentParts[0].$this->content;
  1132. $this->doPrintContent = FALSE;
  1133. flush();
  1134. echo '
  1135. <br />
  1136. <br />
  1137. <p id="progress-message">
  1138. ' . $GLOBALS['LANG']->getLL('translation_check_status') . '
  1139. </p>
  1140. <br />
  1141. <div style="width:100%; height:20px; border: 1px solid black;">
  1142. <div id="progress-bar" style="float: left; width: 0%; height: 20px; background-color:green;">&nbsp;</div>
  1143. <div id="transparent-bar" style="float: left; width: 100%; height: 20px; background-color:'.$this->doc->bgColor2.';">&nbsp;</div>
  1144. </div>
  1145. <br />
  1146. <br /><p>' . $GLOBALS['LANG']->getLL('translation_table_check') . '</p><br />
  1147. <table border="0" cellpadding="2" cellspacing="2">
  1148. <tr class="t3-row-header"><td>' . $GLOBALS['LANG']->getLL('translation_extension_key') . '</td>
  1149. ';
  1150. foreach($selectedLanguages as $lang) {
  1151. echo ('<td>'.$LANG->getLL('lang_'.$lang,1).'</td>');
  1152. }
  1153. echo ('</tr>');
  1154. $counter = 1;
  1155. foreach($loadedExtensions as $extKey) {
  1156. $percentDone = intval (($counter / count($loadedExtensions)) * 100);
  1157. echo ('
  1158. <script type="text/javascript">
  1159. document.getElementById("progress-bar").style.width = "'.$percentDone.'%";
  1160. document.getElementById("transparent-bar").style.width = "'.(100-$percentDone).'%";
  1161. document.getElementById("progress-message").firstChild.data="' .
  1162. sprintf($GLOBALS['LANG']->getLL('translation_checking_extension'), $extKey) . '";
  1163. </script>
  1164. ');
  1165. flush();
  1166. $translationStatusArr = $this->terConnection->fetchTranslationStatus($extKey,$mirrorURL);
  1167. echo ('<tr class="bgColor4"><td>'.$extKey.'</td>');
  1168. foreach($selectedLanguages as $lang) {
  1169. // remote unknown -> no l10n available
  1170. if(!isset($translationStatusArr[$lang])) {
  1171. echo ('<td title="' . $GLOBALS['LANG']->getLL('translation_no_translation') . '">' .
  1172. $GLOBALS['LANG']->getLL('translation_n_a') . '</td>');
  1173. continue;
  1174. }
  1175. // determine local md5 from zip
  1176. if(is_file(PATH_site.'typo3temp/'.$extKey.'-l10n-'.$lang.'.zip')) {
  1177. $localmd5 = md5_file(PATH_site.'typo3temp/'.$extKey.'-l10n-'.$lang.'.zip');
  1178. } else {
  1179. echo ('<td title="' . $GLOBALS['LANG']->getLL('translation_not_installed') .
  1180. '" style="background-color:#ff0">' . $GLOBALS['LANG']->getLL('translation_status_unknown') .
  1181. '</td>');
  1182. continue;
  1183. }
  1184. // local!=remote -> needs update
  1185. if($localmd5 != $translationStatusArr[$lang]['md5']) {
  1186. echo ('<td title="' . $GLOBALS['LANG']->getLL('translation_needs_update') .
  1187. '" style="background-color:#ff0">' . $GLOBALS['LANG']->getLL('translation_status_update') .
  1188. '</td>');
  1189. continue;
  1190. }
  1191. echo ('<td title="' . $GLOBALS['LANG']->getLL('translation_is_ok') .
  1192. '" style="background-color:#69a550">' . $GLOBALS['LANG']->getLL('translation_status_ok') .
  1193. '</td>');
  1194. }
  1195. echo ('</tr>');
  1196. $counter ++;
  1197. }
  1198. echo '</table>
  1199. <script type="text/javascript">
  1200. document.getElementById("progress-message").firstChild.data="' .
  1201. $GLOBALS['LANG']->getLL('translation_check_done') . '";
  1202. </script>
  1203. ';
  1204. echo $contentParts[1] . $this->doc->endPage();
  1205. exit;
  1206. } elseif(t3lib_div::_GET('l10n') == 'update') {
  1207. $loadedExtensions = array_keys($TYPO3_LOADED_EXT);
  1208. $loadedExtensions = array_diff($loadedExtensions,array('_CACHEFILE'));
  1209. // Override content output - we now do that ourselves:
  1210. $this->content .= $this->doc->section($GLOBALS['LANG']->getLL('translation_status'), $content, 0, 1);
  1211. // Setting up the buttons and markers for docheader
  1212. $content = $this->doc->startPage('Extension Manager');
  1213. $content.= $this->doc->moduleBody($this->pageinfo, $docHeaderButtons, $markers);
  1214. $contentParts=explode('###CONTENT###',$content);
  1215. echo $contentParts[0].$this->content;
  1216. $this->doPrintContent = FALSE;
  1217. flush();
  1218. echo ('
  1219. <br />
  1220. <br />
  1221. <p id="progress-message">
  1222. ' . $GLOBALS['LANG']->getLL('translation_update_status') . '
  1223. </p>
  1224. <br />
  1225. <div style="width:100%; height:20px; border: 1px solid black;">
  1226. <div id="progress-bar" style="float: left; width: 0%; height: 20px; background-color:green;">&nbsp;</div>
  1227. <div id="transparent-bar" style="float: left; width: 100%; height: 20px; background-color:'.$this->doc->bgColor2.';">&nbsp;</div>
  1228. </div>
  1229. <br />
  1230. <br /><p>' . $GLOBALS['LANG']->getLL('translation_table_update') . '<br />
  1231. <em>' . $GLOBALS['LANG']->getLL('translation_full_check_update') . '</em></p><br />
  1232. <table border="0" cellpadding="2" cellspacing="2">
  1233. <tr class="t3-row-header"><td>' . $GLOBALS['LANG']->getLL('translation_extension_key') . '</td>
  1234. ');
  1235. foreach($selectedLanguages as $lang) {
  1236. echo '<td>'.$LANG->getLL('lang_'.$lang,1).'</td>';
  1237. }
  1238. echo '</tr>';
  1239. $counter = 1;
  1240. foreach($loadedExtensions as $extKey) {
  1241. $percentDone = intval (($counter / count($loadedExtensions)) * 100);
  1242. echo ('
  1243. <script type="text/javascript">
  1244. document.getElementById("progress-bar").style.width = "'.$percentDone.'%";
  1245. document.getElementById("transparent-bar").style.width = "'.(100-$percentDone).'%";
  1246. document.getElementById("progress-message").firstChild.data="' .
  1247. sprintf($GLOBALS['LANG']->getLL('translation_updating_extension'), $extKey) . '";
  1248. </script>
  1249. ');
  1250. flush();
  1251. $translationStatusArr = $this->terConnection->fetchTranslationStatus($extKey,$mirrorURL);
  1252. echo ('<tr class="bgColor4"><td>'.$extKey.'</td>');
  1253. if(is_array($translationStatusArr)) {
  1254. foreach($selectedLanguages as $lang) {
  1255. // remote unknown -> no l10n available
  1256. if(!isset($translationStatusArr[$lang])) {
  1257. echo ('<td title="' . $GLOBALS['LANG']->getLL('translation_no_translation') .
  1258. '">' . $GLOBALS['LANG']->getLL('translation_n_a') . '</td>');
  1259. continue;
  1260. }
  1261. // determine local md5 from zip
  1262. if(is_file(PATH_site.'typo3temp/'.$extKey.'-l10n-'.$lang.'.zip')) {
  1263. $localmd5 = md5_file(PATH_site.'typo3temp/'.$extKey.'-l10n-'.$lang.'.zip');
  1264. } else {
  1265. $localmd5 = 'zzz';
  1266. }
  1267. // local!=remote or not installed -> needs update
  1268. if($localmd5 != $translationStatusArr[$lang]['md5']) {
  1269. $ret = $this->updateTranslation($extKey, $lang, $mirrorURL);
  1270. if($ret === true) {
  1271. echo ('<td title="' . $GLOBALS['LANG']->getLL('translation_has_been_updated') .
  1272. '" style="background-color:#69a550">' . $GLOBALS['LANG']->getLL('translation_status_update') .
  1273. '</td>');
  1274. } else {
  1275. echo ('<td title="' . htmlspecialchars($ret) .
  1276. '" style="background-color:#cb3352">' . $GLOBALS['LANG']->getLL('translation_status_error') .
  1277. '</td>');
  1278. }
  1279. continue;
  1280. }
  1281. echo ('<td title="' . $GLOBALS['LANG']->getLL('translation_is_ok') .
  1282. '" style="background-color:#69a550">' . $GLOBALS['LANG']->getLL('translation_status_ok') . '</td>');
  1283. }
  1284. } else {
  1285. echo ('<td colspan="' . count($selectedLanguages) .
  1286. '" title="' . $GLOBALS['LANG']->getLL('translation_problems') .
  1287. '">' . $GLOBALS['LANG']->getLL('translation_status_could_not_fetch') . '</td>');
  1288. }
  1289. echo ('</tr>');
  1290. $counter++;
  1291. }
  1292. echo '</table>
  1293. <script type="text/javascript">
  1294. document.getElementById("progress-message").firstChild.data="' .
  1295. $GLOBALS['LANG']->getLL('translation_update_done') . '";
  1296. </script>
  1297. ';
  1298. // Fix permissions on unzipped language xml files in the entire l10n folder and all subfolders
  1299. t3lib_div::fixPermissions(PATH_typo3conf . 'l10n', TRUE);
  1300. echo $contentParts[1] . $this->doc->endPage();
  1301. exit;
  1302. }
  1303. $this->content .= $this->doc->section($GLOBALS['LANG']->getLL('translation_status'), $content, 0, 1);
  1304. }
  1305. }
  1306. /**
  1307. * Install translations for all selected languages for an extension
  1308. *
  1309. * @param string $extKey The extension key to install the translations for
  1310. * @param string $lang Language code of translation to fetch
  1311. * @param string $mirrorURL Mirror URL to fetch data from
  1312. * @return mixed true on success, error string on fauilure
  1313. */
  1314. function updateTranslation($extKey, $lang, $mirrorURL) {
  1315. $l10n = $this->terConnection->fetchTranslation($extKey, $lang, $mirrorURL);
  1316. if(is_array($l10n)) {
  1317. $file = PATH_site.'typo3temp/'.$extKey.'-l10n-'.$lang.'.zip';
  1318. $path = 'l10n/'.$lang.'/';
  1319. if(!is_dir(PATH_typo3conf.$path)) t3lib_div::mkdir_deep(PATH_typo3conf,$path);
  1320. t3lib_div::writeFile($file, $l10n[0]);
  1321. if($this->unzip($file, PATH_typo3conf.$path)) {
  1322. return true;
  1323. } else {
  1324. return $GLOBALS['LANG']->getLL('translation_unpacking_failed');
  1325. }
  1326. } else {
  1327. return $l10n;
  1328. }
  1329. }
  1330. /**
  1331. * Install translations for all selected languages for an extension
  1332. *
  1333. * @param string $extKey The extension key to install the translations for
  1334. * @param string $mirrorURL Mirror URL to fetch data from
  1335. * @return mixed true on success, error string on fauilure
  1336. */
  1337. function installTranslationsForExtension($extKey, $mirrorURL) {
  1338. $selectedLanguages = unserialize($this->MOD_SETTINGS['selectedLanguages']);
  1339. if(!is_array($selectedLanguages)) $selectedLanguages = array();
  1340. foreach($selectedLanguages as $lang) {
  1341. $l10n = $this->terConnection->fetchTranslation($extKey, $lang, $mirrorURL);
  1342. if(is_array($l10n)) {
  1343. $file = PATH_typo3conf.'l10n/'.$extKey.'-l10n-'.$lang.'.zip';
  1344. $path = 'l10n/'.$lang.'/'.$extKey;
  1345. t3lib_div::writeFile($file, $l10n[0]);
  1346. if(!is_dir(PATH_typo3conf.$path)) t3lib_div::mkdir_deep(PATH_typo3conf,$path);
  1347. if($this->unzip($file, PATH_typo3conf.$path)) {
  1348. return true;
  1349. } else {
  1350. return $GLOBALS['LANG']->getLL('translation_unpacking_failed');
  1351. }
  1352. } else {
  1353. return $l10n;
  1354. }
  1355. }
  1356. }
  1357. /**
  1358. * Unzips a zip file in the given path.
  1359. *
  1360. * Uses unzip binary if available, otherwise a pure PHP unzip is used.
  1361. *
  1362. * @param string $file Full path to zip file
  1363. * @param string $path Path to change to before extracting
  1364. * @return boolean True on success, false in failure
  1365. */
  1366. function unzip($file, $path) {
  1367. if(strlen($GLOBALS['TYPO3_CONF_VARS']['BE']['unzip_path'])) {
  1368. chdir($path);
  1369. $cmd = $GLOBALS['TYPO3_CONF_VARS']['BE']['unzip_path'].' -o '.escapeshellarg($file);
  1370. exec($cmd, $list, $ret);
  1371. return ($ret === 0);
  1372. } else {
  1373. // we use a pure PHP unzip
  1374. $unzip = new em_unzip($file);
  1375. $ret = $unzip->extract(array('add_path'=>$path));
  1376. return (is_array($ret));
  1377. }
  1378. }
  1379. /*********************************
  1380. *
  1381. * Command Applications (triggered by GET var)
  1382. *
  1383. *********************************/
  1384. /**
  1385. * Returns detailed info about an extension in the online repository
  1386. *
  1387. * @param string Extension repository uid + optional "private key": [uid]-[key].
  1388. * @param [type] $version: ...
  1389. * @return void
  1390. */
  1391. function importExtInfo($extKey, $version='') {
  1392. $content = '<form action="index.php" method="post" name="pageform">';
  1393. // Fetch remote data:
  1394. $this->xmlhandler->searchExtensionsXMLExact($extKey, '', '', true, true);
  1395. list($fetchData,) = $this->prepareImportExtList(true);
  1396. $versions = array_keys($fetchData[$extKey]['versions']);
  1397. natsort($versions);
  1398. $version = ($version == '') ? end($versions) : $version;
  1399. $opt = array();
  1400. foreach($versions as $ver) {
  1401. $opt[]='<option value="'.$ver.'"'.(($version == $ver) ? ' selected="selected"' : '').'>'.$ver.'</option>';
  1402. }
  1403. // "Select version" box:
  1404. $onClick = 'window.location.href=\'index.php?CMD[importExtInfo]='.$extKey.'&CMD[extVersion]=\'+document.pageform.extVersion.options[document.pageform.extVersion.selectedIndex].value; return false;';
  1405. $select = '<select name="extVersion">' . implode('', $opt) .
  1406. '</select> <input type="submit" value="' . $GLOBALS['LANG']->getLL('ext_load_details_button') .
  1407. '" onclick="' . htmlspecialchars($onClick) . '" />';
  1408. if ($this->importAtAll()) {
  1409. // Check for write-protected extension
  1410. list($inst_list,) = $this->getInstalledExtensions();
  1411. if ($inst_list[$extKey]['EM_CONF']['state'] != 'excludeFromUpdates') {
  1412. $onClick = '
  1413. window.location.href=\'index.php?CMD[importExt]='.$extKey.'\'
  1414. +\'&CMD[extVersion]=\'+document.pageform.extVersion.options[document.pageform.extVersion.selectedIndex].value
  1415. +\'&CMD[loc]=\'+document.pageform.loc.options[document.pageform.loc.selectedIndex].value;
  1416. return false;';
  1417. $select .= ' ' . $GLOBALS['LANG']->getLL('ext_or') . '<br /><br />
  1418. <input type="submit" value="' . $GLOBALS['LANG']->getLL('ext_import_update_button') .
  1419. '" onclick="' . htmlspecialchars($onClick) . '" /> ' . $GLOBALS['LANG']->getLL('ext_import_update_to') . '
  1420. <select name="loc">'.
  1421. ($this->importAsType('G', $fetchData['emconf_lockType']) ?
  1422. '<option value="G">' . $GLOBALS['LANG']->getLL('ext_import_global') . ' ' . $this->typePaths['G'] . $extKey . '/' .
  1423. (@is_dir(PATH_site . $this->typePaths['G'] . $extKey) ?
  1424. ' ' . $GLOBALS['LANG']->getLL('ext_import_overwrite') :
  1425. ' ' . $GLOBALS['LANG']->getLL('ext_import_folder_empty')
  1426. ) . '</option>' : ''
  1427. ) .
  1428. ($this->importAsType('L', $fetchData['emconf_lockType']) ?
  1429. '<option value="L">' . $GLOBALS['LANG']->getLL('ext_import_local') . ' ' . $this->typePaths['L'] . $extKey . '/' .
  1430. (@is_dir(PATH_site . $this->typePaths['L'] . $extKey) ?
  1431. ' ' . $GLOBALS['LANG']->getLL('ext_import_overwrite') :
  1432. ' ' . $GLOBALS['LANG']->getLL('ext_import_folder_empty')
  1433. ) . '</option>' : ''
  1434. ) .
  1435. ($this->importAsType('S', $fetchData['emconf_lockType']) ?
  1436. '<option value="S">' . $GLOBALS['LANG']->getLL('ext_import_system') . ' ' . $this->typePaths['S'] . $extKey . '/' .
  1437. (@is_dir(PATH_site . $this->typePaths['S'] . $extKey) ?
  1438. ' ' . $GLOBALS['LANG']->getLL('ext_import_overwrite') :
  1439. ' ' . $GLOBALS['LANG']->getLL('ext_import_folder_empty')
  1440. ) . '</option>' : ''
  1441. ) .
  1442. '</select>
  1443. </form>';
  1444. } else {
  1445. $select .= '<br /><br />' . $GLOBALS['LANG']->getLL('ext_import_excluded_from_updates');
  1446. }
  1447. } else {
  1448. $select .= '<br /><br />' . $this->noImportMsg();
  1449. }
  1450. $content.= $select;
  1451. $this->content .= $this->doc->section($GLOBALS['LANG']->getLL('ext_import_select_command'), $content, 0, 1);
  1452. // Details:
  1453. $eInfo = $fetchData[$extKey]['versions'][$version];
  1454. $content='<strong>'.$fetchData[$extKey]['_ICON'].' &nbsp;'.$eInfo['EM_CONF']['title'].' ('.$extKey.', '.$version.')</strong><br /><br />';
  1455. $content.=$this->extInformationArray($extKey,$eInfo,1);
  1456. $this->content.=$this->doc->spacer(10);
  1457. $this->content .= $this->doc->section($GLOBALS['LANG']->getLL('ext_import_remote_ext_details'), $content, 0, 1);
  1458. }
  1459. /**
  1460. * Fetches metadata and stores it to the corresponding place. This includes the mirror list,
  1461. * extension XML files.
  1462. *
  1463. * @param string Type of data to fetch: (mirrors)
  1464. * @param boolean If true the method doesn't produce any output
  1465. * @return void
  1466. */
  1467. function fetchMetaData($metaType) {
  1468. global $TYPO3_CONF_VARS;
  1469. switch($metaType) {
  1470. case 'mirrors':
  1471. $mfile = t3lib_div::tempnam('mirrors');
  1472. $mirrorsFile = t3lib_div::getURL($this->MOD_SETTINGS['mirrorListURL'], 0, array(TYPO3_user_agent));
  1473. if($mirrorsFile===false) {
  1474. t3lib_div::unlink_tempfile($mfile);
  1475. $content = '<p>' .
  1476. sprintf($GLOBALS['LANG']->getLL('ext_import_list_not_updated'),
  1477. $this->MOD_SETTINGS['mirrorListURL']
  1478. ) . ' ' .
  1479. $GLOBALS['LANG']->getLL('translation_problems') . '</p>';
  1480. } else {
  1481. t3lib_div::writeFile($mfile, $mirrorsFile);
  1482. $mirrors = implode('',gzfile($mfile));
  1483. t3lib_div::unlink_tempfile($mfile);
  1484. $mirrors = $this->xmlhandler->parseMirrorsXML($mirrors);
  1485. if(is_array($mirrors) && count($mirrors)) {
  1486. t3lib_BEfunc::getModuleData($this->MOD_MENU, array('extMirrors' => serialize($mirrors)), $this->MCONF['name'], '', 'extMirrors');
  1487. $this->MOD_SETTINGS['extMirrors'] = serialize($mirrors);
  1488. $content = '<p>' .
  1489. sprintf($GLOBALS['LANG']->getLL('ext_import_list_updated'),
  1490. count($mirrors)
  1491. ) . '</p>';
  1492. }
  1493. else {
  1494. $content = '<p>' . $mirrors . '<br />' . $GLOBALS['LANG']->getLL('ext_import_list_empty') . '</p>';
  1495. }
  1496. }
  1497. break;
  1498. case 'extensions':
  1499. $this->fetchMetaData('mirrors'); // if we fetch the extensions anyway, we can as well keep this up-to-date
  1500. $mirror = $this->getMirrorURL();
  1501. $extfile = $mirror.'extensions.xml.gz';
  1502. $extmd5 = t3lib_div::getURL($mirror.'extensions.md5', 0, array(TYPO3_user_agent));
  1503. if (is_file(PATH_site.'typo3temp/extensions.xml.gz')) {
  1504. $localmd5 = md5_file(PATH_site.'typo3temp/extensions.xml.gz');
  1505. }
  1506. // count cached extensions. If cache is empty re-fill it
  1507. $cacheCount = $GLOBALS['TYPO3_DB']->exec_SELECTcountRows('extkey', 'cache_extensions');
  1508. if($extmd5 === false) {
  1509. $content .= '<p>' .
  1510. sprintf($GLOBALS['LANG']->getLL('ext_import_md5_not_updated'),
  1511. $mirror . 'extensions.md5'
  1512. ) .
  1513. $GLOBALS['LANG']->getLL('translation_problems') . '</p>';
  1514. } elseif($extmd5 == $localmd5 && $cacheCount) {
  1515. $flashMessage = t3lib_div::makeInstance(
  1516. 't3lib_FlashMessage',
  1517. $GLOBALS['LANG']->getLL('ext_import_list_unchanged'),
  1518. $GLOBALS['LANG']->getLL('ext_import_list_unchanged_header'),
  1519. t3lib_FlashMessage::INFO
  1520. );
  1521. $content .= $flashMessage->render();
  1522. } else {
  1523. $extXML = t3lib_div::getURL($extfile, 0, array(TYPO3_user_agent));
  1524. if($extXML === false) {
  1525. $content .= '<p>' .
  1526. sprintf($GLOBALS['LANG']->getLL('ext_import_list_unchanged'),
  1527. $extfile
  1528. ) . ' ' .
  1529. $GLOBALS['LANG']->getLL('translation_problems') . '</p>';
  1530. } else {
  1531. t3lib_div::writeFile(PATH_site.'typo3temp/extensions.xml.gz', $extXML);
  1532. $content .= $this->xmlhandler->parseExtensionsXML(PATH_site.'typo3temp/extensions.xml.gz');
  1533. }
  1534. }
  1535. break;
  1536. }
  1537. return $content;
  1538. }
  1539. /**
  1540. * Returns the base URL for the slected or a random mirror.
  1541. *
  1542. * @return string The URL for the selected or a random mirror
  1543. */
  1544. function getMirrorURL() {
  1545. if(strlen($this->MOD_SETTINGS['rep_url'])) return $this->MOD_SETTINGS['rep_url'];
  1546. $mirrors = unserialize($this->MOD_SETTINGS['extMirrors']);
  1547. if(!is_array($mirrors)) {
  1548. $this->fetchMetaData('mirrors');
  1549. $mirrors = unserialize($this->MOD_SETTINGS['extMirrors']);
  1550. if(!is_array($mirrors)) return false;
  1551. }
  1552. if($this->MOD_SETTINGS['selectedMirror']=='') {
  1553. $rand = array_rand($mirrors);
  1554. $url = 'http://'.$mirrors[$rand]['host'].$mirrors[$rand]['path'];
  1555. }
  1556. else {
  1557. $url = 'http://'.$mirrors[$this->MOD_SETTINGS['selectedMirror']]['host'].$mirrors[$this->MOD_SETTINGS['selectedMirror']]['path'];
  1558. }
  1559. return $url;
  1560. }
  1561. /**
  1562. * Installs (activates) an extension
  1563. *
  1564. * For $mode use the three constants EM_INSTALL_VERSION_MIN, EM_INSTALL_VERSION_MAX, EM_INSTALL_VERSION_STRICT
  1565. *
  1566. * If an extension is loaded or imported already and the version requirement is matched, it will not be
  1567. * fetched from the repository. This means, if you use EM_INSTALL_VERSION_MIN, you will not always get the latest
  1568. * version of an extension!
  1569. *
  1570. * @param string $extKey The extension key to install
  1571. * @param string $version A version number that should be installed
  1572. * @param int $mode If a version is requested, this determines if it is the min, max or strict version requested
  1573. * @return [type] ...
  1574. * @todo Make the method able to handle needed interaction somehow (unmatched dependencies)
  1575. */
  1576. function installExtension($extKey, $version=null, $mode=EM_INSTALL_VERSION_MIN) {
  1577. list($inst_list,) = $this->getInstalledExtensions();
  1578. // check if it is already installed and loaded with sufficient version
  1579. if(isset($inst_list[$extKey])) {
  1580. $currentVersion = $inst_list[$extKey]['EM_CONF']['version'];
  1581. if(t3lib_extMgm::isLoaded($extKey)) {
  1582. if($version===null) {
  1583. return array(true, $GLOBALS['LANG']->getLL('ext_import_ext_already_installed_loaded'));
  1584. } else {
  1585. switch($mode) {
  1586. case EM_INSTALL_VERSION_STRICT:
  1587. if ($currentVersion == $version) {
  1588. return array(true, $GLOBALS['LANG']->getLL('ext_import_ext_already_installed_loaded'));
  1589. }
  1590. break;
  1591. case EM_INSTALL_VERSION_MIN:
  1592. if (version_compare($currentVersion, $version, '>=')) {
  1593. return array(true, $GLOBALS['LANG']->getLL('ext_import_ext_already_installed_loaded'));
  1594. }
  1595. break;
  1596. case EM_INSTALL_VERSION_MAX:
  1597. if (version_compare($currentVersion, $version, '<=')) {
  1598. return array(true, $GLOBALS['LANG']->getLL('ext_import_ext_already_installed_loaded'));
  1599. }
  1600. break;
  1601. }
  1602. }
  1603. } else {
  1604. if (!t3lib_extMgm::isLocalconfWritable()) {
  1605. return array(false, $GLOBALS['LANG']->getLL('ext_import_p_localconf'));
  1606. }
  1607. $newExtList = -1;
  1608. switch($mode) {
  1609. case EM_INSTALL_VERSION_STRICT:
  1610. if ($currentVersion == $version) {
  1611. $newExtList = $this->addExtToList($extKey, $inst_list);
  1612. }
  1613. break;
  1614. case EM_INSTALL_VERSION_MIN:
  1615. if (version_compare($currentVersion, $version, '>=')) {
  1616. $newExtList = $this->addExtToList($extKey, $inst_list);
  1617. }
  1618. break;
  1619. case EM_INSTALL_VERSION_MAX:
  1620. if (version_compare($currentVersion, $version, '<=')) {
  1621. $newExtList = $this->addExtToList($extKey, $inst_list);
  1622. }
  1623. break;
  1624. }
  1625. if ($newExtList!=-1) {
  1626. $this->writeNewExtensionList($newExtList);
  1627. $this->refreshGlobalExtList();
  1628. $this->forceDBupdates($extKey, $inst_list[$extKey]);
  1629. return array(true, $GLOBALS['LANG']->getLL('ext_import_ext_loaded'));
  1630. }
  1631. }
  1632. }
  1633. // at this point we know we need to import (a matching version of) the extension from TER2
  1634. // see if we have an extension list at all
  1635. if (!$this->xmlhandler->countExtensions()) {
  1636. $this->fetchMetaData('extensions');
  1637. }
  1638. $this->xmlhandler->searchExtensionsXMLExact($extKey, '', '', TRUE, TRUE);
  1639. // check if extension can be fetched
  1640. if(isset($this->xmlhandler->extensionsXML[$extKey])) {
  1641. $versions = array_keys($this->xmlhandler->extensionsXML[$extKey]['versions']);
  1642. $latestVersion = end($versions);
  1643. switch($mode) {
  1644. case EM_INSTALL_VERSION_STRICT:
  1645. if(!isset($this->xmlhandler->extensionsXML[$extKey]['versions'][$version])) {
  1646. return array(false, $GLOBALS['LANG']->getLL('ext_import_ext_n_a'));
  1647. }
  1648. break;
  1649. case EM_INSTALL_VERSION_MIN:
  1650. if (version_compare($latestVersion, $version, '>=')) {
  1651. $version = $latestVersion;
  1652. } else {
  1653. return array(false, $GLOBALS['LANG']->getLL('ext_import_ext_n_a'));
  1654. }
  1655. break;
  1656. case EM_INSTALL_VERSION_MAX:
  1657. while (($v = array_pop($versions)) && version_compare($v, $version, '>=')) {
  1658. // Loop until a version is found
  1659. }
  1660. if ($v !== null && version_compare($v, $version, '<=')) {
  1661. $version = $v;
  1662. } else {
  1663. return array(false, $GLOBALS['LANG']->getLL('ext_import_ext_n_a'));
  1664. }
  1665. break;
  1666. }
  1667. $this->importExtFromRep($extKey, $version, 'L');
  1668. $newExtList = $this->addExtToList($extKey, $inst_list);
  1669. if ($newExtList!=-1) {
  1670. $this->writeNewExtensionList($newExtList);
  1671. $this->refreshGlobalExtList();
  1672. $this->forceDBupdates($extKey, $inst_list[$extKey]);
  1673. $this->installTranslationsForExtension($extKey, $this->getMirrorURL());
  1674. return array(true, $GLOBALS['LANG']->getLL('ext_import_ext_imported'));
  1675. } else {
  1676. return array(false, $GLOBALS['LANG']->getLL('ext_import_ext_not_loaded'));
  1677. }
  1678. } else {
  1679. return array(false, $GLOBALS['LANG']->getLL('ext_import_ext_n_a_rep'));
  1680. }
  1681. }
  1682. function refreshGlobalExtList() {
  1683. global $TYPO3_LOADED_EXT;
  1684. $TYPO3_LOADED_EXT = t3lib_extMgm::typo3_loadExtensions();
  1685. if ($TYPO3_LOADED_EXT['_CACHEFILE']) {
  1686. require(PATH_typo3conf.$TYPO3_LOADED_EXT['_CACHEFILE'].'_ext_localconf.php');
  1687. }
  1688. return;
  1689. $GLOBALS['TYPO3_LOADED_EXT'] = t3lib_extMgm::typo3_loadExtensions();
  1690. if ($TYPO3_LOADED_EXT['_CACHEFILE']) {
  1691. require(PATH_typo3conf.$TYPO3_LOADED_EXT['_CACHEFILE'].'_ext_localconf.php');
  1692. } else {
  1693. $temp_TYPO3_LOADED_EXT = $TYPO3_LOADED_EXT;
  1694. foreach ($temp_TYPO3_LOADED_EXT as $_EXTKEY => $temp_lEDat) {
  1695. if (is_array($temp_lEDat) && $temp_lEDat['ext_localconf.php']) {
  1696. $_EXTCONF = $TYPO3_CONF_VARS['EXT']['extConf'][$_EXTKEY];
  1697. require($temp_lEDat['ext_localconf.php']);
  1698. }
  1699. }
  1700. }
  1701. }
  1702. /**
  1703. * Imports an extensions from the online repository
  1704. * NOTICE: in version 4.0 this changed from "importExtFromRep_old($extRepUid,$loc,$uploadFlag=0,$directInput='',$recentTranslations=0,$incManual=0,$dontDelete=0)"
  1705. *
  1706. * @param string Extension key
  1707. * @param string Version
  1708. * @param string Install scope: "L" or "G" or "S"
  1709. * @param boolean If true, extension is uploaded as file
  1710. * @param boolean If true, extension directory+files will not be deleted before writing the new ones. That way custom files stored in the extension folder will be kept.
  1711. * @param array Direct input array (like from kickstarter)
  1712. * @return string Return false on success, returns error message if error.
  1713. */
  1714. function importExtFromRep($extKey,$version,$loc,$uploadFlag=0,$dontDelete=0,$directInput='') {
  1715. $uploadSucceed = false;
  1716. $uploadedTempFile = '';
  1717. if (is_array($directInput)) {
  1718. $fetchData = array($directInput,'');
  1719. $loc = ($loc==='G'||$loc==='S') ? $loc : 'L';
  1720. } elseif ($uploadFlag) {
  1721. if (($uploadedTempFile = $this->CMD['alreadyUploaded']) || $_FILES['upload_ext_file']['tmp_name']) {
  1722. // Read uploaded file:
  1723. if (!$uploadedTempFile) {
  1724. if (!is_uploaded_file($_FILES['upload_ext_file']['tmp_name'])) {
  1725. t3lib_div::sysLog('Possible file upload attack: '.$_FILES['upload_ext_file']['tmp_name'], 'Extension Manager', 3);
  1726. return $GLOBALS['LANG']->getLL('ext_import_file_not_uploaded');
  1727. }
  1728. $uploadedTempFile = t3lib_div::upload_to_tempfile($_FILES['upload_ext_file']['tmp_name']);
  1729. }
  1730. $fileContent = t3lib_div::getUrl($uploadedTempFile);
  1731. if (!$fileContent) return $GLOBALS['LANG']->getLL('ext_import_file_empty');
  1732. // Decode file data:
  1733. $fetchData = $this->terConnection->decodeExchangeData($fileContent);
  1734. if (is_array($fetchData)) {
  1735. $extKey = $fetchData[0]['extKey'];
  1736. if ($extKey) {
  1737. if (!$this->CMD['uploadOverwrite']) {
  1738. $loc = ($loc==='G'||$loc==='S') ? $loc : 'L';
  1739. $comingExtPath = PATH_site.$this->typePaths[$loc].$extKey.'/';
  1740. if (@is_dir($comingExtPath)) {
  1741. $flashMessage = t3lib_div::makeInstance(
  1742. 't3lib_FlashMessage',
  1743. sprintf($GLOBALS['LANG']->getLL('ext_import_ext_present_no_overwrite'), $comingExtPath) .
  1744. '<br />' . $GLOBALS['LANG']->getLL('ext_import_ext_present_nothing_done'),
  1745. '',
  1746. t3lib_FlashMessage::ERROR
  1747. );
  1748. return $flashMessage->render();
  1749. } // ... else go on, install...
  1750. } // ... else go on, install...
  1751. } else return $GLOBALS['LANG']->getLL('ext_import_no_key');
  1752. } else return sprintf($GLOBALS['LANG']->getLL('ext_import_wrong_file_format'), $fetchData);
  1753. } else return $GLOBALS['LANG']->getLL('ext_import_no_file');
  1754. } else {
  1755. $this->xmlhandler->searchExtensionsXMLExact($extKey, '', '', true, true);
  1756. // Fetch extension from TER:
  1757. if(!strlen($version)) {
  1758. $versions = array_keys($this->xmlhandler->extensionsXML[$extKey]['versions']);
  1759. $version = end($versions);
  1760. }
  1761. $fetchData = $this->terConnection->fetchExtension($extKey, $version, $this->xmlhandler->extensionsXML[$extKey]['versions'][$version]['t3xfilemd5'], $this->getMirrorURL());
  1762. }
  1763. // At this point the extension data should be present; so we want to write it to disc:
  1764. if ($this->importAsType($loc)) {
  1765. if (is_array($fetchData)) { // There was some data successfully transferred
  1766. if ($fetchData[0]['extKey'] && is_array($fetchData[0]['FILES'])) {
  1767. $extKey = $fetchData[0]['extKey'];
  1768. if(!isset($fetchData[0]['EM_CONF']['constraints'])) $fetchData[0]['EM_CONF']['constraints'] = $this->xmlhandler->extensionsXML[$extKey]['versions'][$version]['dependencies'];
  1769. $EM_CONF = $this->fixEMCONF($fetchData[0]['EM_CONF']);
  1770. if (!$EM_CONF['lockType'] || !strcmp($EM_CONF['lockType'],$loc)) {
  1771. // check dependencies, act accordingly if ext is loaded
  1772. list($instExtInfo,)=$this->getInstalledExtensions();
  1773. $depStatus = $this->checkDependencies($extKey, $EM_CONF, $instExtInfo);
  1774. if(t3lib_extMgm::isLoaded($extKey) && !$depStatus['returnCode']) {
  1775. $this->content .= $depStatus['html'];
  1776. if ($uploadedTempFile) {
  1777. $this->content .= '<input type="hidden" name="CMD[alreadyUploaded]" value="'.$uploadedTempFile.'" />';
  1778. }
  1779. } else {
  1780. $res = $this->clearAndMakeExtensionDir($fetchData[0],$loc,$dontDelete);
  1781. if (is_array($res)) {
  1782. $extDirPath = trim($res[0]);
  1783. if ($extDirPath && @is_dir($extDirPath) && substr($extDirPath,-1)=='/') {
  1784. $emConfFile = $this->construct_ext_emconf_file($extKey,$EM_CONF);
  1785. $dirs = $this->extractDirsFromFileList(array_keys($fetchData[0]['FILES']));
  1786. $res = $this->createDirsInPath($dirs,$extDirPath);
  1787. if (!$res) {
  1788. $writeFiles = $fetchData[0]['FILES'];
  1789. $writeFiles['ext_emconf.php']['content'] = $emConfFile;
  1790. $writeFiles['ext_emconf.php']['content_md5'] = md5($emConfFile);
  1791. // Write files:
  1792. foreach($writeFiles as $theFile => $fileData) {
  1793. t3lib_div::writeFile($extDirPath.$theFile,$fileData['content']);
  1794. if (!@is_file($extDirPath.$theFile)) {
  1795. $content .= sprintf($GLOBALS['LANG']->getLL('ext_import_file_not_created'),
  1796. $extDirPath . $theFile) . '<br />';
  1797. } elseif (md5(t3lib_div::getUrl($extDirPath.$theFile)) != $fileData['content_md5']) {
  1798. $content .= sprintf($GLOBALS['LANG']->getLL('ext_import_file_corrupted'),
  1799. $extDirPath . $theFile) . '<br />';
  1800. }
  1801. }
  1802. t3lib_div::fixPermissions($extDirPath, TRUE);
  1803. // No content, no errors. Create success output here:
  1804. if (!$content) {
  1805. $messageContent = sprintf($GLOBALS['LANG']->getLL('ext_import_success_folder'), $extDirPath) . '<br />';
  1806. $uploadSucceed = true;
  1807. // Fix TYPO3_MOD_PATH for backend modules in extension:
  1808. $modules = t3lib_div::trimExplode(',', $EM_CONF['module'], 1);
  1809. if (count($modules)) {
  1810. foreach($modules as $mD) {
  1811. $confFileName = $extDirPath . $mD . '/conf.php';
  1812. if (@is_file($confFileName)) {
  1813. $messageContent .= $this->writeTYPO3_MOD_PATH($confFileName, $loc, $extKey . '/' . $mD . '/') . '<br />';
  1814. } else {
  1815. $messageContent .= sprintf($GLOBALS['LANG']->getLL('ext_import_no_conf_file'),
  1816. $confFileName) . '<br />';
  1817. }
  1818. }
  1819. }
  1820. // 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.
  1821. // But this order of the code works.... (using the empty Array with type, EMCONF and files hereunder).
  1822. // Writing to ext_emconf.php:
  1823. $sEMD5A = $this->serverExtensionMD5Array($extKey,array('type' => $loc, 'EM_CONF' => array(), 'files' => array()));
  1824. $EM_CONF['_md5_values_when_last_written'] = serialize($sEMD5A);
  1825. $emConfFile = $this->construct_ext_emconf_file($extKey, $EM_CONF);
  1826. t3lib_div::writeFile($extDirPath . 'ext_emconf.php', $emConfFile);
  1827. $messageContent .= 'ext_emconf.php: ' . $extDirPath . 'ext_emconf.php<br />';
  1828. $messageContent .= $GLOBALS['LANG']->getLL('ext_import_ext_type') . ' ';
  1829. $messageContent .= $this->typeLabels[$loc] . '<br />';
  1830. $messageContent .= '<br />';
  1831. // Remove cache files:
  1832. $updateContent = '';
  1833. if (t3lib_extMgm::isLoaded($extKey)) {
  1834. if ($this->removeCacheFiles()) {
  1835. $messageContent .= $GLOBALS['LANG']->getLL('ext_import_cache_files_removed') . '<br />';
  1836. }
  1837. list($new_list) = $this->getInstalledExtensions();
  1838. $updateContent = $this->updatesForm($extKey, $new_list[$extKey], 1, 'index.php?CMD[showExt]=' . $extKey . '&SET[singleDetails]=info');
  1839. }
  1840. $flashMessage = t3lib_div::makeInstance(
  1841. 't3lib_FlashMessage',
  1842. $messageContent,
  1843. $GLOBALS['LANG']->getLL('ext_import_success')
  1844. );
  1845. $content = $flashMessage->render() . $updateContent;
  1846. // Install / Uninstall:
  1847. if(!$this->CMD['standAlone']) {
  1848. $content .= '<h3>' . $GLOBALS['LANG']->getLL('ext_import_install_uninstall') . '</h3>';
  1849. $content.= $new_list[$extKey] ?
  1850. '<a href="' . htmlspecialchars('index.php?CMD[showExt]=' . $extKey .
  1851. '&CMD[remove]=1&CMD[clrCmd]=1&SET[singleDetails]=info') . '">' .
  1852. $this->removeButton() . ' ' . $GLOBALS['LANG']->getLL('ext_import_uninstall') . '</a>' :
  1853. '<a href="' . htmlspecialchars('index.php?CMD[showExt]=' . $extKey .
  1854. '&CMD[load]=1&CMD[clrCmd]=1&SET[singleDetails]=info') . '">' .
  1855. $this->installButton() . ' ' . $GLOBALS['LANG']->getLL('ext_import_install') . '</a>';
  1856. } else {
  1857. $content = $GLOBALS['LANG']->getLL('ext_import_imported') .
  1858. '<br /><br /><a href="javascript:opener.top.content.document.forms[0].submit();window.close();">' .
  1859. $GLOBALS['LANG']->getLL('ext_import_close_check') . '</a>';
  1860. }
  1861. }
  1862. } else $content = $res;
  1863. } else $content = sprintf($GLOBALS['LANG']->getLL('ext_import_ext_path_different'), $extDirPath);
  1864. } else $content = $res;
  1865. }
  1866. } else $content = sprintf($GLOBALS['LANG']->getLL('ext_import_ext_only_here'),
  1867. $this->typePaths[$EM_CONF['lockType']], $EM_CONF['lockType']);
  1868. } else $content = $GLOBALS['LANG']->getLL('ext_import_no_ext_key_files');
  1869. } else $content = sprintf($GLOBALS['LANG']->getLL('ext_import_data_transfer'), $fetchData);
  1870. } else $content = sprintf($GLOBALS['LANG']->getLL('ext_import_no_install_here'), $this->typePaths[$loc]);
  1871. $this->content .= $this->doc->section($GLOBALS['LANG']->getLL('ext_import_results'), $content, 0, 1);
  1872. if ($uploadSucceed && $uploadedTempFile) {
  1873. t3lib_div::unlink_tempfile($uploadedTempFile);
  1874. }
  1875. return false;
  1876. }
  1877. /**
  1878. * Display extensions details.
  1879. *
  1880. * @param string Extension key
  1881. * @return void Writes content to $this->content
  1882. */
  1883. function showExtDetails($extKey) {
  1884. global $TYPO3_LOADED_EXT;
  1885. list($list,)=$this->getInstalledExtensions();
  1886. $absPath = $this->getExtPath($extKey,$list[$extKey]['type']);
  1887. // Check updateModule:
  1888. if (isset($list[$extKey]) && @is_file($absPath.'class.ext_update.php')) {
  1889. require_once($absPath.'class.ext_update.php');
  1890. $updateObj = new ext_update;
  1891. if (!$updateObj->access()) {
  1892. unset($this->MOD_MENU['singleDetails']['updateModule']);
  1893. }
  1894. } else {
  1895. unset($this->MOD_MENU['singleDetails']['updateModule']);
  1896. }
  1897. if($this->CMD['doDelete']) {
  1898. $this->MOD_MENU['singleDetails'] = array();
  1899. }
  1900. // Function menu here:
  1901. if(!$this->CMD['standAlone'] && !t3lib_div::_GP('standAlone')) {
  1902. $content = $GLOBALS['LANG']->getLL('ext_details_ext') . '&nbsp;<strong>' .
  1903. $this->extensionTitleIconHeader($extKey, $list[$extKey]) . '</strong> (' . htmlspecialchars($extKey) . ')';
  1904. $this->content.= $this->doc->section('', $content);
  1905. }
  1906. // Show extension details:
  1907. if ($list[$extKey]) {
  1908. // Checking if a command for install/uninstall is executed:
  1909. if (($this->CMD['remove'] || $this->CMD['load']) && !in_array($extKey,$this->requiredExt)) {
  1910. // Install / Uninstall extension here:
  1911. if (t3lib_extMgm::isLocalconfWritable()) {
  1912. // Check dependencies:
  1913. $depStatus = $this->checkDependencies($extKey, $list[$extKey]['EM_CONF'], $list);
  1914. if(!$this->CMD['remove'] && !$depStatus['returnCode']) {
  1915. $this->content .= $depStatus['html'];
  1916. $newExtList = -1;
  1917. } elseif ($this->CMD['remove']) {
  1918. $newExtList = $this->removeExtFromList($extKey,$list);
  1919. } else {
  1920. $newExtList = $this->addExtToList($extKey,$list);
  1921. }
  1922. // Successful installation:
  1923. if ($newExtList!=-1) {
  1924. $updates = '';
  1925. if ($this->CMD['load']) {
  1926. if($_SERVER['REQUEST_METHOD'] == 'POST') {
  1927. $script = t3lib_div::linkThisScript(array('CMD[showExt]' => $extKey, 'CMD[load]' => 1, 'CMD[clrCmd]' => $this->CMD['clrCmd'], 'SET[singleDetails]' => 'info'));
  1928. } else {
  1929. $script = '';
  1930. }
  1931. if($this->CMD['standAlone']) {
  1932. $standaloneUpdates = '<input type="hidden" name="standAlone" value="1" />';
  1933. }
  1934. $depsolver = t3lib_div::_POST('depsolver');
  1935. if(is_array($depsolver['ignore'])) {
  1936. foreach($depsolver['ignore'] as $depK => $depV) {
  1937. $dependencyUpdates .= '<input type="hidden" name="depsolver[ignore]['.$depK.']" value="1" />';
  1938. }
  1939. }
  1940. $updatesForm = $this->updatesForm($extKey,$list[$extKey],1,$script, $dependencyUpdates.$standaloneUpdates.'<input type="hidden" name="_do_install" value="1" /><input type="hidden" name="_clrCmd" value="'.$this->CMD['clrCmd'].'" />', TRUE);
  1941. if ($updatesForm) {
  1942. $updates = $GLOBALS['LANG']->getLL('ext_details_new_tables_fields') . '<br />' .
  1943. $GLOBALS['LANG']->getLL('ext_details_new_tables_fields_select') . $updatesForm;
  1944. $labelDBUpdate = $GLOBALS['LANG']->csConvObj->conv_case(
  1945. $GLOBALS['LANG']->charSet,
  1946. $GLOBALS['LANG']->getLL('ext_details_db_needs_update'),
  1947. 'toUpper'
  1948. );
  1949. $this->content .= $this->doc->section(
  1950. sprintf($GLOBALS['LANG']->getLL('ext_details_installing') . ' ',
  1951. $this->extensionTitleIconHeader($extKey, $list[$extKey])
  1952. ) . ' ' .
  1953. $labelDBUpdate,
  1954. $updates, 1, 1, 1, 1
  1955. );
  1956. }
  1957. } elseif ($this->CMD['remove']) {
  1958. $updates.= $this->checkClearCache($list[$extKey]);
  1959. if ($updates) {
  1960. $updates = '
  1961. <form action="'.t3lib_div::linkThisScript().'" method="post">'.$updates.'
  1962. <br /><input type="submit" name="write" value="' .
  1963. $GLOBALS['LANG']->getLL('ext_details_remove_ext') . '" />
  1964. <input type="hidden" name="_do_install" value="1" />
  1965. <input type="hidden" name="_clrCmd" value="'.$this->CMD['clrCmd'].'" />
  1966. <input type="hidden" name="standAlone" value="'.$this->CMD['standAlone'].'" />
  1967. </form>';
  1968. $labelDBUpdate = $GLOBALS['LANG']->csConvObj->conv_case(
  1969. $GLOBALS['LANG']->charSet,
  1970. $GLOBALS['LANG']->getLL('ext_details_db_needs_update'),
  1971. 'toUpper'
  1972. );
  1973. $this->content .= $this->doc->section(
  1974. sprintf($GLOBALS['LANG']->getLL('ext_details_removing') . ' ',
  1975. $this->extensionTitleIconHeader($extKey, $list[$extKey])
  1976. ) . ' ' .
  1977. $labelDBUpdate,
  1978. $updates, 1, 1, 1, 1
  1979. );
  1980. }
  1981. }
  1982. if (!$updates || t3lib_div::_GP('_do_install')) {
  1983. $this->writeNewExtensionList($newExtList);
  1984. $action = $this->CMD['load'] ? 'installed' : 'removed';
  1985. $GLOBALS['BE_USER']->writelog(5, 1, 0, 0, 'Extension list has been changed, extension %s has been %s', array($extKey, $action));
  1986. $messageLabel = 'ext_details_ext_' . $action . '_with_key';
  1987. $flashMessage = t3lib_div::makeInstance(
  1988. 't3lib_FlashMessage',
  1989. sprintf($GLOBALS['LANG']->getLL($messageLabel), $extKey),
  1990. '',
  1991. t3lib_FlashMessage::OK,
  1992. TRUE
  1993. );
  1994. t3lib_FlashMessageQueue::addMessage($flashMessage);
  1995. if ($this->CMD['clrCmd'] || t3lib_div::_GP('_clrCmd')) {
  1996. if ($this->CMD['load'] && @is_file($absPath.'ext_conf_template.txt')) {
  1997. $vA = array('CMD'=>Array('showExt'=>$extKey));
  1998. } else {
  1999. $vA = array('CMD'=>'');
  2000. }
  2001. } else {
  2002. $vA = array('CMD'=>Array('showExt'=>$extKey));
  2003. }
  2004. if($this->CMD['standAlone'] || t3lib_div::_GP('standAlone')) {
  2005. $this->content .= sprintf($GLOBALS['LANG']->getLL('ext_details_ext_installed_removed'),
  2006. ($this->CMD['load'] ?
  2007. $GLOBALS['LANG']->getLL('ext_details_installed') :
  2008. $GLOBALS['LANG']->getLL('ext_details_removed')
  2009. )
  2010. ) .
  2011. '<br /><br /><a href="javascript:opener.top.content.document.forms[0].submit();window.close();">' .
  2012. $GLOBALS['LANG']->getLL('ext_import_close_check') . '</a>';
  2013. } else {
  2014. // Determine if new modules were installed:
  2015. $techInfo = $this->makeDetailedExtensionAnalysis($extKey, $list[$extKey]);
  2016. if (($this->CMD['load'] || $this->CMD['remove']) && is_array($techInfo['flags']) && in_array('Module', $techInfo['flags'], true)) {
  2017. $vA['CMD']['refreshMenu'] = 1;
  2018. }
  2019. t3lib_utility_Http::redirect(t3lib_div::linkThisScript($vA));
  2020. }
  2021. }
  2022. }
  2023. } else {
  2024. $writeAccessError = $GLOBALS['LANG']->csConvObj->conv_case(
  2025. $GLOBALS['LANG']->charSet,
  2026. $GLOBALS['LANG']->getLL('ext_details_write_access_error'),
  2027. 'toUpper'
  2028. );
  2029. $this->content .= $this->doc->section(
  2030. sprintf($GLOBALS['LANG']->getLL('ext_details_installing') . ' ',
  2031. $this->extensionTitleIconHeader($extKey, $list[$extKey])
  2032. ) . ' ' .
  2033. $writeAccessError,
  2034. $GLOBALS['LANG']->getLL('ext_details_write_error_localconf'),
  2035. 1, 1, 2, 1
  2036. );
  2037. }
  2038. } elseif ($this->CMD['downloadFile'] && !in_array($extKey,$this->requiredExt)) {
  2039. // Link for downloading extension has been clicked - deliver content stream:
  2040. $dlFile = $this->CMD['downloadFile'];
  2041. if (t3lib_div::isFirstPartOfStr($dlFile,PATH_site) && t3lib_div::isFirstPartOfStr($dlFile,$absPath) && @is_file($dlFile)) {
  2042. $mimeType = 'application/octet-stream';
  2043. Header('Content-Type: '.$mimeType);
  2044. Header('Content-Disposition: attachment; filename='.basename($dlFile));
  2045. echo t3lib_div::getUrl($dlFile);
  2046. exit;
  2047. } else {
  2048. throw new RuntimeException(
  2049. 'TYPO3 Fatal Error: ' . $GLOBALS['LANG']->getLL('ext_details_error_downloading'),
  2050. 1270853980
  2051. );
  2052. }
  2053. } elseif ($this->CMD['editFile'] && !in_array($extKey,$this->requiredExt)) {
  2054. // Editing extension file:
  2055. $editFile = $this->CMD['editFile'];
  2056. if (t3lib_div::isAllowedAbsPath($editFile) && t3lib_div::isFirstPartOfStr($editFile, $absPath)) {
  2057. $fI = t3lib_div::split_fileref($editFile);
  2058. if (@is_file($editFile) && t3lib_div::inList($this->editTextExtensions,($fI['fileext']?$fI['fileext']:$fI['filebody']))) {
  2059. if (filesize($editFile)<($this->kbMax*1024)) {
  2060. $outCode = '<form action="index.php" method="post" name="editfileform">';
  2061. $info = '';
  2062. $submittedContent = t3lib_div::_POST('edit');
  2063. $saveFlag = 0;
  2064. if(isset($submittedContent['file']) && !$GLOBALS['TYPO3_CONF_VARS']['EXT']['noEdit']) { // Check referer here?
  2065. $oldFileContent = t3lib_div::getUrl($editFile);
  2066. if($oldFileContent != $submittedContent['file']) {
  2067. $oldMD5 = md5(str_replace(CR,'',$oldFileContent));
  2068. $info .= sprintf(
  2069. $GLOBALS['LANG']->getLL('ext_details_md5_previous'),
  2070. '<strong>' . $oldMD5 . '</strong>'
  2071. ) . '<br />';
  2072. t3lib_div::writeFile($editFile,$submittedContent['file']);
  2073. $saveFlag = 1;
  2074. } else {
  2075. $info .= $GLOBALS['LANG']->getLL('ext_details_no_changes') . '<br />';
  2076. }
  2077. }
  2078. $fileContent = t3lib_div::getUrl($editFile);
  2079. $outCode.= sprintf(
  2080. $GLOBALS['LANG']->getLL('ext_details_file'),
  2081. '<strong>' . substr($editFile, strlen($absPath)) . '</strong> (' .
  2082. t3lib_div::formatSize(filesize($editFile)) . ')<br />'
  2083. );
  2084. $fileMD5 = md5(str_replace(CR,'',$fileContent));
  2085. $info .= sprintf(
  2086. $GLOBALS['LANG']->getLL('ext_details_md5_current'),
  2087. '<strong>' . $fileMD5 . '</strong>'
  2088. ) . '<br />';
  2089. if($saveFlag) {
  2090. $saveMD5 = md5(str_replace(CR,'',$submittedContent['file']));
  2091. $info .= sprintf(
  2092. $GLOBALS['LANG']->getLL('ext_details_md5_submitted'),
  2093. '<strong>' . $saveMD5 . '</strong>'
  2094. ) . '<br />';
  2095. if ($fileMD5!=$saveMD5) {
  2096. $info .= $GLOBALS['TBE_TEMPLATE']->rfw(
  2097. '<br /><strong>' . $GLOBALS['LANG']->getLL('ext_details_saving_failed_changes_lost') . '</strong>'
  2098. ) . '<br />';
  2099. }
  2100. else {
  2101. $info .= $GLOBALS['TBE_TEMPLATE']->rfw(
  2102. '<br /><strong>' . $GLOBALS['LANG']->getLL('ext_details_file_saved') . '</strong>'
  2103. ) . '<br />';
  2104. }
  2105. }
  2106. $outCode.= '<textarea name="edit[file]" rows="35" wrap="off"'.$this->doc->formWidthText(48,'width:98%;height:70%','off').' class="fixed-font enable-tab">'.t3lib_div::formatForTextarea($fileContent).'</textarea>';
  2107. $outCode.= '<input type="hidden" name="edit[filename]" value="'.$editFile.'" />';
  2108. $outCode.= '<input type="hidden" name="CMD[editFile]" value="'.htmlspecialchars($editFile).'" />';
  2109. $outCode.= '<input type="hidden" name="CMD[showExt]" value="'.$extKey.'" />';
  2110. $outCode.= $info;
  2111. if (!$GLOBALS['TYPO3_CONF_VARS']['EXT']['noEdit']) {
  2112. $outCode .= '<br /><input type="submit" name="save_file" value="' .
  2113. $GLOBALS['LANG']->getLL('ext_details_file_save_button') . '" />';
  2114. }
  2115. else {
  2116. $outCode .= $GLOBALS['TBE_TEMPLATE']->rfw(
  2117. '<br />' . $GLOBALS['LANG']->getLL('ext_details_saving_disabled') . ' '
  2118. );
  2119. }
  2120. $onClick = 'window.location.href=\'index.php?CMD[showExt]='.$extKey.'\';return false;';
  2121. $outCode .= '<input type="submit" name="cancel" value="' .
  2122. $GLOBALS['LANG']->getLL('ext_details_cancel_button') . '" onclick="' .
  2123. htmlspecialchars($onClick) . '" /></form>';
  2124. $theOutput.=$this->doc->spacer(15);
  2125. $theOutput .= $this->doc->section($GLOBALS['LANG']->getLL('ext_details_edit_file'), '', 0, 1);
  2126. $theOutput.=$this->doc->sectionEnd().$outCode;
  2127. $this->content.=$theOutput;
  2128. } else {
  2129. $theOutput.=$this->doc->spacer(15);
  2130. $theOutput .= $this->doc->section(
  2131. sprintf(
  2132. $GLOBALS['LANG']->getLL('ext_details_filesize_exceeded_kb'),
  2133. $this->kbMax
  2134. ),
  2135. sprintf(
  2136. $GLOBALS['LANG']->getLL('ext_details_file_too_large'),
  2137. $this->kbMax
  2138. )
  2139. );
  2140. }
  2141. }
  2142. } else {
  2143. die (sprintf($GLOBALS['LANG']->getLL('ext_details_fatal_edit_error'),
  2144. htmlspecialchars($editFile)
  2145. )
  2146. );
  2147. }
  2148. } else {
  2149. // MAIN:
  2150. switch((string)$this->MOD_SETTINGS['singleDetails']) {
  2151. case 'info':
  2152. // Loaded / Not loaded:
  2153. if (!in_array($extKey,$this->requiredExt)) {
  2154. if ($TYPO3_LOADED_EXT[$extKey]) {
  2155. $content = '<strong>' . $GLOBALS['LANG']->getLL('ext_details_loaded_and_running') . '</strong><br />' .
  2156. '<a href="' . htmlspecialchars('index.php?CMD[showExt]=' . $extKey . '&CMD[remove]=1') .
  2157. '">' . $GLOBALS['LANG']->getLL('ext_details_remove_button') . ' ' . $this->removeButton() . '</a>';
  2158. } else {
  2159. $content = $GLOBALS['LANG']->getLL('ext_details_not_loaded') . '<br />'.
  2160. '<a href="' . htmlspecialchars('index.php?CMD[showExt]=' . $extKey . '&CMD[load]=1') .
  2161. '">' . $GLOBALS['LANG']->getLL('ext_details_install_button') . ' ' . $this->installButton() . '</a>';
  2162. }
  2163. } else {
  2164. $content = $GLOBALS['LANG']->getLL('ext_details_always_loaded');
  2165. }
  2166. $this->content.=$this->doc->spacer(10);
  2167. $this->content .= $this->doc->section(
  2168. $GLOBALS['LANG']->getLL('ext_details_current_status'), $content, 0, 1
  2169. );
  2170. if (t3lib_extMgm::isLoaded($extKey)) {
  2171. $updates=$this->updatesForm($extKey,$list[$extKey]);
  2172. if ($updates) {
  2173. $this->content.=$this->doc->spacer(10);
  2174. $this->content .= $this->doc->section(
  2175. $GLOBALS['LANG']->getLL('ext_details_update_needed'),
  2176. $updates . '<br /><br />' . $GLOBALS['LANG']->getLL('ext_details_notice_static_data'),
  2177. 0, 1
  2178. );
  2179. }
  2180. }
  2181. // Config:
  2182. if (@is_file($absPath.'ext_conf_template.txt')) {
  2183. $this->content.=$this->doc->spacer(10);
  2184. $this->content .= $this->doc->section(
  2185. $GLOBALS['LANG']->getLL('ext_details_configuration'),
  2186. $GLOBALS['LANG']->getLL('ext_details_notice_clear_cache') . '<br /><br />',
  2187. 0, 1
  2188. );
  2189. $this->tsStyleConfigForm($extKey, $list[$extKey]);
  2190. }
  2191. // Show details:
  2192. $content = t3lib_BEfunc::cshItem('_MOD_tools_em', 'info', $GLOBALS['BACK_PATH'], '|<br />');
  2193. $content.= $this->extInformationArray($extKey,$list[$extKey]);
  2194. $this->content.=$this->doc->spacer(10);
  2195. $this->content .= $this->doc->section(
  2196. $GLOBALS['LANG']->getLL('ext_details_details'), $content, 0, 1
  2197. );
  2198. break;
  2199. case 'upload':
  2200. $em = t3lib_div::_POST('em');
  2201. if($em['action'] == 'doUpload') {
  2202. $em['extKey'] = $extKey;
  2203. $em['extInfo'] = $list[$extKey];
  2204. $content = $this->uploadExtensionToTER($em);
  2205. $content .= $this->doc->spacer(10);
  2206. // Must reload this, because EM_CONF information has been updated!
  2207. list($list,)=$this->getInstalledExtensions();
  2208. } else {
  2209. // CSH:
  2210. $content = t3lib_BEfunc::cshItem('_MOD_tools_em', 'upload', $GLOBALS['BACK_PATH'], '|<br />');
  2211. // Upload:
  2212. if (substr($extKey,0,5)!='user_') {
  2213. $content.= $this->getRepositoryUploadForm($extKey,$list[$extKey]);
  2214. $eC=0;
  2215. } else {
  2216. $content .= $GLOBALS['LANG']->getLL('ext_details_no_unique_ext');
  2217. $eC=2;
  2218. }
  2219. if (!$this->fe_user['username']) {
  2220. $flashMessage = t3lib_div::makeInstance(
  2221. 't3lib_FlashMessage',
  2222. sprintf($GLOBALS['LANG']->getLL('ext_details_no_username'),
  2223. '<a href="index.php?SET[function]=3">', '</a>'
  2224. ),
  2225. '',
  2226. t3lib_FlashMessage::INFO
  2227. );
  2228. $content .= '<br />' . $flashMessage->render();
  2229. }
  2230. }
  2231. $this->content .= $this->doc->section(
  2232. $GLOBALS['LANG']->getLL('ext_details_upload_to_ter'),
  2233. $content, 0, 1, $eC
  2234. );
  2235. break;
  2236. case 'backup':
  2237. if($this->CMD['doDelete']) {
  2238. $content = $this->extDelete($extKey,$list[$extKey]);
  2239. $this->content .= $this->doc->section(
  2240. $GLOBALS['LANG']->getLL('ext_details_delete'),
  2241. $content, 0, 1
  2242. );
  2243. } else {
  2244. $csh = t3lib_BEfunc::cshItem('_MOD_tools_em', 'backup_delete', $GLOBALS['BACK_PATH'], '|<br />');
  2245. $content = $this->extBackup($extKey, $list[$extKey]);
  2246. $this->content .= $this->doc->section(
  2247. $GLOBALS['LANG']->getLL('ext_details_backup') . '&nbsp;' . $csh,
  2248. $content, 0, 1, 0, 1
  2249. );
  2250. $content = $this->extDelete($extKey,$list[$extKey]);
  2251. $this->content .= $this->doc->section(
  2252. $GLOBALS['LANG']->getLL('ext_details_delete'),
  2253. $content, 0, 1
  2254. );
  2255. $content = $this->extUpdateEMCONF($extKey,$list[$extKey]);
  2256. $this->content .= $this->doc->section(
  2257. $GLOBALS['LANG']->getLL('ext_details_update_em_conf'),
  2258. $content, 0, 1
  2259. );
  2260. }
  2261. break;
  2262. case 'dump':
  2263. $this->extDumpTables($extKey,$list[$extKey]);
  2264. break;
  2265. case 'edit':
  2266. $content = t3lib_BEfunc::cshItem('_MOD_tools_em', 'editfiles', $GLOBALS['BACK_PATH'], '|<br />');
  2267. $content.= $this->getFileListOfExtension($extKey,$list[$extKey]);
  2268. $this->content.=$this->doc->section(
  2269. $GLOBALS['LANG']->getLL('ext_details_ext_files'),
  2270. $content, 0, 1
  2271. );
  2272. break;
  2273. case 'updateModule':
  2274. $this->content .= $this->doc->section(
  2275. $GLOBALS['LANG']->getLL('ext_details_update'),
  2276. is_object($updateObj) ?
  2277. $updateObj->main() :
  2278. $GLOBALS['LANG']->getLL('ext_details_no_update_object'),
  2279. 0, 1
  2280. );
  2281. break;
  2282. default:
  2283. $this->extObjContent();
  2284. break;
  2285. }
  2286. }
  2287. }
  2288. }
  2289. /**
  2290. * Outputs a screen from where you can install multiple extensions in one go
  2291. * This can be called from external modules with "...index.php?CMD[requestInstallExtensions]=
  2292. *
  2293. * @param string Comma list of extension keys to install. Renders a screen with checkboxes for all extensions not already imported or installed
  2294. * @return void
  2295. */
  2296. function requestInstallExtensions($extList) {
  2297. // Return URL:
  2298. $returnUrl = t3lib_div::sanitizeLocalUrl(t3lib_div::_GP('returnUrl'));
  2299. $installOrImportExtension = t3lib_div::_POST('installOrImportExtension');
  2300. // Extension List:
  2301. $extArray = explode(',',$extList);
  2302. $outputRow = array();
  2303. $outputRow[] = '
  2304. <tr class="t3-row-header tableheader">
  2305. <td>' . $GLOBALS['LANG']->getLL('reqInstExt_install_import') . '</td>
  2306. <td>' . $GLOBALS['LANG']->getLL('reqInstExt_ext_key') . '</td>
  2307. </tr>
  2308. ';
  2309. foreach($extArray as $extKey) {
  2310. // Check for the request:
  2311. if ($installOrImportExtension[$extKey]) {
  2312. $this->installExtension($extKey);
  2313. }
  2314. // Display:
  2315. if (!t3lib_extMgm::isLoaded($extKey)) {
  2316. $outputRow[] = '
  2317. <tr class="bgColor4">
  2318. <td><input type="checkbox" name="'.htmlspecialchars('installOrImportExtension['.$extKey.']').'" value="1" checked="checked" id="check_'.$extKey.'" /></td>
  2319. <td><label for="check_'.$extKey.'">'.htmlspecialchars($extKey).'</label></td>
  2320. </tr>
  2321. ';
  2322. }
  2323. }
  2324. if (count($outputRow)>1 || !$returnUrl) {
  2325. $content = '
  2326. <!-- ending page form ... -->
  2327. <form action="'.htmlspecialchars(t3lib_div::getIndpEnv('REQUEST_URI')).'" method="post">
  2328. <table border="0" cellpadding="1" cellspacing="1">'.implode('',$outputRow).'</table>
  2329. <input type="submit" name="_" value="' . $GLOBALS['LANG']->getLL('reqInstExt_import_install_selected') . '" />
  2330. </form>';
  2331. if ($returnUrl) {
  2332. $content.= '
  2333. <br />
  2334. <br />
  2335. <a href="' . htmlspecialchars($returnUrl) . '">' . $GLOBALS['LANG']->getLL('reqInstExt_return') . '</a>
  2336. ';
  2337. }
  2338. $this->content.= $this->doc->section(
  2339. $GLOBALS['LANG']->getLL('reqInstExt_imp_inst_ext'), $content, 0, 1
  2340. );
  2341. } else {
  2342. t3lib_utility_Http::redirect($returnUrl);
  2343. }
  2344. }
  2345. /***********************************
  2346. *
  2347. * Application Sub-functions (HTML parts)
  2348. *
  2349. **********************************/
  2350. /**
  2351. * Creates a form for an extension which contains all options for configuration, updates of database, clearing of cache etc.
  2352. * This form is shown when
  2353. *
  2354. * @param string Extension key
  2355. * @param array Extension information array
  2356. * @param boolean If set, the form will ONLY show if fields/tables should be updated (suppressing forms like general configuration and cache clearing).
  2357. * @param string Alternative action=""-script
  2358. * @param string HTML: Additional form fields
  2359. * @return string HTML
  2360. */
  2361. function updatesForm($extKey,$extInfo,$notSilent=0,$script='',$addFields='') {
  2362. $script = $script ? $script : t3lib_div::linkThisScript();
  2363. $updates.= $this->checkDBupdates($extKey,$extInfo);
  2364. $uCache = $this->checkClearCache($extInfo);
  2365. if ($notSilent) $updates.= $uCache;
  2366. $updates.= $this->checkUploadFolder($extKey,$extInfo);
  2367. $absPath = $this->getExtPath($extKey, $extInfo['type']);
  2368. if ($notSilent && @is_file($absPath.'ext_conf_template.txt')) {
  2369. $configForm = $this->tsStyleConfigForm($extKey, $extInfo, 1, $script, $updates.$addFields.'<br />');
  2370. }
  2371. if ($updates || $configForm) {
  2372. if ($configForm) {
  2373. $updates = '</form>'.$configForm.'<form action="'.htmlspecialchars($script).'">';
  2374. } else {
  2375. $updates = '</form><form action="'.htmlspecialchars($script).'" method="post">'.$updates.$addFields.'
  2376. <br /><input type="submit" name="write" value="' . $GLOBALS['LANG']->getLL('updatesForm_make_updates') . '" />
  2377. ';
  2378. }
  2379. }
  2380. return $updates;
  2381. }
  2382. /**
  2383. * Creates view for dumping static tables and table/fields structures...
  2384. *
  2385. * @param string Extension key
  2386. * @param array Extension information array
  2387. * @return void
  2388. */
  2389. function extDumpTables($extKey,$extInfo) {
  2390. // Get dbInfo which holds the structure known from the tables.sql file
  2391. $techInfo = $this->makeDetailedExtensionAnalysis($extKey,$extInfo);
  2392. $absPath = $this->getExtPath($extKey,$extInfo['type']);
  2393. // Static tables:
  2394. if (is_array($techInfo['static'])) {
  2395. if ($this->CMD['writeSTATICdump']) { // Writing static dump:
  2396. $writeFile = $absPath.'ext_tables_static+adt.sql';
  2397. if (@is_file($writeFile)) {
  2398. $dump_static = $this->dumpStaticTables(implode(',',$techInfo['static']));
  2399. t3lib_div::writeFile($writeFile,$dump_static);
  2400. $this->content .= $this->doc->section(
  2401. $GLOBALS['LANG']->getLL('extDumpTables_tables_fields'),
  2402. sprintf($GLOBALS['LANG']->getLL('extDumpTables_bytes_written_to'),
  2403. t3lib_div::formatSize(strlen($dump_static)),
  2404. substr($writeFile, strlen(PATH_site))
  2405. ),
  2406. 0, 1
  2407. );
  2408. }
  2409. } else { // Showing info about what tables to dump - and giving the link to execute it.
  2410. $msg = $GLOBALS['LANG']->getLL('extDumpTables_dumping_content') . '<br />';
  2411. $msg.= '<br />'.implode('<br />',$techInfo['static']).'<br />';
  2412. // ... then feed that to this function which will make new CREATE statements of the same fields but based on the current database content.
  2413. $this->content .= $this->doc->section(
  2414. $GLOBALS['LANG']->getLL('extDumpTables_static_tables'),
  2415. $msg . '<hr /><strong><a href="' . htmlspecialchars('index.php?CMD[showExt]=' . $extKey .
  2416. '&CMD[writeSTATICdump]=1') . '">' . $GLOBALS['LANG']->getLL('extDumpTables_write_static') . '</a></strong>',
  2417. 0, 1
  2418. );
  2419. $this->content.=$this->doc->spacer(20);
  2420. }
  2421. }
  2422. // Table and field definitions:
  2423. if (is_array($techInfo['dump_tf'])) {
  2424. $dump_tf_array = $this->getTableAndFieldStructure($techInfo['dump_tf']);
  2425. $dump_tf = $this->dumpTableAndFieldStructure($dump_tf_array);
  2426. if ($this->CMD['writeTFdump']) {
  2427. $writeFile = $absPath.'ext_tables.sql';
  2428. if (@is_file($writeFile)) {
  2429. t3lib_div::writeFile($writeFile,$dump_tf);
  2430. $this->content .= $this->doc->section(
  2431. $GLOBALS['LANG']->getLL('extDumpTables_tables_fields'),
  2432. sprintf($GLOBALS['LANG']->getLL('extDumpTables_bytes_written_to'),
  2433. t3lib_div::formatSize(strlen($dump_tf)),
  2434. substr($writeFile, strlen(PATH_site))
  2435. ),
  2436. 0, 1
  2437. );
  2438. }
  2439. } else {
  2440. $msg = $GLOBALS['LANG']->getLL('extDumpTables_dumping_db_structure') . '<br />';
  2441. if (is_array($techInfo['tables'])) {
  2442. $msg .= '<br /><strong>' . $GLOBALS['LANG']->getLL('extDumpTables_tables') . '</strong><br />' .
  2443. implode('<br />', $techInfo['tables']) . '<br />';
  2444. }
  2445. if (is_array($techInfo['fields'])) {
  2446. $msg .= '<br /><strong>' . $GLOBALS['LANG']->getLL('extDumpTables_solo_fields') . '</strong><br />' .
  2447. implode('<br />', $techInfo['fields']) . '<br />';
  2448. }
  2449. // ... then feed that to this function which will make new CREATE statements of the same fields but based on the current database content.
  2450. $this->content.=$this->doc->section(
  2451. $GLOBALS['LANG']->getLL('extDumpTables_tables_fields'),
  2452. $msg . '<hr /><strong><a href="' . htmlspecialchars('index.php?CMD[showExt]=' .
  2453. $extKey . '&CMD[writeTFdump]=1') .
  2454. '">' . $GLOBALS['LANG']->getLL('extDumpTables_write_dump') . '</a></strong><hr />
  2455. <pre>' . htmlspecialchars($dump_tf) . '</pre>',
  2456. 0, 1
  2457. );
  2458. $details = ' ' . $GLOBALS['LANG']->getLL('extDumpTables_based_on') . '<br />
  2459. <ul>
  2460. <li>' . $GLOBALS['LANG']->getLL('extDumpTables_based_on_one') . '</li>
  2461. <li>' . $GLOBALS['LANG']->getLL('extDumpTables_based_on_two') . '</li>
  2462. </ul>
  2463. ' . $GLOBALS['LANG']->getLL('extDumpTables_bottomline') . '<br />';
  2464. $this->content.=$this->doc->section('',$details);
  2465. }
  2466. }
  2467. }
  2468. /**
  2469. * Returns file-listing of an extension
  2470. *
  2471. * @param string Extension key
  2472. * @param array Extension information array
  2473. * @return string HTML table.
  2474. */
  2475. function getFileListOfExtension($extKey,$conf) {
  2476. $content = '';
  2477. $extPath = $this->getExtPath($extKey,$conf['type']);
  2478. if ($extPath) {
  2479. // Read files:
  2480. $fileArr = array();
  2481. $fileArr = t3lib_div::getAllFilesAndFoldersInPath($fileArr,$extPath,'',0,99,$this->excludeForPackaging);
  2482. // Start table:
  2483. $lines = array();
  2484. $totalSize = 0;
  2485. // Header:
  2486. $lines[] = '
  2487. <tr class="t3-row-header">
  2488. <td>' . $GLOBALS['LANG']->getLL('extFileList_file') . '</td>
  2489. <td>' . $GLOBALS['LANG']->getLL('extFileList_size') . '</td>
  2490. <td>' . $GLOBALS['LANG']->getLL('extFileList_edit') . '</td>
  2491. </tr>';
  2492. foreach($fileArr as $file) {
  2493. $fI = t3lib_div::split_fileref($file);
  2494. $lines[] = '
  2495. <tr class="bgColor4">
  2496. <td><a href="' . htmlspecialchars('index.php?CMD[showExt]=' . $extKey .
  2497. '&CMD[downloadFile]=' . rawurlencode($file)) .
  2498. '" title="' . $GLOBALS['LANG']->getLL('extFileList_download') . '">' .
  2499. substr($file, strlen($extPath)) . '</a></td>
  2500. <td>'.t3lib_div::formatSize(filesize($file)).'</td>
  2501. <td>' . (!in_array($extKey, $this->requiredExt) &&
  2502. t3lib_div::inList($this->editTextExtensions,
  2503. ($fI['fileext'] ? $fI['fileext'] : $fI['filebody'])) ?
  2504. '<a href="' . htmlspecialchars('index.php?CMD[showExt]=' . $extKey .
  2505. '&CMD[editFile]=' . rawurlencode($file)) . '">' .
  2506. $GLOBALS['LANG']->getLL('extFileList_edit_file') . '</a>' : ''
  2507. ) . '</td>
  2508. </tr>';
  2509. $totalSize+=filesize($file);
  2510. }
  2511. $lines[] = '
  2512. <tr class="bgColor6">
  2513. <td><strong>' . $GLOBALS['LANG']->getLL('extFileList_total') . '</strong></td>
  2514. <td><strong>'.t3lib_div::formatSize($totalSize).'</strong></td>
  2515. <td>&nbsp;</td>
  2516. </tr>';
  2517. $content = '
  2518. Path: '.$extPath.'<br /><br />
  2519. <table border="0" cellpadding="1" cellspacing="2">'.implode('',$lines).'</table>';
  2520. }
  2521. return $content;
  2522. }
  2523. /**
  2524. * Delete extension from the file system
  2525. *
  2526. * @param string Extension key
  2527. * @param array Extension info array
  2528. * @return string Returns message string about the status of the operation
  2529. */
  2530. function extDelete($extKey,$extInfo) {
  2531. $absPath = $this->getExtPath($extKey,$extInfo['type']);
  2532. if (t3lib_extMgm::isLoaded($extKey)) {
  2533. return $GLOBALS['LANG']->getLL('extDelete_ext_active');
  2534. } elseif (!$this->deleteAsType($extInfo['type'])) {
  2535. return sprintf($GLOBALS['LANG']->getLL('extDelete_wrong_scope'),
  2536. $this->typeLabels[$extInfo['type']]
  2537. );
  2538. } elseif (t3lib_div::inList('G,L',$extInfo['type'])) {
  2539. if ($this->CMD['doDelete'] && !strcmp($absPath,$this->CMD['absPath'])) {
  2540. $res = $this->removeExtDirectory($absPath);
  2541. if ($res) {
  2542. $flashMessage = t3lib_div::makeInstance(
  2543. 't3lib_FlashMessage',
  2544. nl2br($res),
  2545. sprintf($GLOBALS['LANG']->getLL('extDelete_remove_dir_failed'), $absPath),
  2546. t3lib_FlashMessage::ERROR
  2547. );
  2548. return $flashMessage->render();
  2549. } else {
  2550. $flashMessage = t3lib_div::makeInstance(
  2551. 't3lib_FlashMessage',
  2552. sprintf($GLOBALS['LANG']->getLL('extDelete_removed'), $absPath),
  2553. $GLOBALS['LANG']->getLL('extDelete_removed_header'),
  2554. t3lib_FlashMessage::OK
  2555. );
  2556. return $flashMessage->render();
  2557. }
  2558. } else {
  2559. $areYouSure = $GLOBALS['LANG']->getLL('extDelete_sure');
  2560. $deleteFromServer = $GLOBALS['LANG']->getLL('extDelete_from_server');
  2561. $onClick = "if (confirm('$areYouSure')) {window.location.href='index.php?CMD[showExt]=" .
  2562. $extKey . '&CMD[doDelete]=1&CMD[absPath]=' . rawurlencode($absPath) . "';}";
  2563. $content .= '<a class="t3-link" href="#" onclick="' . htmlspecialchars($onClick) .
  2564. ' return false;"><strong>' . $deleteFromServer . '</strong> ' .
  2565. sprintf($GLOBALS['LANG']->getLL('extDelete_from_location'),
  2566. $this->typeLabels[$extInfo['type']],
  2567. substr($absPath,strlen(PATH_site))
  2568. ) . '</a>';
  2569. $content .= '<br /><br />' . $GLOBALS['LANG']->getLL('extDelete_backup');
  2570. return $content;
  2571. }
  2572. } else return $GLOBALS['LANG']->getLL('extDelete_neither_global_nor_local');
  2573. }
  2574. /**
  2575. * Update extension EM_CONF...
  2576. *
  2577. * @param string Extension key
  2578. * @param array Extension information array
  2579. * @return string HTML content.
  2580. */
  2581. function extUpdateEMCONF($extKey,$extInfo) {
  2582. $absPath = $this->getExtPath($extKey,$extInfo['type']);
  2583. if ($this->CMD['doUpdateEMCONF']) {
  2584. return $this->updateLocalEM_CONF($extKey,$extInfo);
  2585. } else {
  2586. $sure = $GLOBALS['LANG']->getLL('extUpdateEMCONF_sure');
  2587. $updateEMConf = $GLOBALS['LANG']->getLL('extUpdateEMCONF_file');
  2588. $onClick = "if (confirm('$sure')) {window.location.href='index.php?CMD[showExt]=" .
  2589. $extKey . "&CMD[doUpdateEMCONF]=1';}";
  2590. $content .= '<a class="t3-link" href="#" onclick="' . htmlspecialchars($onClick) .
  2591. ' return false;"><strong>' . $updateEMConf . '</strong> ' .
  2592. sprintf($GLOBALS['LANG']->getLL('extDelete_from_location'),
  2593. $this->typeLabels[$extInfo['type']],
  2594. substr($absPath, strlen(PATH_site))
  2595. ) . '</a>';
  2596. $content .= '<br /><br />' . $GLOBALS['LANG']->getLL('extUpdateEMCONF_info_changes') . '<br />
  2597. ' . $GLOBALS['LANG']->getLL('extUpdateEMCONF_info_reset');
  2598. return $content;
  2599. }
  2600. }
  2601. /**
  2602. * Download extension as file / make backup
  2603. *
  2604. * @param string Extension key
  2605. * @param array Extension information array
  2606. * @return string HTML content
  2607. */
  2608. function extBackup($extKey,$extInfo) {
  2609. $uArr = $this->makeUploadArray($extKey,$extInfo);
  2610. if (is_array($uArr)) {
  2611. $backUpData = $this->terConnection->makeUploadDataFromArray($uArr);
  2612. $filename = 'T3X_'.$extKey.'-'.str_replace('.','_',$extInfo['EM_CONF']['version']).'-z-'.date('YmdHi').'.t3x';
  2613. if (intval($this->CMD['doBackup'])==1) {
  2614. header('Content-Type: application/octet-stream');
  2615. header('Content-Disposition: attachment; filename='.$filename);
  2616. echo $backUpData;
  2617. exit;
  2618. } elseif ($this->CMD['dumpTables']) {
  2619. $filename='T3X_'.$extKey;
  2620. $cTables = count(explode(',',$this->CMD['dumpTables']));
  2621. if ($cTables>1) {
  2622. $filename.='-'.$cTables.'tables';
  2623. } else {
  2624. $filename.='-'.$this->CMD['dumpTables'];
  2625. }
  2626. $filename.='+adt.sql';
  2627. header('Content-Type: application/octet-stream');
  2628. header('Content-Disposition: attachment; filename='.$filename);
  2629. echo $this->dumpStaticTables($this->CMD['dumpTables']);
  2630. exit;
  2631. } else {
  2632. $techInfo = $this->makeDetailedExtensionAnalysis($extKey,$extInfo);
  2633. $lines=array();
  2634. $lines[] = '<tr class="t3-row-header"><td colspan="2">' .
  2635. $GLOBALS['LANG']->getLL('extBackup_select') . '</td></tr>';
  2636. $lines[]='<tr class="bgColor4"><td><strong>' .
  2637. $GLOBALS['LANG']->getLL('extBackup_files') . '</strong></td><td>' .
  2638. '<a class="t3-link" href="' . htmlspecialchars('index.php?CMD[doBackup]=1&CMD[showExt]=' . $extKey) .
  2639. '">' . sprintf($GLOBALS['LANG']->getLL('extBackup_download'),
  2640. $extKey
  2641. ) . '</a><br />
  2642. (' . $filename . ', <br />' .
  2643. t3lib_div::formatSize(strlen($backUpData)) . ', <br />' .
  2644. $GLOBALS['LANG']->getLL('extBackup_md5') . ' ' . md5($backUpData) . ')
  2645. <br /></td></tr>';
  2646. if (is_array($techInfo['tables'])) {
  2647. $lines[] = '<tr class="bgColor4"><td><strong>' . $GLOBALS['LANG']->getLL('extBackup_data_tables') .
  2648. '</strong></td><td>' . $this->extBackup_dumpDataTablesLine($techInfo['tables'], $extKey) . '</td></tr>';
  2649. }
  2650. if (is_array($techInfo['static'])) {
  2651. $lines[] = '<tr class="bgColor4"><td><strong>' . $GLOBALS['LANG']->getLL('extBackup_static_tables') .
  2652. '</strong></td><td>' . $this->extBackup_dumpDataTablesLine($techInfo['static'], $extKey) . '</td></tr>';
  2653. }
  2654. $content = '<table border="0" cellpadding="2" cellspacing="2">'.implode('',$lines).'</table>';
  2655. return $content;
  2656. }
  2657. } else {
  2658. throw new RuntimeException(
  2659. 'TYPO3 Fatal Error: ' . $GLOBALS['LANG']->getLL('extBackup_unexpected_error'),
  2660. 1270853981
  2661. );
  2662. }
  2663. }
  2664. /**
  2665. * Link to dump of database tables
  2666. *
  2667. * @param string Extension key
  2668. * @param array Extension information array
  2669. * @return string HTML
  2670. */
  2671. function extBackup_dumpDataTablesLine($tablesArray,$extKey) {
  2672. $tables = array();
  2673. $tablesNA = array();
  2674. $allTables = array_keys($GLOBALS['TYPO3_DB']->admin_get_tables());
  2675. foreach($tablesArray as $tN) {
  2676. if (in_array($tN, $allTables)) {
  2677. $count = $GLOBALS['TYPO3_DB']->exec_SELECTcountRows('*', $tN);
  2678. $tables[$tN] = '<tr><td>&nbsp;</td><td>
  2679. <a class="t3-link" href="' . htmlspecialchars('index.php?CMD[dumpTables]=' . rawurlencode($tN) .
  2680. '&CMD[showExt]=' . $extKey) .
  2681. '" title="' .
  2682. sprintf($GLOBALS['LANG']->getLL('extBackup_dump_table'),
  2683. $tN) .
  2684. '">' . $tN . '</a></td><td>&nbsp;&nbsp;&nbsp;</td><td>' .
  2685. sprintf($GLOBALS['LANG']->getLL('extBackup_number_of_records'),
  2686. $count) . '</td></tr>';
  2687. } else {
  2688. $tablesNA[$tN] = '<tr><td>&nbsp;</td><td>' . $tN . '</td><td>&nbsp;</td><td>' .
  2689. $GLOBALS['LANG']->getLL('extBackup_table_not_there') . '</td></tr>';
  2690. }
  2691. }
  2692. $label = '<table border="0" cellpadding="0" cellspacing="0">'.implode('',array_merge($tables,$tablesNA)).'</table>';// Candidate for t3lib_div::array_merge() if integer-keys will some day make trouble...
  2693. if (count($tables)) {
  2694. $label = '<a class="t3-link" href="' . htmlspecialchars('index.php?CMD[dumpTables]=' .
  2695. rawurlencode(implode(',', array_keys($tables))) . '&CMD[showExt]=' . $extKey) .
  2696. '" title="' . $GLOBALS['LANG']->getLL('extBackup_dump_all_tables') . '">' .
  2697. $GLOBALS['LANG']->getLL('extBackup_download_all_data') . '</a><br /><br />' . $label;
  2698. }
  2699. else {
  2700. $label = $GLOBALS['LANG']->getLL('extBackup_nothing_to_dump') . '<br /><br />' . $label;
  2701. }
  2702. return $label;
  2703. }
  2704. /**
  2705. * Prints a table with extension information in it.
  2706. *
  2707. * @param string Extension key
  2708. * @param array Extension information array
  2709. * @param boolean If set, the information array shows information for a remote extension in TER, not a local one.
  2710. * @return string HTML content.
  2711. */
  2712. function extInformationArray($extKey,$extInfo,$remote=0) {
  2713. $lines=array();
  2714. $lines[] = '<tr class="t3-row-header"><td colspan="2"><strong>' . $GLOBALS['LANG']->getLL('extInfoArray_general_info') . '</strong></td>' .
  2715. $this->helpCol('') . '</tr>';
  2716. $lines[] = '<tr class="bgColor4"><td>' . $GLOBALS['LANG']->getLL('extInfoArray_title') . '</td>
  2717. <td>' . $extInfo['EM_CONF']['_icon'] . $extInfo['EM_CONF']['title'] . '</td>' .
  2718. $this->helpCol('title') . '</tr>';
  2719. $lines[] = '<tr class="bgColor4"><td>' . $GLOBALS['LANG']->getLL('extInfoArray_description') . '</td>
  2720. <td>' . nl2br(htmlspecialchars($extInfo['EM_CONF']['description'])) . '</td>' .
  2721. $this->helpCol('description') . '</tr>';
  2722. $lines[] = '<tr class="bgColor4"><td>' . $GLOBALS['LANG']->getLL('extInfoArray_author') . '</td>
  2723. <td>' . $this->wrapEmail($extInfo['EM_CONF']['author'] .
  2724. ($extInfo['EM_CONF']['author_email'] ?
  2725. ' <' . $extInfo['EM_CONF']['author_email'] . '>' : ''),
  2726. $extInfo['EM_CONF']['author_email']) .
  2727. ($extInfo['EM_CONF']['author_company'] ?
  2728. ', ' . $extInfo['EM_CONF']['author_company'] : '') . '</td>' .
  2729. $this->helpCol('author') . '</tr>';
  2730. $lines[] = '<tr class="bgColor4"><td>' . $GLOBALS['LANG']->getLL('extInfoArray_version') . '</td>
  2731. <td>' . $extInfo['EM_CONF']['version'] . '</td>' .
  2732. $this->helpCol('version') . '</tr>';
  2733. $lines[] = '<tr class="bgColor4"><td>' . $GLOBALS['LANG']->getLL('extInfoArray_category') . '</td>
  2734. <td>' . $this->categories[$extInfo['EM_CONF']['category']] . '</td>' .
  2735. $this->helpCol('category') . '</tr>';
  2736. $lines[] = '<tr class="bgColor4"><td>' . $GLOBALS['LANG']->getLL('extInfoArray_state') . '</td>
  2737. <td>' . $this->states[$extInfo['EM_CONF']['state']] . '</td>' .
  2738. $this->helpCol('state') . '</tr>';
  2739. $lines[] = '<tr class="bgColor4"><td>' . $GLOBALS['LANG']->getLL('extInfoArray_shy') . '</td>
  2740. <td>' . ($extInfo['EM_CONF']['shy'] ?
  2741. $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:yes')
  2742. : $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:no')) . '</td>' .
  2743. $this->helpCol('shy') . '</tr>';
  2744. $lines[] = '<tr class="bgColor4"><td>' . $GLOBALS['LANG']->getLL('extInfoArray_internal') . '</td>
  2745. <td>' . ($extInfo['EM_CONF']['internal'] ?
  2746. $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:yes')
  2747. : $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:no')) . '</td>' .
  2748. $this->helpCol('internal') . '</tr>';
  2749. $lines[] = '<tr class="bgColor4"><td>' . $GLOBALS['LANG']->getLL('extInfoArray_depends_on') . '</td>
  2750. <td>' . $this->depToString($extInfo['EM_CONF']['constraints']) . '</td>' .
  2751. $this->helpCol('dependencies') . '</tr>';
  2752. $lines[] = '<tr class="bgColor4"><td>' . $GLOBALS['LANG']->getLL('extInfoArray_conflicts_with') . '</td>
  2753. <td>' . $this->depToString($extInfo['EM_CONF']['constraints'], 'conflicts') . '</td>' .
  2754. $this->helpCol('conflicts') . '</tr>';
  2755. $lines[] = '<tr class="bgColor4"><td>' . $GLOBALS['LANG']->getLL('extInfoArray_suggests') . '</td>
  2756. <td>' . $this->depToString($extInfo['EM_CONF']['constraints'], 'suggests') . '</td>' .
  2757. $this->helpCol('suggests') . '</tr>';
  2758. if (!$remote) {
  2759. $lines[] = '<tr class="bgColor4"><td>' . $GLOBALS['LANG']->getLL('extInfoArray_priority') . '</td>
  2760. <td>' . $extInfo['EM_CONF']['priority'] . '</td>' .
  2761. $this->helpCol('priority') . '</tr>';
  2762. $lines[] = '<tr class="bgColor4"><td>' . $GLOBALS['LANG']->getLL('extInfoArray_clear_cache') . '</td>
  2763. <td>' . ($extInfo['EM_CONF']['clearCacheOnLoad'] ?
  2764. $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:yes')
  2765. : $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:no')) . '</td>' .
  2766. $this->helpCol('clearCacheOnLoad') . '</tr>';
  2767. $lines[] = '<tr class="bgColor4"><td>' . $GLOBALS['LANG']->getLL('extInfoArray_incl_modules') . '</td>
  2768. <td>' . $extInfo['EM_CONF']['module'] . '</td>' .
  2769. $this->helpCol('module') . '</tr>';
  2770. $lines[] = '<tr class="bgColor4"><td>' . $GLOBALS['LANG']->getLL('extInfoArray_lock_type') . '</td>
  2771. <td>' . ($extInfo['EM_CONF']['lockType'] ?
  2772. $extInfo['EM_CONF']['lockType'] : '') . '</td>' .
  2773. $this->helpCol('lockType') . '</tr>';
  2774. $lines[] = '<tr class="bgColor4"><td>' . $GLOBALS['LANG']->getLL('extInfoArray_load_in_frontend') . '</td>
  2775. <td>' . ($extInfo['EM_CONF']['doNotLoadInFE'] ?
  2776. $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:no')
  2777. : $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:yes')) . '</td>' .
  2778. $this->helpCol('doNotLoadInFE') . '</tr>';
  2779. $lines[] = '<tr class="bgColor4"><td>' . $GLOBALS['LANG']->getLL('extInfoArray_modifies_tables') . '</td>
  2780. <td>' . $extInfo['EM_CONF']['modify_tables'] . '</td>' .
  2781. $this->helpCol('modify_tables') . '</tr>';
  2782. // Installation status:
  2783. $techInfo = $this->makeDetailedExtensionAnalysis($extKey,$extInfo,1);
  2784. $lines[] = '<tr><td>&nbsp;</td><td></td>'.$this->helpCol('').'</tr>';
  2785. $lines[] = '<tr class="t3-row-header"><td colspan="2"><strong>' . $GLOBALS['LANG']->getLL('extInfoArray_inst_status') . '</strong></td>' .
  2786. $this->helpCol('') . '</tr>';
  2787. $lines[] = '<tr class="bgColor4"><td>' . $GLOBALS['LANG']->getLL('extInfoArray_inst_type') . '</td>
  2788. <td>' . $this->typeLabels[$extInfo['type']] . ' - <em>' . $this->typeDescr[$extInfo['type']] . '</em></td>' .
  2789. $this->helpCol('type') . '</tr>';
  2790. $lines[] = '<tr class="bgColor4"><td>' . $GLOBALS['LANG']->getLL('extInfoArray_inst_twice') . '</td>
  2791. <td>' . $this->extInformationArray_dbInst($extInfo['doubleInstall'], $extInfo['type']) . '</td>' .
  2792. $this->helpCol('doubleInstall') . '</tr>';
  2793. if (is_array($extInfo['files'])) {
  2794. sort($extInfo['files']);
  2795. $lines[] = '<tr class="bgColor4"><td>' . $GLOBALS['LANG']->getLL('extInfoArray_root_files') . '</td>
  2796. <td>' . implode('<br />', $extInfo['files']) . '</td>' .
  2797. $this->helpCol('rootfiles') . '</tr>';
  2798. }
  2799. if ($techInfo['tables']||$techInfo['static']||$techInfo['fields']) {
  2800. if (!$remote && t3lib_extMgm::isLoaded($extKey)) {
  2801. $tableStatus = $GLOBALS['TBE_TEMPLATE']->rfw(($techInfo['tables_error'] ?
  2802. '<strong>' . $GLOBALS['LANG']->getLL('extInfoArray_table_error') . '</strong><br />' .
  2803. $GLOBALS['LANG']->getLL('extInfoArray_missing_fields') : '') .
  2804. ($techInfo['static_error'] ?
  2805. '<strong>' . $GLOBALS['LANG']->getLL('extInfoArray_static_table_error') . '</strong><br />' .
  2806. $GLOBALS['LANG']->getLL('extInfoArray_static_tables_missing_empty') : ''));
  2807. } else {
  2808. $tableStatus = $techInfo['tables_error']||$techInfo['static_error'] ?
  2809. $GLOBALS['LANG']->getLL('extInfoArray_db_update_needed') : $GLOBALS['LANG']->getLL('extInfoArray_tables_ok');
  2810. }
  2811. }
  2812. $lines[] = '<tr class="bgColor4"><td>' . $GLOBALS['LANG']->getLL('extInfoArray_db_requirements') . '</td>
  2813. <td>' . $this->extInformationArray_dbReq($techInfo, 1) . '</td>' .
  2814. $this->helpCol('dbReq') . '</tr>';
  2815. $lines[] = '<tr class="bgColor4"><td>' . $GLOBALS['LANG']->getLL('extInfoArray_db_status') . '</td>
  2816. <td>' . $tableStatus . '</td>' .
  2817. $this->helpCol('dbStatus') . '</tr>';
  2818. $lines[] = '<tr class="bgColor4"><td>' . $GLOBALS['LANG']->getLL('extInfoArray_flags') . '</td>
  2819. <td>' . (is_array($techInfo['flags']) ?
  2820. implode('<br />', $techInfo['flags']) : '') . '</td>' .
  2821. $this->helpCol('flags') . '</tr>';
  2822. $lines[] = '<tr class="bgColor4"><td>' . $GLOBALS['LANG']->getLL('extInfoArray_config_template') . '</td>
  2823. <td>' . ($techInfo['conf'] ?
  2824. $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:yes') : '') . '</td>' .
  2825. $this->helpCol('conf') . '</tr>';
  2826. $lines[] = '<tr class="bgColor4"><td>' . $GLOBALS['LANG']->getLL('extInfoArray_typoscript_files') . '</td>
  2827. <td>' . (is_array($techInfo['TSfiles']) ?
  2828. implode('<br />', $techInfo['TSfiles']) : '') . '</td>' .
  2829. $this->helpCol('TSfiles') . '</tr>';
  2830. $lines[] = '<tr class="bgColor4"><td>' . $GLOBALS['LANG']->getLL('extInfoArray_language_files') . '</td>
  2831. <td>' . (is_array($techInfo['locallang']) ?
  2832. implode('<br />', $techInfo['locallang']) : '') . '</td>' .
  2833. $this->helpCol('locallang') . '</tr>';
  2834. $lines[] = '<tr class="bgColor4"><td>' . $GLOBALS['LANG']->getLL('extInfoArray_upload_folder') . '</td>
  2835. <td>' . ($techInfo['uploadfolder'] ?
  2836. $techInfo['uploadfolder'] : '') . '</td>' .
  2837. $this->helpCol('uploadfolder') . '</tr>';
  2838. $lines[] = '<tr class="bgColor4"><td>' . $GLOBALS['LANG']->getLL('extInfoArray_create_directories') . '</td>
  2839. <td>' . (is_array($techInfo['createDirs']) ?
  2840. implode('<br />', $techInfo['createDirs']) : '') . '</td>' .
  2841. $this->helpCol('createDirs') . '</tr>';
  2842. $lines[] = '<tr class="bgColor4"><td>' . $GLOBALS['LANG']->getLL('extInfoArray_module_names') . '</td>
  2843. <td>' . (is_array($techInfo['moduleNames']) ?
  2844. implode('<br />', $techInfo['moduleNames']) : '') . '</td>' .
  2845. $this->helpCol('moduleNames') . '</tr>';
  2846. $lines[] = '<tr class="bgColor4"><td>' . $GLOBALS['LANG']->getLL('extInfoArray_class_names') . '</td>
  2847. <td>' . (is_array($techInfo['classes']) ?
  2848. implode('<br />', $techInfo['classes']) : '') . '</td>' .
  2849. $this->helpCol('classNames') . '</tr>';
  2850. $lines[] = '<tr class="bgColor4"><td>' . $GLOBALS['LANG']->getLL('extInfoArray_code_warnings') . '<br />' .
  2851. $GLOBALS['LANG']->getLL('extInfoArray_dev_relevant') . '</td>
  2852. <td>' . (is_array($techInfo['errors']) ?
  2853. $GLOBALS['TBE_TEMPLATE']->rfw(implode('<br />', $techInfo['errors'])) : '') . '</td>' .
  2854. $this->helpCol('errors') . '</tr>';
  2855. $lines[] = '<tr class="bgColor4"><td>' . $GLOBALS['LANG']->getLL('extInfoArray_annoyances') . '<br />' .
  2856. $GLOBALS['LANG']->getLL('extInfoArray_dev_relevant') . '</td>
  2857. <td>' . (is_array($techInfo['NSerrors']) ?
  2858. (!t3lib_div::inList($this->nameSpaceExceptions, $extKey) ?
  2859. t3lib_div::view_array($techInfo['NSerrors']) :
  2860. $GLOBALS['TBE_TEMPLATE']->dfw($GLOBALS['LANG']->getLL('extInfoArray_exception'))) : '') . '</td>' .
  2861. $this->helpCol('NSerrors') . '</tr>';
  2862. $currentMd5Array = $this->serverExtensionMD5Array($extKey,$extInfo);
  2863. $affectedFiles='';
  2864. $msgLines=array();
  2865. if (strcmp($extInfo['EM_CONF']['_md5_values_when_last_written'],serialize($currentMd5Array))) {
  2866. $msgLines[] = $GLOBALS['TBE_TEMPLATE']->rfw('<br /><strong>' . $GLOBALS['LANG']->getLL('extInfoArray_difference_detected') . '</strong>');
  2867. $affectedFiles = $this->findMD5ArrayDiff($currentMd5Array,unserialize($extInfo['EM_CONF']['_md5_values_when_last_written']));
  2868. if (count($affectedFiles)) {
  2869. $msgLines[] = '<br /><strong>' . $GLOBALS['LANG']->getLL('extInfoArray_modified_files') . '</strong><br />' .
  2870. $GLOBALS['TBE_TEMPLATE']->rfw(implode('<br />', $affectedFiles));
  2871. }
  2872. }
  2873. $lines[] = '<tr class="bgColor4"><td>' . $GLOBALS['LANG']->getLL('extInfoArray_files_changed') . '</td>
  2874. <td>' . implode('<br />', $msgLines) . '</td>' .
  2875. $this->helpCol('filesChanged') . '</tr>';
  2876. }
  2877. return '<table border="0" cellpadding="1" cellspacing="2">
  2878. '.implode('
  2879. ',$lines).'
  2880. </table>';
  2881. }
  2882. /**
  2883. * Returns HTML with information about database requirements
  2884. *
  2885. * @param array Technical information array
  2886. * @param boolean Table header displayed
  2887. * @return string HTML content.
  2888. */
  2889. function extInformationArray_dbReq($techInfo,$tableHeader=0) {
  2890. return nl2br(trim((is_array($techInfo['tables']) ?
  2891. ($tableHeader ?
  2892. "\n\n<strong>" . $GLOBALS['LANG']->getLL('extDumpTables_tables') . "</strong>\n" : '') .
  2893. implode(LF, $techInfo['tables']) : '') .
  2894. (is_array($techInfo['static']) ?
  2895. "\n\n<strong>" . $GLOBALS['LANG']->getLL('extBackup_static_tables') . "</strong>\n" .
  2896. implode(LF, $techInfo['static']) : '').
  2897. (is_array($techInfo['fields']) ?
  2898. "\n\n<strong>" . $GLOBALS['LANG']->getLL('extInfoArray_additional_fields') . "</strong>\n" .
  2899. implode('<hr />', $techInfo['fields']) : '')));
  2900. }
  2901. /**
  2902. * Double install warning.
  2903. *
  2904. * @param string Double-install string, eg. "LG" etc.
  2905. * @param string Current scope, eg. "L" or "G" or "S"
  2906. * @return string Message
  2907. */
  2908. function extInformationArray_dbInst($dbInst,$current) {
  2909. if (strlen($dbInst)>1) {
  2910. $others = array();
  2911. for($a=0;$a<strlen($dbInst);$a++) {
  2912. if (substr($dbInst,$a,1)!=$current) {
  2913. $others[]='"'.$this->typeLabels[substr($dbInst,$a,1)].'"';
  2914. }
  2915. }
  2916. return $GLOBALS['TBE_TEMPLATE']->rfw(
  2917. sprintf($GLOBALS['LANG']->getLL('extInfoArray_double_installation_infotext'),
  2918. implode(' ' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:and') . ' ', $others),
  2919. $this->typeLabels[$current]
  2920. )
  2921. );
  2922. } else return '';
  2923. }
  2924. /**
  2925. * Prints the upload form for extensions
  2926. *
  2927. * @param string Extension key
  2928. * @param array Extension information array
  2929. * @return string HTML content.
  2930. */
  2931. function getRepositoryUploadForm($extKey,$extInfo) {
  2932. $content = '<form action="index.php" method="post" name="repuploadform">
  2933. <input type="hidden" name="CMD[showExt]" value="'.$extKey.'" />
  2934. <input type="hidden" name="em[action]" value="doUpload" />
  2935. <table border="0" cellpadding="2" cellspacing="1">
  2936. <tr class="bgColor4">
  2937. <td>' . $GLOBALS['LANG']->getLL('repositoryUploadForm_username') . '</td>
  2938. <td><input'.$this->doc->formWidth(20).' type="text" name="em[user][fe_u]" value="'.$this->fe_user['username'].'" /></td>
  2939. </tr>
  2940. <tr class="bgColor4">
  2941. <td>' . $GLOBALS['LANG']->getLL('repositoryUploadForm_password') . '</td>
  2942. <td><input'.$this->doc->formWidth(20).' type="password" name="em[user][fe_p]" value="'.$this->fe_user['password'].'" /></td>
  2943. </tr>
  2944. <tr class="bgColor4">
  2945. <td>' . $GLOBALS['LANG']->getLL('repositoryUploadForm_changelog') . '</td>
  2946. <td><textarea'.$this->doc->formWidth(30,1).' rows="5" name="em[upload][comment]"></textarea></td>
  2947. </tr>
  2948. <tr class="bgColor4">
  2949. <td>' . $GLOBALS['LANG']->getLL('repositoryUploadForm_command') . '</td>
  2950. <td nowrap="nowrap">
  2951. <input type="radio" name="em[upload][mode]" id="new_dev" value="new_dev" checked="checked" />
  2952. <label for="new_dev">' . sprintf($GLOBALS['LANG']->getLL('repositoryUploadForm_new_bugfix'),
  2953. 'x.x.<strong>' . $GLOBALS['TBE_TEMPLATE']->rfw('x+1') . '</strong>'
  2954. ) . '</label><br />
  2955. <input type="radio" name="em[upload][mode]" id="new_sub" value="new_sub" />
  2956. <label for="new_sub">' . sprintf($GLOBALS['LANG']->getLL('repositoryUploadForm_new_sub_version'),
  2957. 'x.<strong>' . $GLOBALS['TBE_TEMPLATE']->rfw('x+1') . '</strong>.0'
  2958. ) . '</label><br />
  2959. <input type="radio" name="em[upload][mode]" id="new_main" value="new_main" />
  2960. <label for="new_main">' . sprintf($GLOBALS['LANG']->getLL('repositoryUploadForm_new_main_version'),
  2961. '<strong>' . $GLOBALS['TBE_TEMPLATE']->rfw('x+1') . '</strong>.0.0'
  2962. ) . '</label><br />
  2963. </td>
  2964. </tr>
  2965. <tr class="bgColor4">
  2966. <td>&nbsp;</td>
  2967. <td><input type="submit" name="submit" value="' . $GLOBALS['LANG']->getLL('repositoryUploadForm_upload') . '" />
  2968. </td>
  2969. </tr>
  2970. </table>
  2971. </form>';
  2972. return $content;
  2973. }
  2974. /***********************************
  2975. *
  2976. * Extension list rendering
  2977. *
  2978. **********************************/
  2979. /**
  2980. * Prints the header row for the various listings
  2981. *
  2982. * @param string Attributes for the <tr> tag
  2983. * @param array Preset cells in the beginning of the row. Typically a blank cell with a clear-gif
  2984. * @param boolean If set, the list is coming from remote server.
  2985. * @return string HTML <tr> table row
  2986. */
  2987. function extensionListRowHeader($trAttrib,$cells,$import=0) {
  2988. $cells[] = '<td></td>';
  2989. $cells[] = '<td>' . $GLOBALS['LANG']->getLL('extInfoArray_title') . '</td>';
  2990. if (!$this->MOD_SETTINGS['display_details']) {
  2991. $cells[] = '<td>' . $GLOBALS['LANG']->getLL('extInfoArray_description') . '</td>';
  2992. $cells[] = '<td>' . $GLOBALS['LANG']->getLL('extInfoArray_author') . '</td>';
  2993. } elseif ($this->MOD_SETTINGS['display_details']==2) {
  2994. $cells[] = '<td>' . $GLOBALS['LANG']->getLL('extInfoArray_priority') . '</td>';
  2995. $cells[] = '<td>' . $GLOBALS['LANG']->getLL('listRowHeader_modifies_tables_short') . '</td>';
  2996. $cells[] = '<td>' . $GLOBALS['LANG']->getLL('listRowHeader_modules') . '</td>';
  2997. $cells[] = '<td>' . $GLOBALS['LANG']->getLL('listRowHeader_clear_cache_short') . '</td>';
  2998. $cells[] = '<td>' . $GLOBALS['LANG']->getLL('extInfoArray_internal') . '</td>';
  2999. $cells[] = '<td>' . $GLOBALS['LANG']->getLL('extInfoArray_shy') . '</td>';
  3000. } elseif ($this->MOD_SETTINGS['display_details']==3) {
  3001. $cells[] = '<td>' . $GLOBALS['LANG']->getLL('listRowHeader_tables_fields') . '</td>';
  3002. $cells[] = '<td>' . $GLOBALS['LANG']->getLL('listRowHeader_ts_files') . '</td>';
  3003. $cells[] = '<td>' . $GLOBALS['LANG']->getLL('listRowHeader_affects') . '</td>';
  3004. $cells[] = '<td>' . $GLOBALS['LANG']->getLL('listRowHeader_modules') . '</td>';
  3005. $cells[] = '<td>' . $GLOBALS['LANG']->getLL('listRowHeader_config') . '</td>';
  3006. $cells[] = '<td>' . $GLOBALS['LANG']->getLL('extInfoArray_code_warnings') . '</td>';
  3007. } elseif ($this->MOD_SETTINGS['display_details']==4) {
  3008. $cells[] = '<td>' . $GLOBALS['LANG']->getLL('listRowHeader_locallang') . '</td>';
  3009. $cells[] = '<td>' . $GLOBALS['LANG']->getLL('listRowHeader_classes') . '</td>';
  3010. $cells[] = '<td>' . $GLOBALS['LANG']->getLL('extInfoArray_code_warnings') . '</td>';
  3011. $cells[] = '<td>' . $GLOBALS['LANG']->getLL('extInfoArray_annoyances') . '</td>';
  3012. } elseif ($this->MOD_SETTINGS['display_details']==5) {
  3013. $cells[] = '<td>' . $GLOBALS['LANG']->getLL('listRowHeader_changed_files') . '</td>';
  3014. } else {
  3015. $cells[] = '<td>' . $GLOBALS['LANG']->getLL('listRowHeader_ext_key') . '</td>';
  3016. $cells[] = '<td>' . $GLOBALS['LANG']->getLL('extInfoArray_version') . '</td>';
  3017. if (!$import) {
  3018. $cells[] = '<td>' . $GLOBALS['LANG']->getLL('listRowHeader_download_short') . '</td>';
  3019. $cells[] = '<td>' . $GLOBALS['LANG']->getLL('listRowHeader_documentation_short') . '</td>';
  3020. $cells[] = '<td>' . $GLOBALS['LANG']->getLL('listRowHeader_type') . '</td>';
  3021. } else {
  3022. $cells[] = '<td' . $this->labelInfo($GLOBALS['LANG']->getLL('listRowHeader_title_upload_date')) . '>' .
  3023. $GLOBALS['LANG']->getLL('listRowHeader_upload_date') . '</td>';
  3024. $cells[] = '<td>' . $GLOBALS['LANG']->getLL('extInfoArray_author') . '</td>';
  3025. $cells[] = '<td' . $this->labelInfo($GLOBALS['LANG']->getLL('listRowHeader_title_current_version')) . '>' .
  3026. $GLOBALS['LANG']->getLL('listRowHeader_current_version') . '</td>';
  3027. $cells[] = '<td' . $this->labelInfo($GLOBALS['LANG']->getLL('listRowHeader_title_current_type')) . '>' .
  3028. $GLOBALS['LANG']->getLL('listRowHeader_current_type') . '</td>';
  3029. $cells[] = '<td' . $this->labelInfo($GLOBALS['LANG']->getLL('listRowHeader_title_number_of_downloads')) . '>' .
  3030. $GLOBALS['LANG']->getLL('listRowHeader_download_short') . '</td>';
  3031. }
  3032. $cells[] = '<td>' . $GLOBALS['LANG']->getLL('extInfoArray_state') . '</td>';
  3033. }
  3034. return '
  3035. <tr'.$trAttrib.'>
  3036. '.implode('
  3037. ',$cells).'
  3038. </tr>';
  3039. }
  3040. /**
  3041. * Prints a row with data for the various extension listings
  3042. *
  3043. * @param string Extension key
  3044. * @param array Extension information array
  3045. * @param array Preset table cells, eg. install/uninstall icons.
  3046. * @param string <tr> tag class
  3047. * @param array Array with installed extension keys (as keys)
  3048. * @param boolean If set, the list is coming from remote server.
  3049. * @param string Alternative link URL
  3050. * @return string HTML <tr> content
  3051. */
  3052. function extensionListRow($extKey,$extInfo,$cells,$bgColorClass='',$inst_list=array(),$import=0,$altLinkUrl='') {
  3053. // Icon:
  3054. $imgInfo = @getImageSize($this->getExtPath($extKey,$extInfo['type']).'/ext_icon.gif');
  3055. if (is_array($imgInfo)) {
  3056. $cells[] = '<td><img src="'.$GLOBALS['BACK_PATH'].$this->typeRelPaths[$extInfo['type']].$extKey.'/ext_icon.gif'.'" '.$imgInfo[3].' alt="" /></td>';
  3057. } elseif ($extInfo['_ICON']) {
  3058. $cells[] = '<td>'.$extInfo['_ICON'].'</td>';
  3059. } else {
  3060. $cells[] = '<td><img src="clear.gif" width="1" height="1" alt="" /></td>';
  3061. }
  3062. // Extension title:
  3063. $cells[] = '<td nowrap="nowrap"><a href="' . htmlspecialchars($altLinkUrl ? $altLinkUrl : 'index.php?CMD[showExt]=' . $extKey . '&SET[singleDetails]=info') . '" title="' . htmlspecialchars($extInfo['EM_CONF']['description']) . '">' . t3lib_div::fixed_lgd_cs($extInfo['EM_CONF']['title'] ? htmlspecialchars($extInfo['EM_CONF']['title']) : '<em>' . $extKey . '</em>', 40) . '</a></td>';
  3064. // Based on the display mode you will see more or less details:
  3065. if (!$this->MOD_SETTINGS['display_details']) {
  3066. $cells[] = '<td>'.htmlspecialchars(t3lib_div::fixed_lgd_cs($extInfo['EM_CONF']['description'],400)).'<br /><img src="clear.gif" width="300" height="1" alt="" /></td>';
  3067. $cells[] = '<td nowrap="nowrap">'.($extInfo['EM_CONF']['author_email'] ? '<a href="mailto:'.htmlspecialchars($extInfo['EM_CONF']['author_email']).'">' : '').htmlspecialchars($extInfo['EM_CONF']['author']).(htmlspecialchars($extInfo['EM_CONF']['author_email']) ? '</a>' : '').($extInfo['EM_CONF']['author_company'] ? '<br />'.htmlspecialchars($extInfo['EM_CONF']['author_company']) : '').'</td>';
  3068. } elseif ($this->MOD_SETTINGS['display_details']==2) {
  3069. $cells[] = '<td nowrap="nowrap">'.$extInfo['EM_CONF']['priority'].'</td>';
  3070. $cells[] = '<td nowrap="nowrap">'.implode('<br />',t3lib_div::trimExplode(',',$extInfo['EM_CONF']['modify_tables'],1)).'</td>';
  3071. $cells[] = '<td nowrap="nowrap">'.$extInfo['EM_CONF']['module'].'</td>';
  3072. $cells[] = '<td nowrap="nowrap">'.($extInfo['EM_CONF']['clearCacheOnLoad'] ? $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:yes') : '').'</td>';
  3073. $cells[] = '<td nowrap="nowrap">'.($extInfo['EM_CONF']['internal'] ? $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:yes') : '').'</td>';
  3074. $cells[] = '<td nowrap="nowrap">'.($extInfo['EM_CONF']['shy'] ? $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:yes') : '').'</td>';
  3075. } elseif ($this->MOD_SETTINGS['display_details']==3) {
  3076. $techInfo = $this->makeDetailedExtensionAnalysis($extKey,$extInfo);
  3077. $cells[] = '<td>'.$this->extInformationArray_dbReq($techInfo).
  3078. '</td>';
  3079. $cells[] = '<td nowrap="nowrap">'.(is_array($techInfo['TSfiles']) ? implode('<br />',$techInfo['TSfiles']) : '').'</td>';
  3080. $cells[] = '<td nowrap="nowrap">'.(is_array($techInfo['flags']) ? implode('<br />',$techInfo['flags']) : '').'</td>';
  3081. $cells[] = '<td nowrap="nowrap">'.(is_array($techInfo['moduleNames']) ? implode('<br />',$techInfo['moduleNames']) : '').'</td>';
  3082. $cells[] = '<td nowrap="nowrap">'.($techInfo['conf'] ? $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:yes') : '').'</td>';
  3083. $cells[] = '<td>'.
  3084. $GLOBALS['TBE_TEMPLATE']->rfw((t3lib_extMgm::isLoaded($extKey) && $techInfo['tables_error'] ?
  3085. '<strong>' . $GLOBALS['LANG']->getLL('extInfoArray_table_error') . '</strong><br />' .
  3086. $GLOBALS['LANG']->getLL('extInfoArray_missing_fields') : '') .
  3087. (t3lib_extMgm::isLoaded($extKey) && $techInfo['static_error'] ?
  3088. '<strong>' . $GLOBALS['LANG']->getLL('extInfoArray_static_table_error') . '</strong><br />' .
  3089. $GLOBALS['LANG']->getLL('extInfoArray_static_tables_missing_empty') : '')) .
  3090. '</td>';
  3091. } elseif ($this->MOD_SETTINGS['display_details']==4) {
  3092. $techInfo=$this->makeDetailedExtensionAnalysis($extKey,$extInfo,1);
  3093. $cells[] = '<td>'.(is_array($techInfo['locallang']) ? implode('<br />',$techInfo['locallang']) : '').'</td>';
  3094. $cells[] = '<td>'.(is_array($techInfo['classes']) ? implode('<br />',$techInfo['classes']) : '').'</td>';
  3095. $cells[] = '<td>'.(is_array($techInfo['errors']) ? $GLOBALS['TBE_TEMPLATE']->rfw(implode('<hr />',$techInfo['errors'])) : '').'</td>';
  3096. $cells[] = '<td>'.(is_array($techInfo['NSerrors']) ?
  3097. (!t3lib_div::inList($this->nameSpaceExceptions, $extKey) ?
  3098. t3lib_div::view_array($techInfo['NSerrors']) :
  3099. $GLOBALS['TBE_TEMPLATE']->dfw($GLOBALS['LANG']->getLL('extInfoArray_exception'))) : '') . '</td>';
  3100. } elseif ($this->MOD_SETTINGS['display_details']==5) {
  3101. $currentMd5Array = $this->serverExtensionMD5Array($extKey,$extInfo);
  3102. $affectedFiles = '';
  3103. $msgLines = array();
  3104. $msgLines[] = $GLOBALS['LANG']->getLL('listRow_files') . ' ' . count($currentMd5Array);
  3105. if (strcmp($extInfo['EM_CONF']['_md5_values_when_last_written'],serialize($currentMd5Array))) {
  3106. $msgLines[] = $GLOBALS['TBE_TEMPLATE']->rfw('<br /><strong>' . $GLOBALS['LANG']->getLL('extInfoArray_difference_detected') . '</strong>');
  3107. $affectedFiles = $this->findMD5ArrayDiff($currentMd5Array,unserialize($extInfo['EM_CONF']['_md5_values_when_last_written']));
  3108. if (count($affectedFiles)) {
  3109. $msgLines[] = '<br /><strong>' . $GLOBALS['LANG']->getLL('extInfoArray_modified_files') . '</strong><br />' .
  3110. $GLOBALS['TBE_TEMPLATE']->rfw(implode('<br />', $affectedFiles));
  3111. }
  3112. }
  3113. $cells[] = '<td>'.implode('<br />',$msgLines).'</td>';
  3114. } else {
  3115. // Default view:
  3116. $verDiff = $inst_list[$extKey] && $this->versionDifference($extInfo['EM_CONF']['version'],$inst_list[$extKey]['EM_CONF']['version'],$this->versionDiffFactor);
  3117. $cells[] = '<td nowrap="nowrap"><em>'.$extKey.'</em></td>';
  3118. $cells[] = '<td nowrap="nowrap">'.($verDiff ? '<strong>'.$GLOBALS['TBE_TEMPLATE']->rfw(htmlspecialchars($extInfo['EM_CONF']['version'])).'</strong>' : $extInfo['EM_CONF']['version']).'</td>';
  3119. if (!$import) { // Listing extension on LOCAL server:
  3120. // Extension Download:
  3121. $cells[] = '<td nowrap="nowrap"><a href="' . htmlspecialchars('index.php?CMD[doBackup]=1&SET[singleDetails]=backup&CMD[showExt]=' . $extKey) . '" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:download') . '">' .
  3122. t3lib_iconWorks::getSpriteIcon('actions-system-extension-download') .
  3123. '</a></td>';
  3124. // Manual download
  3125. $fileP = PATH_site.$this->typePaths[$extInfo['type']].$extKey.'/doc/manual.sxw';
  3126. $cells[] = '<td nowrap="nowrap">'.
  3127. ($this->typePaths[$extInfo['type']] && @is_file($fileP) ?
  3128. '<a href="' . htmlspecialchars(t3lib_div::resolveBackPath($this->doc->backPath . '../' . $this->typePaths[$extInfo['type']] . $extKey . '/doc/manual.sxw')).'" target="_blank" title="' . $GLOBALS['LANG']->getLL('listRow_local_manual') . '">' .
  3129. t3lib_iconWorks::getSpriteIcon('actions-system-extension-documentation') . '</a>' : '') .
  3130. '</td>';
  3131. // Double installation (inclusion of an extension in more than one of system, global or local scopes)
  3132. $doubleInstall = '';
  3133. if (strlen($extInfo['doubleInstall']) > 1) {
  3134. // Separate the "SL" et al. string into an array and replace L by Local, G by Global etc.
  3135. $doubleInstallations = str_replace(
  3136. array('S', 'G', 'L'),
  3137. array(
  3138. $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_mod_tools_em.xml:sysext'),
  3139. $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_mod_tools_em.xml:globalext'),
  3140. $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_mod_tools_em.xml:localext')
  3141. ),
  3142. str_split($extInfo['doubleInstall'])
  3143. );
  3144. // Last extension is the one actually used
  3145. $usedExtension = array_pop($doubleInstallations);
  3146. // Next extension is overridden
  3147. $overriddenExtensions = array_pop($doubleInstallations);
  3148. // If the array is not yet empty, the extension is actually installed 3 times (SGL)
  3149. if (count($doubleInstallations) > 0) {
  3150. $lastExtension = array_pop($doubleInstallations);
  3151. $overriddenExtensions .= ' ' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:and') . ' ' . $lastExtension;
  3152. }
  3153. $doubleInstallTitle = sprintf(
  3154. $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_mod_tools_em.xml:double_inclusion'),
  3155. $usedExtension,
  3156. $overriddenExtensions
  3157. );
  3158. $doubleInstall = ' <strong><abbr title="' . $doubleInstallTitle .'">' . $GLOBALS['TBE_TEMPLATE']->rfw($extInfo['doubleInstall']) . '</abbr></strong>';
  3159. }
  3160. $cells[] = '<td nowrap="nowrap">' . $this->typeLabels[$extInfo['type']] . $doubleInstall . '</td>';
  3161. } else { // Listing extensions from REMOTE repository:
  3162. $inst_curVer = $inst_list[$extKey]['EM_CONF']['version'];
  3163. if (isset($inst_list[$extKey])) {
  3164. if ($verDiff) $inst_curVer = '<strong>'.$GLOBALS['TBE_TEMPLATE']->rfw($inst_curVer).'</strong>';
  3165. }
  3166. $cells[] = '<td nowrap="nowrap">' . t3lib_befunc::date($extInfo['EM_CONF']['lastuploaddate']) . '</td>';
  3167. $cells[] = '<td nowrap="nowrap">' . htmlspecialchars(t3lib_div::fixed_lgd_cs($extInfo['EM_CONF']['author'], $GLOBALS['BE_USER']->uc[titleLen])) . '</td>';
  3168. $cells[] = '<td nowrap="nowrap">'.$inst_curVer.'</td>';
  3169. $cells[] = '<td nowrap="nowrap">'.$this->typeLabels[$inst_list[$extKey]['type']].(strlen($inst_list[$extKey]['doubleInstall'])>1?'<strong> '.$GLOBALS['TBE_TEMPLATE']->rfw($inst_list[$extKey]['doubleInstall']).'</strong>':'').'</td>';
  3170. $cells[] = '<td nowrap="nowrap">'.($extInfo['downloadcounter_all']?$extInfo['downloadcounter_all']:'&nbsp;&nbsp;').'/'.($extInfo['downloadcounter']?$extInfo['downloadcounter']:'&nbsp;').'</td>';
  3171. }
  3172. $cells[] = '<td nowrap="nowrap" class="extstate" style="background-color:'.$this->stateColors[$extInfo['EM_CONF']['state']].';">'.$this->states[$extInfo['EM_CONF']['state']].'</td>';
  3173. }
  3174. // show a different background through a different class for insecure (-1) extensions,
  3175. // for unreviewed (0) an reviewed extensions (1), just use the regular class
  3176. if ($this->xmlhandler->getReviewState($extKey,$extInfo['EM_CONF']['version']) < 0) {
  3177. $bgclass = ' class="unsupported-ext"';
  3178. } else {
  3179. $bgclass = ' class="' . ($bgColorClass ? $bgColorClass : 'em-listbg1') . '"';
  3180. }
  3181. return '
  3182. <tr'.$bgclass.'>
  3183. '.implode('
  3184. ',$cells).'
  3185. </tr>';
  3186. }
  3187. /************************************
  3188. *
  3189. * Output helper functions
  3190. *
  3191. ************************************/
  3192. /**
  3193. * Wrapping input string in a link tag with link to email address
  3194. *
  3195. * @param string Input string, being wrapped in <a> tags
  3196. * @param string Email address for use in link.
  3197. * @return string Output
  3198. */
  3199. function wrapEmail($str,$email) {
  3200. if ($email) {
  3201. $str = '<a href="mailto:'.htmlspecialchars($email).'">'.htmlspecialchars($str).'</a>';
  3202. }
  3203. return $str;
  3204. }
  3205. /**
  3206. * Returns help text if applicable.
  3207. *
  3208. * @param string Help text key
  3209. * @return string HTML table cell
  3210. */
  3211. function helpCol($key) {
  3212. global $BE_USER;
  3213. if ($BE_USER->uc['edit_showFieldHelp']) {
  3214. if (empty($key)) {
  3215. return '<td>&nbsp;</td>';
  3216. }
  3217. else {
  3218. return t3lib_BEfunc::cshItem($this->descrTable, 'emconf_'.$key, $GLOBALS['BACK_PATH'], '<td>|</td>');
  3219. }
  3220. }
  3221. else {
  3222. return '';
  3223. }
  3224. }
  3225. /**
  3226. * Returns title and style attribute for mouseover help text.
  3227. *
  3228. * @param string Help text.
  3229. * @return string title="" attribute prepended with a single space
  3230. */
  3231. function labelInfo($str) {
  3232. return ' title="'.htmlspecialchars($str).'" style="cursor:help;"';
  3233. }
  3234. /**
  3235. * Returns a header for an extensions including icon if any
  3236. *
  3237. * @param string Extension key
  3238. * @param array Extension information array
  3239. * @param string align-attribute value (for <img> tag)
  3240. * @return string HTML; Extension title and image.
  3241. */
  3242. function extensionTitleIconHeader($extKey,$extInfo,$align='top') {
  3243. $imgInfo = @getImageSize($this->getExtPath($extKey,$extInfo['type']).'/ext_icon.gif');
  3244. $out = '';
  3245. if (is_array($imgInfo)) {
  3246. $out.= '<img src="'.$GLOBALS['BACK_PATH'].$this->typeRelPaths[$extInfo['type']].$extKey.'/ext_icon.gif" '.$imgInfo[3].' align="'.$align.'" alt="" />';
  3247. }
  3248. $out.= $extInfo['EM_CONF']['title'] ? htmlspecialchars(t3lib_div::fixed_lgd_cs($extInfo['EM_CONF']['title'],40)) : '<em>' . htmlspecialchars($extKey) . '</em>';
  3249. return $out;
  3250. }
  3251. /**
  3252. * Returns image tag for "uninstall"
  3253. *
  3254. * @return string <img> tag
  3255. */
  3256. function removeButton() {
  3257. return t3lib_iconWorks::getSpriteIcon('actions-system-extension-uninstall', array('title' => $GLOBALS['LANG']->getLL('ext_details_remove_ext')));
  3258. }
  3259. /**
  3260. * Returns image for "install"
  3261. *
  3262. * @return string <img> tag
  3263. */
  3264. function installButton() {
  3265. return t3lib_iconWorks::getSpriteIcon('actions-system-extension-install', array('title' => $GLOBALS['LANG']->getLL('helperFunction_install_extension')));
  3266. }
  3267. /**
  3268. * Warning (<img> + text string) message about the impossibility to import extensions (both local and global locations are disabled...)
  3269. *
  3270. * @return string <img> + text string.
  3271. */
  3272. function noImportMsg() {
  3273. return t3lib_iconWorks::getSpriteIcon('status-dialog-warning') .
  3274. '<strong>' . $GLOBALS['LANG']->getLL('helperFunction_import_not_possible') . '</strong>';
  3275. }
  3276. /**
  3277. * Checks whether the passed dependency is TER2-style (array) and returns a single string for displaying the dependencies.
  3278. *
  3279. * It leaves out all version numbers and the "php" and "typo3" dependencies, as they are implicit and of no interest without the version number.
  3280. *
  3281. * @param mixed $dep Either a string or an array listing dependencies.
  3282. * @param string $type The dependency type to list if $dep is an array
  3283. * @return string A simple dependency list for display
  3284. */
  3285. function depToString($dep,$type='depends') {
  3286. if(is_array($dep)) {
  3287. unset($dep[$type]['php']);
  3288. unset($dep[$type]['typo3']);
  3289. $s = (count($dep[$type])) ? implode(',', array_keys($dep[$type])) : '';
  3290. return $s;
  3291. }
  3292. return '';
  3293. }
  3294. /**
  3295. * Checks whether the passed dependency is TER-style (string) or TER2-style (array) and returns a single string for displaying the dependencies.
  3296. *
  3297. * It leaves out all version numbers and the "php" and "typo3" dependencies, as they are implicit and of no interest without the version number.
  3298. *
  3299. * @param mixed $dep Either a string or an array listing dependencies.
  3300. * @param string $type The dependency type to list if $dep is an array
  3301. * @return string A simple dependency list for display
  3302. */
  3303. function stringToDep($dep) {
  3304. $constraint = array();
  3305. if(is_string($dep) && strlen($dep)) {
  3306. $dep = explode(',',$dep);
  3307. foreach($dep as $v) {
  3308. $constraint[$v] = '';
  3309. }
  3310. }
  3311. return $constraint;
  3312. }
  3313. /********************************
  3314. *
  3315. * Read information about all available extensions
  3316. *
  3317. *******************************/
  3318. /**
  3319. * Returns the list of available (installed) extensions
  3320. *
  3321. * @return array Array with two arrays, list array (all extensions with info) and category index
  3322. * @see getInstExtList()
  3323. */
  3324. function getInstalledExtensions() {
  3325. $list = array();
  3326. $cat = $this->defaultCategories;
  3327. $path = PATH_typo3.'sysext/';
  3328. $this->getInstExtList($path,$list,$cat,'S');
  3329. $path = PATH_typo3.'ext/';
  3330. $this->getInstExtList($path,$list,$cat,'G');
  3331. $path = PATH_typo3conf.'ext/';
  3332. $this->getInstExtList($path,$list,$cat,'L');
  3333. return array($list,$cat);
  3334. }
  3335. /**
  3336. * Gathers all extensions in $path
  3337. *
  3338. * @param string Absolute path to local, global or system extensions
  3339. * @param array Array with information for each extension key found. Notice: passed by reference
  3340. * @param array Categories index: Contains extension titles grouped by various criteria.
  3341. * @param string Path-type: L, G or S
  3342. * @return void "Returns" content by reference
  3343. * @access private
  3344. * @see getInstalledExtensions()
  3345. */
  3346. function getInstExtList($path,&$list,&$cat,$type) {
  3347. if (@is_dir($path)) {
  3348. $extList = t3lib_div::get_dirs($path);
  3349. if (is_array($extList)) {
  3350. foreach($extList as $extKey) {
  3351. if (@is_file($path.$extKey.'/ext_emconf.php')) {
  3352. $emConf = $this->includeEMCONF($path.$extKey.'/ext_emconf.php', $extKey);
  3353. if (is_array($emConf)) {
  3354. if (is_array($list[$extKey])) {
  3355. $list[$extKey]=array('doubleInstall'=>$list[$extKey]['doubleInstall']);
  3356. }
  3357. $list[$extKey]['doubleInstall'].= $type;
  3358. $list[$extKey]['type'] = $type;
  3359. $list[$extKey]['EM_CONF'] = $emConf;
  3360. $list[$extKey]['files'] = t3lib_div::getFilesInDir($path.$extKey, '', 0, '', $this->excludeForPackaging);
  3361. $this->setCat($cat,$list[$extKey], $extKey);
  3362. }
  3363. }
  3364. }
  3365. }
  3366. }
  3367. }
  3368. /**
  3369. * Fixes an old style ext_emconf.php array by adding constraints if needed and removing deprecated keys
  3370. *
  3371. * @param array $emConf
  3372. * @return array
  3373. */
  3374. function fixEMCONF($emConf) {
  3375. if(!isset($emConf['constraints']) || !isset($emConf['constraints']['depends']) || !isset($emConf['constraints']['conflicts']) || !isset($emConf['constraints']['suggests'])) {
  3376. if(!isset($emConf['constraints']) || !isset($emConf['constraints']['depends'])) {
  3377. $emConf['constraints']['depends'] = $this->stringToDep($emConf['dependencies']);
  3378. if(strlen($emConf['PHP_version'])) {
  3379. $versionRange = $this->splitVersionRange($emConf['PHP_version']);
  3380. if (version_compare($versionRange[0],'3.0.0','<')) $versionRange[0] = '3.0.0';
  3381. if (version_compare($versionRange[1],'3.0.0','<')) $versionRange[1] = '0.0.0';
  3382. $emConf['constraints']['depends']['php'] = implode('-',$versionRange);
  3383. }
  3384. if(strlen($emConf['TYPO3_version'])) {
  3385. $versionRange = $this->splitVersionRange($emConf['TYPO3_version']);
  3386. if (version_compare($versionRange[0],'3.5.0','<')) $versionRange[0] = '3.5.0';
  3387. if (version_compare($versionRange[1],'3.5.0','<')) $versionRange[1] = '0.0.0';
  3388. $emConf['constraints']['depends']['typo3'] = implode('-',$versionRange);
  3389. }
  3390. }
  3391. if(!isset($emConf['constraints']) || !isset($emConf['constraints']['conflicts'])) {
  3392. $emConf['constraints']['conflicts'] = $this->stringToDep($emConf['conflicts']);
  3393. }
  3394. if(!isset($emConf['constraints']) || !isset($emConf['constraints']['suggests'])) {
  3395. $emConf['constraints']['suggests'] = array();
  3396. }
  3397. } elseif (isset($emConf['constraints']) && isset($emConf['dependencies'])) {
  3398. $emConf['suggests'] = isset($emConf['suggests']) ? $emConf['suggests'] : array();
  3399. $emConf['dependencies'] = $this->depToString($emConf['constraints']);
  3400. $emConf['conflicts'] = $this->depToString($emConf['constraints'], 'conflicts');
  3401. }
  3402. // sanity check for version numbers, intentionally only checks php and typo3
  3403. if(isset($emConf['constraints']['depends']) && isset($emConf['constraints']['depends']['php'])) {
  3404. $versionRange = $this->splitVersionRange($emConf['constraints']['depends']['php']);
  3405. if (version_compare($versionRange[0],'3.0.0','<')) $versionRange[0] = '3.0.0';
  3406. if (version_compare($versionRange[1],'3.0.0','<')) $versionRange[1] = '0.0.0';
  3407. $emConf['constraints']['depends']['php'] = implode('-',$versionRange);
  3408. }
  3409. if(isset($emConf['constraints']['depends']) && isset($emConf['constraints']['depends']['typo3'])) {
  3410. $versionRange = $this->splitVersionRange($emConf['constraints']['depends']['typo3']);
  3411. if (version_compare($versionRange[0],'3.5.0','<')) $versionRange[0] = '3.5.0';
  3412. if (version_compare($versionRange[1],'3.5.0','<')) $versionRange[1] = '0.0.0';
  3413. $emConf['constraints']['depends']['typo3'] = implode('-',$versionRange);
  3414. }
  3415. unset($emConf['private']);
  3416. unset($emConf['download_password']);
  3417. unset($emConf['TYPO3_version']);
  3418. unset($emConf['PHP_version']);
  3419. return $emConf;
  3420. }
  3421. /**
  3422. * Splits a version range into an array.
  3423. *
  3424. * If a single version number is given, it is considered a minimum value.
  3425. * If a dash is found, the numbers left and right are considered as minimum and maximum. Empty values are allowed.
  3426. *
  3427. * @param string $ver A string with a version range.
  3428. * @return array
  3429. */
  3430. function splitVersionRange($ver) {
  3431. $versionRange = array();
  3432. if (strstr($ver, '-')) {
  3433. $versionRange = explode('-', $ver, 2);
  3434. } else {
  3435. $versionRange[0] = $ver;
  3436. $versionRange[1] = '';
  3437. }
  3438. if (!$versionRange[0]) { $versionRange[0] = '0.0.0'; }
  3439. if (!$versionRange[1]) { $versionRange[1] = '0.0.0'; }
  3440. return $versionRange;
  3441. }
  3442. /**
  3443. * Maps remote extensions information into $cat/$list arrays for listing
  3444. *
  3445. * @param boolean If set the info in the internal extensionsXML array will be unset before returning the result.
  3446. * @return array List array and category index as key 0 / 1 in an array.
  3447. */
  3448. function prepareImportExtList($unsetProc = false) {
  3449. $list = array();
  3450. $cat = $this->defaultCategories;
  3451. $filepath = $this->getMirrorURL();
  3452. foreach ($this->xmlhandler->extensionsXML as $extKey => $data) {
  3453. $GLOBALS['LANG']->csConvObj->convArray($data,'utf-8',$GLOBALS['LANG']->charSet); // is there a better place for conversion?
  3454. $list[$extKey]['type'] = '_';
  3455. $version = array_keys($data['versions']);
  3456. $extPath = t3lib_div::strtolower($extKey);
  3457. $list[$extKey]['_ICON'] = '<img alt="" src="' . $filepath . $extPath{0} . '/' . $extPath{1} . '/' . $extPath . '_' . end($version) . '.gif" />';
  3458. $list[$extKey]['downloadcounter'] = $data['downloadcounter'];
  3459. foreach(array_keys($data['versions']) as $version) {
  3460. $list[$extKey]['versions'][$version]['downloadcounter'] = $data['versions'][$version]['downloadcounter'];
  3461. $list[$extKey]['versions'][$version]['EM_CONF'] = array(
  3462. 'version' => $version,
  3463. 'title' => $data['versions'][$version]['title'],
  3464. 'description' => $data['versions'][$version]['description'],
  3465. 'category' => $data['versions'][$version]['category'],
  3466. 'constraints' => $data['versions'][$version]['dependencies'],
  3467. 'state' => $data['versions'][$version]['state'],
  3468. 'reviewstate' => $data['versions'][$version]['reviewstate'],
  3469. 'lastuploaddate' => $data['versions'][$version]['lastuploaddate'],
  3470. 'author' => $data['versions'][$version]['authorname'],
  3471. 'author_email' => $data['versions'][$version]['authoremail'],
  3472. 'author_company' => $data['versions'][$version]['authorcompany'],
  3473. );
  3474. }
  3475. $this->setCat($cat, $list[$extKey]['versions'][$version], $extKey);
  3476. if ($unsetProc) {
  3477. unset($this->xmlhandler->extensionsXML[$extKey]);
  3478. }
  3479. }
  3480. return array($list,$cat);
  3481. }
  3482. /**
  3483. * Set category array entries for extension
  3484. *
  3485. * @param array Category index array
  3486. * @param array Part of list array for extension.
  3487. * @param string Extension key
  3488. * @return array Modified category index array
  3489. */
  3490. function setCat(&$cat,$listArrayPart,$extKey) {
  3491. // Getting extension title:
  3492. $extTitle = $listArrayPart['EM_CONF']['title'];
  3493. // Category index:
  3494. $index = $listArrayPart['EM_CONF']['category'];
  3495. $cat['cat'][$index][$extKey] = $extTitle;
  3496. // Author index:
  3497. $index = $listArrayPart['EM_CONF']['author'].($listArrayPart['EM_CONF']['author_company']?', '.$listArrayPart['EM_CONF']['author_company']:'');
  3498. $cat['author_company'][$index][$extKey] = $extTitle;
  3499. // State index:
  3500. $index = $listArrayPart['EM_CONF']['state'];
  3501. $cat['state'][$index][$extKey] = $extTitle;
  3502. // Type index:
  3503. $index = $listArrayPart['type'];
  3504. $cat['type'][$index][$extKey] = $extTitle;
  3505. // Return categories:
  3506. return $cat;
  3507. }
  3508. /*******************************
  3509. *
  3510. * Extension analyzing (detailed information)
  3511. *
  3512. ******************************/
  3513. /**
  3514. * Perform a detailed, technical analysis of the available extension on server!
  3515. * Includes all kinds of verifications
  3516. * Takes some time to process, therfore use with care, in particular in listings.
  3517. *
  3518. * @param string Extension key
  3519. * @param array Extension information
  3520. * @param boolean If set, checks for validity of classes etc.
  3521. * @return array Information in an array.
  3522. */
  3523. function makeDetailedExtensionAnalysis($extKey,$extInfo,$validity=0) {
  3524. // Get absolute path of the extension
  3525. $absPath = $this->getExtPath($extKey,$extInfo['type']);
  3526. $infoArray = array();
  3527. $table_class_prefix = substr($extKey,0,5)=='user_' ? 'user_' : 'tx_'.str_replace('_','',$extKey).'_';
  3528. $module_prefix = substr($extKey,0,5)=='user_' ? 'u' : 'tx'.str_replace('_','',$extKey);
  3529. // Database status:
  3530. $dbInfo = $this->checkDBupdates($extKey,$extInfo,1);
  3531. // Database structure required:
  3532. if (is_array($dbInfo['structure']['tables_fields'])) {
  3533. $modify_tables = t3lib_div::trimExplode(',',$extInfo['EM_CONF']['modify_tables'],1);
  3534. $infoArray['dump_tf'] = array();
  3535. foreach($dbInfo['structure']['tables_fields'] as $tN => $d) {
  3536. if (in_array($tN,$modify_tables)) {
  3537. $infoArray['fields'][] = $tN.': <i>'.
  3538. (is_array($d['fields']) ? implode(', ',array_keys($d['fields'])) : '').
  3539. (is_array($d['keys']) ?
  3540. ' + ' . count($d['keys']) . ' ' . $GLOBALS['LANG']->getLL('detailedExtAnalysis_keys') : '') .
  3541. '</i>';
  3542. if (is_array($d['fields'])) {
  3543. foreach ($d['fields'] as $fN => $value) {
  3544. $infoArray['dump_tf'][] = $tN.'.'.$fN;
  3545. if (!t3lib_div::isFirstPartOfStr($fN,$table_class_prefix)) {
  3546. $infoArray['NSerrors']['fields'][$fN] = $fN;
  3547. } else {
  3548. $infoArray['NSok']['fields'][$fN] = $fN;
  3549. }
  3550. }
  3551. }
  3552. if (is_array($d['keys'])) {
  3553. foreach ($d['keys'] as $fN => $value) {
  3554. $infoArray['dump_tf'][] = $tN.'.KEY:'.$fN;
  3555. }
  3556. }
  3557. } else {
  3558. $infoArray['dump_tf'][] = $tN;
  3559. $infoArray['tables'][] = $tN;
  3560. if (!t3lib_div::isFirstPartOfStr($tN,$table_class_prefix)) {
  3561. $infoArray['NSerrors']['tables'][$tN] = $tN;
  3562. } else $infoArray['NSok']['tables'][$tN] = $tN;
  3563. }
  3564. }
  3565. if (count($dbInfo['structure']['diff']['diff']) || count($dbInfo['structure']['diff']['extra'])) {
  3566. $msg = array();
  3567. if (count($dbInfo['structure']['diff']['diff'])) {
  3568. $msg[] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_tables_are_missing');
  3569. }
  3570. if (count($dbInfo['structure']['diff']['extra'])) {
  3571. $msg[] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_tables_are_of_wrong_type');
  3572. }
  3573. $infoArray['tables_error'] = 1;
  3574. if (t3lib_extMgm::isLoaded($extKey)) {
  3575. $infoArray['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_tables_are'),
  3576. implode(' ' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:and') . ' ', $msg)
  3577. );
  3578. }
  3579. }
  3580. }
  3581. // Static tables?
  3582. if (is_array($dbInfo['static'])) {
  3583. $infoArray['static'] = array_keys($dbInfo['static']);
  3584. foreach($dbInfo['static'] as $tN => $d) {
  3585. if (!$d['exists']) {
  3586. $infoArray['static_error'] = 1;
  3587. if (t3lib_extMgm::isLoaded($extKey)) {
  3588. $infoArray['errors'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_static_tables_missing');
  3589. }
  3590. if (!t3lib_div::isFirstPartOfStr($tN,$table_class_prefix)) {
  3591. $infoArray['NSerrors']['tables'][$tN] = $tN;
  3592. } else $infoArray['NSok']['tables'][$tN] = $tN;
  3593. }
  3594. }
  3595. }
  3596. // Backend Module-check:
  3597. $knownModuleList = t3lib_div::trimExplode(',',$extInfo['EM_CONF']['module'],1);
  3598. foreach($knownModuleList as $mod) {
  3599. if (@is_dir($absPath.$mod)) {
  3600. if (@is_file($absPath.$mod.'/conf.php')) {
  3601. $confFileInfo = $this->modConfFileAnalysis($absPath.$mod.'/conf.php');
  3602. if (is_array($confFileInfo['TYPO3_MOD_PATH'])) {
  3603. $shouldBePath = $this->typeRelPaths[$extInfo['type']].$extKey.'/'.$mod.'/';
  3604. if (strcmp($confFileInfo['TYPO3_MOD_PATH'][1][1],$shouldBePath)) {
  3605. $infoArray['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_wrong_mod_path'),
  3606. $confFileInfo['TYPO3_MOD_PATH'][1][1],
  3607. $shouldBePath
  3608. );
  3609. }
  3610. } else {
  3611. // It seems like TYPO3_MOD_PATH and therefore also this warning is no longer needed.
  3612. // $infoArray['errors'][] = 'No definition of TYPO3_MOD_PATH constant found inside!';
  3613. }
  3614. if (is_array($confFileInfo['MCONF_name'])) {
  3615. $mName = $confFileInfo['MCONF_name'][1][1];
  3616. $mNameParts = explode('_',$mName);
  3617. $infoArray['moduleNames'][] = $mName;
  3618. if (!t3lib_div::isFirstPartOfStr($mNameParts[0],$module_prefix) &&
  3619. (!$mNameParts[1] || !t3lib_div::isFirstPartOfStr($mNameParts[1],$module_prefix))) {
  3620. $infoArray['NSerrors']['modname'][] = $mName;
  3621. } else $infoArray['NSok']['modname'][] = $mName;
  3622. } else $infoArray['errors'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_mconf_missing');
  3623. } else $infoArray['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_be_module_conf_missing'),
  3624. $mod . '/conf.php'
  3625. );
  3626. } else $infoArray['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_module_folder_missing'),
  3627. $mod . '/'
  3628. );
  3629. }
  3630. $dirs = t3lib_div::get_dirs($absPath);
  3631. if (is_array($dirs)) {
  3632. reset($dirs);
  3633. while(list(,$mod) = each($dirs)) {
  3634. if (!in_array($mod,$knownModuleList) && @is_file($absPath.$mod.'/conf.php')) {
  3635. $confFileInfo = $this->modConfFileAnalysis($absPath.$mod.'/conf.php');
  3636. if (is_array($confFileInfo)) {
  3637. $infoArray['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_unconfigured_module'),
  3638. $mod . '/conf.php'
  3639. );
  3640. }
  3641. }
  3642. }
  3643. }
  3644. // ext_tables.php:
  3645. if (@is_file($absPath.'ext_tables.php')) {
  3646. $content = t3lib_div::getUrl($absPath.'ext_tables.php');
  3647. if (stristr($content, 't3lib_extMgm::addModule')) $infoArray['flags'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_module');
  3648. if (stristr($content, 't3lib_extMgm::insertModuleFunction')) $infoArray['flags'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_module_and_more');
  3649. if (stristr($content, 't3lib_div::loadTCA')) $infoArray['flags'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_loadTCA');
  3650. if (stristr($content, '$TCA[')) $infoArray['flags'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_TCA');
  3651. if (stristr($content, 't3lib_extMgm::addPlugin')) $infoArray['flags'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_plugin');
  3652. }
  3653. // ext_localconf.php:
  3654. if (@is_file($absPath.'ext_localconf.php')) {
  3655. $content = t3lib_div::getUrl($absPath.'ext_localconf.php');
  3656. if (stristr($content, 't3lib_extMgm::addPItoST43')) $infoArray['flags'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_plugin_st43');
  3657. if (stristr($content, 't3lib_extMgm::addPageTSConfig')) $infoArray['flags'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_page_ts');
  3658. if (stristr($content, 't3lib_extMgm::addUserTSConfig')) $infoArray['flags'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_user_ts');
  3659. if (stristr($content, 't3lib_extMgm::addTypoScriptSetup')) $infoArray['flags'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_ts_setup');
  3660. if (stristr($content, 't3lib_extMgm::addTypoScriptConstants')) $infoArray['flags'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_ts_constants');
  3661. }
  3662. if (@is_file($absPath.'ext_typoscript_constants.txt')) {
  3663. $infoArray['TSfiles'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_constants');
  3664. }
  3665. if (@is_file($absPath.'ext_typoscript_setup.txt')) {
  3666. $infoArray['TSfiles'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_setup');
  3667. }
  3668. if (@is_file($absPath.'ext_conf_template.txt')) {
  3669. $infoArray['conf'] = 1;
  3670. }
  3671. // Classes:
  3672. if ($validity) {
  3673. $filesInside = $this->getClassIndexLocallangFiles($absPath,$table_class_prefix,$extKey);
  3674. if (is_array($filesInside['errors'])) $infoArray['errors'] = array_merge((array)$infoArray['errors'],$filesInside['errors']);
  3675. if (is_array($filesInside['NSerrors'])) $infoArray['NSerrors'] = array_merge((array)$infoArray['NSerrors'],$filesInside['NSerrors']);
  3676. if (is_array($filesInside['NSok'])) $infoArray['NSok'] = array_merge((array)$infoArray['NSok'],$filesInside['NSok']);
  3677. $infoArray['locallang'] = $filesInside['locallang'];
  3678. $infoArray['classes'] = $filesInside['classes'];
  3679. }
  3680. // Upload folders
  3681. if ($extInfo['EM_CONF']['uploadfolder']) {
  3682. $infoArray['uploadfolder'] = $this->ulFolder($extKey);
  3683. if (!@is_dir(PATH_site.$infoArray['uploadfolder'])) {
  3684. $infoArray['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_no_upload_folder'),
  3685. $infoArray['uploadfolder']
  3686. );
  3687. $infoArray['uploadfolder'] = '';
  3688. }
  3689. }
  3690. // Create directories:
  3691. if ($extInfo['EM_CONF']['createDirs']) {
  3692. $infoArray['createDirs'] = array_unique(t3lib_div::trimExplode(',',$extInfo['EM_CONF']['createDirs'],1));
  3693. foreach($infoArray['createDirs'] as $crDir) {
  3694. if (!@is_dir(PATH_site.$crDir)) {
  3695. $infoArray['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_no_upload_folder'),
  3696. $crDir
  3697. );
  3698. }
  3699. }
  3700. }
  3701. // Return result array:
  3702. return $infoArray;
  3703. }
  3704. /**
  3705. * Analyses the php-scripts of an available extension on server
  3706. *
  3707. * @param string Absolute path to extension
  3708. * @param string Prefix for tables/classes.
  3709. * @param string Extension key
  3710. * @return array Information array.
  3711. * @see makeDetailedExtensionAnalysis()
  3712. */
  3713. function getClassIndexLocallangFiles($absPath,$table_class_prefix,$extKey) {
  3714. $filesInside = t3lib_div::removePrefixPathFromList(t3lib_div::getAllFilesAndFoldersInPath(array(),$absPath,'php,inc',0,99,$this->excludeForPackaging),$absPath);
  3715. $out = array();
  3716. $reg = array();
  3717. foreach($filesInside as $fileName) {
  3718. if (substr($fileName,0,4)!='ext_' && substr($fileName,0,6)!='tests/') { // ignore supposed-to-be unit tests as well
  3719. $baseName = basename($fileName);
  3720. if (substr($baseName,0,9)=='locallang' && substr($baseName,-4)=='.php') {
  3721. $out['locallang'][] = $fileName;
  3722. } elseif ($baseName!='conf.php') {
  3723. if (filesize($absPath.$fileName)<500*1024) {
  3724. $fContent = t3lib_div::getUrl($absPath.$fileName);
  3725. unset($reg);
  3726. if (preg_match('/\n[[:space:]]*class[[:space:]]*([[:alnum:]_]+)([[:alnum:][:space:]_]*)/',$fContent,$reg)) {
  3727. // Find classes:
  3728. $lines = explode(LF,$fContent);
  3729. foreach($lines as $l) {
  3730. $line = trim($l);
  3731. unset($reg);
  3732. if (preg_match('/^class[[:space:]]*([[:alnum:]_]+)([[:alnum:][:space:]_]*)/',$line,$reg)) {
  3733. $out['classes'][] = $reg[1];
  3734. $out['files'][$fileName]['classes'][] = $reg[1];
  3735. if ($reg[1]!=='ext_update' && substr($reg[1],0,3)!='ux_' && !t3lib_div::isFirstPartOfStr($reg[1],$table_class_prefix) && strcmp(substr($table_class_prefix,0,-1),$reg[1])) {
  3736. $out['NSerrors']['classname'][] = $reg[1];
  3737. } else $out['NSok']['classname'][] = $reg[1];
  3738. }
  3739. }
  3740. // If class file prefixed 'class.'....
  3741. if (substr($baseName,0,6)=='class.') {
  3742. $fI = pathinfo($baseName);
  3743. $testName=substr($baseName,6,-(1+strlen($fI['extension'])));
  3744. if ($testName!=='ext_update' && substr($testName,0,3)!='ux_' && !t3lib_div::isFirstPartOfStr($testName,$table_class_prefix) && strcmp(substr($table_class_prefix,0,-1),$testName)) {
  3745. $out['NSerrors']['classfilename'][] = $baseName;
  3746. } else {
  3747. $out['NSok']['classfilename'][] = $baseName;
  3748. if (is_array($out['files'][$fileName]['classes']) && $this->first_in_array($testName,$out['files'][$fileName]['classes'],1)) {
  3749. $out['msg'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_class_ok'),
  3750. $fileName, $testName
  3751. );
  3752. } else $out['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_class_not_ok'),
  3753. $fileName, $testName
  3754. );
  3755. }
  3756. }
  3757. // Check for proper XCLASS definition
  3758. // Match $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS'] with single or doublequotes
  3759. $XclassSearch = '\$TYPO3_CONF_VARS\[TYPO3_MODE\]\[[\'"]XCLASS[\'"]\]';
  3760. $XclassParts = preg_split('/if \(defined\([\'"]TYPO3_MODE[\'"]\) && ' . $XclassSearch . '/', $fContent, 2);
  3761. if (count($XclassParts) !== 2) {
  3762. // Match $GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS'] with single or doublequotes
  3763. $XclassSearch = '\$GLOBALS\[[\'"]TYPO3_CONF_VARS[\'"]\]\[TYPO3_MODE\]\[[\'"]XCLASS[\'"]\]';
  3764. $XclassParts = preg_split('/if \(defined\([\'"]TYPO3_MODE[\'"]\) && ' . $XclassSearch . '/', $fContent, 2);
  3765. }
  3766. if (count($XclassParts)==2) {
  3767. unset($reg);
  3768. preg_match('/^\[[\'"]([[:alnum:]_\/\.]*)[\'"]\]/',$XclassParts[1],$reg);
  3769. if ($reg[1]) {
  3770. $cmpF = 'ext/'.$extKey.'/'.$fileName;
  3771. if (!strcmp($reg[1],$cmpF)) {
  3772. if (preg_match('/_once[[:space:]]*\(' . $XclassSearch . '\[[\'"]' . preg_quote($cmpF, '/') . '[\'"]\]\);/', $XclassParts[1])) {
  3773. $out['msg'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_xclass_ok'), $fileName);
  3774. } else $out['errors'][] = $GLOBALS['LANG']->getLL('detailedExtAnalysis_xclass_no_include');
  3775. } else $out['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_xclass_incorrect'),
  3776. $reg[1], $cmpF
  3777. );
  3778. } else $out['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_no_xclass_filename'), $fileName);
  3779. } elseif (!$this->first_in_array('ux_', $out['files'][$fileName]['classes'])) {
  3780. // No Xclass definition required if classname starts with 'ux_'
  3781. $out['errors'][] = sprintf($GLOBALS['LANG']->getLL('detailedExtAnalysis_no_xclass_found'), $fileName);
  3782. }
  3783. }
  3784. }
  3785. }
  3786. }
  3787. }
  3788. return $out;
  3789. }
  3790. /**
  3791. * Reads $confFilePath (a module $conf-file) and returns information on the existence of TYPO3_MOD_PATH definition and MCONF_name
  3792. *
  3793. * @param string Absolute path to a "conf.php" file of a module which we are analysing.
  3794. * @return array Information found.
  3795. * @see writeTYPO3_MOD_PATH()
  3796. */
  3797. function modConfFileAnalysis($confFilePath) {
  3798. $lines = explode(LF,t3lib_div::getUrl($confFilePath));
  3799. $confFileInfo = array();
  3800. $confFileInfo['lines'] = $lines;
  3801. $reg = array();
  3802. foreach($lines as $k => $l) {
  3803. $line = trim($l);
  3804. unset($reg);
  3805. if (preg_match('/^define[[:space:]]*\([[:space:]]*["\']TYPO3_MOD_PATH["\'][[:space:]]*,[[:space:]]*["\']([[:alnum:]_\/\.]+)["\'][[:space:]]*\)[[:space:]]*;/',$line,$reg)) {
  3806. $confFileInfo['TYPO3_MOD_PATH'] = array($k,$reg);
  3807. }
  3808. unset($reg);
  3809. if (preg_match('/^\$MCONF\[["\']?name["\']?\][[:space:]]*=[[:space:]]*["\']([[:alnum:]_]+)["\'];/',$line,$reg)) {
  3810. $confFileInfo['MCONF_name'] = array($k,$reg);
  3811. }
  3812. }
  3813. return $confFileInfo;
  3814. }
  3815. /**
  3816. * Creates a MD5-hash array over the current files in the extension
  3817. *
  3818. * @param string Extension key
  3819. * @param array Extension information array
  3820. * @return array MD5-keys
  3821. */
  3822. function serverExtensionMD5Array($extKey,$conf) {
  3823. // Creates upload-array - including filelist.
  3824. $mUA = $this->makeUploadArray($extKey,$conf);
  3825. $md5Array = array();
  3826. if (is_array($mUA['FILES'])) {
  3827. // Traverse files.
  3828. foreach($mUA['FILES'] as $fN => $d) {
  3829. if ($fN!='ext_emconf.php') {
  3830. $md5Array[$fN] = substr($d['content_md5'],0,4);
  3831. }
  3832. }
  3833. } else debug($mUA);
  3834. return $md5Array;
  3835. }
  3836. /**
  3837. * Compares two arrays with MD5-hash values for analysis of which files has changed.
  3838. *
  3839. * @param array Current values
  3840. * @param array Past values
  3841. * @return array Affected files
  3842. */
  3843. function findMD5ArrayDiff($current,$past) {
  3844. if (!is_array($current)) $current = array();
  3845. if (!is_array($past)) $past = array();
  3846. $filesInCommon = array_intersect($current,$past);
  3847. $diff1 = array_keys(array_diff($past,$filesInCommon));
  3848. $diff2 = array_keys(array_diff($current,$filesInCommon));
  3849. $affectedFiles = array_unique(array_merge($diff1,$diff2));
  3850. return $affectedFiles;
  3851. }
  3852. /***********************************
  3853. *
  3854. * File system operations
  3855. *
  3856. **********************************/
  3857. /**
  3858. * Creates directories in $extDirPath
  3859. *
  3860. * @param array Array of directories to create relative to extDirPath, eg. "blabla", "blabla/blabla" etc...
  3861. * @param string Absolute path to directory.
  3862. * @return mixed Returns false on success or an error string
  3863. */
  3864. function createDirsInPath($dirs,$extDirPath) {
  3865. if (is_array($dirs)) {
  3866. foreach($dirs as $dir) {
  3867. $error = t3lib_div::mkdir_deep($extDirPath,$dir);
  3868. if ($error) return $error;
  3869. }
  3870. }
  3871. return false;
  3872. }
  3873. /**
  3874. * Removes the extension directory (including content)
  3875. *
  3876. * @param string Extension directory to remove (with trailing slash)
  3877. * @param boolean If set, will leave the extension directory
  3878. * @return boolean False on success, otherwise error string.
  3879. */
  3880. function removeExtDirectory($removePath,$removeContentOnly=0) {
  3881. $errors = array();
  3882. if (@is_dir($removePath) && substr($removePath,-1)=='/' && (
  3883. t3lib_div::isFirstPartOfStr($removePath,PATH_site.$this->typePaths['G']) ||
  3884. t3lib_div::isFirstPartOfStr($removePath,PATH_site.$this->typePaths['L']) ||
  3885. (t3lib_div::isFirstPartOfStr($removePath,PATH_site.$this->typePaths['S']) && $this->systemInstall) ||
  3886. t3lib_div::isFirstPartOfStr($removePath, PATH_site . $GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'] . '_temp_/')) // Playing-around directory...
  3887. ) {
  3888. // All files in extension directory:
  3889. $fileArr = t3lib_div::getAllFilesAndFoldersInPath(array(),$removePath,'',1);
  3890. if (is_array($fileArr)) {
  3891. // Remove files in dirs:
  3892. foreach($fileArr as $removeFile) {
  3893. if (!@is_dir($removeFile)) {
  3894. 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!
  3895. @unlink($removeFile);
  3896. clearstatcache();
  3897. if (@is_file($removeFile)) {
  3898. $errors[] = sprintf($GLOBALS['LANG']->getLL('rmExtDir_could_not_be_deleted'),
  3899. $removeFile
  3900. );
  3901. }
  3902. } else $errors[] = sprintf($GLOBALS['LANG']->getLL('rmExtDir_error_file'),
  3903. $removeFile, $removePath
  3904. );
  3905. }
  3906. }
  3907. // Remove directories:
  3908. $remDirs = $this->extractDirsFromFileList(t3lib_div::removePrefixPathFromList($fileArr,$removePath));
  3909. $remDirs = array_reverse($remDirs); // Must delete outer directories first...
  3910. foreach($remDirs as $removeRelDir) {
  3911. $removeDir = $removePath.$removeRelDir;
  3912. if (@is_dir($removeDir)) {
  3913. @rmdir($removeDir);
  3914. clearstatcache();
  3915. if (@is_dir($removeDir)) {
  3916. $errors[] = sprintf($GLOBALS['LANG']->getLL('rmExtDir_error_files_left'),
  3917. $removeDir
  3918. );
  3919. }
  3920. } else $errors[] = sprintf($GLOBALS['LANG']->getLL('rmExtDir_error_no_dir'),
  3921. $removeDir
  3922. );
  3923. }
  3924. // If extension dir should also be removed:
  3925. if (!$removeContentOnly) {
  3926. @rmdir($removePath);
  3927. clearstatcache();
  3928. if (@is_dir($removePath)) {
  3929. $errors[] = sprintf($GLOBALS['LANG']->getLL('rmExtDir_error_folders_left'),
  3930. $removePath
  3931. );
  3932. }
  3933. }
  3934. } else $errors[] = $GLOBALS['LANG']->getLL('rmExtDir_error') . ' ' . $fileArr;
  3935. } else $errors[] = $GLOBALS['LANG']->getLL('rmExtDir_error_unallowed_path') . ' ' . $removePath;
  3936. // Return errors if any:
  3937. return implode(LF,$errors);
  3938. }
  3939. /**
  3940. * Removes the current extension of $type and creates the base folder for the new one (which is going to be imported)
  3941. *
  3942. * @param array Data for imported extension
  3943. * @param string Extension installation scope (L,G,S)
  3944. * @param boolean If set, nothing will be deleted (neither directory nor files)
  3945. * @return mixed Returns array on success (with extension directory), otherwise an error string.
  3946. */
  3947. function clearAndMakeExtensionDir($importedData,$type,$dontDelete=0) {
  3948. if (!$importedData['extKey']) return $GLOBALS['LANG']->getLL('clearMakeExtDir_no_ext_key');
  3949. // Setting install path (L, G, S or fileadmin/_temp_/)
  3950. $path = '';
  3951. switch((string)$type) {
  3952. case 'G':
  3953. case 'L':
  3954. $path = PATH_site.$this->typePaths[$type];
  3955. $suffix = '';
  3956. // Creates the typo3conf/ext/ directory if it does NOT already exist:
  3957. if ((string)$type=='L' && !@is_dir($path)) {
  3958. t3lib_div::mkdir($path);
  3959. }
  3960. break;
  3961. default:
  3962. if ($this->systemInstall && (string)$type=='S') {
  3963. $path = PATH_site.$this->typePaths[$type];
  3964. $suffix = '';
  3965. } else {
  3966. $path = PATH_site . $GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'] . '_temp_/';
  3967. $suffix = '_'.date('dmy-His');
  3968. }
  3969. break;
  3970. }
  3971. // If the install path is OK...
  3972. if ($path && @is_dir($path)) {
  3973. // Set extension directory:
  3974. $extDirPath = $path.$importedData['extKey'].$suffix.'/';
  3975. // Install dir was found, remove it then:
  3976. if (@is_dir($extDirPath)) {
  3977. if($dontDelete) return array($extDirPath);
  3978. $res = $this->removeExtDirectory($extDirPath);
  3979. if ($res) {
  3980. $flashMessage = t3lib_div::makeInstance(
  3981. 't3lib_FlashMessage',
  3982. nl2br($res),
  3983. sprintf($GLOBALS['LANG']->getLL('clearMakeExtDir_could_not_remove_dir'), $extDirPath),
  3984. t3lib_FlashMessage::ERROR
  3985. );
  3986. return $flashMessage->render();
  3987. }
  3988. }
  3989. // We go create...
  3990. t3lib_div::mkdir($extDirPath);
  3991. if (!is_dir($extDirPath)) {
  3992. return sprintf($GLOBALS['LANG']->getLL('clearMakeExtDir_could_not_create_dir'),
  3993. $extDirPath);
  3994. }
  3995. return array($extDirPath);
  3996. } else return sprintf($GLOBALS['LANG']->getLL('clearMakeExtDir_no_dir'),
  3997. $path);
  3998. }
  3999. /**
  4000. * Unlink (delete) cache files
  4001. *
  4002. * @return integer Number of deleted files.
  4003. */
  4004. function removeCacheFiles() {
  4005. return t3lib_extMgm::removeCacheFiles();
  4006. }
  4007. /**
  4008. * Extracts the directories in the $files array
  4009. *
  4010. * @param array Array of files / directories
  4011. * @return array Array of directories from the input array.
  4012. */
  4013. function extractDirsFromFileList($files) {
  4014. $dirs = array();
  4015. if (is_array($files)) {
  4016. // Traverse files / directories array:
  4017. foreach($files as $file) {
  4018. if (substr($file,-1)=='/') {
  4019. $dirs[$file] = $file;
  4020. } else {
  4021. $pI = pathinfo($file);
  4022. if (strcmp($pI['dirname'],'') && strcmp($pI['dirname'],'.')) {
  4023. $dirs[$pI['dirname'].'/'] = $pI['dirname'].'/';
  4024. }
  4025. }
  4026. }
  4027. }
  4028. return $dirs;
  4029. }
  4030. /**
  4031. * Returns the absolute path where the extension $extKey is installed (based on 'type' (SGL))
  4032. *
  4033. * @param string Extension key
  4034. * @param string Install scope type: L, G, S
  4035. * @return string Returns the absolute path to the install scope given by input $type variable. It is checked if the path is a directory. Slash is appended.
  4036. */
  4037. function getExtPath($extKey,$type) {
  4038. $typeP = $this->typePaths[$type];
  4039. if ($typeP) {
  4040. $path = PATH_site.$typeP.$extKey.'/';
  4041. return @is_dir($path) ? $path : '';
  4042. } else {
  4043. return '';
  4044. }
  4045. }
  4046. /*******************************
  4047. *
  4048. * Writing to "conf.php" and "localconf.php" files
  4049. *
  4050. ******************************/
  4051. /**
  4052. * Write new TYPO3_MOD_PATH to "conf.php" file.
  4053. *
  4054. * @param string Absolute path to a "conf.php" file of the backend module which we want to write back to.
  4055. * @param string Install scope type: L, G, S
  4056. * @param string Relative path for the module folder in extenson
  4057. * @return string Returns message about the status.
  4058. * @see modConfFileAnalysis()
  4059. */
  4060. function writeTYPO3_MOD_PATH($confFilePath,$type,$mP) {
  4061. $lines = explode(LF,t3lib_div::getUrl($confFilePath));
  4062. $confFileInfo = array();
  4063. $confFileInfo['lines'] = $lines;
  4064. $reg = array();
  4065. $flag_M = 0;
  4066. $flag_B = 0;
  4067. $flag_Dispatch = 0;
  4068. foreach($lines as $k => $l) {
  4069. $line = trim($l);
  4070. unset($reg);
  4071. if (preg_match('/^define[[:space:]]*\([[:space:]]*["\']TYPO3_MOD_PATH["\'][[:space:]]*,[[:space:]]*["\']([[:alnum:]_\/\.]+)["\'][[:space:]]*\)[[:space:]]*;/',$line,$reg)) {
  4072. $lines[$k] = str_replace($reg[0], 'define(\'TYPO3_MOD_PATH\', \''.$this->typeRelPaths[$type].$mP.'\');', $lines[$k]);
  4073. $flag_M = $k+1;
  4074. }
  4075. unset($reg);
  4076. if (preg_match('/^\$BACK_PATH[[:space:]]*=[[:space:]]*["\']([[:alnum:]_\/\.]+)["\'][[:space:]]*;/', $line, $reg)) {
  4077. $lines[$k] = str_replace($reg[0], '$BACK_PATH=\'' . $this->typeBackPaths[$type] . '\';', $lines[$k]);
  4078. $flag_B = $k + 1;
  4079. }
  4080. // Check if this module uses new API (see http://bugs.typo3.org/view.php?id=5278)
  4081. // where TYPO3_MOD_PATH and BACK_PATH are not required
  4082. unset($reg);
  4083. if (preg_match('/^\$MCONF\[["\']script["\']\][[:space:]]*=[[:space:]]*["\']_DISPATCH["\'][[:space:]]*;/', $line, $reg)) {
  4084. $flag_Dispatch = $k+1;
  4085. }
  4086. }
  4087. if ($flag_B && $flag_M) {
  4088. t3lib_div::writeFile($confFilePath,implode(LF,$lines));
  4089. return sprintf($GLOBALS['LANG']->getLL('writeModPath_ok'),
  4090. substr($confFilePath, strlen(PATH_site)));
  4091. } elseif ($flag_Dispatch){
  4092. return sprintf(
  4093. $GLOBALS['LANG']->getLL('writeModPath_notRequired'),
  4094. substr($confFilePath, strlen(PATH_site))
  4095. );
  4096. } else return $GLOBALS["TBE_TEMPLATE"]->rfw(
  4097. sprintf($GLOBALS['LANG']->getLL('writeModPath_error'),
  4098. $confFilePath)
  4099. );
  4100. }
  4101. /**
  4102. * Writes the extension list to "localconf.php" file
  4103. * Removes the temp_CACHED* files before return.
  4104. *
  4105. * @param string List of extensions
  4106. * @return void
  4107. */
  4108. function writeNewExtensionList($newExtList) {
  4109. global $TYPO3_CONF_VARS;
  4110. $strippedExtensionList = $this->stripNonFrontendExtensions($newExtList);
  4111. // Instance of install tool
  4112. $instObj = new t3lib_install;
  4113. $instObj->allowUpdateLocalConf =1;
  4114. $instObj->updateIdentity = 'TYPO3 Extension Manager';
  4115. // Get lines from localconf file
  4116. $lines = $instObj->writeToLocalconf_control();
  4117. $instObj->setValueInLocalconfFile($lines, '$TYPO3_CONF_VARS[\'EXT\'][\'extList\']', $newExtList);
  4118. $instObj->setValueInLocalconfFile($lines, '$TYPO3_CONF_VARS[\'EXT\'][\'extList_FE\']', $strippedExtensionList);
  4119. $instObj->writeToLocalconf_control($lines);
  4120. $TYPO3_CONF_VARS['EXT']['extList'] = $newExtList;
  4121. $TYPO3_CONF_VARS['EXT']['extList_FE'] = $strippedExtensionList;
  4122. $this->removeCacheFiles();
  4123. }
  4124. /**
  4125. * Removes unneeded extensions from the frontend based on
  4126. * EMCONF doNotLoadInFE = 1
  4127. *
  4128. * @param string $extList
  4129. * @return string
  4130. */
  4131. function stripNonFrontendExtensions($extList) {
  4132. $fullExtList = $this->getInstalledExtensions();
  4133. $extListArray = t3lib_div::trimExplode(',', $extList);
  4134. foreach ($extListArray as $arrayKey => $extKey) {
  4135. if ($fullExtList[0][$extKey]['EM_CONF']['doNotLoadInFE'] == 1) {
  4136. unset($extListArray[$arrayKey]);
  4137. }
  4138. }
  4139. $nonFEList = implode(',', $extListArray);
  4140. return $nonFEList;
  4141. }
  4142. /**
  4143. * Writes the TSstyleconf values to "localconf.php"
  4144. * Removes the temp_CACHED* files before return.
  4145. *
  4146. * @param string Extension key
  4147. * @param array Configuration array to write back
  4148. * @return void
  4149. */
  4150. function writeTsStyleConfig($extKey,$arr) {
  4151. // Instance of install tool
  4152. $instObj = new t3lib_install;
  4153. $instObj->allowUpdateLocalConf =1;
  4154. $instObj->updateIdentity = 'TYPO3 Extension Manager';
  4155. // Get lines from localconf file
  4156. $lines = $instObj->writeToLocalconf_control();
  4157. $instObj->setValueInLocalconfFile($lines, '$TYPO3_CONF_VARS[\'EXT\'][\'extConf\'][\''.$extKey.'\']', serialize($arr)); // This will be saved only if there are no linebreaks in it !
  4158. $instObj->writeToLocalconf_control($lines);
  4159. $this->removeCacheFiles();
  4160. }
  4161. /**
  4162. * Forces update of local EM_CONF. This will renew the information of changed files.
  4163. *
  4164. * @param string Extension key
  4165. * @param array Extension information array
  4166. * @return string Status message
  4167. */
  4168. function updateLocalEM_CONF($extKey,$extInfo) {
  4169. $extInfo['EM_CONF']['_md5_values_when_last_written'] = serialize($this->serverExtensionMD5Array($extKey,$extInfo));
  4170. $emConfFileContent = $this->construct_ext_emconf_file($extKey,$extInfo['EM_CONF']);
  4171. $absPath = $this->getExtPath($extKey,$extInfo['type']);
  4172. $emConfFileName = $absPath.'ext_emconf.php';
  4173. if($emConfFileContent) {
  4174. if(@is_file($emConfFileName)) {
  4175. if(t3lib_div::writeFile($emConfFileName,$emConfFileContent) === true) {
  4176. return sprintf($GLOBALS['LANG']->getLL('updateLocalEM_CONF_ok'),
  4177. substr($emConfFileName, strlen($absPath)));
  4178. } else {
  4179. return '<strong>' . sprintf($GLOBALS['LANG']->getLL('updateLocalEM_CONF_not_writable'),
  4180. $emConfFileName) . '</strong>';
  4181. }
  4182. } else return('<strong>' . sprintf($GLOBALS['LANG']->getLL('updateLocalEM_CONF_not_found'),
  4183. $emConfFileName) . '</strong>');
  4184. } else {
  4185. return sprintf($GLOBALS['LANG']->getLL('updateLocalEM_CONF_no_content'),
  4186. substr($emConfFileName, strlen($absPath)));
  4187. }
  4188. }
  4189. /*******************************************
  4190. *
  4191. * Compiling upload information, emconf-file etc.
  4192. *
  4193. *******************************************/
  4194. /**
  4195. * Compiles the ext_emconf.php file
  4196. *
  4197. * @param string Extension key
  4198. * @param array EM_CONF array
  4199. * @return string PHP file content, ready to write to ext_emconf.php file
  4200. */
  4201. function construct_ext_emconf_file($extKey,$EM_CONF) {
  4202. // clean version number:
  4203. $vDat = $this->renderVersion($EM_CONF['version']);
  4204. $EM_CONF['version']=$vDat['version'];
  4205. $code = '<?php
  4206. ########################################################################
  4207. # Extension Manager/Repository config file for ext "'.$extKey.'".
  4208. #
  4209. # Auto generated '.date('d-m-Y H:i').'
  4210. #
  4211. # Manual updates:
  4212. # Only the data in the array - everything else is removed by next
  4213. # writing. "version" and "dependencies" must not be touched!
  4214. ########################################################################
  4215. $EM_CONF[$_EXTKEY] = '.$this->arrayToCode($EM_CONF, 0).';
  4216. ?>';
  4217. return str_replace(CR, '', $code);
  4218. }
  4219. /**
  4220. * Enter description here...
  4221. *
  4222. * @param unknown_type $array
  4223. * @param unknown_type $lines
  4224. * @param unknown_type $level
  4225. * @return unknown
  4226. */
  4227. function arrayToCode($array, $level=0) {
  4228. $lines = 'array('.LF;
  4229. $level++;
  4230. foreach($array as $k => $v) {
  4231. if(strlen($k) && is_array($v)) {
  4232. $lines .= str_repeat(TAB,$level)."'".$k."' => ".$this->arrayToCode($v, $level);
  4233. } elseif(strlen($k)) {
  4234. $lines .= str_repeat(TAB,$level)."'".$k."' => ".(t3lib_div::testInt($v) ? intval($v) : "'".t3lib_div::slashJS(trim($v),1)."'").','.LF;
  4235. }
  4236. }
  4237. $lines .= str_repeat(TAB,$level-1).')'.($level-1==0 ? '':','.LF);
  4238. return $lines;
  4239. }
  4240. /**
  4241. * Make upload array out of extension
  4242. *
  4243. * @param string Extension key
  4244. * @param array Extension information array
  4245. * @return mixed Returns array with extension upload array on success, otherwise an error string.
  4246. */
  4247. function makeUploadArray($extKey,$conf) {
  4248. $extPath = $this->getExtPath($extKey,$conf['type']);
  4249. if ($extPath) {
  4250. // Get files for extension:
  4251. $fileArr = array();
  4252. $fileArr = t3lib_div::getAllFilesAndFoldersInPath($fileArr,$extPath,'',0,99,$this->excludeForPackaging);
  4253. // Calculate the total size of those files:
  4254. $totalSize = 0;
  4255. foreach($fileArr as $file) {
  4256. $totalSize+=filesize($file);
  4257. }
  4258. // If the total size is less than the upper limit, proceed:
  4259. if ($totalSize < $this->maxUploadSize) {
  4260. // Initialize output array:
  4261. $uploadArray = array();
  4262. $uploadArray['extKey'] = $extKey;
  4263. $uploadArray['EM_CONF'] = $conf['EM_CONF'];
  4264. $uploadArray['misc']['codelines'] = 0;
  4265. $uploadArray['misc']['codebytes'] = 0;
  4266. $uploadArray['techInfo'] = $this->makeDetailedExtensionAnalysis($extKey,$conf,1);
  4267. // Read all files:
  4268. foreach($fileArr as $file) {
  4269. $relFileName = substr($file,strlen($extPath));
  4270. $fI = pathinfo($relFileName);
  4271. if ($relFileName!='ext_emconf.php') { // This file should be dynamically written...
  4272. $uploadArray['FILES'][$relFileName] = array(
  4273. 'name' => $relFileName,
  4274. 'size' => filesize($file),
  4275. 'mtime' => filemtime($file),
  4276. 'is_executable' => (TYPO3_OS=='WIN' ? 0 : is_executable($file)),
  4277. 'content' => t3lib_div::getUrl($file)
  4278. );
  4279. if (t3lib_div::inList('php,inc',strtolower($fI['extension']))) {
  4280. $uploadArray['FILES'][$relFileName]['codelines']=count(explode(LF,$uploadArray['FILES'][$relFileName]['content']));
  4281. $uploadArray['misc']['codelines']+=$uploadArray['FILES'][$relFileName]['codelines'];
  4282. $uploadArray['misc']['codebytes']+=$uploadArray['FILES'][$relFileName]['size'];
  4283. // locallang*.php files:
  4284. if (substr($fI['basename'],0,9)=='locallang' && strstr($uploadArray['FILES'][$relFileName]['content'],'$LOCAL_LANG')) {
  4285. $uploadArray['FILES'][$relFileName]['LOCAL_LANG']=$this->getSerializedLocalLang($file,$uploadArray['FILES'][$relFileName]['content']);
  4286. }
  4287. }
  4288. $uploadArray['FILES'][$relFileName]['content_md5'] = md5($uploadArray['FILES'][$relFileName]['content']);
  4289. }
  4290. }
  4291. // Return upload-array:
  4292. return $uploadArray;
  4293. } else return sprintf($GLOBALS['LANG']->getLL('makeUploadArray_error_size'),
  4294. $totalSize, t3lib_div::formatSize($this->maxUploadSize));
  4295. } else {
  4296. return sprintf($GLOBALS['LANG']->getLL('makeUploadArray_error_path'),
  4297. $extKey);
  4298. }
  4299. }
  4300. /**
  4301. * Include a locallang file and return the $LOCAL_LANG array serialized.
  4302. *
  4303. * @param string Absolute path to locallang file to include.
  4304. * @param string Old content of a locallang file (keeping the header content)
  4305. * @return array Array with header/content as key 0/1
  4306. * @see makeUploadArray()
  4307. */
  4308. function getSerializedLocalLang($file, $content) {
  4309. $LOCAL_LANG = NULL;
  4310. $returnParts = explode('$LOCAL_LANG', $content, 2);
  4311. include($file);
  4312. if (is_array($LOCAL_LANG)) {
  4313. $returnParts[1] = serialize($LOCAL_LANG);
  4314. return $returnParts;
  4315. } else {
  4316. return array();
  4317. }
  4318. }
  4319. /********************************
  4320. *
  4321. * Managing dependencies, conflicts, priorities, load order of extension keys
  4322. *
  4323. *******************************/
  4324. /**
  4325. * Adds extension to extension list and returns new list. If -1 is returned, an error happend.
  4326. * Checks dependencies etc.
  4327. *
  4328. * @param string Extension key
  4329. * @param array Extension information array - information about installed extensions
  4330. * @return string New list of installed extensions or -1 if error
  4331. * @see showExtDetails()
  4332. */
  4333. function addExtToList($extKey,$instExtInfo) {
  4334. global $TYPO3_LOADED_EXT;
  4335. // ext_emconf.php information:
  4336. $conf = $instExtInfo[$extKey]['EM_CONF'];
  4337. // Get list of installed extensions and add this one.
  4338. $listArr = array_keys($TYPO3_LOADED_EXT);
  4339. if ($conf['priority']=='top') {
  4340. array_unshift($listArr,$extKey);
  4341. } else {
  4342. $listArr[]=$extKey;
  4343. }
  4344. // Manage other circumstances:
  4345. $listArr = $this->managesPriorities($listArr,$instExtInfo);
  4346. $listArr = $this->removeRequiredExtFromListArr($listArr);
  4347. // Implode unique list of extensions to load and return:
  4348. $list = implode(',',array_unique($listArr));
  4349. return $list;
  4350. }
  4351. /**
  4352. * Enter description here...
  4353. *
  4354. * @param string $extKey
  4355. * @param array $conf
  4356. * @param array $instExtInfo
  4357. * @return array
  4358. */
  4359. function checkDependencies($extKey, $conf, $instExtInfo) {
  4360. $content = '';
  4361. $depError = false;
  4362. $depIgnore = false;
  4363. $msg = array();
  4364. $depsolver = t3lib_div::_POST('depsolver');
  4365. if (isset($conf['constraints']['depends']) && is_array($conf['constraints']['depends'])) {
  4366. foreach($conf['constraints']['depends'] as $depK => $depV) {
  4367. if($depsolver['ignore'][$depK]) {
  4368. $msg[] = '<br />' . sprintf($GLOBALS['LANG']->getLL('checkDependencies_ignored'),
  4369. $depK) . '
  4370. <input type="hidden" value="1" name="depsolver[ignore]['.$depK.']" />';
  4371. $depIgnore = true;
  4372. continue;
  4373. }
  4374. if($depK == 'php') {
  4375. if(!$depV) continue;
  4376. $versionRange = $this->splitVersionRange($depV);
  4377. $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!
  4378. if ($versionRange[0]!='0.0.0' && version_compare($phpv,$versionRange[0],'<')) {
  4379. $msg[] = '<br />' . sprintf($GLOBALS['LANG']->getLL('checkDependencies_php_too_low'),
  4380. $phpv, $versionRange[0]);
  4381. $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" value="1" name="depsolver[ignore][' . $depK . ']" id="checkIgnore_' . $depK . '" />
  4382. <label for="checkIgnore_' . $depK . '">' . $GLOBALS['LANG']->getLL('checkDependencies_ignore_requirement') . '</label>';
  4383. $depError = true;
  4384. continue;
  4385. } elseif ($versionRange[1]!='0.0.0' && version_compare($phpv,$versionRange[1],'>')) {
  4386. $msg[] = '<br />' . sprintf($GLOBALS['LANG']->getLL('checkDependencies_php_too_high'),
  4387. $phpv, $versionRange[1]);
  4388. $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" value="1" name="depsolver[ignore][' . $depK . ']" id="checkIgnore_' . $depK . '" />
  4389. <label for="checkIgnore_' . $depK . '">' . $GLOBALS['LANG']->getLL('checkDependencies_ignore_requirement') . '</label>';
  4390. $depError = true;
  4391. continue;
  4392. }
  4393. } elseif ($depK == 'typo3') {
  4394. if (!$depV) continue;
  4395. // if the current TYPO3 version is a development version (like TYPO3 4.4-dev),
  4396. // then it should behave like TYPO3 4.4.0
  4397. $t3version = TYPO3_version;
  4398. if (stripos($t3version, '-dev')
  4399. || stripos($t3version, '-alpha')
  4400. || stripos($t3version, '-beta')
  4401. || stripos($t3version, '-RC')) {
  4402. // find the last occurence of "-" and replace that part with a ".0"
  4403. $t3version = substr($t3version, 0, strrpos($t3version, '-')) . '.0';
  4404. }
  4405. $versionRange = $this->splitVersionRange($depV);
  4406. if ($versionRange[0]!='0.0.0' && version_compare($t3version, $versionRange[0], '<')) {
  4407. $msg[] = '<br />' . sprintf($GLOBALS['LANG']->getLL('checkDependencies_typo3_too_low'),
  4408. $t3version, $versionRange[0]);
  4409. $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" value="1" name="depsolver[ignore][' . $depK . ']" id="checkIgnore_' . $depK . '" />
  4410. <label for="checkIgnore_' . $depK . '">' . $GLOBALS['LANG']->getLL('checkDependencies_ignore_requirement') . '</label>';
  4411. $depError = true;
  4412. continue;
  4413. } elseif ($versionRange[1]!='0.0.0' && version_compare($t3version, $versionRange[1], '>')) {
  4414. $msg[] = '<br />' . sprintf($GLOBALS['LANG']->getLL('checkDependencies_typo3_too_high'),
  4415. $t3version, $versionRange[1]);
  4416. $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" value="1" name="depsolver[ignore][' . $depK . ']" id="checkIgnore_' . $depK . '" />
  4417. <label for="checkIgnore_' . $depK . '">' . $GLOBALS['LANG']->getLL('checkDependencies_ignore_requirement') . '</label>';
  4418. $depError = true;
  4419. continue;
  4420. }
  4421. } elseif (strlen($depK) && !t3lib_extMgm::isLoaded($depK)) { // strlen check for braindead empty dependencies coming from extensions...
  4422. if(!isset($instExtInfo[$depK])) {
  4423. $msg[] = '<br />' . sprintf($GLOBALS['LANG']->getLL('checkDependencies_ext_not_available'),
  4424. $depK);
  4425. $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;' . t3lib_iconWorks::getSpriteIcon('actions-system-extension-import', array('title' => $GLOBALS['LANG']->getLL('checkDependencies_import_ext'))) . '&nbsp;
  4426. <a href="index.php?CMD[importExt]=' . $depK . '&CMD[loc]=L&CMD[standAlone]=1" target="_blank">' . $GLOBALS['LANG']->getLL('checkDependencies_import_now') . '</a>';
  4427. $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" value="1" name="depsolver[ignore][' . $depK . ']" id="checkIgnore_' . $depK . '" />
  4428. <label for="checkIgnore_' . $depK . '">' . $GLOBALS['LANG']->getLL('checkDependencies_ignore_ext_requirement') . '</label>';
  4429. } else {
  4430. $msg[] = '<br />' . sprintf($GLOBALS['LANG']->getLL('checkDependencies_ext_not_installed'),
  4431. $depK, $instExtInfo[$depK]['EM_CONF']['title']);
  4432. $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;' . $this->installButton() . '&nbsp;
  4433. <a href="' . htmlspecialchars('index.php?CMD[showExt]=' . $depK . '&CMD[load]=1&CMD[clrCmd]=1&CMD[standAlone]=1&SET[singleDetails]=info') .
  4434. '" target="_blank">' . $GLOBALS['LANG']->getLL('checkDependencies_install_now') . '</a>';
  4435. $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" value="1" name="depsolver[ignore][' . $depK . ']" id="checkIgnore_' . $depK . '" />
  4436. <label for="checkIgnore_' . $depK . '">' . $GLOBALS['LANG']->getLL('checkDependencies_ignore_ext_requirement') . '</label>';
  4437. }
  4438. $depError = true;
  4439. } else {
  4440. $versionRange = $this->splitVersionRange($depV);
  4441. if ($versionRange[0]!='0.0.0' && version_compare($instExtInfo[$depK]['EM_CONF']['version'],$versionRange[0],'<')) {
  4442. $msg[] = '<br />' . sprintf($GLOBALS['LANG']->getLL('checkDependencies_ext_too_low'),
  4443. $depK, $instExtInfo[$depK]['EM_CONF']['version'], $versionRange[0]);
  4444. $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" value="1" name="depsolver[ignore][' . $depK . ']" id="checkIgnore_' . $depK . '" />
  4445. <label for="checkIgnore_' . $depK . '">' . $GLOBALS['LANG']->getLL('checkDependencies_ignore_requirement') . '</label>';
  4446. $depError = true;
  4447. continue;
  4448. } elseif ($versionRange[1]!='0.0.0' && version_compare($instExtInfo[$depK]['EM_CONF']['version'],$versionRange[1],'>')) {
  4449. $msg[] = '<br />' . sprintf($GLOBALS['LANG']->getLL('checkDependencies_ext_too_high'),
  4450. $depK, $instExtInfo[$depK]['EM_CONF']['version'], $versionRange[1]);
  4451. $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" value="1" name="depsolver[ignore][' . $depK . ']" id="checkIgnore_' . $depK . '" />
  4452. <label for="checkIgnore_' . $depK . '">' . $GLOBALS['LANG']->getLL('checkDependencies_ignore_requirement') . '</label>';
  4453. $depError = true;
  4454. continue;
  4455. }
  4456. }
  4457. }
  4458. }
  4459. if($depError || $depIgnore) {
  4460. $content .= $this->doc->section(
  4461. $GLOBALS['LANG']->getLL('removeExtFromList_dependency_error'),
  4462. implode('<br />', $msg), 0, 1, 2
  4463. );
  4464. }
  4465. // Check conflicts with other extensions:
  4466. $conflictError = false;
  4467. $conflictIgnore = false;
  4468. $msg = array();
  4469. if (isset($conf['constraints']['conflicts']) && is_array($conf['constraints']['conflicts'])) {
  4470. foreach((array)$conf['constraints']['conflicts'] as $conflictK => $conflictV) {
  4471. if($depsolver['ignore'][$conflictK]) {
  4472. $msg[] = '<br />' . sprintf($GLOBALS['LANG']->getLL('checkDependencies_conflict_ignored'),
  4473. $conflictK) . '
  4474. <input type="hidden" value="1" name="depsolver[ignore]['.$conflictK.']" />';
  4475. $conflictIgnore = true;
  4476. continue;
  4477. }
  4478. if (t3lib_extMgm::isLoaded($conflictK)) {
  4479. $versionRange = $this->splitVersionRange($conflictV);
  4480. if ($versionRange[0] != '0.0.0' && version_compare($instExtInfo[$conflictK]['EM_CONF']['version'],$versionRange[0],'<')) {
  4481. continue;
  4482. }
  4483. elseif ($versionRange[1] != '0.0.0' && version_compare($instExtInfo[$conflictK]['EM_CONF']['version'],$versionRange[1],'>')) {
  4484. continue;
  4485. }
  4486. $msg[] = sprintf($GLOBALS['LANG']->getLL('checkDependencies_conflict_remove'),
  4487. $extKey, $conflictK, $instExtInfo[$conflictK]['EM_CONF']['title'], $conflictK, $extKey);
  4488. $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;' . $this->removeButton() . '&nbsp;
  4489. <a href="' . htmlspecialchars('index.php?CMD[showExt]=' . $conflictK . '&CMD[remove]=1&CMD[clrCmd]=1&CMD[standAlone]=1&SET[singleDetails]=info') .
  4490. '" target="_blank">' . $GLOBALS['LANG']->getLL('checkDependencies_remove_now') . '</a>';
  4491. $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" value="1" name="depsolver[ignore][' . $conflictK . ']" id="checkIgnore_' . $conflictK . '" />
  4492. <label for="checkIgnore_' . $conflictK . '">' . $GLOBALS['LANG']->getLL('checkDependencies_ignore_conflict') . '</label>';
  4493. $conflictError = true;
  4494. }
  4495. }
  4496. }
  4497. if($conflictError || $conflictIgnore) {
  4498. $content .= $this->doc->section(
  4499. $GLOBALS['LANG']->getLL('checkDependencies_conflict_error'), implode('<br />', $msg), 0, 1, 2
  4500. );
  4501. }
  4502. // Check suggests on other extensions:
  4503. if(isset($conf['constraints']['suggests']) && is_array($conf['constraints']['suggests'])) {
  4504. $suggestion = false;
  4505. $suggestionIgnore = false;
  4506. $msg = array();
  4507. foreach($conf['constraints']['suggests'] as $suggestK => $suggestV) {
  4508. if($depsolver['ignore'][$suggestK]) {
  4509. $msg[] = '<br />' . sprintf($GLOBALS['LANG']->getLL('checkDependencies_suggestion_ignored'),
  4510. $suggestK) . '
  4511. <input type="hidden" value="1" name="depsolver[ignore]['.$suggestK.']" />';
  4512. $suggestionIgnore = true;
  4513. continue;
  4514. }
  4515. if (!t3lib_extMgm::isLoaded($suggestK)) {
  4516. if (!isset($instExtInfo[$suggestK])) {
  4517. $msg[] = sprintf($GLOBALS['LANG']->getLL('checkDependencies_suggest_import'),
  4518. $suggestK);
  4519. $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;' . t3lib_iconWorks::getSpriteIcon('actions-system-extension-import', array('title' => $GLOBALS['LANG']->getLL('checkDependencies_import_ext'))) . '&nbsp;
  4520. <a href="index.php?CMD[importExt]=' . $suggestK . '&CMD[loc]=L&CMD[standAlone]=1" target="_blank">' . $GLOBALS['LANG']->getLL('checkDependencies_import_now') . '</a>';
  4521. $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" value="1" name="depsolver[ignore][' . $suggestK . ']" id="checkIgnore_' . $suggestK . '" />
  4522. <label for="checkIgnore_' . $suggestK . '">' . $GLOBALS['LANG']->getLL('checkDependencies_ignore_suggestion') . '</label>';
  4523. } else {
  4524. $msg[] = sprintf($GLOBALS['LANG']->getLL('checkDependencies_suggest_installation'),
  4525. $suggestK, $instExtInfo[$suggestK]['EM_CONF']['title']);
  4526. $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;' . $this->installButton() . '&nbsp;
  4527. <a href="' . htmlspecialchars('index.php?CMD[showExt]=' . $suggestK . '&CMD[load]=1&CMD[clrCmd]=1&CMD[standAlone]=1&SET[singleDetails]=info') .
  4528. '" target="_blank">' . $GLOBALS['LANG']->getLL('checkDependencies_install_now') . '</a>';
  4529. $msg[] = '&nbsp;&nbsp;&nbsp;&nbsp;<input type="checkbox" value="1" name="depsolver[ignore][' . $suggestK . ']" id="checkIgnore_' . $suggestK . '" />
  4530. <label for="checkIgnore_' . $suggestK . '">' . $GLOBALS['LANG']->getLL('checkDependencies_ignore_suggestion') . '</label>';
  4531. }
  4532. $suggestion = true;
  4533. }
  4534. }
  4535. if($suggestion || $suggestionIgnore) {
  4536. $content .= $this->doc->section(
  4537. sprintf($GLOBALS['LANG']->getLL('checkDependencies_exts_suggested_by_ext'), $extKey),
  4538. implode('<br />', $msg), 0, 1, 1
  4539. );
  4540. }
  4541. }
  4542. if($depError || $conflictError || $suggestion) {
  4543. foreach($this->CMD as $k => $v) {
  4544. $content .= '<input type="hidden" name="CMD['.$k.']" value="'.$v.'" />';
  4545. }
  4546. $content .= '<br /><br /><input type="submit" value="' . $GLOBALS['LANG']->getLL('checkDependencies_try_again') . '" />';
  4547. return array('returnCode' => false, 'html' => '<form action="index.php" method="post" name="depform">'.$content.'</form>');
  4548. }
  4549. return array('returnCode' => true);
  4550. }
  4551. /**
  4552. * Remove extension key from the list of currently installed extensions and return list. If -1 is returned, an error happend.
  4553. * Checks dependencies etc.
  4554. *
  4555. * @param string Extension key
  4556. * @param array Extension information array - information about installed extensions
  4557. * @return string New list of installed extensions or -1 if error
  4558. * @see showExtDetails()
  4559. */
  4560. function removeExtFromList($extKey,$instExtInfo) {
  4561. global $TYPO3_LOADED_EXT;
  4562. // Initialize:
  4563. $depList = array();
  4564. $listArr = array_keys($TYPO3_LOADED_EXT);
  4565. // Traverse all installed extensions to check if any of them have this extension as dependency since if that is the case it will not work out!
  4566. foreach($listArr as $k => $ext) {
  4567. if ($instExtInfo[$ext]['EM_CONF']['dependencies']) {
  4568. $dep = t3lib_div::trimExplode(',',$instExtInfo[$ext]['EM_CONF']['dependencies'],1);
  4569. if (in_array($extKey,$dep)) {
  4570. $depList[] = $ext;
  4571. }
  4572. }
  4573. if (!strcmp($ext,$extKey)) unset($listArr[$k]);
  4574. }
  4575. // Returns either error or the new list
  4576. if (count($depList)) {
  4577. $msg = sprintf($GLOBALS['LANG']->getLL('removeExtFromList_dependency'),
  4578. implode(', ', $depList)
  4579. );
  4580. $this->content .= $this->doc->section($GLOBALS['LANG']->getLL('removeExtFromList_dependency_error'), $msg, 0, 1, 2);
  4581. return -1;
  4582. } else {
  4583. $listArr = $this->removeRequiredExtFromListArr($listArr);
  4584. $list = implode(',',array_unique($listArr));
  4585. return $list;
  4586. }
  4587. }
  4588. /**
  4589. * This removes any required extensions from the $listArr - they should NOT be added to the common extension list, because they are found already in "requiredExt" list
  4590. *
  4591. * @param array Array of extension keys as values
  4592. * @return array Modified array
  4593. * @see removeExtFromList(), addExtToList()
  4594. */
  4595. function removeRequiredExtFromListArr($listArr) {
  4596. foreach($listArr as $k => $ext) {
  4597. if (in_array($ext,$this->requiredExt) || !strcmp($ext,'_CACHEFILE')) unset($listArr[$k]);
  4598. }
  4599. return $listArr;
  4600. }
  4601. /**
  4602. * Traverse the array of installed extensions keys and arranges extensions in the priority order they should be in
  4603. *
  4604. * @param array Array of extension keys as values
  4605. * @param array Extension information array
  4606. * @return array Modified array of extention keys as values
  4607. * @see addExtToList()
  4608. */
  4609. function managesPriorities($listArr,$instExtInfo) {
  4610. // Initialize:
  4611. $levels = array(
  4612. 'top' => array(),
  4613. 'middle' => array(),
  4614. 'bottom' => array(),
  4615. );
  4616. // Traverse list of extensions:
  4617. foreach($listArr as $ext) {
  4618. $prio = trim($instExtInfo[$ext]['EM_CONF']['priority']);
  4619. switch((string)$prio) {
  4620. case 'top':
  4621. case 'bottom':
  4622. $levels[$prio][] = $ext;
  4623. break;
  4624. default:
  4625. $levels['middle'][] = $ext;
  4626. break;
  4627. }
  4628. }
  4629. return array_merge(
  4630. $levels['top'],
  4631. $levels['middle'],
  4632. $levels['bottom']
  4633. );
  4634. }
  4635. /*******************************
  4636. *
  4637. * System Update functions (based on extension requirements)
  4638. *
  4639. ******************************/
  4640. /**
  4641. * Check if clear-cache should be performed, otherwise show form (for installation of extension)
  4642. * Shown only if the extension has the clearCacheOnLoad flag set.
  4643. *
  4644. * @param string Extension key
  4645. * @param array Extension information array
  4646. * @return string HTML output (if form is shown)
  4647. */
  4648. function checkClearCache($extInfo) {
  4649. if ($extInfo['EM_CONF']['clearCacheOnLoad']) {
  4650. if (t3lib_div::_POST('_clear_all_cache')) { // Action: Clearing the cache
  4651. $tce = t3lib_div::makeInstance('t3lib_TCEmain');
  4652. $tce->stripslashes_values = 0;
  4653. $tce->start(Array(),Array());
  4654. $tce->clear_cacheCmd('all');
  4655. } else { // Show checkbox for clearing cache:
  4656. $content.= '
  4657. <br />
  4658. <h3>' . $GLOBALS['LANG']->getLL('checkUploadFolder_clear_cache') . '</h3>
  4659. <p>' . $GLOBALS['LANG']->getLL('checkUploadFolder_clear_cache_requested') . '<br />
  4660. <label for="check_clear_all_cache">' . $GLOBALS['LANG']->getLL('checkUploadFolder_clear_all_cache') . '</label>
  4661. <input type="checkbox" name="_clear_all_cache" id="check_clear_all_cache" checked="checked" value="1" /><br />
  4662. </p>
  4663. ';
  4664. }
  4665. }
  4666. return $content;
  4667. }
  4668. /**
  4669. * Check if upload folder / "createDir" directories should be created.
  4670. *
  4671. * @param string Extension key
  4672. * @param array Extension information array
  4673. * @return string HTML content.
  4674. */
  4675. function checkUploadFolder($extKey,$extInfo) {
  4676. // Checking for upload folder:
  4677. $uploadFolder = PATH_site.$this->ulFolder($extKey);
  4678. if ($extInfo['EM_CONF']['uploadfolder'] && !@is_dir($uploadFolder)) {
  4679. if (t3lib_div::_POST('_uploadfolder')) { // CREATE dir:
  4680. t3lib_div::mkdir($uploadFolder);
  4681. $indexContent = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
  4682. <HTML>
  4683. <HEAD>
  4684. <TITLE></TITLE>
  4685. <META http-equiv=Refresh Content="0; Url=../../">
  4686. </HEAD>
  4687. </HTML>';
  4688. t3lib_div::writeFile($uploadFolder.'index.html',$indexContent);
  4689. } else { // Show checkbox / HTML for creation:
  4690. $content.='
  4691. <br /><h3>' . $GLOBALS['LANG']->getLL('checkUploadFolder_create_upload_folder') . '</h3>
  4692. <p>' . sprintf($GLOBALS['LANG']->getLL('checkUploadFolder_upload_folder_needed'),
  4693. $this->ulFolder($extKey)
  4694. ) . '<br />
  4695. <label for="check_uploadfolder">' . sprintf($GLOBALS['LANG']->getLL('checkUploadFolder_create_dir'),
  4696. $this->ulFolder($extKey)
  4697. ) . '</label>
  4698. <input type="checkbox" name="_uploadfolder" id="check_uploadfolder" checked="checked" value="1" /><br />
  4699. </p>
  4700. ';
  4701. }
  4702. }
  4703. // Additional directories that should be created:
  4704. if ($extInfo['EM_CONF']['createDirs']) {
  4705. $createDirs = array_unique(t3lib_div::trimExplode(',',$extInfo['EM_CONF']['createDirs'],1));
  4706. foreach($createDirs as $crDir) {
  4707. if (!@is_dir(PATH_site.$crDir)) {
  4708. if (t3lib_div::_POST('_createDir_'.md5($crDir))) { // CREATE dir:
  4709. // Initialize:
  4710. $crDirStart = '';
  4711. $dirs_in_path = explode('/',preg_replace('/\/$/','',$crDir));
  4712. // Traverse each part of the dir path and create it one-by-one:
  4713. foreach($dirs_in_path as $dirP) {
  4714. if (strcmp($dirP,'')) {
  4715. $crDirStart.= $dirP.'/';
  4716. if (!@is_dir(PATH_site.$crDirStart)) {
  4717. t3lib_div::mkdir(PATH_site.$crDirStart);
  4718. $finalDir = PATH_site.$crDirStart;
  4719. }
  4720. } else {
  4721. throw new RuntimeException(
  4722. 'TYPO3 Fatal Error: ' . sprintf($GLOBALS['LANG']->getLL('checkUploadFolder_error'), PATH_site . $crDir),
  4723. 1270853982
  4724. );
  4725. }
  4726. }
  4727. if ($finalDir) {
  4728. $indexContent = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
  4729. <HTML>
  4730. <HEAD>
  4731. <TITLE></TITLE>
  4732. <META http-equiv=Refresh Content="0; Url=/">
  4733. </HEAD>
  4734. </HTML>';
  4735. t3lib_div::writeFile($finalDir.'index.html',$indexContent);
  4736. }
  4737. } else { // Show checkbox / HTML for creation:
  4738. $md5CrDir = md5($crDir);
  4739. $content.='
  4740. <br />
  4741. <h3>' . $GLOBALS['LANG']->getLL('checkUploadFolder_create_folder') . '</h3>
  4742. <p>' . sprintf($GLOBALS['LANG']->getLL('checkUploadFolder_folder_needed'),
  4743. $crDir
  4744. ) . '<br />
  4745. <label for="check_createDir_' . $md5CrDir . '">' . sprintf($GLOBALS['LANG']->getLL('checkUploadFolder_create_dir'),
  4746. $crDir
  4747. ) . '</label>
  4748. <input type="checkbox" name="_createDir_' . $md5CrDir . '" id="check_createDir_' . $md5CrDir . '" checked="checked" value="1" /><br />
  4749. </p>
  4750. ';
  4751. }
  4752. }
  4753. }
  4754. }
  4755. return $content;
  4756. }
  4757. /**
  4758. * Validates the database according to extension requirements
  4759. * Prints form for changes if any. If none, returns blank. If an update is ordered, empty is returned as well.
  4760. * DBAL compliant (based on Install Tool code)
  4761. *
  4762. * @param string Extension key
  4763. * @param array Extension information array
  4764. * @param boolean If true, returns array with info.
  4765. * @return mixed If $infoOnly, returns array with information. Otherwise performs update.
  4766. */
  4767. function checkDBupdates($extKey,$extInfo,$infoOnly=0) {
  4768. // Initializing Install Tool object:
  4769. $instObj = new t3lib_install;
  4770. $instObj->INSTALL = t3lib_div::_GP('TYPO3_INSTALL');
  4771. $dbStatus = array();
  4772. // Updating tables and fields?
  4773. if (is_array($extInfo['files']) && in_array('ext_tables.sql', $extInfo['files'])) {
  4774. $fileContent = t3lib_div::getUrl($this->getExtPath($extKey,$extInfo['type']).'ext_tables.sql');
  4775. $FDfile = $instObj->getFieldDefinitions_fileContent($fileContent);
  4776. if (count($FDfile)) {
  4777. $FDdb = $instObj->getFieldDefinitions_database(TYPO3_db);
  4778. $diff = $instObj->getDatabaseExtra($FDfile, $FDdb);
  4779. $update_statements = $instObj->getUpdateSuggestions($diff);
  4780. $dbStatus['structure']['tables_fields'] = $FDfile;
  4781. $dbStatus['structure']['diff'] = $diff;
  4782. // Updating database...
  4783. if (!$infoOnly && is_array($instObj->INSTALL['database_update'])) {
  4784. $instObj->performUpdateQueries($update_statements['add'],$instObj->INSTALL['database_update']);
  4785. $instObj->performUpdateQueries($update_statements['change'],$instObj->INSTALL['database_update']);
  4786. $instObj->performUpdateQueries($update_statements['create_table'],$instObj->INSTALL['database_update']);
  4787. } else {
  4788. $content .= $instObj->generateUpdateDatabaseForm_checkboxes(
  4789. $update_statements['add'], $GLOBALS['LANG']->getLL('checkDBupdates_add_fields'));
  4790. $content .= $instObj->generateUpdateDatabaseForm_checkboxes(
  4791. $update_statements['change'], $GLOBALS['LANG']->getLL('checkDBupdates_changing_fields'), 1, 0, $update_statements['change_currentValue']);
  4792. $content .= $instObj->generateUpdateDatabaseForm_checkboxes(
  4793. $update_statements['create_table'], $GLOBALS['LANG']->getLL('checkDBupdates_add_tables'));
  4794. }
  4795. }
  4796. }
  4797. // Importing static tables?
  4798. if (is_array($extInfo['files']) && in_array('ext_tables_static+adt.sql',$extInfo['files'])) {
  4799. $fileContent = t3lib_div::getUrl($this->getExtPath($extKey,$extInfo['type']).'ext_tables_static+adt.sql');
  4800. $statements = $instObj->getStatementArray($fileContent,1);
  4801. list($statements_table, $insertCount) = $instObj->getCreateTables($statements,1);
  4802. // Execute import of static table content:
  4803. if (!$infoOnly && is_array($instObj->INSTALL['database_import'])) {
  4804. // Traverse the tables
  4805. foreach($instObj->INSTALL['database_import'] as $table => $md5str) {
  4806. if ($md5str == md5($statements_table[$table])) {
  4807. $GLOBALS['TYPO3_DB']->admin_query('DROP TABLE IF EXISTS '.$table);
  4808. $GLOBALS['TYPO3_DB']->admin_query($statements_table[$table]);
  4809. if ($insertCount[$table]) {
  4810. $statements_insert = $instObj->getTableInsertStatements($statements, $table);
  4811. foreach($statements_insert as $v) {
  4812. $GLOBALS['TYPO3_DB']->admin_query($v);
  4813. }
  4814. }
  4815. }
  4816. }
  4817. } else {
  4818. $whichTables = $instObj->getListOfTables();
  4819. if (count($statements_table)) {
  4820. $out = '';
  4821. foreach($statements_table as $table => $definition) {
  4822. $exist = isset($whichTables[$table]);
  4823. $dbStatus['static'][$table]['exists'] = $exist;
  4824. $dbStatus['static'][$table]['count'] = $insertCount[$table];
  4825. $out.= '<tr>
  4826. <td><input type="checkbox" name="TYPO3_INSTALL[database_import]['.$table.']" checked="checked" value="'.md5($definition).'" /></td>
  4827. <td><strong>'.$table.'</strong></td>
  4828. <td><img src="clear.gif" width="10" height="1" alt="" /></td>
  4829. <td nowrap="nowrap">' .
  4830. ($insertCount[$table] ?
  4831. $GLOBALS['LANG']->getLL('checkDBupdates_rows') . ' ' . $insertCount[$table]
  4832. : '') .
  4833. '</td>
  4834. <td><img src="clear.gif" width="10" height="1" alt="" /></td>
  4835. <td nowrap="nowrap">' .
  4836. ($exist ?
  4837. t3lib_iconWorks::getSpriteIcon('status-dialog-warning') .
  4838. $GLOBALS['LANG']->getLL('checkDBupdates_table_exists')
  4839. : '') .
  4840. '</td>
  4841. </tr>';
  4842. }
  4843. $content.= '
  4844. <br />
  4845. <h3>' . $GLOBALS['LANG']->getLL('checkDBupdates_import_static_data') . '</h3>
  4846. <table border="0" cellpadding="0" cellspacing="0">'.$out.'</table>
  4847. ';
  4848. }
  4849. }
  4850. }
  4851. // Return array of information if $infoOnly, otherwise content.
  4852. return $infoOnly ? $dbStatus : $content;
  4853. }
  4854. /**
  4855. * Updates the database according to extension requirements
  4856. * DBAL compliant (based on Install Tool code)
  4857. *
  4858. * @param string Extension key
  4859. * @param array Extension information array
  4860. * @return void
  4861. */
  4862. function forceDBupdates($extKey, $extInfo) {
  4863. $instObj = new t3lib_install;
  4864. // Updating tables and fields?
  4865. if (is_array($extInfo['files']) && in_array('ext_tables.sql',$extInfo['files'])) {
  4866. $fileContent = t3lib_div::getUrl($this->getExtPath($extKey,$extInfo['type']).'ext_tables.sql');
  4867. $FDfile = $instObj->getFieldDefinitions_fileContent($fileContent);
  4868. if (count($FDfile)) {
  4869. $FDdb = $instObj->getFieldDefinitions_database(TYPO3_db);
  4870. $diff = $instObj->getDatabaseExtra($FDfile, $FDdb);
  4871. $update_statements = $instObj->getUpdateSuggestions($diff);
  4872. foreach((array)$update_statements['add'] as $string) {
  4873. $GLOBALS['TYPO3_DB']->admin_query($string);
  4874. }
  4875. foreach((array)$update_statements['change'] as $string) {
  4876. $GLOBALS['TYPO3_DB']->admin_query($string);
  4877. }
  4878. foreach((array)$update_statements['create_table'] as $string) {
  4879. $GLOBALS['TYPO3_DB']->admin_query($string);
  4880. }
  4881. }
  4882. }
  4883. // Importing static tables?
  4884. if (is_array($extInfo['files']) && in_array('ext_tables_static+adt.sql',$extInfo['files'])) {
  4885. $fileContent = t3lib_div::getUrl($this->getExtPath($extKey,$extInfo['type']).'ext_tables_static+adt.sql');
  4886. $statements = $instObj->getStatementArray($fileContent,1);
  4887. list($statements_table, $insertCount) = $instObj->getCreateTables($statements,1);
  4888. // Traverse the tables
  4889. foreach($statements_table as $table => $query) {
  4890. $GLOBALS['TYPO3_DB']->admin_query('DROP TABLE IF EXISTS '.$table);
  4891. $GLOBALS['TYPO3_DB']->admin_query($query);
  4892. if ($insertCount[$table]) {
  4893. $statements_insert = $instObj->getTableInsertStatements($statements, $table);
  4894. foreach($statements_insert as $v) {
  4895. $GLOBALS['TYPO3_DB']->admin_query($v);
  4896. }
  4897. }
  4898. }
  4899. }
  4900. }
  4901. /**
  4902. * Produces the config form for an extension (if any template file, ext_conf_template.txt is found)
  4903. *
  4904. * @param string Extension key
  4905. * @param array Extension information array
  4906. * @param boolean If true, the form HTML content is returned, otherwise the content is set in $this->content.
  4907. * @param string Submit-to URL (supposedly)
  4908. * @param string Additional form fields to include.
  4909. * @return string Depending on $output. Can return the whole form.
  4910. */
  4911. function tsStyleConfigForm($extKey,$extInfo,$output=0,$script='',$addFields='') {
  4912. global $TYPO3_CONF_VARS;
  4913. // Initialize:
  4914. $absPath = $this->getExtPath($extKey,$extInfo['type']);
  4915. $relPath = $this->typeRelPaths[$extInfo['type']].$extKey.'/';
  4916. // Look for template file for form:
  4917. if (t3lib_extMgm::isLoaded($extKey) && @is_file($absPath.'ext_conf_template.txt')) {
  4918. // Load tsStyleConfig class and parse configuration template:
  4919. $tsStyleConfig = t3lib_div::makeInstance('t3lib_tsStyleConfig');
  4920. $tsStyleConfig->doNotSortCategoriesBeforeMakingForm = TRUE;
  4921. $theConstants = $tsStyleConfig->ext_initTSstyleConfig(
  4922. t3lib_div::getUrl($absPath.'ext_conf_template.txt'),
  4923. $relPath,
  4924. $absPath,
  4925. $GLOBALS['BACK_PATH']
  4926. );
  4927. // Load the list of resources.
  4928. $tsStyleConfig->ext_loadResources($absPath.'res/');
  4929. // Load current value:
  4930. $arr = unserialize($TYPO3_CONF_VARS['EXT']['extConf'][$extKey]);
  4931. $arr = is_array($arr) ? $arr : array();
  4932. // Call processing function for constants config and data before write and form rendering:
  4933. if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['typo3/mod/tools/em/index.php']['tsStyleConfigForm'])) {
  4934. $_params = array('fields' => &$theConstants, 'data' => &$arr, 'extKey' => $extKey);
  4935. foreach($TYPO3_CONF_VARS['SC_OPTIONS']['typo3/mod/tools/em/index.php']['tsStyleConfigForm'] as $_funcRef) {
  4936. t3lib_div::callUserFunction($_funcRef,$_params,$this);
  4937. }
  4938. unset($_params);
  4939. }
  4940. // If saving operation is done:
  4941. if (t3lib_div::_POST('submit')) {
  4942. $tsStyleConfig->ext_procesInput(t3lib_div::_POST(),array(),$theConstants,array());
  4943. $arr = $tsStyleConfig->ext_mergeIncomingWithExisting($arr);
  4944. $this->writeTsStyleConfig($extKey,$arr);
  4945. }
  4946. // Setting value array
  4947. $tsStyleConfig->ext_setValueArray($theConstants,$arr);
  4948. // Getting session data:
  4949. $MOD_MENU = array();
  4950. $MOD_MENU['constant_editor_cat'] = $tsStyleConfig->ext_getCategoriesForModMenu();
  4951. $MOD_SETTINGS = t3lib_BEfunc::getModuleData($MOD_MENU, t3lib_div::_GP('SET'), 'xMod_test');
  4952. // Resetting the menu (stop)
  4953. if (count($MOD_MENU['constant_editor_cat']) > 1) {
  4954. $menu = $GLOBALS['LANG']->getLL('extInfoArray_category') . ' ' .
  4955. t3lib_BEfunc::getFuncMenu(0, 'SET[constant_editor_cat]', $MOD_SETTINGS['constant_editor_cat'], $MOD_MENU['constant_editor_cat'], '', '&CMD[showExt]=' . $extKey);
  4956. $this->content.=$this->doc->section('','<span class="nobr">'.$menu.'</span>');
  4957. $this->content.=$this->doc->spacer(10);
  4958. }
  4959. // Category and constant editor config:
  4960. $form = '
  4961. <table border="0" cellpadding="0" cellspacing="0" width="600">
  4962. <tr>
  4963. <td>'.$tsStyleConfig->ext_getForm($MOD_SETTINGS['constant_editor_cat'],$theConstants,$script,$addFields).'</form></td>
  4964. </tr>
  4965. </table>';
  4966. } else {
  4967. $flashMessage = t3lib_div::makeInstance(
  4968. 't3lib_FlashMessage',
  4969. $GLOBALS['LANG']->getLL('tsStyleConfigForm_additional_config'),
  4970. '',
  4971. t3lib_FlashMessage::INFO
  4972. );
  4973. $form = '
  4974. <table border="0" cellpadding="0" cellspacing="0" width="600">
  4975. <tr>
  4976. <td>
  4977. <form action="' . htmlspecialchars($script) . '" method="post">' .
  4978. $addFields .
  4979. $flashMessage->render() .
  4980. '<br /><input type="submit" name="write" value="' . $GLOBALS['LANG']->getLL('updatesForm_make_updates') . '" />
  4981. </form>
  4982. </td>
  4983. </tr>
  4984. </table>';
  4985. }
  4986. if ($output) {
  4987. return $form;
  4988. } else {
  4989. $this->content.=$this->doc->section('', $form);
  4990. }
  4991. }
  4992. /*******************************
  4993. *
  4994. * Dumping database (MySQL compliant)
  4995. *
  4996. ******************************/
  4997. /**
  4998. * Makes a dump of the tables/fields definitions for an extension
  4999. *
  5000. * @param array Array with table => field/key definition arrays in
  5001. * @return string SQL for the table definitions
  5002. * @see dumpStaticTables()
  5003. */
  5004. function dumpTableAndFieldStructure($arr) {
  5005. $tables = array();
  5006. if (count($arr)) {
  5007. // Get file header comment:
  5008. $tables[] = $this->dumpHeader();
  5009. // Traverse tables, write each table/field definition:
  5010. foreach($arr as $table => $fieldKeyInfo) {
  5011. $tables[] = $this->dumpTableHeader($table,$fieldKeyInfo);
  5012. }
  5013. }
  5014. // Return result:
  5015. return implode(LF.LF.LF,$tables);
  5016. }
  5017. /**
  5018. * Dump content for static tables
  5019. *
  5020. * @param string Comma list of tables from which to dump content
  5021. * @return string Returns the content
  5022. * @see dumpTableAndFieldStructure()
  5023. */
  5024. function dumpStaticTables($tableList) {
  5025. $instObj = new t3lib_install;
  5026. $dbFields = $instObj->getFieldDefinitions_database(TYPO3_db);
  5027. $out = '';
  5028. $parts = t3lib_div::trimExplode(',',$tableList,1);
  5029. // Traverse the table list and dump each:
  5030. foreach($parts as $table) {
  5031. if (is_array($dbFields[$table]['fields'])) {
  5032. $dHeader = $this->dumpHeader();
  5033. $header = $this->dumpTableHeader($table,$dbFields[$table],1);
  5034. $insertStatements = $this->dumpTableContent($table,$dbFields[$table]['fields']);
  5035. $out.= $dHeader.LF.LF.LF.
  5036. $header.LF.LF.LF.
  5037. $insertStatements.LF.LF.LF;
  5038. } else {
  5039. throw new RuntimeException(
  5040. 'TYPO3 Fatal Error: ' . $GLOBALS['LANG']->getLL('dumpStaticTables_table_not_found'),
  5041. 1270853983
  5042. );
  5043. }
  5044. }
  5045. return $out;
  5046. }
  5047. /**
  5048. * Header comments of the SQL dump file
  5049. *
  5050. * @return string Table header
  5051. */
  5052. function dumpHeader() {
  5053. return trim('
  5054. # TYPO3 Extension Manager dump 1.1
  5055. #
  5056. # Host: '.TYPO3_db_host.' Database: '.TYPO3_db.'
  5057. #--------------------------------------------------------
  5058. ');
  5059. }
  5060. /**
  5061. * Dump CREATE TABLE definition
  5062. *
  5063. * @param string Table name
  5064. * @param array Field and key information (as provided from Install Tool class!)
  5065. * @param boolean If true, add "DROP TABLE IF EXISTS"
  5066. * @return string Table definition SQL
  5067. */
  5068. function dumpTableHeader($table,$fieldKeyInfo,$dropTableIfExists=0) {
  5069. $lines = array();
  5070. $dump = '';
  5071. // Create field definitions
  5072. if (is_array($fieldKeyInfo['fields'])) {
  5073. foreach($fieldKeyInfo['fields'] as $fieldN => $data) {
  5074. $lines[]=' '.$fieldN.' '.$data;
  5075. }
  5076. }
  5077. // Create index key definitions
  5078. if (is_array($fieldKeyInfo['keys'])) {
  5079. foreach($fieldKeyInfo['keys'] as $fieldN => $data) {
  5080. $lines[]=' '.$data;
  5081. }
  5082. }
  5083. // Compile final output:
  5084. if (count($lines)) {
  5085. $dump = trim('
  5086. #
  5087. # Table structure for table "'.$table.'"
  5088. #
  5089. '.($dropTableIfExists ? 'DROP TABLE IF EXISTS '.$table.';
  5090. ' : '').'CREATE TABLE '.$table.' (
  5091. '.implode(','.LF,$lines).'
  5092. );'
  5093. );
  5094. }
  5095. return $dump;
  5096. }
  5097. /**
  5098. * Dump table content
  5099. * Is DBAL compliant, but the dump format is written as MySQL standard. If the INSERT statements should be imported in a DBMS using other quoting than MySQL they must first be translated. t3lib_sqlengine can parse these queries correctly and translate them somehow.
  5100. *
  5101. * @param string Table name
  5102. * @param array Field structure
  5103. * @return string SQL Content of dump (INSERT statements)
  5104. */
  5105. function dumpTableContent($table,$fieldStructure) {
  5106. // Substitution of certain characters (borrowed from phpMySQL):
  5107. $search = array('\\', '\'', "\x00", "\x0a", "\x0d", "\x1a");
  5108. $replace = array('\\\\', '\\\'', '\0', '\n', '\r', '\Z');
  5109. $lines = array();
  5110. // Select all rows from the table:
  5111. $result = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', $table, '');
  5112. // Traverse the selected rows and dump each row as a line in the file:
  5113. while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result)) {
  5114. $values = array();
  5115. foreach ($fieldStructure as $field => $dummyValue) {
  5116. $values[] = isset($row[$field]) ? "'".str_replace($search, $replace, $row[$field])."'" : 'NULL';
  5117. }
  5118. $lines[] = 'INSERT INTO '.$table.' VALUES ('.implode(', ',$values).');';
  5119. }
  5120. // Free DB result:
  5121. $GLOBALS['TYPO3_DB']->sql_free_result($result);
  5122. // Implode lines and return:
  5123. return implode(LF,$lines);
  5124. }
  5125. /**
  5126. * Gets the table and field structure from database.
  5127. * Which fields and which tables are determined from the ext_tables.sql file
  5128. *
  5129. * @param string Array with table.field values
  5130. * @return array Array of tables and fields splitted.
  5131. */
  5132. function getTableAndFieldStructure($parts) {
  5133. // Instance of install tool
  5134. $instObj = new t3lib_install;
  5135. $dbFields = $instObj->getFieldDefinitions_database(TYPO3_db);
  5136. $outTables = array();
  5137. foreach($parts as $table) {
  5138. $tP = explode('.',$table);
  5139. if ($tP[0] && isset($dbFields[$tP[0]])) {
  5140. if ($tP[1]) {
  5141. $kfP = explode('KEY:',$tP[1],2);
  5142. if (count($kfP)==2 && !$kfP[0]) { // key:
  5143. if (isset($dbFields[$tP[0]]['keys'][$kfP[1]])) $outTables[$tP[0]]['keys'][$kfP[1]] = $dbFields[$tP[0]]['keys'][$kfP[1]];
  5144. } else {
  5145. if (isset($dbFields[$tP[0]]['fields'][$tP[1]])) $outTables[$tP[0]]['fields'][$tP[1]] = $dbFields[$tP[0]]['fields'][$tP[1]];
  5146. }
  5147. } else {
  5148. $outTables[$tP[0]] = $dbFields[$tP[0]];
  5149. }
  5150. }
  5151. }
  5152. return $outTables;
  5153. }
  5154. /*******************************
  5155. *
  5156. * TER Communication functions
  5157. *
  5158. ******************************/
  5159. /**
  5160. * Processes return-data from online repository.
  5161. * Currently only the returned emconf array is written to extension.
  5162. *
  5163. * @param array Command array returned from TER
  5164. * @return string Message
  5165. */
  5166. function uploadExtensionToTER($em) {
  5167. $msg = '';
  5168. $response = $this->terConnection->uploadToTER($em);
  5169. if(!is_array($response)) return $response;
  5170. if($response['resultCode']==TX_TER_RESULT_EXTENSIONSUCCESSFULLYUPLOADED) {
  5171. $em['extInfo']['EM_CONF']['version'] = $response['version'];
  5172. $response['resultMessages'][] = sprintf($GLOBALS['LANG']->getLL('terCommunication_ext_version'),
  5173. $response['version']
  5174. );
  5175. $response['resultMessages'][] = $this->updateLocalEM_CONF($em['extKey'],$em['extInfo']);
  5176. }
  5177. $msg = '<ul><li>'.implode('</li><li>',$response['resultMessages']).'</li></ul>';
  5178. return $msg;
  5179. }
  5180. /************************************
  5181. *
  5182. * Various helper functions
  5183. *
  5184. ************************************/
  5185. /**
  5186. * Returns subtitles for the extension listings
  5187. *
  5188. * @param string List order type
  5189. * @param string Key value
  5190. * @return string output.
  5191. */
  5192. function listOrderTitle($listOrder,$key) {
  5193. switch($listOrder) {
  5194. case 'cat':
  5195. return isset($this->categories[$key]) ? $this->categories[$key] : '[' . $key . ']';
  5196. break;
  5197. case 'author_company':
  5198. return $key;
  5199. break;
  5200. case 'state':
  5201. return $this->states[$key];
  5202. break;
  5203. case 'type':
  5204. return $this->typeDescr[$key];
  5205. break;
  5206. }
  5207. }
  5208. /**
  5209. * Returns version information
  5210. *
  5211. * @param string Version code, x.x.x
  5212. * @param string part: "", "int", "main", "sub", "dev"
  5213. * @return string
  5214. * @see renderVersion()
  5215. */
  5216. function makeVersion($v,$mode) {
  5217. $vDat = $this->renderVersion($v);
  5218. return $vDat['version_'.$mode];
  5219. }
  5220. /**
  5221. * Parses the version number x.x.x and returns an array with the various parts.
  5222. *
  5223. * @param string Version code, x.x.x
  5224. * @param string Increase version part: "main", "sub", "dev"
  5225. * @return string
  5226. */
  5227. function renderVersion($v,$raise='') {
  5228. $parts = t3lib_div::intExplode('.',$v.'..');
  5229. $parts[0] = t3lib_div::intInRange($parts[0],0,999);
  5230. $parts[1] = t3lib_div::intInRange($parts[1],0,999);
  5231. $parts[2] = t3lib_div::intInRange($parts[2],0,999);
  5232. switch((string)$raise) {
  5233. case 'main':
  5234. $parts[0]++;
  5235. $parts[1]=0;
  5236. $parts[2]=0;
  5237. break;
  5238. case 'sub':
  5239. $parts[1]++;
  5240. $parts[2]=0;
  5241. break;
  5242. case 'dev':
  5243. $parts[2]++;
  5244. break;
  5245. }
  5246. $res = array();
  5247. $res['version'] = $parts[0].'.'.$parts[1].'.'.$parts[2];
  5248. $res['version_int'] = intval($parts[0]*1000000+$parts[1]*1000+$parts[2]);
  5249. $res['version_main'] = $parts[0];
  5250. $res['version_sub'] = $parts[1];
  5251. $res['version_dev'] = $parts[2];
  5252. return $res;
  5253. }
  5254. /**
  5255. * Returns upload folder for extension
  5256. *
  5257. * @param string Extension key
  5258. * @return string Upload folder for extension
  5259. */
  5260. function ulFolder($extKey) {
  5261. return 'uploads/tx_'.str_replace('_','',$extKey).'/';
  5262. }
  5263. /**
  5264. * Returns true if global OR local installation of extensions is allowed/possible.
  5265. *
  5266. * @return boolean Returns true if global OR local installation of extensions is allowed/possible.
  5267. */
  5268. function importAtAll() {
  5269. return ($GLOBALS['TYPO3_CONF_VARS']['EXT']['allowGlobalInstall'] || $GLOBALS['TYPO3_CONF_VARS']['EXT']['allowLocalInstall']);
  5270. }
  5271. /**
  5272. * Reports back if installation in a certain scope is possible.
  5273. *
  5274. * @param string Scope: G, L, S
  5275. * @param string Extension lock-type (eg. "L" or "G")
  5276. * @return boolean True if installation is allowed.
  5277. */
  5278. function importAsType($type,$lockType='') {
  5279. switch($type) {
  5280. case 'G':
  5281. return $GLOBALS['TYPO3_CONF_VARS']['EXT']['allowGlobalInstall'] && (!$lockType || !strcmp($lockType,$type));
  5282. break;
  5283. case 'L':
  5284. return $GLOBALS['TYPO3_CONF_VARS']['EXT']['allowLocalInstall'] && (!$lockType || !strcmp($lockType,$type));
  5285. break;
  5286. case 'S':
  5287. return $this->systemInstall;
  5288. break;
  5289. default:
  5290. return false;
  5291. }
  5292. }
  5293. /**
  5294. * Returns true if extensions in scope, $type, can be deleted (or installed for that sake)
  5295. *
  5296. * @param string Scope: "G" or "L"
  5297. * @return boolean True if possible.
  5298. */
  5299. function deleteAsType($type) {
  5300. switch($type) {
  5301. case 'G':
  5302. return $GLOBALS['TYPO3_CONF_VARS']['EXT']['allowGlobalInstall'];
  5303. break;
  5304. case 'L':
  5305. return $GLOBALS['TYPO3_CONF_VARS']['EXT']['allowLocalInstall'];
  5306. break;
  5307. default:
  5308. return false;
  5309. }
  5310. }
  5311. /**
  5312. * Evaluates differences in version numbers with three parts, x.x.x. Returns true if $v1 is greater than $v2
  5313. *
  5314. * @param string Version number 1
  5315. * @param string Version number 2
  5316. * @param integer Tolerance factor. For instance, set to 1000 to ignore difference in dev-version (third part)
  5317. * @return boolean True if version 1 is greater than version 2
  5318. */
  5319. function versionDifference($v1,$v2,$div=1) {
  5320. return floor($this->makeVersion($v1,'int')/$div) > floor($this->makeVersion($v2,'int')/$div);
  5321. }
  5322. /**
  5323. * Returns true if the $str is found as the first part of a string in $array
  5324. *
  5325. * @param string String to test with.
  5326. * @param array Input array
  5327. * @param boolean If set, the test is case insensitive
  5328. * @return boolean True if found.
  5329. */
  5330. function first_in_array($str,$array,$caseInsensitive=FALSE) {
  5331. if ($caseInsensitive) $str = strtolower($str);
  5332. if (is_array($array)) {
  5333. foreach($array as $cl) {
  5334. if ($caseInsensitive) $cl = strtolower($cl);
  5335. if (t3lib_div::isFirstPartOfStr($cl,$str)) return true;
  5336. }
  5337. }
  5338. return false;
  5339. }
  5340. /**
  5341. * Returns the $EM_CONF array from an extensions ext_emconf.php file
  5342. *
  5343. * @param string Absolute path to EMCONF file.
  5344. * @param string Extension key.
  5345. * @return array EMconf array values.
  5346. */
  5347. function includeEMCONF($path, $_EXTKEY) {
  5348. $EM_CONF = NULL;
  5349. @include($path);
  5350. if(is_array($EM_CONF[$_EXTKEY])) {
  5351. return $this->fixEMCONF($EM_CONF[$_EXTKEY]);
  5352. }
  5353. return false;
  5354. }
  5355. /**
  5356. * Searches for ->lookUpStr in extension and returns true if found (or if no search string is set)
  5357. *
  5358. * @param string Extension key
  5359. * @param array Extension content
  5360. * @return boolean If true, display extension in list
  5361. */
  5362. function searchExtension($extKey,$row) {
  5363. if ($this->lookUpStr) {
  5364. return (
  5365. stristr($extKey,$this->lookUpStr) ||
  5366. stristr($row['EM_CONF']['title'],$this->lookUpStr) ||
  5367. stristr($row['EM_CONF']['description'],$this->lookUpStr) ||
  5368. stristr($row['EM_CONF']['author'],$this->lookUpStr) ||
  5369. stristr($row['EM_CONF']['author_company'],$this->lookUpStr)
  5370. );
  5371. } else return true;
  5372. }
  5373. /**
  5374. * Checks if there are newer versions of installed extensions in the TER
  5375. * integrated from the extension "ter_update_check" for TYPO3 4.2 by Christian Welzel
  5376. *
  5377. * @return nothing
  5378. */
  5379. function checkForUpdates() {
  5380. global $LANG;
  5381. $content = '';
  5382. if (is_file(PATH_site.'typo3temp/extensions.xml.gz')) {
  5383. $content = $this->showExtensionsToUpdate()
  5384. .t3lib_BEfunc::getFuncCheck(0, 'SET[display_installed]', $this->MOD_SETTINGS['display_installed'], '', '', 'id="checkDisplayInstalled"')
  5385. . '&nbsp;<label for="checkDisplayInstalled">' . $LANG->sL('LLL:EXT:lang/locallang_mod_tools_em.xml:display_nle') . '</label><br />'
  5386. .t3lib_BEfunc::getFuncCheck(0, 'SET[display_files]', $this->MOD_SETTINGS['display_files'], '', '', 'id="checkDisplayFiles"')
  5387. .'&nbsp;<label for="checkDisplayFiles">'.$LANG->sL('LLL:EXT:lang/locallang_mod_tools_em.xml:display_files').'</label>';
  5388. $this->content .= $this->doc->section($LANG->sL('LLL:EXT:lang/locallang_mod_tools_em.xml:header_upd_ext'), $content, 0, 1);
  5389. $dateFormat = $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'];
  5390. $timeFormat = $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'];
  5391. $content = sprintf($GLOBALS['LANG']->getLL('note_last_update_new'),
  5392. date(
  5393. $dateFormat . ', ' . $timeFormat,
  5394. filemtime(PATH_site . 'typo3temp/extensions.xml.gz')
  5395. )
  5396. ) . '<br />';
  5397. }
  5398. $content .= sprintf($GLOBALS['LANG']->getLL('note_last_update2_new'),
  5399. '<a href="index.php?SET[function]=2">', '</a>');
  5400. $this->content .= $this->doc->section($LANG->sL('LLL:EXT:lang/locallang_mod_tools_em.xml:header_vers_ret'), $content, 0, 1);
  5401. }
  5402. /**
  5403. * Displays a list of extensions where a newer version is available
  5404. * in the TER than the one that is installed right now
  5405. * integrated from the extension "ter_update_check" for TYPO3 4.2 by Christian Welzel
  5406. *
  5407. * @return nothing
  5408. */
  5409. function showExtensionsToUpdate() {
  5410. global $LANG;
  5411. $extList = $this->getInstalledExtensions();
  5412. $content = '<table border="0" cellpadding="2" cellspacing="1">'.
  5413. '<tr class="t3-row-header">'.
  5414. '<td></td>'.
  5415. '<td>'.$LANG->sL('LLL:EXT:lang/locallang_mod_tools_em.xml:tab_mod_name').'</td>'.
  5416. '<td>'.$LANG->sL('LLL:EXT:lang/locallang_mod_tools_em.xml:tab_mod_key').'</td>'.
  5417. '<td>'.$LANG->sL('LLL:EXT:lang/locallang_mod_tools_em.xml:tab_mod_loc_ver').'</td>'.
  5418. '<td>'.$LANG->sL('LLL:EXT:lang/locallang_mod_tools_em.xml:tab_mod_rem_ver').'</td>'.
  5419. '<td>'.$LANG->sL('LLL:EXT:lang/locallang_mod_tools_em.xml:tab_mod_location').'</td>'.
  5420. '<td>'.$LANG->sL('LLL:EXT:lang/locallang_mod_tools_em.xml:tab_mod_comment').'</td>'.
  5421. '</tr>';
  5422. foreach ($extList[0] as $name => $data) {
  5423. $this->xmlhandler->searchExtensionsXMLExact($name, '', '', TRUE, TRUE);
  5424. if (!is_array($this->xmlhandler->extensionsXML[$name])) {
  5425. continue;
  5426. }
  5427. $v = $this->xmlhandler->extensionsXML[$name]['versions'];
  5428. $versions = array_keys($v);
  5429. natsort($versions);
  5430. $lastversion = end($versions);
  5431. if ((t3lib_extMgm::isLoaded($name) || $this->MOD_SETTINGS['display_installed']) &&
  5432. ($data['EM_CONF']['shy'] == 0 || $this->MOD_SETTINGS['display_shy']) &&
  5433. $this->versionDifference($lastversion, $data['EM_CONF']['version'], 1)) {
  5434. $imgInfo = @getImageSize($this->getExtPath($name, $data['type']) . '/ext_icon.gif');
  5435. if (is_array($imgInfo)) {
  5436. $icon = '<img src="'.$GLOBALS['BACK_PATH'].$this->typeRelPaths[$data['type']].$name.'/ext_icon.gif'.'" '.$imgInfo[3].' alt="" />';
  5437. } elseif ($data['_ICON']) { //TODO: see if this can be removed, seems to be wrong in this context
  5438. $icon = $data['_ICON'];
  5439. } else {
  5440. $icon = '<img src="clear.gif" width="1" height="1" alt="" />';
  5441. }
  5442. $comment = '<table cellpadding="0" cellspacing="0" width="100%">';
  5443. foreach ($versions as $vk) {
  5444. $va = & $v[$vk];
  5445. if (t3lib_div::int_from_ver($vk) < t3lib_div::int_from_ver($data['EM_CONF']['version'])) {
  5446. continue;
  5447. }
  5448. $comment .= '<tr><td valign="top" style="padding-right:2px;border-bottom:1px dotted gray">'.$vk.'</td>'.'<td valign="top" style="border-bottom:1px dotted gray">'.nl2br($va[uploadcomment]).'</td></tr>';
  5449. }
  5450. $comment .= '</table>';
  5451. $serverMD5Array = $this->serverExtensionMD5Array($name,$data);
  5452. if (is_array($serverMD5Array)) {
  5453. ksort($serverMD5Array);
  5454. }
  5455. $currentMD5Array = unserialize($data['EM_CONF']['_md5_values_when_last_written']);
  5456. if (is_array($currentMD5Array)) {
  5457. @ksort($currentMD5Array);
  5458. }
  5459. $warn = '';
  5460. if (strcmp(serialize($currentMD5Array), serialize($serverMD5Array))) {
  5461. $warn = '<tr class="bgColor4" style="color:red"><td colspan="7">'.$GLOBALS['TBE_TEMPLATE']->rfw('<br /><strong>'.$name.': '.$LANG->sL('LLL:EXT:lang/locallang_mod_tools_em.xml:msg_warn_diff').'</strong>').'</td></tr>'.LF;
  5462. if ($this->MOD_SETTINGS['display_files'] == 1) {
  5463. $affectedFiles = $this->findMD5ArrayDiff($serverMD5Array,$currentMD5Array);
  5464. if (count($affectedFiles)) {
  5465. $warn .= '<tr class="bgColor4"><td colspan="7"><strong>'.$LANG->sL('LLL:EXT:lang/locallang_mod_tools_em.xml:msg_modified').'</strong><br />'.$GLOBALS['TBE_TEMPLATE']->rfw(implode('<br />',$affectedFiles)).'</td></tr>'.LF;
  5466. }
  5467. }
  5468. }
  5469. $content .= '<tr class="bgColor4"><td valign="top">'.$icon.'</td>'.
  5470. '<td valign="top">' . ($data['EM_CONF']['state'] == 'excludeFromUpdates' ? '<span style="color:#cf7307">' . $data['EM_CONF']['title'] . ' ' . $LANG->sL('LLL:EXT:lang/locallang_mod_tools_em.xml:write_protected') . '</span>' : '<a href="?CMD[importExtInfo]='.$name.'">'.$data[EM_CONF][title].'</a>') . '</td>'.
  5471. '<td valign="top">'.$name.'</td>'.
  5472. '<td valign="top" align="right">'.$data[EM_CONF][version].'</td>'.
  5473. '<td valign="top" align="right">'.$lastversion.'</td>'.
  5474. '<td valign="top" nowrap="nowrap">'.$this->typeLabels[$data['type']].(strlen($data['doubleInstall'])>1?'<strong> '.$GLOBALS['TBE_TEMPLATE']->rfw($extInfo['doubleInstall']).'</strong>':'').'</td>'.
  5475. '<td valign="top">'.$comment.'</td></tr>'.LF.
  5476. $warn.
  5477. '<tr class="bgColor4"><td colspan="7"><hr style="margin:0px" /></td></tr>'.LF;
  5478. }
  5479. }
  5480. return $content . '</table><br />';
  5481. }
  5482. }
  5483. if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['typo3/mod/tools/em/index.php']) {
  5484. include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['typo3/mod/tools/em/index.php']);
  5485. }
  5486. ?>