2 /***************************************************************
5 * (c) 1999-2009 Kasper Skaarhoj (kasperYYYY@typo3.com)
6 * (c) 2005-2009 Karsten Dambekalns <karsten@typo3.org>
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.
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.
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.
26 * This copyright notice MUST APPEAR in all copies of the script!
27 ***************************************************************/
29 * Module: Extension manager
33 * @author Kasper Skaarhoj <kasperYYYY@typo3.com>
34 * @author Karsten Dambekalns <karsten@typo3.org>
37 * [CLASS/FUNCTION INDEX of SCRIPT]
41 * 194: class SC_mod_tools_em_index extends t3lib_SCbase
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()
50 * SECTION: Function Menu Applications
51 * 609: function extensionList_loaded()
52 * 664: function extensionList_installed()
53 * 736: function extensionList_import()
54 * 903: function alterSettings()
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)
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)
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='')
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)
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)
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)
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)
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)
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)
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)
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='')
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)
149 * SECTION: TER Communication functions
150 * 4373: function uploadExtensionToTER($em)
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)
165 * TOTAL FUNCTIONS: 90
166 * (This index is automatically created/updated by the extension "extdeveval")
170 // Include classes needed:
171 require_once('class.em_xmlhandler.php');
172 require_once('class.em_terconnection.php');
173 require_once('class.em_unzip.php');
175 $GLOBALS['LANG']->includeLLFile('EXT:lang/locallang_mod_tools_em.xml');
177 // from tx_ter by Robert Lemke
178 define('TX_TER_RESULT_EXTENSIONSUCCESSFULLYUPLOADED', '10504');
180 define('EM_INSTALL_VERSION_MIN', 1);
181 define('EM_INSTALL_VERSION_MAX', 2);
182 define('EM_INSTALL_VERSION_STRICT', 3);
185 * Module: Extension manager
187 * @author Kasper Skaarhoj <kasperYYYY@typo3.com>
188 * @author Karsten Dambekalns <karsten@typo3.org>
192 class SC_mod_tools_em_index
extends t3lib_SCbase
{
195 var $versionDiffFactor = 1; // This means that version difference testing for import is detected for sub-versions only, not dev-versions. Default: 1000
196 var $systemInstall = 0; // If "1" then installs in the sysext directory is allowed. Default: 0
197 var $requiredExt = ''; // List of required extension (from TYPO3_CONF_VARS)
198 var $maxUploadSize = 31457280; // Max size in bytes of extension upload to repository
199 var $kbMax = 500; // Max size in kilobytes for files to be edited.
200 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
201 var $listingLimit = 500; // List that many extension maximally at one time (fixing memory problems)
202 var $listingLimitAuthor = 250; // List that many extension maximally at one time (fixing memory problems)
205 * Internal variable loaded with extension categories (for display/listing). Should reflect $categories above
208 var $defaultCategories = Array(
215 'services' => array(),
216 'templates' => array(),
217 'example' => array(),
222 var $categories = array(); // Extension Categories (static var); see init()
224 var $states = array(); // Extension States; see init()
227 * Colors for extension states
229 var $stateColors = Array (
230 'alpha' => '#d12438',
232 'stable' => '#3bb65c',
233 'experimental' => '#007eba',
235 'obsolete' => '#000000',
236 'excludeFromUpdates' => '#cf7307'
240 * "TYPE" information; labels, paths, description etc. See init()
242 var $typeLabels = array();
243 var $typeDescr = array();
244 var $typePaths = Array(); // Also static, set in init()
245 var $typeBackPaths = Array(); // Also static, set in init()
247 var $typeRelPaths = Array (
250 'L' => '../typo3conf/ext/',
253 var $detailCols = Array (
262 var $fe_user = array(
267 var $privacyNotice; // Set in init()
268 var $securityHint; // Set in init()
269 var $editTextExtensions = 'html,htm,txt,css,tmpl,inc,php,sql,conf,cnf,pl,pm,sh,xml,ChangeLog';
270 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';
276 // Default variables for backend modules
277 var $MCONF = array(); // Module configuration
278 var $MOD_MENU = array(); // Module menu items
279 var $MOD_SETTINGS = array(); // Module session settings
281 * Document Template Object
286 var $content; // Accumulated content
288 var $inst_keys = array(); // Storage of installed extensions
289 var $gzcompress = 0; // Is set true, if system support compression.
292 * instance of TER connection handler
294 * @var SC_mod_tools_em_terconnection
299 * XML handling class for the TYPO3 Extension Manager
301 * @var SC_mod_tools_em_xmlhandler
304 var $JScode; // JavaScript code to be forwared to $this->doc->JScode
307 var $CMD = array(); // CMD array
308 var $listRemote; // If set, connects to remote repository
309 var $lookUpStr; // Search string when listing local extensions
314 /*********************************
316 * Standard module initialization
318 *********************************/
321 * Standard init function of a module.
326 global $BE_USER,$LANG,$BACK_PATH,$TYPO3_CONF_VARS;
329 * Extension Categories (static var)
330 * Content must be redundant with the same internal variable as in class.tx_extrep.php!
332 $this->categories
= array(
333 'be' => $GLOBALS['LANG']->getLL('category_BE'),
334 'module' => $GLOBALS['LANG']->getLL('category_BE_modules'),
335 'fe' => $GLOBALS['LANG']->getLL('category_FE'),
336 'plugin' => $GLOBALS['LANG']->getLL('category_FE_plugins'),
337 'misc' => $GLOBALS['LANG']->getLL('category_miscellanous'),
338 'services' => $GLOBALS['LANG']->getLL('category_services'),
339 'templates' => $GLOBALS['LANG']->getLL('category_templates'),
340 'example' => $GLOBALS['LANG']->getLL('category_examples'),
341 'doc' => $GLOBALS['LANG']->getLL('category_documentation')
346 * Content must be redundant with the same internal variable as in class.tx_extrep.php!
348 $this->states
= array(
349 'alpha' => $GLOBALS['LANG']->getLL('state_alpha'),
350 'beta' => $GLOBALS['LANG']->getLL('state_beta'),
351 'stable' => $GLOBALS['LANG']->getLL('state_stable'),
352 'experimental' => $GLOBALS['LANG']->getLL('state_experimental'),
353 'test' => $GLOBALS['LANG']->getLL('state_test'),
354 'obsolete' => $GLOBALS['LANG']->getLL('state_obsolete'),
355 'excludeFromUpdates' => $GLOBALS['LANG']->getLL('state_exclude_from_updates')
359 * "TYPE" information; labels, paths, description etc.
361 $this->typeLabels
= array(
362 'S' => $GLOBALS['LANG']->getLL('type_system'),
363 'G' => $GLOBALS['LANG']->getLL('type_global'),
364 'L' => $GLOBALS['LANG']->getLL('type_local'),
366 $this->typeDescr
= array(
367 'S' => $GLOBALS['LANG']->getLL('descr_system'),
368 'G' => $GLOBALS['LANG']->getLL('descr_global'),
369 'L' => $GLOBALS['LANG']->getLL('descr_local'),
372 // Setting paths of install scopes:
373 $this->typePaths
= Array (
374 'S' => TYPO3_mainDir
.'sysext/',
375 'G' => TYPO3_mainDir
.'ext/',
376 'L' => 'typo3conf/ext/'
378 $this->typeBackPaths
= Array (
381 'L' => '../../../../'.TYPO3_mainDir
384 $this->privacyNotice
= $GLOBALS['LANG']->getLL('privacy_notice');
385 $securityMessage = sprintf($GLOBALS['LANG']->getLL('security_descr'),
386 '<a href="http://typo3.org/teams/security/" target="_blank">', '</a>'
388 $flashMessage = t3lib_div
::makeInstance(
389 't3lib_FlashMessage',
391 $GLOBALS['LANG']->getLL('security_header'),
392 t3lib_FlashMessage
::INFO
394 $this->securityHint
= $flashMessage->render();
396 $this->excludeForPackaging
= $GLOBALS['TYPO3_CONF_VARS']['EXT']['excludeForPackaging'];
398 // Setting module configuration:
399 $this->MCONF
= $GLOBALS['MCONF'];
402 $this->CMD
= is_array(t3lib_div
::_GP('CMD')) ? t3lib_div
::_GP('CMD') : array();
403 $this->lookUpStr
= trim(t3lib_div
::_GP('_lookUp'));
404 $this->listRemote
= t3lib_div
::_GP('ter_connect');
405 $this->listRemote_search
= trim(t3lib_div
::_GP('ter_search'));
411 // Setting internal static:
412 if ($TYPO3_CONF_VARS['EXT']['allowSystemInstall']) $this->systemInstall
= 1;
413 $this->requiredExt
= t3lib_div
::trimExplode(',',$TYPO3_CONF_VARS['EXT']['requiredExt'],1);
416 // Initialize helper object
417 $this->terConnection
= t3lib_div
::makeInstance('SC_mod_tools_em_terconnection');
418 $this->terConnection
->emObj
= $this;
419 $this->terConnection
->wsdlURL
= $TYPO3_CONF_VARS['EXT']['em_wsdlURL'];
420 $this->xmlhandler
= t3lib_div
::makeInstance('SC_mod_tools_em_xmlhandler');
421 $this->xmlhandler
->emObj
= $this;
422 $this->xmlhandler
->useUnchecked
= $this->MOD_SETTINGS
['display_unchecked'];
423 $this->xmlhandler
->useObsolete
= $this->MOD_SETTINGS
['display_obsolete'];
425 // Initialize Document Template object:
426 $this->doc
= t3lib_div
::makeInstance('template');
427 $this->doc
->backPath
= $BACK_PATH;
428 $this->doc
->setModuleTemplate('templates/em_index.html');
431 $this->doc
->JScode
= $this->doc
->wrapScriptTags('
433 function jumpToUrl(URL) { //
434 window.location.href = URL;
438 // Reload left frame menu
439 if ($this->CMD
['refreshMenu']) {
440 $this->doc
->JScode
.= $this->doc
->wrapScriptTags('
441 if(top.refreshMenu) {
444 top.TYPO3ModuleMenu.refreshMenu();
451 $this->descrTable
= '_MOD_'.$this->MCONF
['name'];
452 if ($BE_USER->uc
['edit_showFieldHelp']) {
453 $LANG->loadSingleTableDescription($this->descrTable
);
456 // Setting username/password etc. for upload-user:
457 $this->fe_user
['username'] = $this->MOD_SETTINGS
['fe_u'];
458 $this->fe_user
['password'] = $this->MOD_SETTINGS
['fe_p'];
460 $this->handleExternalFunctionValue('singleDetails');
464 * This function is a copy of the same function in t3lib_SCbase with one modification:
465 * In contrast to t3lib_SCbase::handleExternalFunctionValue() this function merges the $this->extClassConf array
466 * instead of overwriting it. That was necessary for including the Kickstarter as a submodule into the 'singleDetails'
467 * selectorbox as well as in the main 'function' selectorbox.
469 * @param string Mod-setting array key
470 * @param string Mod setting value, overriding the one in the key
472 * @see t3lib_SCbase::handleExternalFunctionValue()
474 function handleExternalFunctionValue($MM_key='function', $MS_value=NULL) {
475 $MS_value = is_null($MS_value) ?
$this->MOD_SETTINGS
[$MM_key] : $MS_value;
476 $externalItems = $this->getExternalItemConfig($this->MCONF
['name'],$MM_key,$MS_value);
477 if (is_array($externalItems)) $this->extClassConf
= array_merge($externalItems,is_array($this->extClassConf
)?
$this->extClassConf
:array());
478 if (is_array($this->extClassConf
) && $this->extClassConf
['path']) {
479 $this->include_once[]=$this->extClassConf
['path'];
484 * Configuration of which mod-menu items can be used
488 function menuConfig() {
489 global $BE_USER, $TYPO3_CONF_VARS;
492 $this->MOD_MENU
= array(
494 0 => $GLOBALS['LANG']->getLL('menu_loaded_extensions'),
495 1 => $GLOBALS['LANG']->getLL('menu_install_extensions'),
496 2 => $GLOBALS['LANG']->getLL('menu_import_extensions'),
497 4 => $GLOBALS['LANG']->getLL('menu_translation_handling'),
498 3 => $GLOBALS['LANG']->getLL('menu_settings'),
499 5 => $GLOBALS['LANG']->getLL('menu_extension_updates'),
501 'listOrder' => array(
502 'cat' => $GLOBALS['LANG']->getLL('list_order_category'),
503 'author_company' => $GLOBALS['LANG']->getLL('list_order_author'),
504 'state' => $GLOBALS['LANG']->getLL('list_order_state'),
505 'type' => $GLOBALS['LANG']->getLL('list_order_type'),
507 'display_details' => array(
508 1 => $GLOBALS['LANG']->getLL('show_details'),
509 0 => $GLOBALS['LANG']->getLL('show_description'),
510 2 => $GLOBALS['LANG']->getLL('show_more_details'),
512 3 => $GLOBALS['LANG']->getLL('show_technical'),
513 4 => $GLOBALS['LANG']->getLL('show_validating'),
514 5 => $GLOBALS['LANG']->getLL('show_changed'),
518 'display_unchecked' => '',
519 'display_obsolete' => '',
520 'display_installed' => '',
521 'display_files' => '',
524 'singleDetails' => array(
525 'info' => $GLOBALS['LANG']->getLL('details_info'),
526 'edit' => $GLOBALS['LANG']->getLL('details_edit'),
527 'backup' => $GLOBALS['LANG']->getLL('details_backup_delete'),
528 'dump' => $GLOBALS['LANG']->getLL('details_dump_db'),
529 'upload' => $GLOBALS['LANG']->getLL('details_upload'),
530 'updateModule' => $GLOBALS['LANG']->getLL('details_update'),
535 'mirrorListURL' => '',
538 'selectedMirror' => '',
540 'selectedLanguages' => ''
543 $this->MOD_MENU
['singleDetails'] = $this->mergeExternalItems($this->MCONF
['name'],'singleDetails',$this->MOD_MENU
['singleDetails']);
545 // page/be_user TSconfig settings and blinding of menu-items
546 if (!$BE_USER->getTSConfigVal('mod.'.$this->MCONF
['name'].'.allowTVlisting')) {
547 unset($this->MOD_MENU
['display_details'][3]);
548 unset($this->MOD_MENU
['display_details'][4]);
549 unset($this->MOD_MENU
['display_details'][5]);
553 $this->MOD_SETTINGS
= t3lib_BEfunc
::getModuleData($this->MOD_MENU
, t3lib_div
::_GP('SET'), $this->MCONF
['name']);
555 if ($this->MOD_SETTINGS
['function']==2) {
556 // If listing from online repository, certain items are removed though:
557 unset($this->MOD_MENU
['listOrder']['type']);
558 unset($this->MOD_MENU
['display_details'][2]);
559 unset($this->MOD_MENU
['display_details'][3]);
560 unset($this->MOD_MENU
['display_details'][4]);
561 unset($this->MOD_MENU
['display_details'][5]);
562 $this->MOD_SETTINGS
= t3lib_BEfunc
::getModuleData($this->MOD_MENU
, t3lib_div
::_GP('SET'), $this->MCONF
['name']);
564 parent
::menuConfig();
568 * Main function for Extension Manager module.
573 global $BE_USER,$LANG,$TYPO3_CONF_VARS;
575 if (empty($this->MOD_SETTINGS
['mirrorListURL'])) $this->MOD_SETTINGS
['mirrorListURL'] = $TYPO3_CONF_VARS['EXT']['em_mirrorListURL'];
578 $this->content
.=$this->doc
->header($GLOBALS['LANG']->getLL('header'));
579 $this->content
.=$this->doc
->spacer(5);
581 // Command given which is executed regardless of main menu setting:
582 if ($this->CMD
['showExt']) { // Show details for a single extension
583 $this->showExtDetails($this->CMD
['showExt']);
584 } elseif ($this->CMD
['requestInstallExtensions']) { // Show details for a single extension
585 $this->requestInstallExtensions($this->CMD
['requestInstallExtensions']);
586 } elseif ($this->CMD
['importExt'] ||
$this->CMD
['uploadExt']) { // Imports an extension from online rep.
587 $err = $this->importExtFromRep($this->CMD
['importExt'],$this->CMD
['extVersion'],$this->CMD
['loc'],$this->CMD
['uploadExt']);
589 $this->content
.=$this->doc
->section('',$GLOBALS['TBE_TEMPLATE']->rfw($err));
591 if(!$err && $this->CMD
['importExt']) {
592 $this->installTranslationsForExtension($this->CMD
['importExt'], $this->getMirrorURL());
594 } elseif ($this->CMD
['importExtInfo']) { // Gets detailed information of an extension from online rep.
595 $this->importExtInfo($this->CMD
['importExtInfo'],$this->CMD
['extVersion']);
596 } else { // No command - we show what the menu setting tells us:
597 if (t3lib_div
::inList('0,1,2',$this->MOD_SETTINGS
['function'])) {
598 $menu .= ' ' . $GLOBALS['LANG']->getLL('group_by') . ' ' . t3lib_BEfunc
::getFuncMenu(0, 'SET[listOrder]', $this->MOD_SETTINGS
['listOrder'], $this->MOD_MENU
['listOrder']) .
599 ' ' . $GLOBALS['LANG']->getLL('show') . ' ' . t3lib_BEfunc
::getFuncMenu(0, 'SET[display_details]', $this->MOD_SETTINGS
['display_details'], $this->MOD_MENU
['display_details']) . '<br />';
601 if (t3lib_div
::inList('0,1,5',$this->MOD_SETTINGS
['function'])) {
602 $menu.='<label for="checkDisplayShy">' . $GLOBALS['LANG']->getLL('display_shy') . '</label> ' . t3lib_BEfunc
::getFuncCheck(0, 'SET[display_shy]', $this->MOD_SETTINGS
['display_shy'], '', '', 'id="checkDisplayShy"');
604 if (t3lib_div
::inList('2',$this->MOD_SETTINGS
['function']) && strlen($this->fe_user
['username'])) {
605 $menu.='<label for="checkDisplayOwn">' . $GLOBALS['LANG']->getLL('only_my_ext') . '</label> ' . t3lib_BEfunc
::getFuncCheck(0, 'SET[display_own]', $this->MOD_SETTINGS
['display_own'], '', '', 'id="checkDisplayOwn"');
607 if (t3lib_div
::inList('0,1,2',$this->MOD_SETTINGS
['function'])) {
608 $menu.=' <label for="checkDisplayObsolete">' . $GLOBALS['LANG']->getLL('show_obsolete') . '</label> ' . t3lib_BEfunc
::getFuncCheck(0, 'SET[display_obsolete]', $this->MOD_SETTINGS
['display_obsolete'], '', '', 'id="checkDisplayObsolete"');
611 $this->content
.=$this->doc
->section('','<form action="index.php" method="post" name="pageform"><span class="nobr">'.$menu.'</span></form>');
612 $this->content
.=$this->doc
->spacer(10);
614 switch((string)$this->MOD_SETTINGS
['function']) {
616 // Lists loaded (installed) extensions
617 $this->extensionList_loaded();
620 // Lists the installed (available) extensions
621 $this->extensionList_installed();
624 // Lists the extensions available from online rep.
625 $this->extensionList_import();
628 // Shows the settings screen
629 $this->alterSettings();
632 // Allows to set the translation preferences and check the status
633 $this->translationHandling();
636 // Shows a list of extensions with updates in TER
637 $this->checkForUpdates();
640 $this->extObjContent();
646 $formTags = substr_count($this->content
, '<form') +
substr_count($this->content
, '</form');
647 if ($formTags %
2 > 0) {
648 $this->content
.= '</form>';
651 // Setting up the buttons and markers for docheader
652 $docHeaderButtons = $this->getButtons();
654 'CSH' => $docHeaderButtons['csh'],
655 'FUNC_MENU' => $this->getFuncMenu(),
656 'CONTENT' => $this->content
659 // Build the <body> for the module
660 $this->content
= $this->doc
->startPage('Extension Manager');
661 $this->content
.= $this->doc
->moduleBody($this->pageinfo
, $docHeaderButtons, $markers);
662 $this->content
.= $this->doc
->endPage();
663 $this->content
= $this->doc
->insertStylesAndJS($this->content
);
667 * Print module content. Called as last thing in the global scope.
671 function printContent() {
672 if ($this->doPrintContent
) {
678 * Create the function menu
680 * @return string HTML of the function menu
682 protected function getFuncMenu() {
684 if(!$this->CMD
['showExt'] && !$this->CMD
['requestInstallExtensions'] && !$this->CMD
['importExt'] && !$this->CMD
['uploadExt'] && !$this->CMD
['importExtInfo']) {
685 $funcMenu = t3lib_BEfunc
::getFuncMenu(0, 'SET[function]', $this->MOD_SETTINGS
['function'], $this->MOD_MENU
['function']);
686 } elseif($this->CMD
['showExt'] && (!$this->CMD
['standAlone'] && !t3lib_div
::_GP('standAlone'))) {
687 $funcMenu = t3lib_BEfunc
::getFuncMenu(0, 'SET[singleDetails]', $this->MOD_SETTINGS
['singleDetails'], $this->MOD_MENU
['singleDetails'], '', '&CMD[showExt]=' . $this->CMD
['showExt']);
693 * Create the panel of buttons for submitting the form or otherwise perform operations.
695 * @return array all available buttons as an assoc. array
697 protected function getButtons() {
705 //$buttons['csh'] = t3lib_BEfunc::cshItem('_MOD_web_func', '', $GLOBALS['BACK_PATH']);
708 if ($GLOBALS['BE_USER']->mayMakeShortcut()) {
709 $buttons['shortcut'] = $this->doc
->makeShortcutIcon('CMD','function',$this->MCONF
['name']);
712 if(($this->CMD
['showExt'] && (!$this->CMD
['standAlone'] && !t3lib_div
::_GP('standAlone'))) ||
($this->CMD
['importExt'] ||
$this->CMD
['uploadExt'] && (!$this->CMD
['standAlone'])) ||
$this->CMD
['importExtInfo']) {
713 $buttons['back'] = '<a href="index.php" class="typo3-goBack"><img' . t3lib_iconWorks
::skinImg($this->doc
->backPath
, 'gfx/goback.gif') . ' title="' . $GLOBALS['LANG']->getLL('go_back') . '" class="absmiddle" alt="" /></a>';
726 /*********************************
728 * Function Menu Applications
730 *********************************/
733 * Listing of loaded (installed) extensions
737 function extensionList_loaded() {
738 global $TYPO3_LOADED_EXT;
740 list($list,$cat) = $this->getInstalledExtensions();
746 // Available extensions
747 if (is_array($cat[$this->MOD_SETTINGS
['listOrder']])) {
750 $lines[] = $this->extensionListRowHeader(' class="bgColor5"',array('<td><img src="clear.gif" width="1" height="1" alt="" /></td>'));
752 foreach($cat[$this->MOD_SETTINGS
['listOrder']] as $catName => $extEkeys) {
753 natcasesort($extEkeys);
755 $extensions = array();
756 while(list($extKey)=each($extEkeys)) {
757 if (array_key_exists($extKey,$TYPO3_LOADED_EXT) && ($this->MOD_SETTINGS
['display_shy'] ||
!$list[$extKey]['EM_CONF']['shy']) && $this->searchExtension($extKey,$list[$extKey])) {
758 if (in_array($extKey, $this->requiredExt
)) {
759 $loadUnloadLink = '<strong>' . $GLOBALS['TBE_TEMPLATE']->rfw($GLOBALS['LANG']->getLL('extension_required_short')) . '</strong>';
761 $loadUnloadLink = '<a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[remove]=1').'">'.$this->removeButton().'</a>';
764 $extensions[] = $this->extensionListRow($extKey,$list[$extKey],array('<td class="bgColor">'.$loadUnloadLink.'</td>'));
767 if(count($extensions)) {
768 $lines[]='<tr><td colspan="'.(3+
$this->detailCols
[$this->MOD_SETTINGS
['display_details']]).'"><br /></td></tr>';
769 $lines[]='<tr><td colspan="'.(3+
$this->detailCols
[$this->MOD_SETTINGS
['display_details']]).'"><img '.t3lib_iconWorks
::skinImg($GLOBALS['BACK_PATH'],'gfx/i/sysf.gif"', 'width="18" height="16"').' align="top" alt="" /><strong>'.$this->listOrderTitle($this->MOD_SETTINGS
['listOrder'],$catName).'</strong></td></tr>';
770 $lines[] = implode(chr(10),$extensions);
775 $content.= t3lib_BEfunc
::cshItem('_MOD_tools_em', 'loaded', $GLOBALS['BACK_PATH'],'');
776 $content.= '<form action="index.php" method="post" name="lookupform">';
777 $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 />';
781 <!-- Loaded Extensions List -->
782 <table border="0" cellpadding="2" cellspacing="1">'.implode('',$lines).'</table>';
784 $this->content
.=$this->doc
->section($GLOBALS['LANG']->getLL('loaded_exts'),$content,0,1);
788 * Listing of available (installed) extensions
792 function extensionList_installed() {
793 global $TYPO3_LOADED_EXT;
795 list($list,$cat)=$this->getInstalledExtensions();
797 // Available extensions
798 if (is_array($cat[$this->MOD_SETTINGS
['listOrder']])) {
801 $lines[]=$this->extensionListRowHeader(' class="bgColor5"',array('<td><img src="clear.gif" width="18" height="1" alt="" /></td>'));
804 foreach($cat[$this->MOD_SETTINGS
['listOrder']] as $catName => $extEkeys) {
805 if(!$this->MOD_SETTINGS
['display_obsolete'] && $catName=='obsolete') continue;
808 $allKeys[]='TYPE: '.$catName;
810 natcasesort($extEkeys);
812 $extensions = array();
813 while(list($extKey)=each($extEkeys)) {
815 if ((!$list[$extKey]['EM_CONF']['shy'] ||
$this->MOD_SETTINGS
['display_shy']) &&
816 ($list[$extKey]['EM_CONF']['state']!='obsolete' ||
$this->MOD_SETTINGS
['display_obsolete'])
817 && $this->searchExtension($extKey,$list[$extKey])) {
818 $loadUnloadLink = t3lib_extMgm
::isLoaded($extKey)?
819 '<a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[remove]=1&CMD[clrCmd]=1&SET[singleDetails]=info').'">'.$this->removeButton().'</a>':
820 '<a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[load]=1&CMD[clrCmd]=1&SET[singleDetails]=info').'">'.$this->installButton().'</a>';
821 if (in_array($extKey,$this->requiredExt
)) {
822 $loadUnloadLink = '<strong>' . $GLOBALS['TBE_TEMPLATE']->rfw($GLOBALS['LANG']->getLL('extension_required_short')) . '</strong>';
824 $theRowClass = t3lib_extMgm
::isLoaded($extKey)?
'em-listbg1' : 'em-listbg2';
825 $extensions[]=$this->extensionListRow($extKey,$list[$extKey],array('<td class="bgColor">'.$loadUnloadLink.'</td>'),$theRowClass);
828 if(count($extensions)) {
829 $lines[]='<tr><td colspan="'.(3+
$this->detailCols
[$this->MOD_SETTINGS
['display_details']]).'"><br /></td></tr>';
830 $lines[]='<tr><td colspan="'.(3+
$this->detailCols
[$this->MOD_SETTINGS
['display_details']]).'"><img '.t3lib_iconWorks
::skinImg($GLOBALS['BACK_PATH'],'gfx/i/sysf.gif"', 'width="18" height="16"').'align="top" alt="" /><strong>'.$this->listOrderTitle($this->MOD_SETTINGS
['listOrder'],$catName).'</strong></td></tr>';
831 $lines[] = implode(chr(10),$extensions);
841 '.trim(implode(chr(10),$allKeys)).'
847 $content.= t3lib_BEfunc
::cshItem('_MOD_tools_em', 'avail', $GLOBALS['BACK_PATH'], '|<br />');
848 $content.= sprintf($GLOBALS['LANG']->getLL('how_to_install'), $this->installButton()) . ' <br />' .
849 sprintf($GLOBALS['LANG']->getLL('how_to_uninstall'), $this->removeButton()). ' <br /><br />';
850 $content .= '<form action="index.php" method="post" name="lookupform">';
851 $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 />';
852 $content.= $this->securityHint
.'<br /><br />';
854 $content.= '<table border="0" cellpadding="2" cellspacing="1">'.implode('',$lines).'</table>';
856 $this->content
.=$this->doc
->section(sprintf($GLOBALS['LANG']->getLL('available_extensions'), $this->MOD_MENU
['listOrder'][$this->MOD_SETTINGS
['listOrder']]),$content,0,1);
861 * Listing remote extensions from online repository
865 function extensionList_import() {
866 global $TYPO3_LOADED_EXT;
869 // Listing from online repository:
870 if ($this->listRemote
) {
871 list($inst_list,) = $this->getInstalledExtensions();
872 $this->inst_keys
= array_flip(array_keys($inst_list));
874 $this->detailCols
[1]+
=6;
876 // see if we have an extensionlist at all
877 $this->extensionCount
= $this->xmlhandler
->countExtensions();
878 if (!$this->extensionCount
) {
879 $content .= $this->fetchMetaData('extensions');
882 if($this->MOD_SETTINGS
['listOrder']=='author_company') {
883 $this->listingLimit
= $this->listingLimitAuthor
;
886 $this->pointer
= intval(t3lib_div
::_GP('pointer'));
887 $offset = $this->listingLimit
*$this->pointer
;
889 if($this->MOD_SETTINGS
['display_own'] && strlen($this->fe_user
['username'])) {
890 $this->xmlhandler
->searchExtensionsXML($this->listRemote_search
, $this->fe_user
['username'], $this->MOD_SETTINGS
['listOrder']);
892 $this->xmlhandler
->searchExtensionsXML($this->listRemote_search
, '', $this->MOD_SETTINGS
['listOrder'], false, false, $offset, $this->listingLimit
);
894 if (count($this->xmlhandler
->extensionsXML
)) {
895 list($list,$cat) = $this->prepareImportExtList(true);
897 // Available extensions
898 if (is_array($cat[$this->MOD_SETTINGS
['listOrder']])) {
900 $lines[]=$this->extensionListRowHeader(' class="bgColor5"',array('<td><img src="clear.gif" width="18" height="1" alt="" /></td>'),1);
902 foreach($cat[$this->MOD_SETTINGS
['listOrder']] as $catName => $extEkeys) {
903 if (count($extEkeys)) {
904 $lines[]='<tr><td colspan="'.(3+
$this->detailCols
[$this->MOD_SETTINGS
['display_details']]).'"><br /></td></tr>';
905 $lines[]='<tr><td colspan="'.(3+
$this->detailCols
[$this->MOD_SETTINGS
['display_details']]).'"><img '.t3lib_iconWorks
::skinImg($GLOBALS['BACK_PATH'],'gfx/i/sysf.gif"', 'width="18" height="16"').'align="top" alt="" /><strong>'.$this->listOrderTitle($this->MOD_SETTINGS
['listOrder'],$catName).'</strong></td></tr>';
907 natcasesort($extEkeys);
909 while(list($extKey)=each($extEkeys)) {
910 $version = array_keys($list[$extKey]['versions']);
911 $version = end($version);
912 $ext = $list[$extKey]['versions'][$version];
913 $ext['downloadcounter_all'] = $list[$extKey]['downloadcounter'];
914 $ext['_ICON'] = $list[$extKey]['_ICON'];
916 if ($inst_list[$extKey]['type']!='S' && (!isset($inst_list[$extKey]) ||
$this->versionDifference($version,$inst_list[$extKey]['EM_CONF']['version'],$this->versionDiffFactor
))) {
917 if (isset($inst_list[$extKey])) {
919 if ($inst_list[$extKey]['EM_CONF']['state'] != 'excludeFromUpdates') {
920 $loc= ($inst_list[$extKey]['type']=='G'?
'G':'L');
921 $aUrl = 'index.php?CMD[importExt]='.$extKey.'&CMD[extVersion]='.$version.'&CMD[loc]='.$loc;
922 $loadUnloadLink .= '<a href="' . htmlspecialchars($aUrl) . '"><img src="' . $GLOBALS['BACK_PATH'] . 'gfx/import_update.gif" width="12" height="12" title="' . sprintf($GLOBALS['LANG']->getLL('do_update'), ($loc == 'G' ?
$GLOBALS['LANG']->getLL('global') : $GLOBALS['LANG']->getLL('local'))) . '" alt="" /></a>';
924 // extension is marked as "excludeFromUpdates"
925 $loadUnloadLink .= '<img src="' . $GLOBALS['BACK_PATH'] . 'gfx/icon_warning.gif" width="18" height="16" title="' . $GLOBALS['LANG']->getLL('excluded_from_updates') . '" alt="" />';
929 $aUrl = 'index.php?CMD[importExt]='.$extKey.'&CMD[extVersion]='.$version.'&CMD[loc]=L';
930 $loadUnloadLink .= '<a href="' . htmlspecialchars($aUrl) . '"><img src="' . $GLOBALS['BACK_PATH'] . 'gfx/import.gif" width="12" height="12" title="' . $GLOBALS['LANG']->getLL('import_to_local_dir') . '" alt="" /></a>';
933 $loadUnloadLink = ' ';
936 if (isset($inst_list[$extKey])) {
937 $theRowClass = t3lib_extMgm
::isLoaded($extKey) ?
'em-listbg1' : 'em-listbg2';
939 $theRowClass = 'em-listbg3';
942 $lines[]=$this->extensionListRow($extKey,$ext,array('<td class="bgColor">'.$loadUnloadLink.'</td>'),$theRowClass,$inst_list,1,'index.php?CMD[importExtInfo]='.rawurlencode($extKey));
943 unset($list[$extKey]);
950 $content .= t3lib_BEfunc
::cshItem('_MOD_tools_em', 'import_ter', $GLOBALS['BACK_PATH'], '|<br />');
951 $onsubmit = "window.location.href='index.php?ter_connect=1&ter_search='+escape(this.elements['_lookUp'].value);return false;";
952 $content .= '<form action="index.php" method="post" onsubmit="' . htmlspecialchars($onsubmit) .
953 '"><label for="_lookUp">' .
954 sprintf($GLOBALS['LANG']->getLL('list_or_look_up'),
955 ($this->MOD_SETTINGS
['display_unchecked'] ?
956 '<strong style="color:#900;">' . $GLOBALS['LANG']->getLL('list_or_look_up_all') . '</strong>'
957 : '<strong style="color:#090;">' . $GLOBALS['LANG']->getLL('list_or_look_up_reviewed') . '</strong>'
961 <input type="text" id="_lookUp" name="_lookUp" value="' . htmlspecialchars($this->listRemote_search
) .
962 '" /> <input type="submit" value="' . $GLOBALS['LANG']->getLL('look_up_button') . '" /></form><br /><br />';
964 $content .= $this->browseLinks();
968 <!-- TER Extensions list -->
969 <table border="0" cellpadding="2" cellspacing="1">'.implode(chr(10),$lines).'</table>';
970 $content .= '<br />'.$this->browseLinks();
971 $content.= '<br /><br />'.$this->securityHint
;
972 $content .= '<br /><br /><strong>' . $GLOBALS['LANG']->getLL('privacy_notice_header') .
973 '</strong><br /> ' . $this->privacyNotice
;
975 $this->content
.= $this->doc
->section($GLOBALS['LANG']->getLL('extensions_repository_group_by') . ' ' .
976 $this->MOD_MENU
['listOrder'][$this->MOD_SETTINGS
['listOrder']], $content, 0, 1);
978 // Plugins which are NOT uploaded to repository but present on this server.
981 if (count($this->inst_keys
)) {
982 reset($this->inst_keys
);
983 while(list($extKey)=each($this->inst_keys
)) {
984 $this->xmlhandler
->searchExtensionsXMLExact($extKey, '', '', true);
985 if((strlen($this->listRemote_search
) && !stristr($extKey,$this->listRemote_search
)) ||
isset($this->xmlhandler
->extensionsXML
[$extKey])) continue;
987 $loadUnloadLink = t3lib_extMgm
::isLoaded($extKey)?
988 '<a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[remove]=1&CMD[clrCmd]=1&SET[singleDetails]=info').'">'.$this->removeButton().'</a>':
989 '<a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[load]=1&CMD[clrCmd]=1&SET[singleDetails]=info').'">'.$this->installButton().'</a>';
990 if (in_array($extKey,$this->requiredExt
)) {
991 $loadUnloadLink = '<strong>' .$GLOBALS['TBE_TEMPLATE']->rfw($GLOBALS['LANG']->getLL('extension_required_short')) . '</strong>';
993 $lines[]=$this->extensionListRow($extKey,$inst_list[$extKey],array('<td class="bgColor">'.$loadUnloadLink.'</td>'),t3lib_extMgm
::isLoaded($extKey)?
'em-listbg1':'em-listbg2');
997 $content .= $GLOBALS['LANG']->getLL('list_of_local_extensions') .
998 '<br />' . $GLOBALS['LANG']->getLL('might_be_user_defined') . '<br /><br />';
999 $content.= '<table border="0" cellpadding="2" cellspacing="1">'.
1000 $this->extensionListRowHeader(' class="bgColor5"',array('<td><img src="clear.gif" width="18" height="1" alt="" /></td>')).
1001 implode('',$lines).'</table>';
1002 $this->content
.=$this->doc
->spacer(20);
1003 $this->content
.=$this->doc
->section($GLOBALS['LANG']->getLL('only_on_this_server'), $content, 0, 1);
1007 $content .= t3lib_BEfunc
::cshItem('_MOD_tools_em', 'import_ter', $GLOBALS['BACK_PATH'], '|<br />');
1008 $onsubmit = "window.location.href='index.php?ter_connect=1&ter_search='+escape(this.elements['_lookUp'].value);return false;";
1009 $content .= '<form action="index.php" method="post" onsubmit="' . htmlspecialchars($onsubmit) .
1010 '"><label for="_lookUp">' .
1011 sprintf($GLOBALS['LANG']->getLL('list_or_look_up'),
1012 ($this->MOD_SETTINGS
['display_unchecked'] ?
1013 '<strong style="color:#900;">' . $GLOBALS['LANG']->getLL('list_or_look_up_all') . '</strong>'
1014 : '<strong style="color:#090;">' . $GLOBALS['LANG']->getLL('list_or_look_up_reviewed') . '</strong>'
1018 <input type="text" id="_lookUp" name="_lookUp" value="' . htmlspecialchars($this->listRemote_search
) .
1019 '" /> <input type="submit" value="' . $GLOBALS['LANG']->getLL('look_up_button') . '" /></form><br /><br />';
1021 $content .= '<p><strong>' . $GLOBALS['LANG']->getLL('no_matching_extensions') . '</strong></p>';
1023 $content .= '<br /><br /><strong>' . $GLOBALS['LANG']->getLL('privacy_notice_header') .
1024 '</strong><br /> ' . $this->privacyNotice
;
1025 $this->content
.=$this->doc
->section($GLOBALS['LANG']->getLL('extensions_repository_group_by') . ' ' .
1026 $this->MOD_MENU
['listOrder'][$this->MOD_SETTINGS
['listOrder']], $content, 0, 1);
1030 $content .= t3lib_BEfunc
::cshItem('_MOD_tools_em', 'import', $GLOBALS['BACK_PATH'], '|<br />');
1032 $onsubmit = "window.location.href='index.php?ter_connect=1&ter_search='+escape(this.elements['_lookUp'].value);return false;";
1033 $content .= '<form action="index.php" method="post" onsubmit="' . htmlspecialchars($onsubmit) .
1034 '"><label for="_lookUp">' .
1035 sprintf($GLOBALS['LANG']->getLL('list_or_look_up'),
1036 ($this->MOD_SETTINGS
['display_unchecked'] ?
1037 '<strong style="color:#900;">' . $GLOBALS['LANG']->getLL('list_or_look_up_all') . '</strong>'
1038 : '<strong style="color:#090;">' . $GLOBALS['LANG']->getLL('list_or_look_up_reviewed') . '</strong>'
1042 <input type="text" id="_lookUp" name="_lookUp" value="" /> <input type="submit" value="' .
1043 $GLOBALS['LANG']->getLL('look_up_button') . '" /><br /><br />';
1045 if ($this->CMD
['fetchMetaData']) { // fetches mirror/extension data from online rep.
1046 $content .= $this->fetchMetaData($this->CMD
['fetchMetaData']);
1048 $onCLick = "window.location.href='index.php?CMD[fetchMetaData]=extensions';return false;";
1049 $content .= $GLOBALS['LANG']->getLL('connect_to_ter') . '<br />
1050 <input type="submit" value="' . $GLOBALS['LANG']->getLL('retrieve_update') .
1051 '" onclick="' . htmlspecialchars($onCLick) . '" />';
1052 if (is_file(PATH_site
.'typo3temp/extensions.xml.gz')) {
1053 $dateFormat = $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'];
1054 $timeFormat = $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'];
1055 $content .= ' ' . sprintf($GLOBALS['LANG']->getLL('ext_list_last_updated') . ' ',
1057 $dateFormat . ', ' . $timeFormat,
1058 filemtime(PATH_site
. 'typo3temp/extensions.xml.gz')
1063 $content.= '</form><br /><br />'.$this->securityHint
;
1064 $content .= '<br /><br /><strong>' . $GLOBALS['LANG']->getLL('privacy_notice_header') .
1065 '</strong><br />' . $this->privacyNotice
;
1067 $this->content
.=$this->doc
->section($GLOBALS['LANG']->getLL('in_repository'), $content, 0, 1);
1071 if ($this->importAtAll()) {
1072 $content= '<form action="index.php" enctype="'.$GLOBALS['TYPO3_CONF_VARS']['SYS']['form_enctype'].'" method="post">
1073 <label for="upload_ext_file">' . $GLOBALS['LANG']->getLL('upload_t3x') . '</label><br />
1074 <input type="file" size="60" id="upload_ext_file" name="upload_ext_file" /><br />' .
1075 $GLOBALS['LANG']->getLL('upload_to_location') . '<br />
1076 <select name="CMD[loc]">';
1077 if ($this->importAsType('L')) $content .= '<option value="L">' . $GLOBALS['LANG']->getLL('local_folder') . '</option>';
1078 if ($this->importAsType('G')) $content .= '<option value="G">' . $GLOBALS['LANG']->getLL('global_folder') . '</option>';
1079 if ($this->importAsType('S')) $content .= '<option value="S">' . $GLOBALS['LANG']->getLL('system_folder') . '</option>';
1080 $content.='</select><br />
1081 <input type="checkbox" value="1" name="CMD[uploadOverwrite]" id="checkUploadOverwrite" /> <label for="checkUploadOverwrite">' .
1082 $GLOBALS['LANG']->getLL('overwrite_ext') . '</label><br />
1083 <input type="submit" name="CMD[uploadExt]" value="' . $GLOBALS['LANG']->getLL('upload_ext_file') . '" /></form><br />
1085 } else $content=$this->noImportMsg();
1087 $this->content
.=$this->doc
->spacer(20);
1088 $this->content
.= $this->doc
->section($GLOBALS['LANG']->getLL('upload_ext_directly'), $content, 0, 1);
1092 * Generates a link to the next page of extensions
1096 function browseLinks() {
1098 if ($this->pointer
) {
1099 $content .= '<a href="' . t3lib_div
::linkThisScript(array('pointer' => $this->pointer
-1)) .
1100 '" class="typo3-prevPage"><img' . t3lib_iconWorks
::skinImg($GLOBALS['BACK_PATH'],
1101 'gfx/pilleft_n.gif', 'width="14" height="14"') .
1102 ' alt="' . $GLOBALS['LANG']->getLL('previous_page') . '" /> ' .
1103 $GLOBALS['LANG']->getLL('previous_page') . '</a>';
1105 if ($content) $content .= ' ';
1106 if (intval($this->xmlhandler
->matchingCount
/$this->listingLimit
)>$this->pointer
) {
1107 $content .= '<a href="' . t3lib_div
::linkThisScript(array('pointer' => $this->pointer+
1)) .
1108 '" class="typo3-nextPage"><img' . t3lib_iconWorks
::skinImg($GLOBALS['BACK_PATH'],
1109 'gfx/pilright_n.gif', 'width="14" height="14"') .
1110 ' alt="' . $GLOBALS['LANG']->getLL('next_page') . '" /> ' .
1111 $GLOBALS['LANG']->getLL('next_page') . '</a>';
1113 $upper = (($this->pointer+
1)*$this->listingLimit
);
1114 if ($upper>$this->xmlhandler
->matchingCount
) {
1115 $upper = $this->xmlhandler
->matchingCount
;
1117 if ($content) $content .= '<br /><br />' .
1118 sprintf($GLOBALS['LANG']->getLL('showing_extensions_from_to'),
1119 '<strong>' . ($this->pointer
*$this->listingLimit+
1) . '</strong>',
1120 '<strong>' . $upper . '</strong>'
1122 if ($content) $content .= '<br /><br />';
1127 * Allows changing of settings
1131 function alterSettings() {
1133 // Prepare the HTML output:
1135 ' . t3lib_BEfunc
::cshItem('_MOD_tools_em', 'settings', $GLOBALS['BACK_PATH'], '|<br />') . '
1136 <form action="index.php" method="post" name="altersettings">
1137 <fieldset><legend>' . $GLOBALS['LANG']->getLL('security_settings') . '</legend>
1138 <table border="0" cellpadding="2" cellspacing="2">
1139 <tr class="bgColor4">
1140 <td><label for="display_unchecked">' . $GLOBALS['LANG']->getLL('show_exts_without_security_check') . '</label></td>
1141 <td>'.t3lib_BEfunc
::getFuncCheck(0,'SET[display_unchecked]',$this->MOD_SETTINGS
['display_unchecked'],'','','id="display_unchecked"').'</td>
1144 <strong>' . $GLOBALS['LANG']->getLL('notice') . '</strong> ' .
1145 sprintf($GLOBALS['LANG']->getLL('security_notice'),
1146 '<a href="http://typo3.org/extensions/what-are-reviews/" target="_blank">', '</a>'
1151 <fieldset><legend>' . $GLOBALS['LANG']->getLL('user_settings') . '</legend>
1152 <table border="0" cellpadding="2" cellspacing="2">
1153 <tr class="bgColor4">
1154 <td><label for="set_fe_u">' . $GLOBALS['LANG']->getLL('enter_repository_username') . '</label></td>
1155 <td><input type="text" id="set_fe_u" name="SET[fe_u]" value="'.htmlspecialchars($this->MOD_SETTINGS
['fe_u']).'" /></td>
1157 <tr class="bgColor4">
1158 <td><label for="set_fe_p">' . $GLOBALS['LANG']->getLL('enter_repository_password') . '</label></td>
1159 <td><input type="password" id="set_fe_p" name="SET[fe_p]" value="'.htmlspecialchars($this->MOD_SETTINGS
['fe_p']).'" /></td>
1162 <strong>' . $GLOBALS['LANG']->getLL('notice') . '</strong> ' .
1163 $GLOBALS['LANG']->getLL('repository_password_info') . '
1167 <fieldset><legend>' . $GLOBALS['LANG']->getLL('mirror_selection') . '</legend>
1168 <table border="0" cellpadding="2" cellspacing="2">
1169 <tr class="bgColor4">
1170 <td><label for="set_mirror_list_url">' . $GLOBALS['LANG']->getLL('mirror_list_url') . '</label></a></td>
1171 <td><input type="text" size="50" id="set_mirror_list_url" name="SET[mirrorListURL]" value="'.htmlspecialchars($this->MOD_SETTINGS
['mirrorListURL']).'" /></td>
1175 <p>' . $GLOBALS['LANG']->getLL('mirror_select') . '<br /><br /></p>
1176 <fieldset><legend>' . $GLOBALS['LANG']->getLL('mirror_list') . '</legend>';
1177 if(!empty($this->MOD_SETTINGS
['mirrorListURL'])) {
1178 if ($this->CMD
['fetchMetaData']) { // fetches mirror/extension data from online rep.
1179 $content .= $this->fetchMetaData($this->CMD
['fetchMetaData']);
1181 $content .= '<a href="index.php?CMD[fetchMetaData]=mirrors">' . $GLOBALS['LANG']->getLL('mirror_list_reload') . '</a>';
1185 <table cellspacing="4" style="text-align:left; vertical-alignment:top;">
1187 <td>' . $GLOBALS['LANG']->getLL('mirror_use') . '</td>
1188 <td>' . $GLOBALS['LANG']->getLL('mirror_name') . '</td>
1189 <td>' . $GLOBALS['LANG']->getLL('mirror_url') . '</td>
1190 <td>' . $GLOBALS['LANG']->getLL('mirror_country') . '</td>
1191 <td>' . $GLOBALS['LANG']->getLL('mirror_sponsored_by') . '</td>
1195 if (!strlen($this->MOD_SETTINGS
['extMirrors'])) $this->fetchMetaData('mirrors');
1196 $extMirrors = unserialize($this->MOD_SETTINGS
['extMirrors']);
1197 $extMirrors[''] = array('title'=>$GLOBALS['LANG']->getLL('mirror_use_random'));
1199 if(is_array($extMirrors)) {
1200 foreach($extMirrors as $k => $v) {
1201 if(isset($v['sponsor'])) {
1202 $sponsor = '<a href="'.htmlspecialchars($v['sponsor']['link']).'" target="_new"><img src="'.$v['sponsor']['logo'].'" title="'.htmlspecialchars($v['sponsor']['name']).'" alt="'.htmlspecialchars($v['sponsor']['name']).'" /></a>';
1204 $selected = ($this->MOD_SETTINGS
['selectedMirror']==$k) ?
'checked="checked"' : '';
1205 $content.='<tr class="bgColor4">
1206 <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>';
1213 <table border="0" cellpadding="2" cellspacing="2">
1214 <tr class="bgColor4">
1215 <td><label for="set_rep_url">' . $GLOBALS['LANG']->getLL('enter_repository_url') . '</label></td>
1216 <td><input type="text" size="50" id="set_rep_url" name="SET[rep_url]" value="'.htmlspecialchars($this->MOD_SETTINGS
['rep_url']).'" /></td>
1220 ' . $GLOBALS['LANG']->getLL('repository_url_hint') . '<br />
1223 <input type="submit" value="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_tsfe.xml:update') . '" />
1227 $this->content
.= $this->doc
->section($GLOBALS['LANG']->getLL('repository_settings'), $content, 0, 1);
1231 * Allows to set the translation preferences and check the status
1235 function translationHandling() {
1236 global $LANG, $TYPO3_LOADED_EXT;
1237 $LANG->includeLLFile('EXT:setup/mod/locallang.xml');
1240 $docHeaderButtons = $this->getButtons();
1242 'CSH' => $docHeaderButtons['csh'],
1243 'FUNC_MENU' => $this->getFuncMenu(),
1247 $incoming = t3lib_div
::_POST('SET');
1248 if(isset($incoming['selectedLanguages']) && is_array($incoming['selectedLanguages'])) {
1249 t3lib_BEfunc
::getModuleData($this->MOD_MENU
, array('selectedLanguages' => serialize($incoming['selectedLanguages'])), $this->MCONF
['name'], '', 'selectedLanguages');
1250 $this->MOD_SETTINGS
['selectedLanguages'] = serialize($incoming['selectedLanguages']);
1253 $selectedLanguages = unserialize($this->MOD_SETTINGS
['selectedLanguages']);
1254 if(count($selectedLanguages)==1 && empty($selectedLanguages[0])) $selectedLanguages = array();
1255 $theLanguages = t3lib_div
::trimExplode('|',TYPO3_languages
);
1256 foreach($theLanguages as $val) {
1257 if ($val!='default') {
1258 $localLabel = ' - ['.htmlspecialchars($GLOBALS['LOCAL_LANG']['default']['lang_'.$val]).']';
1259 $selected = (is_array($selectedLanguages) && in_array($val, $selectedLanguages)) ?
' selected="selected"' : '';
1260 $opt[$GLOBALS['LOCAL_LANG']['default']['lang_'.$val].'--'.$val]='
1261 <option value="'.$val.'"'.$selected.'>'.$LANG->getLL('lang_'.$val,1).$localLabel.'</option>';
1266 // Prepare the HTML output:
1268 ' . t3lib_BEfunc
::cshItem('_MOD_tools_em', 'translation', $GLOBALS['BACK_PATH'], '|<br />') . '
1269 <form action="index.php" method="post" name="translationform">
1270 <fieldset><legend>' . $GLOBALS['LANG']->getLL('translation_settings') . '</legend>
1271 <table border="0" cellpadding="2" cellspacing="2">
1272 <tr class="bgColor4">
1273 <td>' . $GLOBALS['LANG']->getLL('languages_to_fetch') . '</td>
1275 <select name="SET[selectedLanguages][]" multiple="multiple" size="10">
1283 <p>' . $GLOBALS['LANG']->getLL('translation_info') . '<br />
1284 <br />' . $GLOBALS['LANG']->getLL('translation_loaded_exts') . '</p>
1287 <input type="submit" value="' . $GLOBALS['LANG']->getLL('translation_save_selection') . '" />
1292 $this->content
.= $this->doc
->section($GLOBALS['LANG']->getLL('translation_settings'), $content, 0, 1);
1294 if(count($selectedLanguages)>0) {
1295 $mirrorURL = $this->getMirrorURL();
1296 $content = '<input type="button" value="' . $GLOBALS['LANG']->getLL('translation_check_status_button') .
1297 '" onclick="document.location.href=\'' . t3lib_div
::linkThisScript(array('l10n'=>'check')) .
1298 '\'" /> <input type="button" value="' . $GLOBALS['LANG']->getLL('translation_update_button') .
1299 '" onclick="document.location.href=\'' . t3lib_div
::linkThisScript(array('l10n'=>'update')) .
1302 if(t3lib_div
::_GET('l10n') == 'check') {
1303 $loadedExtensions = array_keys($TYPO3_LOADED_EXT);
1304 $loadedExtensions = array_diff($loadedExtensions,array('_CACHEFILE'));
1306 // Override content output - we now do that ourselves:
1307 $this->content
.= $this->doc
->section($GLOBALS['LANG']->getLL('translation_status'), $content, 0, 1);
1308 // Setting up the buttons and markers for docheader
1309 $content = $this->doc
->startPage('Extension Manager');
1310 $content.= $this->doc
->moduleBody($this->pageinfo
, $docHeaderButtons, $markers);
1311 $contentParts=explode('###CONTENT###',$content);
1313 echo $contentParts[0].$this->content
;
1315 $this->doPrintContent
= FALSE;
1321 <p id="progress-message">
1322 ' . $GLOBALS['LANG']->getLL('translation_check_status') . '
1325 <div style="width:100%; height:20px; border: 1px solid black;">
1326 <div id="progress-bar" style="float: left; width: 0%; height: 20px; background-color:green;"> </div>
1327 <div id="transparent-bar" style="float: left; width: 100%; height: 20px; background-color:'.$this->doc
->bgColor2
.';"> </div>
1330 <br /><p>' . $GLOBALS['LANG']->getLL('translation_table_check') . '</p><br />
1331 <table border="0" cellpadding="2" cellspacing="2">
1332 <tr class="bgColor2"><td>' . $GLOBALS['LANG']->getLL('translation_extension_key') . '</td>
1335 foreach($selectedLanguages as $lang) {
1336 echo ('<td>'.$LANG->getLL('lang_'.$lang,1).'</td>');
1341 foreach($loadedExtensions as $extKey) {
1343 $percentDone = intval (($counter / count($loadedExtensions)) * 100);
1346 document.getElementById("progress-bar").style.width = "'.$percentDone.'%";
1347 document.getElementById("transparent-bar").style.width = "'.(100-$percentDone).'%";
1348 document.getElementById("progress-message").firstChild.data="' .
1349 sprintf($GLOBALS['LANG']->getLL('translation_checking_extension'), $extKey) . '";
1354 $translationStatusArr = $this->terConnection
->fetchTranslationStatus($extKey,$mirrorURL);
1356 echo ('<tr class="bgColor4"><td>'.$extKey.'</td>');
1357 foreach($selectedLanguages as $lang) {
1358 // remote unknown -> no l10n available
1359 if(!isset($translationStatusArr[$lang])) {
1360 echo ('<td title="' . $GLOBALS['LANG']->getLL('translation_no_translation') . '">' .
1361 $GLOBALS['LANG']->getLL('translation_n_a') . '</td>');
1364 // determine local md5 from zip
1365 if(is_file(PATH_site
.'typo3temp/'.$extKey.'-l10n-'.$lang.'.zip')) {
1366 $localmd5 = md5_file(PATH_site
.'typo3temp/'.$extKey.'-l10n-'.$lang.'.zip');
1368 echo ('<td title="' . $GLOBALS['LANG']->getLL('translation_not_installed') .
1369 '" style="background-color:#ff0">' . $GLOBALS['LANG']->getLL('translation_status_unknown') .
1373 // local!=remote -> needs update
1374 if($localmd5 != $translationStatusArr[$lang]['md5']) {
1375 echo ('<td title="' . $GLOBALS['LANG']->getLL('translation_needs_update') .
1376 '" style="background-color:#ff0">' . $GLOBALS['LANG']->getLL('translation_status_update') .
1380 echo ('<td title="' . $GLOBALS['LANG']->getLL('translation_is_ok') .
1381 '" style="background-color:#69a550">' . $GLOBALS['LANG']->getLL('translation_status_ok') .
1390 document.getElementById("progress-message").firstChild.data="' .
1391 $GLOBALS['LANG']->getLL('translation_check_done') . '";
1394 echo $contentParts[1] . $this->doc
->endPage();
1397 } elseif(t3lib_div
::_GET('l10n') == 'update') {
1398 $loadedExtensions = array_keys($TYPO3_LOADED_EXT);
1399 $loadedExtensions = array_diff($loadedExtensions,array('_CACHEFILE'));
1401 // Override content output - we now do that ourselves:
1402 $this->content
.= $this->doc
->section($GLOBALS['LANG']->getLL('translation_status'), $content, 0, 1);
1403 // Setting up the buttons and markers for docheader
1404 $content = $this->doc
->startPage('Extension Manager');
1405 $content.= $this->doc
->moduleBody($this->pageinfo
, $docHeaderButtons, $markers);
1406 $contentParts=explode('###CONTENT###',$content);
1408 echo $contentParts[0].$this->content
;
1410 $this->doPrintContent
= FALSE;
1416 <p id="progress-message">
1417 ' . $GLOBALS['LANG']->getLL('translation_update_status') . '
1420 <div style="width:100%; height:20px; border: 1px solid black;">
1421 <div id="progress-bar" style="float: left; width: 0%; height: 20px; background-color:green;"> </div>
1422 <div id="transparent-bar" style="float: left; width: 100%; height: 20px; background-color:'.$this->doc
->bgColor2
.';"> </div>
1425 <br /><p>' . $GLOBALS['LANG']->getLL('translation_table_update') . '<br />
1426 <em>' . $GLOBALS['LANG']->getLL('translation_full_check_update') . '</em></p><br />
1427 <table border="0" cellpadding="2" cellspacing="2">
1428 <tr class="bgColor2"><td>' . $GLOBALS['LANG']->getLL('translation_extension_key') . '</td>
1431 foreach($selectedLanguages as $lang) {
1432 echo '<td>'.$LANG->getLL('lang_'.$lang,1).'</td>';
1437 foreach($loadedExtensions as $extKey) {
1438 $percentDone = intval (($counter / count($loadedExtensions)) * 100);
1441 document.getElementById("progress-bar").style.width = "'.$percentDone.'%";
1442 document.getElementById("transparent-bar").style.width = "'.(100-$percentDone).'%";
1443 document.getElementById("progress-message").firstChild.data="' .
1444 sprintf($GLOBALS['LANG']->getLL('translation_updating_extension'), $extKey) . '";
1449 $translationStatusArr = $this->terConnection
->fetchTranslationStatus($extKey,$mirrorURL);
1451 echo ('<tr class="bgColor4"><td>'.$extKey.'</td>');
1452 if(is_array($translationStatusArr)) {
1453 foreach($selectedLanguages as $lang) {
1454 // remote unknown -> no l10n available
1455 if(!isset($translationStatusArr[$lang])) {
1456 echo ('<td title="' . $GLOBALS['LANG']->getLL('translation_no_translation') .
1457 '">' . $GLOBALS['LANG']->getLL('translation_n_a') . '</td>');
1460 // determine local md5 from zip
1461 if(is_file(PATH_site
.'typo3temp/'.$extKey.'-l10n-'.$lang.'.zip')) {
1462 $localmd5 = md5_file(PATH_site
.'typo3temp/'.$extKey.'-l10n-'.$lang.'.zip');
1466 // local!=remote or not installed -> needs update
1467 if($localmd5 != $translationStatusArr[$lang]['md5']) {
1468 $ret = $this->updateTranslation($extKey, $lang, $mirrorURL);
1470 echo ('<td title="' . $GLOBALS['LANG']->getLL('translation_has_been_updated') .
1471 '" style="background-color:#69a550">' . $GLOBALS['LANG']->getLL('translation_status_update') .
1474 echo ('<td title="' . htmlspecialchars($ret) .
1475 '" style="background-color:#cb3352">' . $GLOBALS['LANG']->getLL('translation_status_error') .
1480 echo ('<td title="' . $GLOBALS['LANG']->getLL('translation_is_ok') .
1481 '" style="background-color:#69a550">' . $GLOBALS['LANG']->getLL('translation_status_ok') . '</td>');
1484 echo ('<td colspan="' . count($selectedLanguages) .
1485 '" title="' . $GLOBALS['LANG']->getLL('translation_problems') .
1486 '">' . $GLOBALS['LANG']->getLL('translation_status_could_not_fetch') . '</td>');
1493 document.getElementById("progress-message").firstChild.data="' .
1494 $GLOBALS['LANG']->getLL('translation_update_done') . '";
1497 echo $contentParts[1] . $this->doc
->endPage();
1501 $this->content
.= $this->doc
->section($GLOBALS['LANG']->getLL('translation_status'), $content, 0, 1);
1506 * Install translations for all selected languages for an extension
1508 * @param string $extKey The extension key to install the translations for
1509 * @param string $lang Language code of translation to fetch
1510 * @param string $mirrorURL Mirror URL to fetch data from
1511 * @return mixed true on success, error string on fauilure
1513 function updateTranslation($extKey, $lang, $mirrorURL) {
1514 $l10n = $this->terConnection
->fetchTranslation($extKey, $lang, $mirrorURL);
1515 if(is_array($l10n)) {
1516 $file = PATH_site
.'typo3temp/'.$extKey.'-l10n-'.$lang.'.zip';
1517 $path = 'l10n/'.$lang.'/';
1518 if(!is_dir(PATH_typo3conf
.$path)) t3lib_div
::mkdir_deep(PATH_typo3conf
,$path);
1519 t3lib_div
::writeFile($file, $l10n[0]);
1520 if($this->unzip($file, PATH_typo3conf
.$path)) {
1523 return $GLOBALS['LANG']->getLL('translation_unpacking_failed');
1531 * Install translations for all selected languages for an extension
1533 * @param string $extKey The extension key to install the translations for
1534 * @param string $mirrorURL Mirror URL to fetch data from
1535 * @return mixed true on success, error string on fauilure
1537 function installTranslationsForExtension($extKey, $mirrorURL) {
1538 $selectedLanguages = unserialize($this->MOD_SETTINGS
['selectedLanguages']);
1539 if(!is_array($selectedLanguages)) $selectedLanguages = array();
1540 foreach($selectedLanguages as $lang) {
1541 $l10n = $this->terConnection
->fetchTranslation($extKey, $lang, $mirrorURL);
1542 if(is_array($l10n)) {
1543 $file = PATH_typo3conf
.'l10n/'.$extKey.'-l10n-'.$lang.'.zip';
1544 $path = 'l10n/'.$lang.'/'.$extKey;
1545 t3lib_div
::writeFile($file, $l10n[0]);
1546 if(!is_dir(PATH_typo3conf
.$path)) t3lib_div
::mkdir_deep(PATH_typo3conf
,$path);
1547 if($this->unzip($file, PATH_typo3conf
.$path)) {
1550 return $GLOBALS['LANG']->getLL('translation_unpacking_failed');
1559 * Unzips a zip file in the given path.
1561 * Uses unzip binary if available, otherwise a pure PHP unzip is used.
1563 * @param string $file Full path to zip file
1564 * @param string $path Path to change to before extracting
1565 * @return boolean True on success, false in failure
1567 function unzip($file, $path) {
1568 if(strlen($GLOBALS['TYPO3_CONF_VARS']['BE']['unzip_path'])) {
1570 $cmd = $GLOBALS['TYPO3_CONF_VARS']['BE']['unzip_path'].' -o '.escapeshellarg($file);
1571 exec($cmd, $list, $ret);
1572 return ($ret === 0);
1574 // we use a pure PHP unzip
1575 $unzip = new em_unzip($file);
1576 $ret = $unzip->extract(array('add_path'=>$path));
1577 return (is_array($ret));
1583 /*********************************
1585 * Command Applications (triggered by GET var)
1587 *********************************/
1590 * Returns detailed info about an extension in the online repository
1592 * @param string Extension repository uid + optional "private key": [uid]-[key].
1593 * @param [type] $version: ...
1596 function importExtInfo($extKey, $version='') {
1598 $content = '<form action="index.php" method="post" name="pageform">';
1600 // Fetch remote data:
1601 $this->xmlhandler
->searchExtensionsXMLExact($extKey, '', '', true, true);
1602 list($fetchData,) = $this->prepareImportExtList(true);
1604 $versions = array_keys($fetchData[$extKey]['versions']);
1605 $version = ($version == '') ?
end($versions) : $version;
1608 foreach(array_keys($fetchData[$extKey]['versions']) as $ver) {
1609 $opt[]='<option value="'.$ver.'"'.(($version == $ver) ?
' selected="selected"' : '').'>'.$ver.'</option>';
1612 // "Select version" box:
1613 $onClick = 'window.location.href=\'index.php?CMD[importExtInfo]='.$extKey.'&CMD[extVersion]=\'+document.pageform.extVersion.options[document.pageform.extVersion.selectedIndex].value; return false;';
1614 $select = '<select name="extVersion">' . implode('', $opt) .
1615 '</select> <input type="submit" value="' . $GLOBALS['LANG']->getLL('ext_load_details_button') .
1616 '" onclick="' . htmlspecialchars($onClick) . '" />';
1618 if ($this->importAtAll()) {
1619 // Check for write-protected extension
1620 list($inst_list,) = $this->getInstalledExtensions();
1621 if ($inst_list[$extKey]['EM_CONF']['state'] != 'excludeFromUpdates') {
1623 window.location.href=\'index.php?CMD[importExt]='.$extKey.'\'
1624 +\'&CMD[extVersion]=\'+document.pageform.extVersion.options[document.pageform.extVersion.selectedIndex].value
1625 +\'&CMD[loc]=\'+document.pageform.loc.options[document.pageform.loc.selectedIndex].value;
1627 $select .= ' ' . $GLOBALS['LANG']->getLL('ext_or') . '<br /><br />
1628 <input type="submit" value="' . $GLOBALS['LANG']->getLL('ext_import_update_button') .
1629 '" onclick="' . htmlspecialchars($onClick) . '"> ' . $GLOBALS['LANG']->getLL('ext_import_update_to') . '
1630 <select name="loc">'.
1631 ($this->importAsType('G', $fetchData['emconf_lockType']) ?
1632 '<option value="G">' . $GLOBALS['LANG']->getLL('ext_import_global') . ' ' . $this->typePaths
['G'] . $extKey . '/' .
1633 (@is_dir
(PATH_site
. $this->typePaths
['G'] . $extKey) ?
1634 ' ' . $GLOBALS['LANG']->getLL('ext_import_overwrite') :
1635 ' ' . $GLOBALS['LANG']->getLL('ext_import_folder_empty')
1636 ) . '</option>' : ''
1638 ($this->importAsType('L', $fetchData['emconf_lockType']) ?
1639 '<option value="L">' . $GLOBALS['LANG']->getLL('ext_import_local') . ' ' . $this->typePaths
['L'] . $extKey . '/' .
1640 (@is_dir
(PATH_site
. $this->typePaths
['L'] . $extKey) ?
1641 ' ' . $GLOBALS['LANG']->getLL('ext_import_overwrite') :
1642 ' ' . $GLOBALS['LANG']->getLL('ext_import_folder_empty')
1643 ) . '</option>' : ''
1645 ($this->importAsType('S', $fetchData['emconf_lockType']) ?
1646 '<option value="S">' . $GLOBALS['LANG']->getLL('ext_import_system') . ' ' . $this->typePaths
['S'] . $extKey . '/' .
1647 (@is_dir
(PATH_site
. $this->typePaths
['S'] . $extKey) ?
1648 ' ' . $GLOBALS['LANG']->getLL('ext_import_overwrite') :
1649 ' ' . $GLOBALS['LANG']->getLL('ext_import_folder_empty')
1650 ) . '</option>' : ''
1655 $select .= '<br /><br />' . $GLOBALS['LANG']->getLL('ext_import_excluded_from_updates');
1658 $select .= '<br /><br />' . $this->noImportMsg();
1661 $this->content
.= $this->doc
->section($GLOBALS['LANG']->getLL('ext_import_select_command'), $content, 0, 1);
1664 $eInfo = $fetchData[$extKey]['versions'][$version];
1665 $content='<strong>'.$fetchData[$extKey]['_ICON'].' '.$eInfo['EM_CONF']['title'].' ('.$extKey.', '.$version.')</strong><br /><br />';
1666 $content.=$this->extInformationArray($extKey,$eInfo,1);
1667 $this->content
.=$this->doc
->spacer(10);
1668 $this->content
.= $this->doc
->section($GLOBALS['LANG']->getLL('ext_import_remote_ext_details'), $content, 0, 1);
1672 * Fetches metadata and stores it to the corresponding place. This includes the mirror list,
1673 * extension XML files.
1675 * @param string Type of data to fetch: (mirrors)
1676 * @param boolean If true the method doesn't produce any output
1679 function fetchMetaData($metaType) {
1680 global $TYPO3_CONF_VARS;
1684 $mfile = t3lib_div
::tempnam('mirrors');
1685 $mirrorsFile = t3lib_div
::getURL($this->MOD_SETTINGS
['mirrorListURL'], 0, array(TYPO3_user_agent
));
1686 if($mirrorsFile===false) {
1687 t3lib_div
::unlink_tempfile($mfile);
1689 sprintf($GLOBALS['LANG']->getLL('ext_import_list_not_updated'),
1690 $this->MOD_SETTINGS
['mirrorListURL']
1692 $GLOBALS['LANG']->getLL('translation_problems') . '</p>';
1694 t3lib_div
::writeFile($mfile, $mirrorsFile);
1695 $mirrors = implode('',gzfile($mfile));
1696 t3lib_div
::unlink_tempfile($mfile);
1698 $mirrors = $this->xmlhandler
->parseMirrorsXML($mirrors);
1699 if(is_array($mirrors) && count($mirrors)) {
1700 t3lib_BEfunc
::getModuleData($this->MOD_MENU
, array('extMirrors' => serialize($mirrors)), $this->MCONF
['name'], '', 'extMirrors');
1701 $this->MOD_SETTINGS
['extMirrors'] = serialize($mirrors);
1703 sprintf($GLOBALS['LANG']->getLL('ext_import_list_updated'),
1708 $content = '<p>' . $mirrors . '<br />' . $GLOBALS['LANG']->getLL('ext_import_list_empty') . '</p>';
1713 $this->fetchMetaData('mirrors'); // if we fetch the extensions anyway, we can as well keep this up-to-date
1715 $mirror = $this->getMirrorURL();
1716 $extfile = $mirror.'extensions.xml.gz';
1717 $extmd5 = t3lib_div
::getURL($mirror.'extensions.md5', 0, array(TYPO3_user_agent
));
1718 if (is_file(PATH_site
.'typo3temp/extensions.xml.gz')) {
1719 $localmd5 = md5_file(PATH_site
.'typo3temp/extensions.xml.gz');
1722 if($extmd5 === false) {
1724 sprintf($GLOBALS['LANG']->getLL('ext_import_md5_not_updated'),
1725 $mirror . 'extensions.md5'
1727 $GLOBALS['LANG']->getLL('translation_problems') . '</p>';
1728 } elseif($extmd5 == $localmd5) {
1729 $flashMessage = t3lib_div
::makeInstance(
1730 't3lib_FlashMessage',
1731 $GLOBALS['LANG']->getLL('ext_import_list_unchanged'),
1732 $GLOBALS['LANG']->getLL('ext_import_list_unchanged_header'),
1733 t3lib_FlashMessage
::INFO
1735 $content .= $flashMessage->render();
1737 $extXML = t3lib_div
::getURL($extfile, 0, array(TYPO3_user_agent
));
1738 if($extXML === false) {
1740 sprintf($GLOBALS['LANG']->getLL('ext_import_list_unchanged'),
1743 $GLOBALS['LANG']->getLL('translation_problems') . '</p>';
1745 t3lib_div
::writeFile(PATH_site
.'typo3temp/extensions.xml.gz', $extXML);
1746 $content .= $this->xmlhandler
->parseExtensionsXML(PATH_site
.'typo3temp/extensions.xml.gz');
1756 * Returns the base URL for the slected or a random mirror.
1758 * @return string The URL for the selected or a random mirror
1760 function getMirrorURL() {
1761 if(strlen($this->MOD_SETTINGS
['rep_url'])) return $this->MOD_SETTINGS
['rep_url'];
1763 $mirrors = unserialize($this->MOD_SETTINGS
['extMirrors']);
1764 if(!is_array($mirrors)) {
1765 $this->fetchMetaData('mirrors');
1766 $mirrors = unserialize($this->MOD_SETTINGS
['extMirrors']);
1767 if(!is_array($mirrors)) return false;
1769 if($this->MOD_SETTINGS
['selectedMirror']=='') {
1770 $rand = array_rand($mirrors);
1771 $url = 'http://'.$mirrors[$rand]['host'].$mirrors[$rand]['path'];
1774 $url = 'http://'.$mirrors[$this->MOD_SETTINGS
['selectedMirror']]['host'].$mirrors[$this->MOD_SETTINGS
['selectedMirror']]['path'];
1783 * Installs (activates) an extension
1785 * For $mode use the three constants EM_INSTALL_VERSION_MIN, EM_INSTALL_VERSION_MAX, EM_INSTALL_VERSION_STRICT
1787 * If an extension is loaded or imported already and the version requirement is matched, it will not be
1788 * fetched from the repository. This means, if you use EM_INSTALL_VERSION_MIN, you will not always get the latest
1789 * version of an extension!
1791 * @param string $extKey The extension key to install
1792 * @param string $version A version number that should be installed
1793 * @param int $mode If a version is requested, this determines if it is the min, max or strict version requested
1794 * @return [type] ...
1795 * @todo Make the method able to handle needed interaction somehow (unmatched dependencies)
1797 function installExtension($extKey, $version=null, $mode=EM_INSTALL_VERSION_MIN
) {
1798 list($inst_list,) = $this->getInstalledExtensions();
1800 // check if it is already installed and loaded with sufficient version
1801 if(isset($inst_list[$extKey])) {
1802 $currentVersion = $inst_list[$extKey]['EM_CONF']['version'];
1804 if(t3lib_extMgm
::isLoaded($extKey)) {
1805 if($version===null) {
1806 return array(true, $GLOBALS['LANG']->getLL('ext_import_ext_already_installed_loaded'));
1809 case EM_INSTALL_VERSION_STRICT
:
1810 if ($currentVersion == $version) {
1811 return array(true, $GLOBALS['LANG']->getLL('ext_import_ext_already_installed_loaded'));
1814 case EM_INSTALL_VERSION_MIN
:
1815 if (version_compare($currentVersion, $version, '>=')) {
1816 return array(true, $GLOBALS['LANG']->getLL('ext_import_ext_already_installed_loaded'));
1819 case EM_INSTALL_VERSION_MAX
:
1820 if (version_compare($currentVersion, $version, '<=')) {
1821 return array(true, $GLOBALS['LANG']->getLL('ext_import_ext_already_installed_loaded'));
1827 if (!t3lib_extMgm
::isLocalconfWritable()) {
1828 return array(false, $GLOBALS['LANG']->getLL('ext_import_p_localconf'));
1832 case EM_INSTALL_VERSION_STRICT
:
1833 if ($currentVersion == $version) {
1834 $newExtList = $this->addExtToList($extKey, $inst_list);
1837 case EM_INSTALL_VERSION_MIN
:
1838 if (version_compare($currentVersion, $version, '>=')) {
1839 $newExtList = $this->addExtToList($extKey, $inst_list);
1842 case EM_INSTALL_VERSION_MAX
:
1843 if (version_compare($currentVersion, $version, '<=')) {
1844 $newExtList = $this->addExtToList($extKey, $inst_list);
1848 if ($newExtList!=-1) {
1849 $this->writeNewExtensionList($newExtList);
1850 $this->refreshGlobalExtList();
1851 $this->forceDBupdates($extKey, $inst_list[$extKey]);
1852 return array(true, $GLOBALS['LANG']->getLL('ext_import_ext_loaded'));
1857 // at this point we know we need to import (a matching version of) the extension from TER2
1859 // see if we have an extension list at all
1860 if (!$this->xmlhandler
->countExtensions()) {
1861 $this->fetchMetaData('extensions');
1863 $this->xmlhandler
->searchExtensionsXMLExact($extKey, '', '', true);
1865 // check if extension can be fetched
1866 if(isset($this->xmlhandler
->extensionsXML
[$extKey])) {
1867 $versions = array_keys($this->xmlhandler
->extensionsXML
[$extKey]['versions']);
1868 $latestVersion = end($versions);
1870 case EM_INSTALL_VERSION_STRICT
:
1871 if(!isset($this->xmlhandler
->extensionsXML
[$extKey]['versions'][$version])) {
1872 return array(false, $GLOBALS['LANG']->getLL('ext_import_ext_n_a'));
1875 case EM_INSTALL_VERSION_MIN
:
1876 if (version_compare($latestVersion, $version, '>=')) {
1877 $version = $latestVersion;
1879 return array(false, $GLOBALS['LANG']->getLL('ext_import_ext_n_a'));
1882 case EM_INSTALL_VERSION_MAX
:
1883 while (($v = array_pop($versions)) && version_compare($v, $version, '>=')) {
1884 // Loop until a version is found
1887 if ($v !== null && version_compare($v, $version, '<=')) {
1890 return array(false, $GLOBALS['LANG']->getLL('ext_import_ext_n_a'));
1894 $this->importExtFromRep($extKey, $version, 'L');
1895 $newExtList = $this->addExtToList($extKey, $inst_list);
1896 if ($newExtList!=-1) {
1897 $this->writeNewExtensionList($newExtList);
1898 $this->refreshGlobalExtList();
1899 $this->forceDBupdates($extKey, $inst_list[$extKey]);
1900 $this->installTranslationsForExtension($extKey, $this->getMirrorURL());
1901 return array(true, $GLOBALS['LANG']->getLL('ext_import_ext_imported'));
1903 return array(false, $GLOBALS['LANG']->getLL('ext_import_ext_not_loaded'));
1906 return array(false, $GLOBALS['LANG']->getLL('ext_import_ext_n_a_rep'));
1910 function refreshGlobalExtList() {
1911 global $TYPO3_LOADED_EXT;
1913 $TYPO3_LOADED_EXT = t3lib_extMgm
::typo3_loadExtensions();
1914 if ($TYPO3_LOADED_EXT['_CACHEFILE']) {
1915 require(PATH_typo3conf
.$TYPO3_LOADED_EXT['_CACHEFILE'].'_ext_localconf.php');
1919 $GLOBALS['TYPO3_LOADED_EXT'] = t3lib_extMgm
::typo3_loadExtensions();
1920 if ($TYPO3_LOADED_EXT['_CACHEFILE']) {
1921 require(PATH_typo3conf
.$TYPO3_LOADED_EXT['_CACHEFILE'].'_ext_localconf.php');
1923 $temp_TYPO3_LOADED_EXT = $TYPO3_LOADED_EXT;
1924 reset($temp_TYPO3_LOADED_EXT);
1925 while(list($_EXTKEY,$temp_lEDat)=each($temp_TYPO3_LOADED_EXT)) {
1926 if (is_array($temp_lEDat) && $temp_lEDat['ext_localconf.php']) {
1927 $_EXTCONF = $TYPO3_CONF_VARS['EXT']['extConf'][$_EXTKEY];
1928 require($temp_lEDat['ext_localconf.php']);
1936 * Imports an extensions from the online repository
1937 * NOTICE: in version 4.0 this changed from "importExtFromRep_old($extRepUid,$loc,$uploadFlag=0,$directInput='',$recentTranslations=0,$incManual=0,$dontDelete=0)"
1939 * @param string Extension key
1940 * @param string Version
1941 * @param string Install scope: "L" or "G" or "S"
1942 * @param boolean If true, extension is uploaded as file
1943 * @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.
1944 * @param array Direct input array (like from kickstarter)
1945 * @return string Return false on success, returns error message if error.
1947 function importExtFromRep($extKey,$version,$loc,$uploadFlag=0,$dontDelete=0,$directInput='') {
1949 $uploadSucceed = false;
1950 $uploadedTempFile = '';
1951 if (is_array($directInput)) {
1952 $fetchData = array($directInput,'');
1953 $loc = ($loc==='G'||
$loc==='S') ?
$loc : 'L';
1954 } elseif ($uploadFlag) {
1955 if (($uploadedTempFile = $this->CMD
['alreadyUploaded']) ||
$_FILES['upload_ext_file']['tmp_name']) {
1957 // Read uploaded file:
1958 if (!$uploadedTempFile) {
1959 if (!is_uploaded_file($_FILES['upload_ext_file']['tmp_name'])) {
1960 t3lib_div
::sysLog('Possible file upload attack: '.$_FILES['upload_ext_file']['tmp_name'], 'Extension Manager', 3);
1962 return $GLOBALS['LANG']->getLL('ext_import_file_not_uploaded');
1965 $uploadedTempFile = t3lib_div
::upload_to_tempfile($_FILES['upload_ext_file']['tmp_name']);
1967 $fileContent = t3lib_div
::getUrl($uploadedTempFile);
1969 if (!$fileContent) return $GLOBALS['LANG']->getLL('ext_import_file_empty');
1971 // Decode file data:
1972 $fetchData = $this->terConnection
->decodeExchangeData($fileContent);
1974 if (is_array($fetchData)) {
1975 $extKey = $fetchData[0]['extKey'];
1977 if (!$this->CMD
['uploadOverwrite']) {
1978 $loc = ($loc==='G'||
$loc==='S') ?
$loc : 'L';
1979 $comingExtPath = PATH_site
.$this->typePaths
[$loc].$extKey.'/';
1980 if (@is_dir
($comingExtPath)) {
1981 $flashMessage = t3lib_div
::makeInstance(
1982 't3lib_FlashMessage',
1983 sprintf($GLOBALS['LANG']->getLL('ext_import_ext_present_no_overwrite'), $comingExtPath) .
1984 '<br />' . $GLOBALS['LANG']->getLL('ext_import_ext_present_nothing_done'),
1986 t3lib_FlashMessage
::ERROR
1988 return $flashMessage->render();
1989 } // ... else go on, install...
1990 } // ... else go on, install...
1991 } else return $GLOBALS['LANG']->getLL('ext_import_no_key');
1992 } else return sprintf($GLOBALS['LANG']->getLL('ext_import_wrong_file_format'), $fetchData);
1993 } else return $GLOBALS['LANG']->getLL('ext_import_no_file');
1995 $this->xmlhandler
->searchExtensionsXMLExact($extKey, '', '', true, true);
1997 // Fetch extension from TER:
1998 if(!strlen($version)) {
1999 $versions = array_keys($this->xmlhandler
->extensionsXML
[$extKey]['versions']);
2000 $version = end($versions);
2002 $fetchData = $this->terConnection
->fetchExtension($extKey, $version, $this->xmlhandler
->extensionsXML
[$extKey]['versions'][$version]['t3xfilemd5'], $this->getMirrorURL());
2005 // At this point the extension data should be present; so we want to write it to disc:
2006 if ($this->importAsType($loc)) {
2007 if (is_array($fetchData)) { // There was some data successfully transferred
2008 if ($fetchData[0]['extKey'] && is_array($fetchData[0]['FILES'])) {
2009 $extKey = $fetchData[0]['extKey'];
2010 if(!isset($fetchData[0]['EM_CONF']['constraints'])) $fetchData[0]['EM_CONF']['constraints'] = $this->xmlhandler
->extensionsXML
[$extKey]['versions'][$version]['dependencies'];
2011 $EM_CONF = $this->fixEMCONF($fetchData[0]['EM_CONF']);
2012 if (!$EM_CONF['lockType'] ||
!strcmp($EM_CONF['lockType'],$loc)) {
2013 // check dependencies, act accordingly if ext is loaded
2014 list($instExtInfo,)=$this->getInstalledExtensions();
2015 $depStatus = $this->checkDependencies($extKey, $EM_CONF, $instExtInfo);
2016 if(t3lib_extMgm
::isLoaded($extKey) && !$depStatus['returnCode']) {
2017 $this->content
.= $depStatus['html'];
2018 if ($uploadedTempFile) {
2019 $this->content
.= '<input type="hidden" name="CMD[alreadyUploaded]" value="'.$uploadedTempFile.'" />';
2022 $res = $this->clearAndMakeExtensionDir($fetchData[0],$loc,$dontDelete);
2023 if (is_array($res)) {
2024 $extDirPath = trim($res[0]);
2025 if ($extDirPath && @is_dir
($extDirPath) && substr($extDirPath,-1)=='/') {
2027 $emConfFile = $this->construct_ext_emconf_file($extKey,$EM_CONF);
2028 $dirs = $this->extractDirsFromFileList(array_keys($fetchData[0]['FILES']));
2030 $res = $this->createDirsInPath($dirs,$extDirPath);
2032 $writeFiles = $fetchData[0]['FILES'];
2033 $writeFiles['ext_emconf.php']['content'] = $emConfFile;
2034 $writeFiles['ext_emconf.php']['content_md5'] = md5($emConfFile);
2037 foreach($writeFiles as $theFile => $fileData) {
2038 t3lib_div
::writeFile($extDirPath.$theFile,$fileData['content']);
2039 if (!@is_file
($extDirPath.$theFile)) {
2040 $content .= sprintf($GLOBALS['LANG']->getLL('ext_import_file_not_created'),
2041 $extDirPath . $theFile) . '<br />';
2042 } elseif (md5(t3lib_div
::getUrl($extDirPath.$theFile)) != $fileData['content_md5']) {
2043 $content .= sprintf($GLOBALS['LANG']->getLL('ext_import_file_corrupted'),
2044 $extDirPath . $theFile) . '<br />';
2048 // No content, no errors. Create success output here:
2050 $content = sprintf($GLOBALS['LANG']->getLL('ext_import_success_folder'), $extDirPath) . '<br />';
2052 $uploadSucceed = true;
2054 // Fix TYPO3_MOD_PATH for backend modules in extension:
2055 $modules = t3lib_div
::trimExplode(',',$EM_CONF['module'],1);
2056 if (count($modules)) {
2057 foreach($modules as $mD) {
2058 $confFileName = $extDirPath.$mD.'/conf.php';
2059 if (@is_file
($confFileName)) {
2060 $content.= $this->writeTYPO3_MOD_PATH($confFileName,$loc,$extKey.'/'.$mD.'/').'<br />';
2061 } else $content .= sprintf($GLOBALS['LANG']->getLL('ext_import_no_conf_file'),
2062 $confFileName) . '<br />';
2065 // 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.
2066 // But this order of the code works.... (using the empty Array with type, EMCONF and files hereunder).
2068 // Writing to ext_emconf.php:
2069 $sEMD5A = $this->serverExtensionMD5Array($extKey,array('type' => $loc, 'EM_CONF' => array(), 'files' => array()));
2070 $EM_CONF['_md5_values_when_last_written'] = serialize($sEMD5A);
2071 $emConfFile = $this->construct_ext_emconf_file($extKey,$EM_CONF);
2072 t3lib_div
::writeFile($extDirPath.'ext_emconf.php',$emConfFile);
2074 $content .= 'ext_emconf.php: '.$extDirPath.'ext_emconf.php<br />';
2075 $content .= $GLOBALS['LANG']->getLL('ext_import_ext_type') . ' ';
2079 $content .= $GLOBALS['LANG']->getLL('type_local');
2082 $content .= $GLOBALS['LANG']->getLL('type_global');
2085 $content .= $GLOBALS['LANG']->getLL('type_system');
2088 $content .= '<br />';
2090 // Remove cache files:
2091 if (t3lib_extMgm
::isLoaded($extKey)) {
2092 if ($this->removeCacheFiles()) {
2093 $content .= $GLOBALS['LANG']->getLL('ext_import_cache_files_removed') . '<br />';
2096 list($new_list)=$this->getInstalledExtensions();
2097 $content.=$this->updatesForm($extKey,$new_list[$extKey],1,'index.php?CMD[showExt]='.$extKey.'&SET[singleDetails]=info');
2100 $flashMessage = t3lib_div
::makeInstance(
2101 't3lib_FlashMessage',
2103 $GLOBALS['LANG']->getLL('ext_import_success')
2105 $content = $flashMessage->render();
2107 // Install / Uninstall:
2108 if(!$this->CMD
['standAlone']) {
2109 $content .= '<h3>' . $GLOBALS['LANG']->getLL('ext_import_install_uninstall') . '</h3>';
2110 $content.= $new_list[$extKey] ?
2111 '<a href="' . htmlspecialchars('index.php?CMD[showExt]=' . $extKey .
2112 '&CMD[remove]=1&CMD[clrCmd]=1&SET[singleDetails]=info') . '">' .
2113 $this->removeButton() . ' ' . $GLOBALS['LANG']->getLL('ext_import_uninstall') . '</a>' :
2114 '<a href="' . htmlspecialchars('index.php?CMD[showExt]=' . $extKey .
2115 '&CMD[load]=1&CMD[clrCmd]=1&SET[singleDetails]=info') . '">' .
2116 $this->installButton() . ' ' . $GLOBALS['LANG']->getLL('ext_import_install') . '</a>';
2118 $content = $GLOBALS['LANG']->getLL('ext_import_imported') .
2119 '<br /><br /><a href="javascript:opener.top.content.document.forms[0].submit();window.close();">' .
2120 $GLOBALS['LANG']->getLL('ext_import_close_check') . '</a>';
2123 } else $content = $res;
2124 } else $content = sprintf($GLOBALS['LANG']->getLL('ext_import_ext_path_different'), $extDirPath);
2125 } else $content = $res;
2127 } else $content = sprintf($GLOBALS['LANG']->getLL('ext_import_ext_only_here'),
2128 $this->typePaths
[$EM_CONF['lockType']], $EM_CONF['lockType']);
2129 } else $content = $GLOBALS['LANG']->getLL('ext_import_no_ext_key_files');
2130 } else $content = sprintf($GLOBALS['LANG']->getLL('ext_import_data_transfer'), $fetchData);
2131 } else $content = sprintf($GLOBALS['LANG']->getLL('ext_import_no_install_here'), $this->typePaths
[$loc]);
2133 $this->content
.= $this->doc
->section($GLOBALS['LANG']->getLL('ext_import_results'), $content, 0, 1);
2135 if ($uploadSucceed && $uploadedTempFile) {
2136 t3lib_div
::unlink_tempfile($uploadedTempFile);
2143 * Display extensions details.
2145 * @param string Extension key
2146 * @return void Writes content to $this->content
2148 function showExtDetails($extKey) {
2149 global $TYPO3_LOADED_EXT;
2151 list($list,)=$this->getInstalledExtensions();
2152 $absPath = $this->getExtPath($extKey,$list[$extKey]['type']);
2154 // Check updateModule:
2155 if (isset($list[$extKey]) && @is_file
($absPath.'class.ext_update.php')) {
2156 require_once($absPath.'class.ext_update.php');
2157 $updateObj = new ext_update
;
2158 if (!$updateObj->access()) {
2159 unset($this->MOD_MENU
['singleDetails']['updateModule']);
2162 unset($this->MOD_MENU
['singleDetails']['updateModule']);
2165 if($this->CMD
['doDelete']) {
2166 $this->MOD_MENU
['singleDetails'] = array();
2169 // Function menu here:
2170 if(!$this->CMD
['standAlone'] && !t3lib_div
::_GP('standAlone')) {
2171 $content = $GLOBALS['LANG']->getLL('ext_details_ext') . ' <strong>' .
2172 $this->extensionTitleIconHeader($extKey, $list[$extKey]) . '</strong> (' . $extKey . ')';
2173 $this->content
.= $this->doc
->section('', $content);
2176 // Show extension details:
2177 if ($list[$extKey]) {
2179 // Checking if a command for install/uninstall is executed:
2180 if (($this->CMD
['remove'] ||
$this->CMD
['load']) && !in_array($extKey,$this->requiredExt
)) {
2182 // Install / Uninstall extension here:
2183 if (t3lib_extMgm
::isLocalconfWritable()) {
2184 // Check dependencies:
2185 $depStatus = $this->checkDependencies($extKey, $list[$extKey]['EM_CONF'], $list);
2186 if(!$this->CMD
['remove'] && !$depStatus['returnCode']) {
2187 $this->content
.= $depStatus['html'];
2189 } elseif ($this->CMD
['remove']) {
2190 $newExtList = $this->removeExtFromList($extKey,$list);
2192 $newExtList = $this->addExtToList($extKey,$list);
2195 // Successful installation:
2196 if ($newExtList!=-1) {
2198 if ($this->CMD
['load']) {
2199 if($_SERVER['REQUEST_METHOD'] == 'POST') {
2200 $script = t3lib_div
::linkThisScript(array('CMD[showExt]' => $extKey, 'CMD[load]' => 1, 'CMD[clrCmd]' => $this->CMD
['clrCmd'], 'SET[singleDetails]' => 'info'));
2204 if($this->CMD
['standAlone']) {
2205 $standaloneUpdates = '<input type="hidden" name="standAlone" value="1" />';
2207 $depsolver = t3lib_div
::_POST('depsolver');
2208 if(is_array($depsolver['ignore'])) {
2209 foreach($depsolver['ignore'] as $depK => $depV) {
2210 $dependencyUpdates .= '<input type="hidden" name="depsolver[ignore]['.$depK.']" value="1" />';
2213 $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'].'" />');
2215 $updates = $GLOBALS['LANG']->getLL('ext_details_new_tables_fields') . '<br />' .
2216 $GLOBALS['LANG']->getLL('ext_details_new_tables_fields_select') . $updatesForm;
2217 $labelDBUpdate = $GLOBALS['LANG']->csConvObj
->conv_case(
2218 $GLOBALS['LANG']->charSet
,
2219 $GLOBALS['LANG']->getLL('ext_details_db_needs_update'),
2222 $this->content
.= $this->doc
->section(
2223 sprintf($GLOBALS['LANG']->getLL('ext_details_installing') . ' ',
2224 $this->extensionTitleIconHeader($extKey, $list[$extKey])
2227 $updates, 1, 1, 1, 1
2230 } elseif ($this->CMD
['remove']) {
2231 $updates.= $this->checkClearCache($list[$extKey]);
2234 <form action="'.t3lib_div
::linkThisScript().'" method="post">'.$updates.'
2235 <br /><input type="submit" name="write" value="' .
2236 $GLOBALS['LANG']->getLL('ext_details_remove_ext') . '" />
2237 <input type="hidden" name="_do_install" value="1" />
2238 <input type="hidden" name="_clrCmd" value="'.$this->CMD
['clrCmd'].'" />
2239 <input type="hidden" name="standAlone" value="'.$this->CMD
['standAlone'].'" />
2241 $labelDBUpdate = $GLOBALS['LANG']->csConvObj
->conv_case(
2242 $GLOBALS['LANG']->charSet
,
2243 $GLOBALS['LANG']->getLL('ext_details_db_needs_update'),
2246 $this->content
.= $this->doc
->section(
2247 sprintf($GLOBALS['LANG']->getLL('ext_details_removing') . ' ',
2248 $this->extensionTitleIconHeader($extKey, $list[$extKey])
2251 $updates, 1, 1, 1, 1
2255 if (!$updates || t3lib_div
::_GP('_do_install')) {
2256 $this->writeNewExtensionList($newExtList);
2257 $GLOBALS['BE_USER']->writelog(5,1,0,0,'Extension list has been changed, extension %s has been %s',array($extKey,($this->CMD
['load']?
'installed':'removed')));
2258 if ($this->CMD
['clrCmd'] || t3lib_div
::_GP('_clrCmd')) {
2259 if ($this->CMD
['load'] && @is_file
($absPath.'ext_conf_template.txt')) {
2260 $vA = array('CMD'=>Array('showExt'=>$extKey));
2262 $vA = array('CMD'=>'');
2265 $vA = array('CMD'=>Array('showExt'=>$extKey));
2267 if($this->CMD
['standAlone'] || t3lib_div
::_GP('standAlone')) {
2268 $this->content
.= sprintf($GLOBALS['LANG']->getLL('ext_details_ext_installed_removed'),
2269 ($this->CMD
['load'] ?
2270 $GLOBALS['LANG']->getLL('ext_details_installed') :
2271 $GLOBALS['LANG']->getLL('ext_details_removed')
2274 '<br /><br /><a href="javascript:opener.top.content.document.forms[0].submit();window.close();">' .
2275 $GLOBALS['LANG']->getLL('ext_import_close_check') . '</a>';
2277 // Determine if new modules were installed:
2278 $techInfo = $this->makeDetailedExtensionAnalysis($extKey, $list[$extKey]);
2279 if (($this->CMD
['load'] ||
$this->CMD
['remove']) && is_array($techInfo['flags']) && in_array('Module', $techInfo['flags'], true)) {
2280 $vA['CMD']['refreshMenu'] = 1;
2282 header('Location: '.t3lib_div
::linkThisScript($vA));
2287 $writeAccessError = $GLOBALS['LANG']->csConvObj
->conv_case(
2288 $GLOBALS['LANG']->charSet
,
2289 $GLOBALS['LANG']->getLL('ext_details_write_access_error'),
2292 $this->content
.= $this->doc
->section(
2293 sprintf($GLOBALS['LANG']->getLL('ext_details_installing') . ' ',
2294 $this->extensionTitleIconHeader($extKey, $list[$extKey])
2297 $GLOBALS['LANG']->getLL('ext_details_write_error_localconf'),
2302 } elseif ($this->CMD
['downloadFile'] && !in_array($extKey,$this->requiredExt
)) {
2304 // Link for downloading extension has been clicked - deliver content stream:
2305 $dlFile = $this->CMD
['downloadFile'];
2306 if (t3lib_div
::isFirstPartOfStr($dlFile,PATH_site
) && t3lib_div
::isFirstPartOfStr($dlFile,$absPath) && @is_file
($dlFile)) {
2307 $mimeType = 'application/octet-stream';
2308 Header('Content-Type: '.$mimeType);
2309 Header('Content-Disposition: attachment; filename='.basename($dlFile));
2310 echo t3lib_div
::getUrl($dlFile);
2312 } else die($GLOBALS['LANG']->getLL('ext_details_error_downloading'));
2314 } elseif ($this->CMD
['editFile'] && !in_array($extKey,$this->requiredExt
)) {
2316 // Editing extension file:
2317 $editFile = $this->CMD
['editFile'];
2318 if (t3lib_div
::isFirstPartOfStr($editFile,PATH_site
) && t3lib_div
::isFirstPartOfStr($editFile,$absPath)) { // Paranoia...
2320 $fI = t3lib_div
::split_fileref($editFile);
2321 if (@is_file
($editFile) && t3lib_div
::inList($this->editTextExtensions
,($fI['fileext']?
$fI['fileext']:$fI['filebody']))) {
2322 if (filesize($editFile)<($this->kbMax
*1024)) {
2323 $outCode = '<form action="index.php" method="post" name="editfileform">';
2325 $submittedContent = t3lib_div
::_POST('edit');
2328 if(isset($submittedContent['file']) && !$GLOBALS['TYPO3_CONF_VARS']['EXT']['noEdit']) { // Check referer here?
2329 $oldFileContent = t3lib_div
::getUrl($editFile);
2330 if($oldFileContent != $submittedContent['file']) {
2331 $oldMD5 = md5(str_replace(chr(13),'',$oldFileContent));
2333 $GLOBALS['LANG']->getLL('ext_details_md5_previous'),
2334 '<b>' . $oldMD5 . '</b>'
2336 t3lib_div
::writeFile($editFile,$submittedContent['file']);
2339 $info .= $GLOBALS['LANG']->getLL('ext_details_no_changes') . '<br />';
2343 $fileContent = t3lib_div
::getUrl($editFile);
2346 $GLOBALS['LANG']->getLL('ext_details_file'),
2347 '<b>' . substr($editFile, strlen($absPath)) . '</b> (' .
2348 t3lib_div
::formatSize(filesize($editFile)) . ')<br />'
2350 $fileMD5 = md5(str_replace(chr(13),'',$fileContent));
2352 $GLOBALS['LANG']->getLL('ext_details_md5_current'),
2353 '<b>' . $fileMD5 . '</b>'
2356 $saveMD5 = md5(str_replace(chr(13),'',$submittedContent['file']));
2358 $GLOBALS['LANG']->getLL('ext_details_md5_submitted'),
2359 '<b>' . $saveMD5 . '</b>'
2361 if ($fileMD5!=$saveMD5) {
2362 $info .= $GLOBALS['TBE_TEMPLATE']->rfw(
2363 '<br /><strong>' . $GLOBALS['LANG']->getLL('ext_details_saving_failed_changes_lost') . '</strong>'
2367 $info .= $GLOBALS['TBE_TEMPLATE']->rfw(
2368 '<br /><strong>' . $GLOBALS['LANG']->getLL('ext_details_file_saved') . '</strong>'
2373 $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>';
2374 $outCode.= '<input type="hidden" name="edit[filename]" value="'.$editFile.'" />';
2375 $outCode.= '<input type="hidden" name="CMD[editFile]" value="'.htmlspecialchars($editFile).'" />';
2376 $outCode.= '<input type="hidden" name="CMD[showExt]" value="'.$extKey.'" />';
2379 if (!$GLOBALS['TYPO3_CONF_VARS']['EXT']['noEdit']) {
2380 $outCode .= '<br /><input type="submit" name="save_file" value="' .
2381 $GLOBALS['LANG']->getLL('ext_details_file_save_button') . '" />';
2384 $outCode .= $GLOBALS['TBE_TEMPLATE']->rfw(
2385 '<br />' . $GLOBALS['LANG']->getLL('ext_details_saving_disabled') . ' '
2389 $onClick = 'window.location.href=\'index.php?CMD[showExt]='.$extKey.'\';return false;';
2390 $outCode .= '<input type="submit" name="cancel" value="' .
2391 $GLOBALS['LANG']->getLL('ext_details_cancel_button') . '" onclick="' .
2392 htmlspecialchars($onClick) . '" /></form>';
2394 $theOutput.=$this->doc
->spacer(15);
2395 $theOutput .= $this->doc
->section($GLOBALS['LANG']->getLL('ext_details_edit_file'), '', 0, 1);
2396 $theOutput.=$this->doc
->sectionEnd().$outCode;
2397 $this->content
.=$theOutput;
2399 $theOutput.=$this->doc
->spacer(15);
2400 $theOutput .= $this->doc
->section(
2402 $GLOBALS['LANG']->getLL('ext_details_filesize_exceeded_kb'),
2406 $GLOBALS['LANG']->getLL('ext_details_file_too_large'),
2413 die (sprintf($GLOBALS['LANG']->getLL('ext_details_fatal_edit_error'),
2421 switch((string)$this->MOD_SETTINGS
['singleDetails']) {
2423 // Loaded / Not loaded:
2424 if (!in_array($extKey,$this->requiredExt
)) {
2425 if ($TYPO3_LOADED_EXT[$extKey]) {
2426 $content = '<strong>' . $GLOBALS['LANG']->getLL('ext_details_loaded_and_running') . '</strong><br />' .
2427 '<a href="' . htmlspecialchars('index.php?CMD[showExt]=' . $extKey . '&CMD[remove]=1') .
2428 '">' . $GLOBALS['LANG']->getLL('ext_details_remove_button') . ' ' . $this->removeButton() . '</a>';
2430 $content = $GLOBALS['LANG']->getLL('ext_details_not_loaded') . '<br />'.
2431 '<a href="' . htmlspecialchars('index.php?CMD[showExt]=' . $extKey . '&CMD[load]=1') .
2432 '">' . $GLOBALS['LANG']->getLL('ext_details_install_button') . ' ' . $this->installButton() . '</a>';
2435 $content = $GLOBALS['LANG']->getLL('ext_details_always_loaded');
2437 $this->content
.=$this->doc
->spacer(10);
2438 $this->content
.= $this->doc
->section(
2439 $GLOBALS['LANG']->getLL('ext_details_current_status'), $content, 0, 1
2442 if (t3lib_extMgm
::isLoaded($extKey)) {
2443 $updates=$this->updatesForm($extKey,$list[$extKey]);
2445 $this->content
.=$this->doc
->spacer(10);
2446 $this->content
.= $this->doc
->section(
2447 $GLOBALS['LANG']->getLL('ext_details_update_needed'),
2448 $updates . '<br /><br />' . $GLOBALS['LANG']->getLL('ext_details_notice_static_data'),
2455 if (@is_file
($absPath.'ext_conf_template.txt')) {
2456 $this->content
.=$this->doc
->spacer(10);
2457 $this->content
.= $this->doc
->section(
2458 $GLOBALS['LANG']->getLL('ext_details_configuration'),
2459 $GLOBALS['LANG']->getLL('ext_details_notice_clear_cache') . '<br /><br />',
2463 $this->tsStyleConfigForm($extKey, $list[$extKey]);
2467 $content = t3lib_BEfunc
::cshItem('_MOD_tools_em', 'info', $GLOBALS['BACK_PATH'], '|<br />');
2468 $content.= $this->extInformationArray($extKey,$list[$extKey]);
2470 $this->content
.=$this->doc
->spacer(10);
2471 $this->content
.= $this->doc
->section(
2472 $GLOBALS['LANG']->getLL('ext_details_details'), $content, 0, 1
2476 $em = t3lib_div
::_POST('em');
2477 if($em['action'] == 'doUpload') {
2478 $em['extKey'] = $extKey;
2479 $em['extInfo'] = $list[$extKey];
2480 $content = $this->uploadExtensionToTER($em);
2481 $content .= $this->doc
->spacer(10);
2482 // Must reload this, because EM_CONF information has been updated!
2483 list($list,)=$this->getInstalledExtensions();
2486 $content = t3lib_BEfunc
::cshItem('_MOD_tools_em', 'upload', $GLOBALS['BACK_PATH'], '|<br />');
2489 if (substr($extKey,0,5)!='user_') {
2490 $content.= $this->getRepositoryUploadForm($extKey,$list[$extKey]);
2493 $content .= $GLOBALS['LANG']->getLL('ext_details_no_unique_ext');
2496 if (!$this->fe_user
['username']) {
2497 $content .= '<br /><br /><img src="' . $GLOBALS['BACK_PATH'] .
2498 'gfx/icon_note.gif" width="18" height="16" align="top" alt="" />' .
2499 sprintf($GLOBALS['LANG']->getLL('ext_details_no_username'),
2500 '<a href="index.php?SET[function]=3">', '</a>'
2505 $this->content
.= $this->doc
->section(
2506 $GLOBALS['LANG']->getLL('ext_details_upload_to_ter'),
2511 if($this->CMD
['doDelete']) {
2512 $content = $this->extDelete($extKey,$list[$extKey]);
2513 $this->content
.= $this->doc
->section(
2514 $GLOBALS['LANG']->getLL('ext_details_delete'),
2518 $content = t3lib_BEfunc
::cshItem('_MOD_tools_em', 'backup_delete', $GLOBALS['BACK_PATH'], '|<br />');
2519 $content.= $this->extBackup($extKey,$list[$extKey]);
2520 $this->content
.= $this->doc
->section(
2521 $GLOBALS['LANG']->getLL('ext_details_backup'),
2525 $content = $this->extDelete($extKey,$list[$extKey]);
2526 $this->content
.= $this->doc
->section(
2527 $GLOBALS['LANG']->getLL('ext_details_delete'),
2531 $content = $this->extUpdateEMCONF($extKey,$list[$extKey]);
2532 $this->content
.= $this->doc
->section(
2533 $GLOBALS['LANG']->getLL('ext_details_update_em_conf'),
2539 $this->extDumpTables($extKey,$list[$extKey]);
2542 $content = t3lib_BEfunc
::cshItem('_MOD_tools_em', 'editfiles', $GLOBALS['BACK_PATH'], '|<br />');
2543 $content.= $this->getFileListOfExtension($extKey,$list[$extKey]);