87e24dff8b584444469c888a8662ef9b4c90a4ed
[Packages/TYPO3.CMS.git] / typo3 / mod / tools / em / index.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 1999-2005 Kasper Skaarhoj (kasperYYYY@typo3.com)
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
18 *
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27 /**
28 * Module: Extension manager
29 *
30 * $Id$
31 *
32 * @author Kasper Skaarhoj <kasperYYYY@typo3.com>
33 */
34 /**
35 * [CLASS/FUNCTION INDEX of SCRIPT]
36 *
37 *
38 *
39 * 191: class SC_mod_tools_em_index extends t3lib_SCbase
40 *
41 * SECTION: Standard module initialization
42 * 341: function init()
43 * 414: function handleExternalFunctionValue($MM_key='function', $MS_value=NULL)
44 * 428: function menuConfig()
45 * 500: function main()
46 * 572: function printContent()
47 *
48 * SECTION: Function Menu Applications
49 * 599: function extensionList_loaded()
50 * 637: function extensionList_installed()
51 * 707: function extensionList_import()
52 * 869: function alterSettings()
53 *
54 * SECTION: Command Applications (triggered by GET var)
55 * 916: function importExtInfo($extRepUid)
56 * 1017: function importExtFromRep($extRepUid,$loc,$uploadFlag=0,$directInput='',$recentTranslations=0,$incManual=0)
57 * 1185: function showExtDetails($extKey)
58 *
59 * SECTION: Application Sub-functions (HTML parts)
60 * 1478: function updatesForm($extKey,$extInfo,$notSilent=0,$script='',$addFields='')
61 * 1509: function extDumpTables($extKey,$extInfo)
62 * 1576: function getFileListOfExtension($extKey,$conf)
63 * 1627: function extDelete($extKey,$extInfo)
64 * 1658: function extUpdateEMCONF($extKey,$extInfo)
65 * 1678: function extBackup($extKey,$extInfo)
66 * 1746: function extBackup_dumpDataTablesLine($tablesArray,$extKey)
67 * 1774: function extInformationArray($extKey,$extInfo,$remote=0)
68 * 1871: function extInformationArray_dbReq($techInfo,$tableHeader=0)
69 * 1884: function extInformationArray_dbInst($dbInst,$current)
70 * 1903: function getRepositoryUploadForm($extKey,$extInfo)
71 *
72 * SECTION: Extension list rendering
73 * 2001: function extensionListRowHeader($trAttrib,$cells,$import=0)
74 * 2066: function extensionListRow($extKey,$extInfo,$cells,$bgColorClass='',$inst_list=array(),$import=0,$altLinkUrl='')
75 *
76 * SECTION: Output helper functions
77 * 2191: function wrapEmail($str,$email)
78 * 2204: function helpCol($key)
79 * 2218: function labelInfo($str)
80 * 2230: function extensionTitleIconHeader($extKey,$extInfo,$align='top')
81 * 2245: function removeButton()
82 * 2254: function installButton()
83 * 2263: function noImportMsg()
84 *
85 * SECTION: Read information about all available extensions
86 * 2288: function getInstalledExtensions()
87 * 2315: function getInstExtList($path,&$list,&$cat,$type)
88 * 2349: function getImportExtList($listArr)
89 * 2401: function setCat(&$cat,$listArrayPart,$extKey)
90 *
91 * SECTION: Extension analyzing (detailed information)
92 * 2463: function makeDetailedExtensionAnalysis($extKey,$extInfo,$validity=0)
93 * 2645: function getClassIndexLocallangFiles($absPath,$table_class_prefix,$extKey)
94 * 2716: function modConfFileAnalysis($confFilePath)
95 * 2744: function serverExtensionMD5Array($extKey,$conf)
96 * 2769: function findMD5ArrayDiff($current,$past)
97 *
98 * SECTION: File system operations
99 * 2801: function createDirsInPath($dirs,$extDirPath)
100 * 2826: function removeExtDirectory($removePath,$removeContentOnly=0)
101 * 2888: function clearAndMakeExtensionDir($importedData,$type)
102 * 2941: function removeCacheFiles()
103 * 2961: function extractDirsFromFileList($files)
104 * 2987: function getExtPath($extKey,$type)
105 *
106 * SECTION: Writing to "conf.php" and "localconf.php" files
107 * 3019: function writeTYPO3_MOD_PATH($confFilePath,$type,$mP)
108 * 3056: function writeNewExtensionList($newExtList)
109 * 3079: function writeTsStyleConfig($extKey,$arr)
110 * 3101: function updateLocalEM_CONF($extKey,$extInfo)
111 *
112 * SECTION: Compiling upload information, emconf-file etc.
113 * 3139: function construct_ext_emconf_file($extKey,$EM_CONF)
114 * 3184: function makeUploadArray($extKey,$conf)
115 * 3251: function getSerializedLocalLang($file,$content)
116 *
117 * SECTION: Managing dependencies, conflicts, priorities, load order of extension keys
118 * 3285: function addExtToList($extKey,$instExtInfo)
119 * 3347: function removeExtFromList($extKey,$instExtInfo)
120 * 3384: function removeRequiredExtFromListArr($listArr)
121 * 3399: function managesPriorities($listArr,$instExtInfo)
122 *
123 * SECTION: System Update functions (based on extension requirements)
124 * 3451: function checkClearCache($extKey,$extInfo)
125 * 3478: function checkUploadFolder($extKey,$extInfo)
126 * 3563: function checkDBupdates($extKey,$extInfo,$infoOnly=0)
127 * 3662: function tsStyleConfigForm($extKey,$extInfo,$output=0,$script='',$addFields='')
128 *
129 * SECTION: Dumping database (MySQL compliant)
130 * 3757: function dumpTableAndFieldStructure($arr)
131 * 3782: function dumpStaticTables($tableList)
132 * 3811: function dumpHeader()
133 * 3828: function dumpTableHeader($table,$fieldKeyInfo,$dropTableIfExists=0)
134 * 3867: function dumpTableContent($table,$fieldStructure)
135 * 3902: function getTableAndFieldStructure($parts)
136 *
137 * SECTION: TER Communication functions
138 * 3950: function fetchServerData($repositoryUrl)
139 * 3980: function decodeServerData($externalData,$stat=array())
140 * 4007: function decodeExchangeData($str)
141 * 4029: function makeUploadDataFromArray($uploadArray,$local_gzcompress=-1)
142 * 4054: function repTransferParams()
143 * 4070: function makeReturnUrl()
144 * 4080: function T3instID()
145 * 4091: function processRepositoryReturnData($TER_CMD)
146 *
147 * SECTION: Various helper functions
148 * 4135: function listOrderTitle($listOrder,$key)
149 * 4166: function makeVersion($v,$mode)
150 * 4178: function renderVersion($v,$raise='')
151 * 4215: function ulFolder($extKey)
152 * 4224: function importAtAll()
153 * 4235: function importAsType($type,$lockType='')
154 * 4255: function deleteAsType($type)
155 * 4273: function getDocManual($extension_key,$loc='')
156 * 4289: function versionDifference($v1,$v2,$div=1)
157 * 4301: function first_in_array($str,$array,$caseInsensitive=FALSE)
158 * 4318: function includeEMCONF($path,$_EXTKEY)
159 *
160 * TOTAL FUNCTIONS: 87
161 * (This index is automatically created/updated by the extension "extdeveval")
162 *
163 */
164
165
166 unset($MCONF);
167 require ('conf.php');
168 require ($BACK_PATH.'init.php');
169 require ($BACK_PATH.'template.php');
170 $BE_USER->modAccess($MCONF,1);
171
172 // Include classes needed:
173 require_once(PATH_t3lib.'class.t3lib_tcemain.php');
174 require_once(PATH_t3lib.'class.t3lib_install.php');
175 require_once(PATH_t3lib.'class.t3lib_tsstyleconfig.php');
176 require_once(PATH_t3lib.'class.t3lib_scbase.php');
177
178
179
180
181
182
183
184 /**
185 * Module: Extension manager
186 *
187 * @author Kasper Skaarhoj <kasperYYYY@typo3.com>
188 * @package TYPO3
189 * @subpackage core
190 */
191 class SC_mod_tools_em_index extends t3lib_SCbase {
192
193 // Internal, static:
194 var $versionDiffFactor = 1000; // This means that version difference testing for import is detected for sub-versions only, not dev-versions. Default: 1000
195 var $systemInstall = 0; // If "1" then installs in the sysext directory is allowed. Default: 0
196 var $repositoryUrl = ''; // Default is "http://ter.typo3.com/?id=t3_extrep" configured in config_default.php
197 var $requiredExt = ''; // List of required extension (from TYPO3_CONF_VARS)
198 var $maxUploadSize = 6024000; // Max size of extension upload to repository
199 var $kbMax = 100; // Max size in kilobytes for files to be edited.
200
201 /**
202 * Internal variable loaded with extension categories (for display/listing). Should reflect $categories above
203 * Dynamic var.
204 */
205 var $defaultCategories = Array(
206 'cat' => Array (
207 'be' => array(),
208 'module' => array(),
209 'fe' => array(),
210 'plugin' => array(),
211 'misc' => array(),
212 'services' => array(),
213 'templates' => array(),
214 'example' => array(),
215 'doc' => array()
216 )
217 );
218
219 /**
220 * Extension Categories (static var)
221 * Content must be redundant with the same internal variable as in class.tx_extrep.php!
222 */
223 var $categories = Array(
224 'be' => 'Backend',
225 'module' => 'Backend Modules',
226 'fe' => 'Frontend',
227 'plugin' => 'Frontend Plugins',
228 'misc' => 'Miscellaneous',
229 'services' => 'Services',
230 'templates' => 'Templates',
231 'example' => 'Examples',
232 'doc' => 'Documentation'
233 );
234
235 /**
236 * Extension States
237 * Content must be redundant with the same internal variable as in class.tx_extrep.php!
238 */
239 var $states = Array (
240 'alpha' => 'Alpha',
241 'beta' => 'Beta',
242 'stable' => 'Stable',
243 'experimental' => 'Experimental',
244 'test' => 'Test',
245 'obsolete' => 'Obsolete',
246 );
247
248 /**
249 * "TYPE" information; labels, paths, description etc.
250 */
251 var $typeLabels = Array (
252 'S' => 'System',
253 'G' => 'Global',
254 'L' => 'Local',
255 );
256 var $typeDescr = Array (
257 'S' => 'System extension (typo3/sysext/) - Always distributed with source code (Static).',
258 'G' => 'Global extensions (typo3/ext/) - Available for shared source on server (Dynamic).',
259 'L' => 'Local extensions (typo3conf/ext/) - Local for this TYPO3 installation only (Dynamic).',
260 );
261 var $typePaths = Array(); // Also static, set in init()
262 var $typeBackPaths = Array(); // Also static, set in init()
263
264 var $typeRelPaths = Array (
265 'S' => 'sysext/',
266 'G' => 'ext/',
267 'L' => '../typo3conf/ext/',
268 );
269
270 /**
271 * Remote access types (labels)
272 */
273 var $remoteAccess = Array (
274 'all' => '',
275 'owner' => 'Owner',
276 'selected' => 'Selected',
277 'member' => 'Member',
278 );
279
280 var $detailCols = Array (
281 0 => 2,
282 1 => 5,
283 2 => 6,
284 3 => 6,
285 4 => 4,
286 5 => 1
287 );
288
289 var $fe_user = array(
290 'username' => '',
291 'password' => '',
292 'uploadPass' => '',
293 );
294
295 var $privacyNotice = 'When ever you interact with the online repository, server information is sent and stored in the repository for statistics. No personal information is sent, only identification of this TYPO3 install. If you want know exactly what is sent, look in typo3/mod/tools/em/index.php, function repTransferParams()';
296 var $editTextExtensions = 'html,htm,txt,css,tmpl,inc,php,sql,conf,cnf,pl,pm,sh,ChangeLog';
297 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';
298
299
300
301
302
303 // Default variables for backend modules
304 var $MCONF = array(); // Module configuration
305 var $MOD_MENU = array(); // Module menu items
306 var $MOD_SETTINGS = array(); // Module session settings
307 var $doc; // Document Template Object
308 var $content; // Accumulated content
309
310 var $inst_keys = array(); // Storage of installed extensions
311 var $gzcompress = 0; // Is set true, if system support compression.
312
313 // GPvars:
314 var $CMD = array(); // CMD array
315 var $listRemote; // If set, connects to remote repository
316 var $lookUpStr; // Search string when listing local extensions
317
318
319
320
321
322
323
324
325
326
327
328
329
330 /*********************************
331 *
332 * Standard module initialization
333 *
334 *********************************/
335
336 /**
337 * Standard init function of a module.
338 *
339 * @return void
340 */
341 function init() {
342 global $BE_USER,$LANG,$BACK_PATH,$TYPO3_CONF_VARS;
343
344 // Setting paths of install scopes:
345 $this->typePaths = Array (
346 'S' => TYPO3_mainDir.'sysext/',
347 'G' => TYPO3_mainDir.'ext/',
348 'L' => 'typo3conf/ext/'
349 );
350 $this->typeBackPaths = Array (
351 'S' => '../../../',
352 'G' => '../../../',
353 'L' => '../../../../'.TYPO3_mainDir
354 );
355
356 // Setting module configuration:
357 $this->MCONF = $GLOBALS['MCONF'];
358
359 // Setting GPvars:
360 $this->CMD = t3lib_div::_GP('CMD');
361 $this->lookUpStr = t3lib_div::_GP('_lookUp');
362 $this->listRemote = t3lib_div::_GP('ter_connect');
363 $this->listRemote_search = t3lib_div::_GP('ter_search');
364
365
366 // Configure menu
367 $this->menuConfig();
368
369 // Setting internal static:
370 $this->gzcompress = function_exists('gzcompress');
371 if ($TYPO3_CONF_VARS['EXT']['em_devVerUpdate']) $this->versionDiffFactor = 1;
372 if ($TYPO3_CONF_VARS['EXT']['em_systemInstall']) $this->systemInstall = 1;
373 $this->repositoryUrl = $TYPO3_CONF_VARS['EXT']['em_TERurls'][0];
374 $this->requiredExt = t3lib_div::trimExplode(',',$TYPO3_CONF_VARS['EXT']['requiredExt'],1);
375
376 // Initialize Document Template object:
377 $this->doc = t3lib_div::makeInstance('noDoc');
378 $this->doc->backPath = $BACK_PATH;
379 $this->doc->docType = 'xhtml_trans';
380
381 // JavaScript
382 $this->doc->JScode = $this->doc->wrapScriptTags('
383 script_ended = 0;
384 function jumpToUrl(URL) { //
385 document.location = URL;
386 }
387 ');
388 $this->doc->form = '<form action="index.php" method="post" name="pageform">';
389
390 // Descriptions:
391 $this->descrTable = '_MOD_'.$this->MCONF['name'];
392 if ($BE_USER->uc['edit_showFieldHelp']) {
393 $LANG->loadSingleTableDescription($this->descrTable);
394 }
395
396 // Setting username/password etc. for upload-user:
397 $this->fe_user['username'] = $this->MOD_SETTINGS['fe_u'];
398 $this->fe_user['password'] = $this->MOD_SETTINGS['fe_p'];
399 $this->fe_user['uploadPass'] = $this->MOD_SETTINGS['fe_up'];
400 parent::init();
401 $this->handleExternalFunctionValue('singleDetails');
402 }
403
404 /**
405 * This function is a copy of the same function in t3lib_SCbase with one modification:
406 * In contrast to t3lib_SCbase::handleExternalFunctionValue() this function merges the $this->extClassConf array
407 * instead of overwriting it. That was necessary for including the Kickstarter as a submodule into the 'singleDetails'
408 * selectorbox as well as in the main 'function' selectorbox.
409 *
410 * @param string Mod-setting array key
411 * @param string Mod setting value, overriding the one in the key
412 * @return void
413 * @see t3lib_SCbase::handleExternalFunctionValue()
414 */
415 function handleExternalFunctionValue($MM_key='function', $MS_value=NULL) {
416 $MS_value = is_null($MS_value) ? $this->MOD_SETTINGS[$MM_key] : $MS_value;
417 $externalItems = $this->getExternalItemConfig($this->MCONF['name'],$MM_key,$MS_value);
418 if (is_array($externalItems)) $this->extClassConf = array_merge($externalItems,is_array($this->extClassConf)?$this->extClassConf:array());
419 if (is_array($this->extClassConf) && $this->extClassConf['path']) {
420 $this->include_once[]=$this->extClassConf['path'];
421 }
422 }
423
424 /**
425 * Configuration of which mod-menu items can be used
426 *
427 * @return void
428 */
429 function menuConfig() {
430 global $BE_USER;
431
432 // MENU-ITEMS:
433 $this->MOD_MENU = array(
434 'function' => array(
435 0 => 'Loaded extensions',
436 1 => 'Available extensions to install',
437 2 => 'Import extensions from online repository',
438 3 => 'Settings',
439 ),
440 'listOrder' => array(
441 'cat' => 'Category',
442 'author_company' => 'Author',
443 'state' => 'State',
444 'private' => 'Private',
445 'type' => 'Type',
446 'dep' => 'Dependencies',
447 ),
448 'display_details' => array(
449 1 => 'Details',
450 0 => 'Description',
451 2 => 'More details',
452
453 3 => 'Technical (takes time!)',
454 4 => 'Validating (takes time!)',
455 5 => 'Changed? (takes time!)',
456 ),
457 'display_shy' => '',
458 'own_member_only' => '',
459 'singleDetails' => array(
460 'info' => 'Information',
461 'edit' => 'Edit files',
462 'backup' => 'Backup/Delete',
463 'dump' => 'Dump DB',
464 'upload' => 'Upload',
465 'updateModule' => 'UPDATE!',
466 ),
467 'fe_u' => '',
468 'fe_p' => '',
469 'fe_up' => '',
470 );
471
472 $this->MOD_MENU['singleDetails'] = $this->mergeExternalItems($this->MCONF['name'],'singleDetails',$this->MOD_MENU['singleDetails']);
473
474 // page/be_user TSconfig settings and blinding of menu-items
475 if (!$BE_USER->getTSConfigVal('mod.'.$this->MCONF['name'].'.allowTVlisting')) {
476 unset($this->MOD_MENU['display_details'][3]);
477 unset($this->MOD_MENU['display_details'][4]);
478 unset($this->MOD_MENU['display_details'][5]);
479 }
480
481 // CLEANSE SETTINGS
482 $this->MOD_SETTINGS = t3lib_BEfunc::getModuleData($this->MOD_MENU, t3lib_div::_GP('SET'), $this->MCONF['name']);
483
484 if ($this->MOD_SETTINGS['function']==2) {
485 // If listing from online repository, certain items are removed though:
486 unset($this->MOD_MENU['listOrder']['type']);
487 unset($this->MOD_MENU['listOrder']['private']);
488 unset($this->MOD_MENU['display_details'][3]);
489 unset($this->MOD_MENU['display_details'][4]);
490 unset($this->MOD_MENU['display_details'][5]);
491 $this->MOD_SETTINGS = t3lib_BEfunc::getModuleData($this->MOD_MENU, t3lib_div::_GP('SET'), $this->MCONF['name']);
492 }
493 parent::menuConfig();
494 }
495
496 /**
497 * Main function for Extension Manager module.
498 *
499 * @return void
500 */
501 function main() {
502 global $BE_USER,$LANG;
503
504 // Starting page:
505 $this->content.=$this->doc->startPage('Extension Manager');
506 $this->content.=$this->doc->header('Extension Manager');
507 $this->content.=$this->doc->spacer(5);
508
509
510 // Commands given which is executed regardless of main menu setting:
511 if ($this->CMD['showExt']) { // Show details for a single extension
512 $this->showExtDetails($this->CMD['showExt']);
513 } elseif ($this->CMD['importExt'] || $this->CMD['uploadExt']) { // Imports an extension from online rep.
514 $err = $this->importExtFromRep($this->CMD['importExt'],$this->CMD['loc'],$this->CMD['uploadExt'],'',$this->CMD['transl'],$this->CMD['inc_manual']);
515 if ($err) {
516 $this->content.=$this->doc->section('',$GLOBALS['TBE_TEMPLATE']->rfw($err));
517 }
518 } elseif ($this->CMD['importExtInfo']) { // Gets detailed information of an extension from online rep.
519 $this->importExtInfo($this->CMD['importExtInfo']);
520 } else { // No command - we show what the menu setting tells us:
521
522 $menu = $LANG->sL('LLL:EXT:lang/locallang_core.php:labels.menu').' '.
523 t3lib_BEfunc::getFuncMenu(0,'SET[function]',$this->MOD_SETTINGS['function'],$this->MOD_MENU['function']);
524
525 if (t3lib_div::inList('0,1,2',$this->MOD_SETTINGS['function'])) {
526 $menu.='&nbsp;Order by:&nbsp;'.t3lib_BEfunc::getFuncMenu(0,'SET[listOrder]',$this->MOD_SETTINGS['listOrder'],$this->MOD_MENU['listOrder']).
527 '&nbsp;&nbsp;Show:&nbsp;'.t3lib_BEfunc::getFuncMenu(0,'SET[display_details]',$this->MOD_SETTINGS['display_details'],$this->MOD_MENU['display_details']).
528 '<br />Display shy extensions:&nbsp;&nbsp;'.t3lib_BEfunc::getFuncCheck(0,'SET[display_shy]',$this->MOD_SETTINGS['display_shy']);
529 }
530
531 if ($this->MOD_SETTINGS['function']==2) {
532 $menu.='&nbsp;&nbsp;&nbsp;Get own/member/selected extensions only:&nbsp;&nbsp;'.
533 t3lib_BEfunc::getFuncCheck(0,'SET[own_member_only]',$this->MOD_SETTINGS['own_member_only']);
534 }
535
536 $this->content.=$this->doc->section('','<span class="nobr">'.$menu.'</span>');
537 $this->content.=$this->doc->spacer(10);
538
539 switch((string)$this->MOD_SETTINGS['function']) {
540 case '0':
541 // Lists loaded (installed) extensions
542 $this->extensionList_loaded();
543 break;
544 case '1':
545 // Lists the installed (available) extensions
546 $this->extensionList_installed();
547 break;
548 case '2':
549 // Lists the extensions available from online rep.
550 $this->extensionList_import();
551 break;
552 case '3':
553 // Lists the extensions available from online rep.
554 $this->alterSettings();
555 break;
556 default:
557 $this->extObjContent();
558 break;
559 }
560 }
561
562 // Shortcuts:
563 if ($BE_USER->mayMakeShortcut()) {
564 $this->content.=$this->doc->spacer(20).$this->doc->section('',$this->doc->makeShortcutIcon('CMD','function',$this->MCONF['name']));
565 }
566 }
567
568 /**
569 * Print module content. Called as last thing in the global scope.
570 *
571 * @return void
572 */
573 function printContent() {
574 global $SOBE;
575
576 $this->content.= $this->doc->endPage();
577 echo $this->content;
578 }
579
580
581
582
583
584
585
586
587
588
589 /*********************************
590 *
591 * Function Menu Applications
592 *
593 *********************************/
594
595 /**
596 * Listing of loaded (installed) extensions
597 *
598 * @return void
599 */
600 function extensionList_loaded() {
601 global $TYPO3_LOADED_EXT;
602
603 list($list) = $this->getInstalledExtensions();
604
605 // Loaded extensions
606 $content = '';
607 $lines = array();
608 $lines[] = $this->extensionListRowHeader(' class="bgColor5"',array('<td><img src="clear.gif" width="1" height="1" alt="" /></td>'));
609
610 foreach($TYPO3_LOADED_EXT as $extKey => $eConf) {
611 if (strcmp($extKey, '_CACHEFILE')) {
612 if (($this->MOD_SETTINGS['display_shy'] || !$list[$extKey]['EM_CONF']['shy']) && $this->searchExtension($extKey,$list[$extKey])) {
613 if (in_array($extKey, $this->requiredExt)) {
614 $loadUnloadLink = '<strong>'.$GLOBALS['TBE_TEMPLATE']->rfw('Rq').'</strong>';
615 } else {
616 $loadUnloadLink = '<a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[remove]=1').'">'.$this->removeButton().'</a>';
617 }
618
619 $lines[] = $this->extensionListRow($extKey,$list[$extKey],array('<td class="bgColor">'.$loadUnloadLink.'</td>'));
620 }
621 }
622 }
623
624 $content.= t3lib_BEfunc::cshItem('_MOD_tools_em', 'loaded', $GLOBALS['BACK_PATH'],'');
625
626
627 $content.= 'Look up: <input type="text" name="_lookUp" value="'.htmlspecialchars($this->lookUpStr).'" /><input type="submit" value="Search"/><br/><br/>';
628
629 $content.= '
630
631 <!-- Loaded Extensions List -->
632 <table border="0" cellpadding="2" cellspacing="1">'.implode('',$lines).'</table>';
633
634 $this->content.=$this->doc->section('Loaded Extensions',$content,0,1);
635 }
636
637 /**
638 * Listing of available (installed) extensions
639 *
640 * @return void
641 */
642 function extensionList_installed() {
643 global $TYPO3_LOADED_EXT;
644
645 list($list,$cat)=$this->getInstalledExtensions();
646
647 // Available extensions
648 if (is_array($cat[$this->MOD_SETTINGS['listOrder']])) {
649 $content='';
650 $lines=array();
651 $lines[]=$this->extensionListRowHeader(' class="bgColor5"',array('<td><img src="clear.gif" width="18" height="1" alt="" /></td>'));
652
653 $allKeys=array();
654 foreach($cat[$this->MOD_SETTINGS['listOrder']] as $catName => $extEkeys) {
655 $allKeys[]='';
656 $allKeys[]='TYPE: '.$catName;
657
658 $lines[]='<tr><td colspan="'.(3+$this->detailCols[$this->MOD_SETTINGS['display_details']]).'"><br /></td></tr>';
659 $lines[]='<tr><td colspan="'.(3+$this->detailCols[$this->MOD_SETTINGS['display_details']]).'"><img src="'.$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>';
660
661 asort($extEkeys);
662 reset($extEkeys);
663 while(list($extKey)=each($extEkeys)) {
664 $allKeys[]=$extKey;
665 if (($this->MOD_SETTINGS['display_shy'] || !$list[$extKey]['EM_CONF']['shy']) && $this->searchExtension($extKey,$list[$extKey])) {
666 $loadUnloadLink = t3lib_extMgm::isLoaded($extKey)?
667 '<a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[remove]=1&CMD[clrCmd]=1&SET[singleDetails]=info').'">'.$this->removeButton().'</a>':
668 '<a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[load]=1&CMD[clrCmd]=1&SET[singleDetails]=info').'">'.$this->installButton().'</a>';
669 if (in_array($extKey,$this->requiredExt)) $loadUnloadLink='<strong>'.$GLOBALS['TBE_TEMPLATE']->rfw('Rq').'</strong>';
670
671 if ($list[$extKey]['EM_CONF']['private']) {
672 $theRowClass = 'em-private';
673 } else {
674 $theRowClass = t3lib_extMgm::isLoaded($extKey)? 'em-listbg1' : 'em-listbg2';
675 }
676 $lines[]=$this->extensionListRow($extKey,$list[$extKey],array('<td class="bgColor">'.$loadUnloadLink.'</td>'),$theRowClass);
677 }
678 }
679 }
680
681 $content.='
682
683
684 <!--
685 EXTENSION KEYS:
686
687
688 '.trim(implode(chr(10),$allKeys)).'
689
690 -->
691
692
693
694
695 ';
696
697 #debug($this->MOD_SETTINGS['listOrder']);
698 $content.= t3lib_BEfunc::cshItem('_MOD_tools_em', 'avail', $GLOBALS['BACK_PATH'],'|<br/>');
699 $content.= 'If you want to use an extension in TYPO3, you should simply click the "plus" button '.$this->installButton().' . <br />
700 Installed extensions can also be removed again - just click the remove button '.$this->removeButton().' .<br /><br />';
701
702 $content.= 'Look up: <input type="text" name="_lookUp" value="'.htmlspecialchars($this->lookUpStr).'" /><input type="submit" value="Search"/><br/><br/>';
703
704 $content.= '<table border="0" cellpadding="2" cellspacing="1">'.implode('',$lines).'</table>';
705
706 $this->content.=$this->doc->section('Available Extensions - Order by: '.$this->MOD_MENU['listOrder'][$this->MOD_SETTINGS['listOrder']],$content,0,1);
707 }
708 }
709
710 /**
711 * Listing remote extensions from online repository
712 *
713 * @return void
714 */
715 function extensionList_import() {
716 global $TYPO3_LOADED_EXT;
717
718 // Listing from online repository:
719 if ($this->listRemote) {
720 list($inst_list,$inst_cat) = $this->getInstalledExtensions();
721 $this->inst_keys = array_flip(array_keys($inst_list));
722
723 $this->detailCols[1]+=6;
724
725 // Getting data from repository:
726 $repositoryUrl=$this->repositoryUrl.
727 $this->repTransferParams().
728 '&tx_extrep[cmd]=currentListing'.
729 ($this->MOD_SETTINGS['own_member_only']?'&tx_extrep[listmode]=1':'').
730 ($this->listRemote_search ? '&tx_extrep[search]='.rawurlencode($this->listRemote_search) : '');
731
732 $fetchData = $this->fetchServerData($repositoryUrl);
733
734 if (is_array($fetchData)) {
735 $listArr = $fetchData[0];
736 list($list,$cat) = $this->getImportExtList($listArr);
737
738 // Available extensions
739 if (is_array($cat[$this->MOD_SETTINGS['listOrder']])) {
740 $content='';
741 $lines=array();
742 $lines[]=$this->extensionListRowHeader(' class="bgColor5"',array('<td><img src="clear.gif" width="18" height="1" alt="" /></td>'),1);
743
744 foreach($cat[$this->MOD_SETTINGS['listOrder']] as $catName => $extEkeys) {
745 if (count($extEkeys)) {
746 $lines[]='<tr><td colspan="'.(3+$this->detailCols[$this->MOD_SETTINGS['display_details']]).'"><br /></td></tr>';
747 $lines[]='<tr><td colspan="'.(3+$this->detailCols[$this->MOD_SETTINGS['display_details']]).'"><img src="'.$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>';
748
749 asort($extEkeys);
750 reset($extEkeys);
751 while(list($extKey)=each($extEkeys)) {
752 if ($this->MOD_SETTINGS['display_shy'] || !$list[$extKey]['EM_CONF']['shy']) {
753 $loadUnloadLink='';
754 if ($inst_list[$extKey]['type']!='S' && (!isset($inst_list[$extKey]) || $this->versionDifference($list[$extKey]['EM_CONF']['version'],$inst_list[$extKey]['EM_CONF']['version'],$this->versionDiffFactor))) {
755 if (isset($inst_list[$extKey])) {
756 // update
757 $loc= ($inst_list[$extKey]['type']=='G'?'G':'L');
758 $aUrl = 'index.php?CMD[importExt]='.$list[$extKey]['extRepUid'].'&CMD[loc]='.$loc.($this->getDocManual($extKey,$loc)?'&CMD[inc_manual]=1':'');
759 $loadUnloadLink.= '<a href="'.htmlspecialchars($aUrl).'"><img src="'.$GLOBALS['BACK_PATH'].'gfx/import_update.gif" width="12" height="12" title="Update the extension in \''.($loc=='G'?'global':'local').'\' from online repository to server" alt="" /></a>';
760 } else {
761 // import
762 $aUrl = 'index.php?CMD[importExt]='.$list[$extKey]['extRepUid'].'&CMD[loc]=L'.($this->getDocManual($extKey)?'&CMD[inc_manual]=1':'');
763 $loadUnloadLink.= '<a href="'.htmlspecialchars($aUrl).'"><img src="'.$GLOBALS['BACK_PATH'].'gfx/import.gif" width="12" height="12" title="Import this extension to \'local\' dir typo3conf/ext/ from online repository." alt="" /></a>';
764 }
765 } else {
766 $loadUnloadLink = '&nbsp;';
767 }
768
769 if ($list[$extKey]['_MEMBERS_ONLY']) {
770 $theRowClass = 'em-private';
771 } elseif (isset($inst_list[$extKey])) {
772 $theRowClass = t3lib_extMgm::isLoaded($extKey) ? 'em-listbg1' : 'em-listbg2';
773 } else {
774 $theRowClass = 'em-listbg3';
775 }
776 $lines[]=$this->extensionListRow($extKey,$list[$extKey],array('<td class="bgColor">'.$loadUnloadLink.'</td>'),$theRowClass,$inst_list,1,'index.php?CMD[importExtInfo]='.$list[$extKey]['extRepUid']);
777 }
778 }
779 }
780 }
781
782 // CSH:
783 $content.= t3lib_BEfunc::cshItem('_MOD_tools_em', 'import_ter', $GLOBALS['BACK_PATH'],'|<br/>');
784
785 $content.= '
786
787 <!-- TER Extensions list -->
788 <table border="0" cellpadding="2" cellspacing="1">'.implode('',$lines).'</table>';
789
790 $content.= '<br />Data fetched: ['.implode('][',$fetchData[1]).']';
791 $content.= '<br /><br /><strong>PRIVACY NOTICE:</strong><br /> '.$this->privacyNotice;
792
793 $this->content.=$this->doc->section('Extensions in TYPO3 Extension Repository (online) - Order by: '.$this->MOD_MENU['listOrder'][$this->MOD_SETTINGS['listOrder']],$content,0,1);
794
795 if (!$this->MOD_SETTINGS['own_member_only'] && !$this->listRemote_search) {
796 // Plugins which are NOT uploaded to repository but present on this server.
797 $content='';
798 $lines=array();
799 if (count($this->inst_keys)) {
800 $lines[]=$this->extensionListRowHeader(' class="bgColor5"',array('<td><img src="clear.gif" width="18" height="1" alt="" /></td>'));
801
802 reset($this->inst_keys);
803 while(list($extKey)=each($this->inst_keys)) {
804 if ($this->MOD_SETTINGS['display_shy'] || !$inst_list[$extKey]['EM_CONF']['shy']) {
805 $loadUnloadLink = t3lib_extMgm::isLoaded($extKey)?
806 '<a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[remove]=1&CMD[clrCmd]=1&SET[singleDetails]=info').'">'.$this->removeButton().'</a>':
807 '<a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[load]=1&CMD[clrCmd]=1&SET[singleDetails]=info').'">'.$this->installButton().'</a>';
808 if (in_array($extKey,$this->requiredExt)) $loadUnloadLink='<strong>'.$GLOBALS['TBE_TEMPLATE']->rfw('Rq').'</strong>';
809 $lines[]=$this->extensionListRow($extKey,$inst_list[$extKey],array('<td class="bgColor">'.$loadUnloadLink.'</td>'),t3lib_extMgm::isLoaded($extKey)?'em-listbg1':'em-listbg2');
810 }
811 }
812 }
813
814 $content.= 'This is the list of extensions which are either user-defined (should be prepended user_ then) or which are private (and does not show up in the public list above).<br /><br />';
815 $content.= '<table border="0" cellpadding="2" cellspacing="1">'.implode('',$lines).'</table>';
816 $this->content.=$this->doc->spacer(20);
817 $this->content.=$this->doc->section('Extensions found only on this server',$content,0,1);
818 }
819 }
820 }
821 } else {
822 // CSH
823 $content.= t3lib_BEfunc::cshItem('_MOD_tools_em', 'import', $GLOBALS['BACK_PATH'],'|<br/>');
824 $content.= 'Click here to connect to "'.$this->repositoryUrl.'" and retrieve the list of publicly available plugins from the TYPO3 Extension Repository.<br />';
825
826 if ($this->fe_user['username']) {
827 $content.= '<br /><img src="'.$GLOBALS['BACK_PATH'].'gfx/icon_note.gif" width="18" height="16" align="top" alt="" />Repository username "'.$this->fe_user['username'].'" will be sent as authentication.<br />';
828 } else {
829 $content.= '<br /><img src="'.$GLOBALS['BACK_PATH'].'gfx/icon_warning2.gif" width="18" height="16" align="top" alt="" />You have not configured a repository username/password yet. Please <a href="index.php?SET[function]=3">go to "Settings"</a> and do that.<br />';
830 }
831
832 $onCLick = "document.location='index.php?ter_connect=1&ter_search='+escape(this.form['_lookUp'].value);return false;";
833 $content.= '<br />
834 Look up: <input type="text" name="_lookUp" value="" />
835 <input type="submit" value="Connect to online repository" onclick="'.htmlspecialchars($onCLick).'" />
836 <br /><br /><strong>PRIVACY NOTICE:</strong><br /> '.$this->privacyNotice;
837
838 $this->content.=$this->doc->section('Extensions in TYPO3 Extension Repository',$content,0,1);
839 }
840
841 // Private lookup:
842 /*
843 $onClick = 'document.location=\'index.php?CMD[importExtInfo]=\'+document.pageform.uid_private_key.value+\'&CMD[download_password]=\'+document.pageform.download_password.value; return false;';
844 $content= 'Privat lookup key: <input type="text" name="uid_private_key" /> Password, if any: <input type="text" name="download_password" /><input type="submit" value="Lookup" onclick="'.htmlspecialchars($onClick).'" />';
845 $this->content.=$this->doc->spacer(20);
846 $this->content.=$this->doc->section('Private extension lookup:',$content,0,1);
847 */
848
849 // Upload:
850 if ($this->importAtAll()) {
851 $content= '</form><form action="index.php" enctype="'.$GLOBALS['TYPO3_CONF_VARS']['SYS']['form_enctype'].'" method="post">
852 Upload extension file (.t3x):<br />
853 <input type="file" size="60" name="upload_ext_file" /><br />
854 ... in location:<br />
855 <select name="CMD[loc]">';
856 if ($this->importAsType('L')) $content.='<option value="L">Local (../typo3conf/ext/)</option>';
857 if ($this->importAsType('G')) $content.='<option value="G">Global (typo3/ext/)</option>';
858 if ($this->importAsType('S')) $content.='<option value="S">System (typo3/sysext/)</option>';
859 $content.='</select><br />
860 <input type="checkbox" value="1" name="CMD[uploadOverwrite]" /> Overwrite any existing extension!<br />
861 <input type="submit" name="CMD[uploadExt]" value="Upload extension file" /><br />
862 ';
863 if (!$this->gzcompress) {
864 $content.='<br />'.$GLOBALS['TBE_TEMPLATE']->rfw("NOTE: No decompression available! Don't upload a compressed extension - it will not succeed.");
865 }
866 } else $content=$this->noImportMsg();
867
868 $this->content.=$this->doc->spacer(20);
869 $this->content.=$this->doc->section('Upload extension file directly (.t3x):',$content,0,1);
870 }
871
872 /**
873 * Allows changing of settings
874 *
875 * @return void
876 */
877 function alterSettings() {
878 $content.= t3lib_BEfunc::cshItem('_MOD_tools_em', 'settings', $GLOBALS['BACK_PATH'],'|<br/>');
879 $content.= '
880 <table border="0" cellpadding="2" cellspacing="2">
881 <tr class="bgColor4">
882 <td>Enter repository username:</td>
883 <td><input type="text" name="SET[fe_u]" value="'.htmlspecialchars($this->MOD_SETTINGS['fe_u']).'" /></td>
884 </tr>
885 <tr class="bgColor4">
886 <td>Enter repository password:</td>
887 <td><input type="password" name="SET[fe_p]" value="'.htmlspecialchars($this->MOD_SETTINGS['fe_p']).'" /></td>
888 </tr>
889 <tr class="bgColor4">
890 <td>Enter default upload password:</td>
891 <td><input type="password" name="SET[fe_up]" value="'.htmlspecialchars($this->MOD_SETTINGS['fe_up']).'" /></td>
892 </tr>
893 </table>
894
895 <strong>Notice:</strong> This is <em>not</em> your password to the TYPO3 backend! This user information is what is needed to log in at typo3.org with your account there!<br />
896 <br />
897 <input type="submit" value="Update" />
898 ';
899
900 $this->content.=$this->doc->section('Repository settings',$content,0,1);
901 }
902
903
904
905
906
907
908
909
910
911
912 /*********************************
913 *
914 * Command Applications (triggered by GET var)
915 *
916 *********************************/
917
918 /**
919 * Returns detailed info about an extension in the online repository
920 *
921 * @param string Extension repository uid + optional "private key": [uid]-[key].
922 * @return void
923 */
924 function importExtInfo($extRepUid) {
925
926 // "Go back" link
927 $content = '<a href="index.php" class="typo3-goBack"><img'.t3lib_iconWorks::skinImg($GLOBALS['BACK_PATH'],'gfx/goback.gif','width="14" height="14"').' alt="" /> Go back</a>';
928 $this->content.= $this->doc->section('',$content);
929 $content = '';
930
931 // Create connection URL:
932 $uidParts = t3lib_div::trimExplode('-',$extRepUid);
933 if (count($uidParts)==2) {
934 $extRepUid = $uidParts[0];
935 $addParams = '&tx_extrep[pKey]='.rawurlencode(trim($uidParts[1]))
936 .'&tx_extrep[pPass]='.rawurlencode(trim($this->CMD['download_password']));
937 $addImportParams = '&CMD[download_password]='.rawurlencode(trim($this->CMD['download_password']));
938 } else $addParams = '';
939
940 $repositoryUrl = $this->repositoryUrl.
941 $this->repTransferParams().
942 $addParams.
943 '&tx_extrep[cmd]=extensionInfo'.
944 '&tx_extrep[uid]='.$extRepUid;
945
946 // Fetch remote data:
947 list($fetchData) = $this->fetchServerData($repositoryUrl);
948 if (is_array($fetchData['_other_versions'])) {
949 $opt = array();
950 $opt[] = '<option value=""></option>';
951 $selectWasSet=0;
952
953 foreach($fetchData['_other_versions'] as $dat) {
954 $setSel = ($dat['uid']==$extRepUid?' selected="selected"':'');
955 if ($setSel) $selectWasSet=1;
956 $opt[]='<option value="'.$dat['uid'].'"'.$setSel.'>'.$dat['version'].'</option>';
957 }
958 if (!$selectWasSet && $fetchData['emconf_private']) {
959 $opt[]='<option value="'.$fetchData['uid'].'-'.$fetchData['private_key'].'" selected="selected">'.$fetchData['version'].' (Private)</option>';
960 }
961
962 // "Select version" box:
963 $onClick = 'document.location=\'index.php?CMD[importExtInfo]=\'+document.pageform.repUid.options[document.pageform.repUid.selectedIndex].value; return false;';
964 $select='<select name="repUid">'.implode('',$opt).'</select> <input type="submit" value="Load details" onclick="'.htmlspecialchars($onClick).'" /> or<br /><br />';
965 if ($this->importAtAll()) {
966 $onClick = '
967 document.location=\'index.php?CMD[importExt]=\'
968 +document.pageform.repUid.options[document.pageform.repUid.selectedIndex].value
969 +\'&CMD[loc]=\'+document.pageform.loc.options[document.pageform.loc.selectedIndex].value
970 +\'&CMD[transl]=\'+(document.pageform.transl.checked?1:0)
971 +\'&CMD[inc_manual]=\'+(document.pageform.inc_manual.checked?1:0)
972 +\''.$addImportParams.'\'; return false;';
973 $select.='
974 <input type="submit" value="Import/Update" onclick="'.htmlspecialchars($onClick).'"> to:
975 <select name="loc">'.
976 ($this->importAsType('G',$fetchData['emconf_lockType'])?'<option value="G">Global: '.$this->typePaths['G'].$fetchData['extension_key'].'/'.(@is_dir(PATH_site.$this->typePaths['G'].$fetchData['extension_key'])?' (OVERWRITE)':' (empty)').'</option>':'').
977 ($this->importAsType('L',$fetchData['emconf_lockType'])?'<option value="L">Local: '.$this->typePaths['L'].$fetchData['extension_key'].'/'.(@is_dir(PATH_site.$this->typePaths['L'].$fetchData['extension_key'])?' (OVERWRITE)':' (empty)').'</option>':'').
978 ($this->importAsType('S',$fetchData['emconf_lockType'])?'<option value="S">System: '.$this->typePaths['S'].$fetchData['extension_key'].'/'.(@is_dir(PATH_site.$this->typePaths['S'].$fetchData['extension_key'])?' (OVERWRITE)':' (empty)').'</option>':'').
979 #'<option value="fileadmin">'.htmlspecialchars('TEST: fileadmin/_temp_/[extension key name + date]').'</option>'.
980 '</select>
981 <br /><input type="checkbox" name="transl" value="1" />Include most recent translations
982 <br /><input type="checkbox" name="inc_manual" value="1"'.($this->getDocManual($fetchData['extension_key'],@is_dir(PATH_site.$this->typePaths['G'].$fetchData['extension_key'])?'G':'L')?' checked="checked"':'').' />Include "doc/manual.sxw", if any
983 ';
984 } else $select.= $this->noImportMsg();
985 $content.= $select;
986 $this->content.= $this->doc->section('Select command',$content,0,1);
987 }
988
989 // Details:
990 $extKey = $fetchData['extension_key'];
991 list($xList) = $this->getImportExtList(array($fetchData));
992 $eInfo = $xList[$extKey];
993 $eInfo['_TECH_INFO'] = unserialize($fetchData['techinfo']);
994 $tempFiles = unserialize($fetchData['files']);
995
996 if (is_array($tempFiles)) {
997 reset($tempFiles);
998 while(list($fk)=each($tempFiles)) {
999 if (!strstr($fk,'/')) $eInfo['files'][]=$fk;
1000 }
1001 }
1002
1003 $content='<strong>'.$fetchData['_ICON'].' &nbsp;'.$eInfo['EM_CONF']['title'].'</strong><br /><br />';
1004 $content.=$this->extInformationArray($extKey,$eInfo,1);
1005 $this->content.=$this->doc->spacer(10);
1006 $this->content.=$this->doc->section('Remote Extension Details:',$content,0,1);
1007
1008 if (is_array($fetchData['_MESSAGES'])) {
1009 $content = implode('<hr />',$fetchData['_MESSAGES']);
1010 $this->content.=$this->doc->section('Messages from repository server:',$content,0,1,1);
1011 }
1012 }
1013
1014 /**
1015 * Imports an extensions from the online repository
1016 *
1017 * @param string Extension repository uid + optional "private key": [uid]-[key].
1018 * @param string Install scope: "L" or "G"
1019 * @param boolean If true, extension is uploaded as file
1020 * @param string "Direct input" of the extension stream. Debugging purpuses, it seems.
1021 * @param boolean If true, recent translations are included.
1022 * @param boolean If true, manual is included.
1023 * @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.
1024 * @return string Return false on success, returns error message if error.
1025 */
1026 function importExtFromRep($extRepUid,$loc,$uploadFlag=0,$directInput='',$recentTranslations=0,$incManual=0,$dontDelete=0) {
1027
1028 if (is_array($directInput)) {
1029 $fetchData = array($directInput,'');
1030 $loc = !strcmp($loc,'G')?'G':'L';
1031 } elseif ($uploadFlag) {
1032 if ($_FILES['upload_ext_file']['tmp_name']) {
1033
1034 // Read uploaded file:
1035 $uploadedTempFile = t3lib_div::upload_to_tempfile($_FILES['upload_ext_file']['tmp_name']);
1036 $fileContent = t3lib_div::getUrl($uploadedTempFile);
1037 t3lib_div::unlink_tempfile($uploadedTempFile);
1038
1039 // Decode file data:
1040 $fetchData = array($this->decodeExchangeData($fileContent),'');
1041
1042 if (is_array($fetchData)) {
1043 $extKey = $fetchData[0]['extKey'];
1044 if ($extKey) {
1045 if (!$this->CMD['uploadOverwrite']) {
1046 $loc = !strcmp($loc,'G')?'G':'L';
1047 $comingExtPath = PATH_site.$this->typePaths[$loc].$extKey.'/';
1048 if (@is_dir($comingExtPath)) {
1049 # debug('!');
1050 return 'Extension was already present in "'.$comingExtPath.'" - and the overwrite flag was not set! So nothing done...';
1051 } // ... else go on, install...
1052 } // ... else go on, install...
1053 } else return 'No extension key in file. Strange...';
1054 } else return 'Wrong file format. No data recognized.';
1055 } else return 'No file uploaded! Probably the file was too large for PHPs internal limit for uploadable files.';
1056 } else {
1057
1058 // Create link:
1059 $content = '<a href="index.php" class="typo3-goBack"><img'.t3lib_iconWorks::skinImg($GLOBALS['BACK_PATH'],'gfx/goback.gif','width="14" height="14"').' alt="" /> Go back</a>';
1060 $this->content.= $this->doc->section('',$content);
1061 $content = '';
1062
1063 // Building request URL:
1064 $uidParts = t3lib_div::trimExplode('-',$extRepUid);
1065 if (count($uidParts)==2) {
1066 $extRepUid=$uidParts[0];
1067 $addParams='&tx_extrep[pKey]='.rawurlencode(trim($uidParts[1]))
1068 .'&tx_extrep[pPass]='.rawurlencode(trim($this->CMD['download_password']));
1069 } else $addParams='';
1070
1071 // If most recent translation should be delivered, send this:
1072 if ($recentTranslations) {
1073 $addParams.='&tx_extrep[transl]=1';
1074 }
1075
1076 // If manual should be included, send this:
1077 if ($incManual) {
1078 $addParams.='&tx_extrep[inc_manual]=1';
1079 }
1080
1081 $repositoryUrl=$this->repositoryUrl.
1082 $this->repTransferParams().
1083 $addParams.
1084 '&tx_extrep[cmd]=importExtension'.
1085 '&tx_extrep[uid]='.$extRepUid;
1086
1087 // Fetch extension from TER:
1088 $fetchData = $this->fetchServerData($repositoryUrl);
1089 }
1090
1091 // At this point the extension data should be present; so we want to write it to disc:
1092 if ($this->importAsType($loc)) {
1093 if (is_array($fetchData)) { // There was some data successfully transferred
1094 if ($fetchData[0]['extKey'] && is_array($fetchData[0]['FILES'])) {
1095 $extKey = $fetchData[0]['extKey'];
1096 $EM_CONF = $fetchData[0]['EM_CONF'];
1097 if (!$EM_CONF['lockType'] || !strcmp($EM_CONF['lockType'],$loc)) {
1098 $res = $this->clearAndMakeExtensionDir($fetchData[0],$loc,$dontDelete);
1099 if (is_array($res)) {
1100 $extDirPath = trim($res[0]);
1101 if ($extDirPath && @is_dir($extDirPath) && substr($extDirPath,-1)=='/') {
1102
1103 $emConfFile = $this->construct_ext_emconf_file($extKey,$EM_CONF);
1104 $dirs = $this->extractDirsFromFileList(array_keys($fetchData[0]['FILES']));
1105
1106 $res = $this->createDirsInPath($dirs,$extDirPath);
1107 if (!$res) {
1108 $writeFiles = $fetchData[0]['FILES'];
1109 $writeFiles['ext_emconf.php']['content'] = $emConfFile;
1110 $writeFiles['ext_emconf.php']['content_md5'] = md5($emConfFile);
1111
1112 // Write files:
1113 foreach($writeFiles as $theFile => $fileData) {
1114 t3lib_div::writeFile($extDirPath.$theFile,$fileData['content']);
1115 if (!@is_file($extDirPath.$theFile)) {
1116 $content.='Error: File "'.$extDirPath.$theFile.'" could not be created!!!<br />';
1117 } elseif (md5(t3lib_div::getUrl($extDirPath.$theFile)) != $fileData['content_md5']) {
1118 $content.='Error: File "'.$extDirPath.$theFile.'" MD5 was different from the original files MD5 - so the file is corrupted!<br />';
1119 } elseif (TYPO3_OS!='WIN') {
1120 #chmod ($extDirPath.$theFile, 0755); # SHOULD NOT do that here since writing the file should already have set adequate permissions!
1121 }
1122 }
1123
1124 // No content, no errors. Create success output here:
1125 if (!$content) {
1126 $content='SUCCESS: '.$extDirPath.'<br />';
1127
1128 // Fix TYPO3_MOD_PATH for backend modules in extension:
1129 $modules = t3lib_div::trimExplode(',',$EM_CONF['module'],1);
1130 if (count($modules)) {
1131 foreach($modules as $mD) {
1132 $confFileName = $extDirPath.$mD.'/conf.php';
1133 if (@is_file($confFileName)) {
1134 $content.= $this->writeTYPO3_MOD_PATH($confFileName,$loc,$extKey.'/'.$mD.'/').'<br />';
1135 } else $content.='Error: Couldn\'t find "'.$confFileName.'"<br />';
1136 }
1137 }
1138 // 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.
1139 // But this order of the code works.... (using the empty Array with type, EMCONF and files hereunder).
1140
1141 // Writing to ext_emconf.php:
1142 $sEMD5A = $this->serverExtensionMD5Array($extKey,array(
1143 'type' => $loc,
1144 'EM_CONF' => array(),
1145 'files' => array()
1146 ));
1147 $EM_CONF['_md5_values_when_last_written'] = serialize($sEMD5A);
1148 $emConfFile = $this->construct_ext_emconf_file($extKey,$EM_CONF);
1149 t3lib_div::writeFile($extDirPath.'ext_emconf.php',$emConfFile);
1150
1151 $content.='ext_emconf.php: '.$extDirPath.'ext_emconf.php<br />';
1152 $content.='Type: '.$loc.'<br />';
1153
1154 // Remove cache files:
1155 if (t3lib_extMgm::isLoaded($extKey)) {
1156 if ($this->removeCacheFiles()) {
1157 $content.='Cache-files are removed and will be re-written upon next hit<br />';
1158 }
1159
1160 list($new_list)=$this->getInstalledExtensions();
1161 $content.=$this->updatesForm($extKey,$new_list[$extKey],1,'index.php?CMD[showExt]='.$extKey.'&SET[singleDetails]=info');
1162 }
1163
1164 // Show any messages:
1165 if (is_array($fetchData[0]['_MESSAGES'])) {
1166 $content.='<hr /><strong>Messages from repository:</strong><br /><br />'.implode('<br />',$fetchData[0]['_MESSAGES']);
1167 }
1168
1169 // Install / Uninstall:
1170 $content.='<h3>Install / Uninstall Extension:</h3>';
1171 $content.=
1172 $new_list[$extKey] ?
1173 '<a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[remove]=1&CMD[clrCmd]=1&SET[singleDetails]=info').'">'.$this->removeButton().' Uninstall extension</a>' :
1174 '<a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[load]=1&CMD[clrCmd]=1&SET[singleDetails]=info').'">'.$this->installButton().' Install extension</a>';
1175
1176 }
1177 } else $content = $res;
1178 } else $content = 'Error: The extension path "'.$extDirPath.'" was different than expected...';
1179 } else $content = $res;
1180 } else $content = 'Error: The extension can only be installed in the path '.$this->typePaths[$EM_CONF['lockType']].' (lockType='.$EM_CONF['lockType'].')';
1181 } else $content = 'Error: No extension key!!! Why? - nobody knows... (Or no files in the file-array...)';
1182 } else $content = 'Error: The datatransfer did not succeed...';
1183 } else $content = 'Error: Installation is not allowed in this path ('.$this->typePaths[$loc].')';
1184
1185 $this->content.=$this->doc->section('Extension copied to server',$content,0,1);
1186 }
1187
1188 /**
1189 * Display extensions details.
1190 *
1191 * @param string Extension key
1192 * @return void Writes content to $this->content
1193 */
1194 function showExtDetails($extKey) {
1195 global $TYPO3_LOADED_EXT;
1196
1197 list($list,$cat)=$this->getInstalledExtensions();
1198 $absPath = $this->getExtPath($extKey,$list[$extKey]['type']);
1199
1200 // Check updateModule:
1201 if (@is_file($absPath.'class.ext_update.php')) {
1202 require_once($absPath.'class.ext_update.php');
1203 $updateObj = new ext_update;
1204 if (!$updateObj->access()) {
1205 unset($this->MOD_MENU['singleDetails']['updateModule']);
1206 }
1207 } else {
1208 unset($this->MOD_MENU['singleDetails']['updateModule']);
1209 }
1210
1211 // Function menu here:
1212 $content = '
1213 <table border="0" cellpadding="0" cellspacing="0" width="100%">
1214 <tr>
1215 <td nowrap="nowrap">Extension:&nbsp;<strong>'.$this->extensionTitleIconHeader($extKey,$list[$extKey]).'</strong> ('.$extKey.')</td>
1216 <td align="right" nowrap="nowrap">'.
1217 t3lib_BEfunc::getFuncMenu(0,'SET[singleDetails]',$this->MOD_SETTINGS['singleDetails'],$this->MOD_MENU['singleDetails'],'','&CMD[showExt]='.$extKey).' &nbsp; &nbsp; '.
1218 '<a href="index.php" class="typo3-goBack"><img'.t3lib_iconWorks::skinImg($this->doc->backPath,'gfx/goback.gif','width="14" height="14"').' class="absmiddle" alt="" /> Go back</a></td>
1219 </tr>
1220 </table>';
1221 $this->content.=$this->doc->section('',$content);
1222
1223 // Show extension details:
1224 if ($list[$extKey]) {
1225
1226 // Checking if a command for install/uninstall is executed:
1227 if (($this->CMD['remove'] || $this->CMD['load']) && !in_array($extKey,$this->requiredExt)) {
1228
1229 // Install / Uninstall extension here:
1230 if (t3lib_extMgm::isLocalconfWritable()) {
1231 if ($this->CMD['remove']) {
1232 $newExtList = $this->removeExtFromList($extKey,$list);
1233 } else {
1234 $newExtList = $this->addExtToList($extKey,$list);
1235 }
1236
1237 // Success-installation:
1238 if ($newExtList!=-1) {
1239 $updates = '';
1240 if ($this->CMD['load']) {
1241 $updates = $this->updatesForm($extKey,$list[$extKey],1,'','<input type="hidden" name="_do_install" value="1" /><input type="hidden" name="_clrCmd" value="'.$this->CMD['clrCmd'].'" />');
1242 if ($updates) {
1243 $updates = 'Before the extension can be installed the database needs to be updated with new tables or fields. Please select which operations to perform:'.$updates;
1244 $this->content.=$this->doc->section('Installing '.$this->extensionTitleIconHeader($extKey,$list[$extKey]).strtoupper(': Database needs to be updated'),$updates,1,1,1,1);
1245 }
1246 # $updates.=$this->checkDBupdates($extKey,$list[$extKey]);
1247 # $updates.= $this->checkClearCache($extKey,$list[$extKey]);
1248 # $updates.= $this->checkUploadFolder($extKey,$list[$extKey]);
1249 /* if ($updates) {
1250 $updates='
1251 Before the extension can be installed the database needs to be updated with new tables or fields. Please select which operations to perform:
1252 </form><form action="'.t3lib_div::linkThisScript().'" method="post">'.$updates.'
1253 <br /><input type="submit" name="write" value="Update database and install extension" />
1254 <input type="hidden" name="_do_install" value="1" />
1255 ';
1256 $this->content.=$this->doc->section('Installing '.$this->extensionTitleIconHeader($extKey,$list[$extKey]).strtoupper(': Database needs to be updated'),$updates,1,1,1);
1257 }
1258 */ } elseif ($this->CMD['remove']) {
1259 $updates.= $this->checkClearCache($extKey,$list[$extKey]);
1260 if ($updates) {
1261 $updates = '
1262 </form><form action="'.t3lib_div::linkThisScript().'" method="post">'.$updates.'
1263 <br /><input type="submit" name="write" value="Remove extension" />
1264 <input type="hidden" name="_do_install" value="1" />
1265 <input type="hidden" name="_clrCmd" value="'.$this->CMD['clrCmd'].'" />
1266 ';
1267 $this->content.=$this->doc->section('Installing '.$this->extensionTitleIconHeader($extKey,$list[$extKey]).strtoupper(': Database needs to be updated'),$updates,1,1,1,1);
1268 }
1269 }
1270 if (!$updates || t3lib_div::_GP('_do_install')) {
1271 $this->writeNewExtensionList($newExtList);
1272
1273
1274 /*
1275 $content = $newExtList;
1276 $this->content.=$this->doc->section('Active status',"
1277 <strong>Extension list is written to localconf.php!</strong><br />
1278 It may be necessary to reload TYPO3 depending on the change.<br />
1279
1280 <em>(".$content.")</em>",0,1);
1281 */
1282 if ($this->CMD['clrCmd'] || t3lib_div::_GP('_clrCmd')) {
1283 $vA = array('CMD'=>'');
1284 } else {
1285 $vA = array('CMD'=>Array('showExt'=>$extKey));
1286 }
1287 header('Location: '.t3lib_div::linkThisScript($vA));
1288 }
1289 }
1290 } else {
1291 $this->content.=$this->doc->section('Installing '.$this->extensionTitleIconHeader($extKey,$list[$extKey]).strtoupper(': Write access error'),'typo3conf/localconf.php seems not to be writable, so the extension cannot be installed automatically!',1,1,2,1);
1292 }
1293
1294 } elseif ($this->CMD['downloadFile'] && !in_array($extKey,$this->requiredExt)) {
1295
1296 // Link for downloading extension has been clicked - deliver content stream:
1297 $dlFile = $this->CMD['downloadFile'];
1298 if (t3lib_div::isFirstPartOfStr($dlFile,PATH_site) && t3lib_div::isFirstPartOfStr($dlFile,$absPath) && @is_file($dlFile)) {
1299 $mimeType = 'application/octet-stream';
1300 Header('Content-Type: '.$mimeType);
1301 Header('Content-Disposition: attachment; filename='.basename($dlFile));
1302 echo t3lib_div::getUrl($dlFile);
1303 exit;
1304 } else die('error....');
1305
1306 } elseif ($this->CMD['editFile'] && !in_array($extKey,$this->requiredExt)) {
1307
1308 // Editing extension file:
1309 $editFile = $this->CMD['editFile'];
1310 if (t3lib_div::isFirstPartOfStr($editFile,PATH_site) && t3lib_div::isFirstPartOfStr($editFile,$absPath)) { // Paranoia...
1311
1312 $fI = t3lib_div::split_fileref($editFile);
1313 if (@is_file($editFile) && t3lib_div::inList($this->editTextExtensions,($fI['fileext']?$fI['fileext']:$fI['filebody']))) {
1314 if (filesize($editFile)<($this->kbMax*1024)) {
1315 $outCode = '';
1316 $info = '';
1317 $submittedContent = t3lib_div::_POST('edit');
1318 $saveFlag = 0;
1319
1320 if(isset($submittedContent['file'])) { // Check referer here?
1321 $info.= $GLOBALS['TBE_TEMPLATE']->rfw('<br /><strong>File saved.</strong>').'<br />';
1322 $oldFileContent = t3lib_div::getUrl($editFile);
1323 $info.= 'MD5: <b>'.md5(str_replace(chr(13),'',$oldFileContent)).'</b> (Previous File)<br />';
1324 if (!$GLOBALS['TYPO3_CONF_VARS']['EXT']['noEdit']) {
1325 t3lib_div::writeFile($editFile,$submittedContent['file']);
1326 $saveFlag = 1;
1327 } else die('Saving disabled!!!');
1328 }
1329
1330 $fileContent = t3lib_div::getUrl($editFile);
1331 $numberOfRows = 35;
1332
1333 $outCode.= 'File: <b>'.substr($editFile,strlen($absPath)).'</b> ('.t3lib_div::formatSize(filesize($editFile)).')<br />';
1334 $info.= 'MD5: <b>'.md5(str_replace(chr(13),'',$fileContent)).'</b> (File)<br />';
1335 if($saveFlag) $info.= 'MD5: <b>'.md5(str_replace(chr(13),'',$submittedContent['file'])).'</b> (Saved)<br />';
1336 $outCode.= '<textarea name="edit[file]" rows="'.$numberOfRows.'" wrap="off"'.$this->doc->formWidthText(48,'width:98%;height:70%','off').'>'.t3lib_div::formatForTextarea($fileContent).'</textarea>';
1337 $outCode.= '<input type="hidden" name="edit[filename]" value="'.$editFile.'" />';
1338 $outCode.= '<input type="hidden" name="CMD[editFile]" value="'.htmlspecialchars($editFile).'" />';
1339 $outCode.= '<input type="hidden" name="CMD[showExt]" value="'.$extKey.'" />';
1340 $outCode.= $info;
1341
1342 if (!$GLOBALS['TYPO3_CONF_VARS']['EXT']['noEdit']) {
1343 $outCode.='<br /><input type="submit" name="save_file" value="Save file" />';
1344 } else $outCode.=$GLOBALS['TBE_TEMPLATE']->rfw('<br />[SAVING IS DISABLED - can be enabled by the TYPO3_CONF_VARS[EXT][noEdit]-flag] ');
1345
1346 $onClick = 'document.location=\'index.php?CMD[showExt]='.$extKey.'\';return false;';
1347 $outCode.='<input type="submit" name="cancel" value="Cancel" onclick="'.htmlspecialchars($onClick).'" />';
1348
1349 $theOutput.=$this->doc->spacer(15);
1350 $theOutput.=$this->doc->section('Edit file:','',0,1);
1351 $theOutput.=$this->doc->sectionEnd().$outCode;
1352 $this->content.=$theOutput;
1353 } else {
1354 $theOutput.=$this->doc->spacer(15);
1355 $theOutput.=$this->doc->section('Filesize exceeded '.$this->kbMax.' Kbytes','Files larger than '.$this->kbMax.' KBytes are not allowed to be edited.');
1356 }
1357 }
1358 } else die('Fatal Edit error: File "'.$editFile.'" was not inside the correct path of the TYPO3 Extension!');
1359 } else {
1360
1361 // MAIN:
1362 switch((string)$this->MOD_SETTINGS['singleDetails']) {
1363 case 'info':
1364 // Loaded / Not loaded:
1365 if (!in_array($extKey,$this->requiredExt)) {
1366 if ($TYPO3_LOADED_EXT[$extKey]) {
1367 $content = '<strong>The extension is installed (loaded and running)!</strong><br />'.
1368 '<a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[remove]=1').'">Click here to remove the extension: '.$this->removeButton().'</a>';
1369 } else {
1370 $content = 'The extension is <strong>not</strong> installed yet.<br />'.
1371 '<a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[load]=1').'">Click here to install the extension: '.$this->installButton().'</a>';
1372 }
1373 } else {
1374 $content = 'This extension is entered in the TYPO3_CONF_VARS[SYS][requiredExt] list and is therefore always loaded.';
1375 }
1376 $this->content.=$this->doc->spacer(10);
1377 $this->content.=$this->doc->section('Active status:',$content,0,1);
1378
1379 if (t3lib_extMgm::isLoaded($extKey)) {
1380 $updates=$this->updatesForm($extKey,$list[$extKey]);
1381 if ($updates) {
1382 $this->content.=$this->doc->spacer(10);
1383 $this->content.=$this->doc->section('Update needed:',$updates.'<br /><br />Notice: "Static data" may not <em>need</em> to be updated. You will only have to import static data each time you upgrade the extension.',0,1);
1384 }
1385 }
1386
1387 // Config:
1388 if (@is_file($absPath.'ext_conf_template.txt')) {
1389 $this->content.=$this->doc->spacer(10);
1390 $this->content.=$this->doc->section('Configuration:','(<em>Notice: You may need to clear the cache after configuration of the extension. This is required if the extension adds TypoScript depending on these settings.</em>)<br /><br />',0,1);
1391 $this->tsStyleConfigForm($extKey,$list[$extKey]);
1392 }
1393
1394 // Show details:
1395 $content = t3lib_BEfunc::cshItem('_MOD_tools_em', 'info', $GLOBALS['BACK_PATH'],'|<br/>');
1396 $content.= $this->extInformationArray($extKey,$list[$extKey]);
1397
1398 $this->content.=$this->doc->spacer(10);
1399 $this->content.=$this->doc->section('Details:',$content,0,1);
1400 break;
1401 case 'upload':
1402 $TER_CMD = t3lib_div::_GP('TER_CMD');
1403 if (is_array($TER_CMD)) {
1404 $msg = $this->processRepositoryReturnData($TER_CMD);
1405 if ($msg) {
1406 $this->content.=$this->doc->section('Local update of EM_CONF',$msg,0,1,1);
1407 $this->content.=$this->doc->spacer(10);
1408 }
1409 // Must reload this, because EM_CONF information has been updated!
1410 list($list,$cat)=$this->getInstalledExtensions();
1411 } else {
1412 // CSH:
1413 $content = t3lib_BEfunc::cshItem('_MOD_tools_em', 'upload', $GLOBALS['BACK_PATH'],'|<br/>');
1414
1415 // Upload:
1416 if (substr($extKey,0,5)!='user_') {
1417 $content.= $this->getRepositoryUploadForm($extKey,$list[$extKey]);
1418 $eC=0;
1419 } else {
1420 $content.='The extensions has an extension key prefixed "user_" which indicates that it is a user-defined extension with no official unique identification. Therefore it cannot be uploaded.<br />
1421 You are encouraged to register a unique extension key for all your TYPO3 extensions - even if the project is current not official.';
1422 $eC=2;
1423 }
1424 $this->content.=$this->doc->section('Upload extension to repository',$content,0,1,$eC);
1425 }
1426 break;
1427 case 'download':
1428 break;
1429 case 'backup':
1430 $content = t3lib_BEfunc::cshItem('_MOD_tools_em', 'backup_delete', $GLOBALS['BACK_PATH'],'|<br/>');
1431 $content.= $this->extBackup($extKey,$list[$extKey]);
1432 $this->content.=$this->doc->section('Backup',$content,0,1);
1433
1434 $content = $this->extDelete($extKey,$list[$extKey]);
1435 $this->content.=$this->doc->section('Delete',$content,0,1);
1436
1437 $content = $this->extUpdateEMCONF($extKey,$list[$extKey]);
1438 $this->content.=$this->doc->section('Update EM_CONF',$content,0,1);
1439 break;
1440 case 'dump':
1441 $this->extDumpTables($extKey,$list[$extKey]);
1442 break;
1443 case 'edit':
1444 // Files:
1445 $content = t3lib_BEfunc::cshItem('_MOD_tools_em', 'editfiles', $GLOBALS['BACK_PATH'],'|<br/>');
1446 $content.= $this->getFileListOfExtension($extKey,$list[$extKey]);
1447
1448 $this->content.=$this->doc->section('Extension files',$content,0,1);
1449 break;
1450 case 'updateModule':
1451 $this->content.=$this->doc->section('Update:',is_object($updateObj) ? $updateObj->main() : 'No update object',0,1);
1452 break;
1453 default:
1454 $this->extObjContent();
1455 break;
1456 }
1457 }
1458 }
1459 }
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470 /***********************************
1471 *
1472 * Application Sub-functions (HTML parts)
1473 *
1474 **********************************/
1475
1476 /**
1477 * Creates a form for an extension which contains all options for configuration, updates of database, clearing of cache etc.
1478 * This form is shown when
1479 *
1480 * @param string Extension key
1481 * @param array Extension information array
1482 * @param boolean If set, the form will ONLY show if fields/tables should be updated (suppressing forms like general configuration and cache clearing).
1483 * @param string Alternative action=""-script
1484 * @param string HTML: Additional form fields
1485 * @return string HTML
1486 */
1487 function updatesForm($extKey,$extInfo,$notSilent=0,$script='',$addFields='') {
1488 $script = $script ? $script : t3lib_div::linkThisScript();
1489 $updates.= $this->checkDBupdates($extKey,$extInfo);
1490 $uCache = $this->checkClearCache($extKey,$extInfo);
1491 if ($notSilent) $updates.= $uCache;
1492 $updates.= $this->checkUploadFolder($extKey,$extInfo);
1493
1494 $absPath = $this->getExtPath($extKey,$extInfo['type']);
1495 if ($notSilent && @is_file($absPath.'ext_conf_template.txt')) {
1496 $cForm = $this->tsStyleConfigForm($extKey,$extInfo,1,$script,$updates.$addFields.'<br />');
1497 }
1498
1499 if ($updates || $cForm) {
1500 if ($cForm) {
1501 $updates = '</form>'.$cForm.'<form>';
1502 } else {
1503 $updates = '</form><form action="'.htmlspecialchars($script).'" method="post">'.$updates.$addFields.'
1504 <br /><input type="submit" name="write" value="Make updates" />
1505 ';
1506 }
1507 }
1508 return $updates;
1509 }
1510
1511 /**
1512 * Creates view for dumping static tables and table/fields structures...
1513 *
1514 * @param string Extension key
1515 * @param array Extension information array
1516 * @return void
1517 */
1518 function extDumpTables($extKey,$extInfo) {
1519
1520 // Get dbInfo which holds the structure known from the tables.sql file
1521 $techInfo = $this->makeDetailedExtensionAnalysis($extKey,$extInfo);
1522 $absPath = $this->getExtPath($extKey,$extInfo['type']);
1523
1524 // Static tables:
1525 if (is_array($techInfo['static'])) {
1526 if ($this->CMD['writeSTATICdump']) { // Writing static dump:
1527 $writeFile = $absPath.'ext_tables_static+adt.sql';
1528 if (@is_file($writeFile)) {
1529 $dump_static = $this->dumpStaticTables(implode(',',$techInfo['static']));
1530 t3lib_div::writeFile($writeFile,$dump_static);
1531 $this->content.=$this->doc->section('Table and field structure required',t3lib_div::formatSize(strlen($dump_static)).'bytes written to '.substr($writeFile,strlen(PATH_site)),0,1);
1532 }
1533 } else { // Showing info about what tables to dump - and giving the link to execute it.
1534 $msg = 'Dumping table content for static tables:<br />';
1535 $msg.= '<br />'.implode('<br />',$techInfo['static']).'<br />';
1536
1537 // ... then feed that to this function which will make new CREATE statements of the same fields but based on the current database content.
1538 $this->content.=$this->doc->section('Static tables',$msg.'<hr /><strong><a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[writeSTATICdump]=1').'">Write current static table contents to ext_tables_static+adt.sql now!</a></strong>',0,1);
1539 $this->content.=$this->doc->spacer(20);
1540 }
1541 }
1542
1543 // Table and field definitions:
1544 if (is_array($techInfo['dump_tf'])) {
1545 $dump_tf_array = $this->getTableAndFieldStructure($techInfo['dump_tf']);
1546 $dump_tf = $this->dumpTableAndFieldStructure($dump_tf_array);
1547 if ($this->CMD['writeTFdump']) {
1548 $writeFile = $absPath.'ext_tables.sql';
1549 if (@is_file($writeFile)) {
1550 t3lib_div::writeFile($writeFile,$dump_tf);
1551 $this->content.=$this->doc->section('Table and field structure required',t3lib_div::formatSize(strlen($dump_tf)).'bytes written to '.substr($writeFile,strlen(PATH_site)),0,1);
1552 }
1553 } else {
1554 $msg = 'Dumping current database structure for:<br />';
1555 if (is_array($techInfo['tables'])) {
1556 $msg.= '<br /><strong>Tables:</strong><br />'.implode('<br />',$techInfo['tables']).'<br />';
1557 }
1558 if (is_array($techInfo['fields'])) {
1559 $msg.= '<br /><strong>Solo-fields:</strong><br />'.implode('<br />',$techInfo['fields']).'<br />';
1560 }
1561
1562 // ... then feed that to this function which will make new CREATE statements of the same fields but based on the current database content.
1563 $this->content.=$this->doc->section('Table and field structure required',$msg.'<hr /><strong><a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[writeTFdump]=1').'">Write this dump to ext_tables.sql now!</a></strong><hr />
1564 <pre>'.htmlspecialchars($dump_tf).'</pre>',0,1);
1565
1566
1567 $details = ' This dump is based on two factors:<br />
1568 <ul>
1569 <li>1) All tablenames in ext_tables.sql which are <em>not</em> found in the "modify_tables" list in ext_emconf.php are dumped with the current database structure.</li>
1570 <li>2) For any tablenames which <em>are</em> listed in "modify_tables" all fields and keys found for the table in ext_tables.sql will be re-dumped with the fresh equalents from the database.</li>
1571 </ul>
1572 Bottomline is: Whole tables are dumped from database with no regard to which fields and keys are defined in ext_tables.sql. But for tables which are only modified, any NEW fields added to the database must in some form or the other exist in the ext_tables.sql file as well.<br />';
1573 $this->content.=$this->doc->section('',$details);
1574 }
1575 }
1576 }
1577
1578 /**
1579 * Returns file-listing of an extension
1580 *
1581 * @param string Extension key
1582 * @param array Extension information array
1583 * @return string HTML table.
1584 */
1585 function getFileListOfExtension($extKey,$conf) {
1586 $extPath = $this->getExtPath($extKey,$conf['type']);
1587
1588 if ($extPath) {
1589 // Read files:
1590 $fileArr = array();
1591 $fileArr = t3lib_div::getAllFilesAndFoldersInPath($fileArr,$extPath);
1592
1593 // Start table:
1594 $lines = array();
1595 $totalSize = 0;
1596
1597 // Header:
1598 $lines[] = '
1599 <tr class="bgColor5">
1600 <td>File:</td>
1601 <td>Size:</td>
1602 <td>Edit:</td>
1603 </tr>';
1604
1605 foreach($fileArr as $file) {
1606 $fI = t3lib_div::split_fileref($file);
1607 $lines[] = '
1608 <tr class="bgColor4">
1609 <td><a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[downloadFile]='.rawurlencode($file)).'" title="Download...">'.substr($file,strlen($extPath)).'</a></td>
1610 <td>'.t3lib_div::formatSize(filesize($file)).'</td>
1611 <td>'.(!in_array($extKey,$this->requiredExt)&&t3lib_div::inList($this->editTextExtensions,($fI['fileext']?$fI['fileext']:$fI['filebody']))?'<a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[editFile]='.rawurlencode($file)).'">Edit file</a>':'').'</td>
1612 </tr>';
1613 $totalSize+=filesize($file);
1614 }
1615
1616 $lines[] = '
1617 <tr class="bgColor6">
1618 <td><strong>Total:</strong></td>
1619 <td><strong>'.t3lib_div::formatSize($totalSize).'</strong></td>
1620 <td>&nbsp;</td>
1621 </tr>';
1622
1623 return '
1624 Path: '.$extPath.'<br /><br />
1625 <table border="0" cellpadding="1" cellspacing="2">'.implode('',$lines).'</table>';
1626 }
1627 }
1628
1629 /**
1630 * Delete extension from the file system
1631 *
1632 * @param string Extension key
1633 * @param array Extension info array
1634 * @return string Returns message string about the status of the operation
1635 */
1636 function extDelete($extKey,$extInfo) {
1637 $absPath = $this->getExtPath($extKey,$extInfo['type']);
1638 if (t3lib_extMgm::isLoaded($extKey)) {
1639 return 'This extension is currently installed (loaded and active) and so cannot be deleted!';
1640 } elseif (!$this->deleteAsType($extInfo['type'])) {
1641 return 'You cannot delete (and install/update) extensions in the '.$this->typeLabels[$extInfo['type']].' scope.';
1642 } elseif (t3lib_div::inList('G,L',$extInfo['type'])) {
1643 if ($this->CMD['doDelete'] && !strcmp($absPath,$this->CMD['absPath'])) {
1644 $res = $this->removeExtDirectory($absPath);
1645 if ($res) {
1646 return 'ERROR: Could not remove extension directory "'.$absPath.'". Had the following errors:<br /><br />'.
1647 nl2br($res);
1648 } else {
1649 return 'Removed extension in path "'.$absPath.'"!';
1650 }
1651 } else {
1652 $onClick = "if (confirm('Are you sure you want to delete this extension from the server?')) {document.location='index.php?CMD[showExt]=".$extKey.'&CMD[doDelete]=1&CMD[absPath]='.rawurlencode($absPath)."';}";
1653 $content.= '<a href="#" onclick="'.htmlspecialchars($onClick).' return false;"><strong>DELETE EXTENSION FROM SERVER</strong> (in the "'.$this->typeLabels[$extInfo['type']].'" location "'.substr($absPath,strlen(PATH_site)).'")!</a>';
1654 $content.= '<br /><br />(Maybe you should make a backup first, see above.)';
1655 return $content;
1656 }
1657 } else return 'Extension is not a global or local extension and cannot be removed.';
1658 }
1659
1660 /**
1661 * Update extension EM_CONF...
1662 *
1663 * @param string Extension key
1664 * @param array Extension information array
1665 * @return string HTML content.
1666 */
1667 function extUpdateEMCONF($extKey,$extInfo) {
1668 $absPath = $this->getExtPath($extKey,$extInfo['type']);
1669 if ($this->CMD['doUpdateEMCONF']) {
1670 return $this->updateLocalEM_CONF($extKey,$extInfo);
1671 } else {
1672 $onClick = "if (confirm('Are you sure you want to update EM_CONF?')) {document.location='index.php?CMD[showExt]=".$extKey."&CMD[doUpdateEMCONF]=1';}";
1673 $content.= '<a href="#" onclick="'.htmlspecialchars($onClick).' return false;"><strong>Update extension EM_CONF file</strong> (in the "'.$this->typeLabels[$extInfo['type']].'" location "'.substr($absPath,strlen(PATH_site)).'")!</a>';
1674 $content.= '<br /><br />If files are changed, added or removed to an extension this is normally detected and displayed so you know that this extension has been locally altered and may need to be uploaded or at least not overridden.<br />
1675 Updating this file will first of all reset this registration.';
1676 return $content;
1677 }
1678 }
1679
1680 /**
1681 * Download extension as file / make backup
1682 *
1683 * @param string Extension key
1684 * @param array Extension information array
1685 * @return string HTML content
1686 */
1687 function extBackup($extKey,$extInfo) {
1688 $uArr = $this->makeUploadArray($extKey,$extInfo);
1689 if (is_array($uArr)) {
1690 $local_gzcompress = $this->gzcompress && !$this->CMD['dontCompress'];
1691 $backUpData = $this->makeUploadDataFromArray($uArr,intval($local_gzcompress));
1692 $filename = 'T3X_'.$extKey.'-'.str_replace('.','_',$extInfo['EM_CONF']['version']).($local_gzcompress?'-z':'').'-'.date('YmdHi').'.t3x';
1693 if (intval($this->CMD['doBackup'])==1) {
1694
1695 $mimeType = 'application/octet-stream';
1696 Header('Content-Type: '.$mimeType);
1697 Header('Content-Disposition: attachment; filename='.$filename);
1698
1699 // New headers suggested by Xin:
1700 // For now they are commented out because a) I have seen no official support yet, b) when clicking the back-link in MSIE after download you see ugly binary stuff and c) I couldn't see a BIG difference, in particular not in Moz/Opera.
1701 /* header('Content-Type: application/force-download');
1702 header('Content-Length: '.strlen($backUpData));
1703
1704 header('Content-Disposition: attachment; filename='.$filename);
1705 header('Content-Description: File Transfer');
1706 header('Content-Transfer-Encoding: binary');
1707 */
1708
1709 // ANYWAYS! The download is NOT always working - in some cases extensions will never get the same MD5 sum as the one shown at the download link - and they should in order to work! We do NOT know why yet.
1710
1711 echo $backUpData;
1712 exit;
1713 } elseif ($this->CMD['dumpTables']) {
1714 $filename='T3X_'.$extKey;
1715 $cTables = count(explode(',',$this->CMD['dumpTables']));
1716 if ($cTables>1) {
1717 $filename.='-'.$cTables.'tables';
1718 } else {
1719 $filename.='-'.$this->CMD['dumpTables'];
1720 }
1721 $filename.='+adt.sql';
1722
1723 $mimeType = 'application/octet-stream';
1724 Header('Content-Type: '.$mimeType);
1725 Header('Content-Disposition: attachment; filename='.$filename);
1726 echo $this->dumpStaticTables($this->CMD['dumpTables']);
1727 exit;
1728 } else {
1729 $techInfo = $this->makeDetailedExtensionAnalysis($extKey,$extInfo);
1730 // if ($techInfo['tables']||$techInfo['static']||$techInfo['fields']) {
1731 #debug($techInfo);
1732 $lines=array();
1733 $lines[]='<tr class="bgColor5"><td colspan="2"><strong>Make selection:</strong></td></tr>';
1734 $lines[]='<tr class="bgColor4"><td><strong>Extension files:</strong></td><td>'.
1735 '<a href="'.htmlspecialchars('index.php?CMD[doBackup]=1&CMD[showExt]='.$extKey).'">Download extension "'.$extKey.'" as a file</a><br />('.$filename.', '.t3lib_div::formatSize(strlen($backUpData)).', MD5: '.md5($backUpData).')<br />'.
1736 ($this->gzcompress ? '<br /><a href="'.htmlspecialchars('index.php?CMD[doBackup]=1&CMD[dontCompress]=1&CMD[showExt]='.$extKey).'">(Click here to download extension without compression.)</a>':'').
1737 '</td></tr>';
1738
1739 if (is_array($techInfo['tables'])) { $lines[]='<tr class="bgColor4"><td><strong>Data tables:</strong></td><td>'.$this->extBackup_dumpDataTablesLine($techInfo['tables'],$extKey).'</td></tr>'; }
1740 if (is_array($techInfo['static'])) { $lines[]='<tr class="bgColor4"><td><strong>Static tables:</strong></td><td>'.$this->extBackup_dumpDataTablesLine($techInfo['static'],$extKey).'</td></tr>'; }
1741
1742 $content = '<table border="0" cellpadding="2" cellspacing="2">'.implode('',$lines).'</table>';
1743 return $content;
1744 }
1745 } else die('Error...');
1746 }
1747
1748 /**
1749 * Link to dump of database tables
1750 *
1751 * @param string Extension key
1752 * @param array Extension information array
1753 * @return string HTML
1754 */
1755 function extBackup_dumpDataTablesLine($tablesArray,$extKey) {
1756 $tables = array();
1757 $tablesNA = array();
1758
1759 foreach($tablesArray as $tN) {
1760 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('count(*)', $tN, '');
1761 if (!$GLOBALS['TYPO3_DB']->sql_error()) {
1762 $row = $GLOBALS['TYPO3_DB']->sql_fetch_row($res);
1763 $tables[$tN]='<tr><td>&nbsp;</td><td><a href="'.htmlspecialchars('index.php?CMD[dumpTables]='.rawurlencode($tN).'&CMD[showExt]='.$extKey).'" title="Dump table \''.$tN.'\'">'.$tN.'</a></td><td>&nbsp;&nbsp;&nbsp;</td><td>'.$row[0].' records</td></tr>';
1764 } else {
1765 $tablesNA[$tN]='<tr><td>&nbsp;</td><td>'.$tN.'</td><td>&nbsp;</td><td>Did not exist.</td></tr>';
1766 }
1767 }
1768 $label = '<table border="0" cellpadding="0" cellspacing="0">'.implode('',array_merge($tables,$tablesNA)).'</table>';// Candidate for t3lib_div::array_merge() if integer-keys will some day make trouble...
1769 if (count($tables)) {
1770 $label = '<a href="'.htmlspecialchars('index.php?CMD[dumpTables]='.rawurlencode(implode(',',array_keys($tables))).'&CMD[showExt]='.$extKey).'" title="Dump all existing tables.">Download all data from:</a><br /><br />'.$label;
1771 } else $label = 'Nothing to dump...<br /><br />'.$label;
1772 return $label;
1773 }
1774
1775 /**
1776 * Prints a table with extension information in it.
1777 *
1778 * @param string Extension key
1779 * @param array Extension information array
1780 * @param boolean If set, the information array shows information for a remote extension in TER, not a local one.
1781 * @return string HTML content.
1782 */
1783 function extInformationArray($extKey,$extInfo,$remote=0) {
1784 $lines=array();
1785 $lines[]='<tr class="bgColor5"><td colspan="2"><strong>General information:</strong></td>'.$this->helpCol('').'</tr>';
1786 $lines[]='<tr class="bgColor4"><td>Title:</td><td>'.$extInfo['EM_CONF']['_icon'].$extInfo['EM_CONF']['title'].'</td>'.$this->helpCol('title').'</tr>';
1787 $lines[]='<tr class="bgColor4"><td>Description:</td><td>'.nl2br(htmlspecialchars($extInfo['EM_CONF']['description'])).'</td>'.$this->helpCol('description').'</tr>';
1788 $lines[]='<tr class="bgColor4"><td>Author:</td><td>'.$this->wrapEmail($extInfo['EM_CONF']['author'].($extInfo['EM_CONF']['author_email'] ? ' <'.$extInfo['EM_CONF']['author_email'].'>' : ''),$extInfo['EM_CONF']['author_email']).
1789 ($extInfo['EM_CONF']['author_company']?', '.$extInfo['EM_CONF']['author_company']:'').
1790 '</td>'.$this->helpCol('description').'</tr>';
1791
1792 $lines[]='<tr class="bgColor4"><td>Version:</td><td>'.$extInfo['EM_CONF']['version'].'</td>'.$this->helpCol('version').'</tr>';
1793 $lines[]='<tr class="bgColor4"><td>Category:</td><td>'.$this->categories[$extInfo['EM_CONF']['category']].'</td>'.$this->helpCol('category').'</tr>';
1794 $lines[]='<tr class="bgColor4"><td>State:</td><td>'.$this->states[$extInfo['EM_CONF']['state']].'</td>'.$this->helpCol('state').'</tr>';
1795 $lines[]='<tr class="bgColor4"><td>Shy?</td><td>'.($extInfo['EM_CONF']['shy']?'Yes':'').'</td>'.$this->helpCol('shy').'</tr>';
1796 $lines[]='<tr class="bgColor4"><td>Internal?</td><td>'.($extInfo['EM_CONF']['internal']?'Yes':'').'</td>'.$this->helpCol('internal').'</tr>';
1797
1798 $lines[]='<tr class="bgColor4"><td>Dependencies:</td><td>'.$extInfo['EM_CONF']['dependencies'].'</td>'.$this->helpCol('dependencies').'</tr>';
1799 if (!$remote) {
1800 $lines[]='<tr class="bgColor4"><td>Conflicts:</td><td>'.$extInfo['EM_CONF']['conflicts'].'</td>'.$this->helpCol('conflicts').'</tr>';
1801 $lines[]='<tr class="bgColor4"><td>Priority:</td><td>'.$extInfo['EM_CONF']['priority'].'</td>'.$this->helpCol('priority').'</tr>';
1802 $lines[]='<tr class="bgColor4"><td>Clear cache?</td><td>'.($extInfo['EM_CONF']['clearCacheOnLoad']?'Yes':'').'</td>'.$this->helpCol('clearCacheOnLoad').'</tr>';
1803 $lines[]='<tr class="bgColor4"><td>Includes modules:</td><td>'.$extInfo['EM_CONF']['module'].'</td>'.$this->helpCol('module').'</tr>';
1804 }
1805 $lines[]='<tr class="bgColor4"><td>Lock Type?</td><td>'.($extInfo['EM_CONF']['lockType']?$extInfo['EM_CONF']['lockType']:'').'</td>'.$this->helpCol('lockType').'</tr>';
1806 $lines[]='<tr class="bgColor4"><td>Modifies tables:</td><td>'.$extInfo['EM_CONF']['modify_tables'].'</td>'.$this->helpCol('modify_tables').'</tr>';
1807
1808 $lines[]='<tr class="bgColor4"><td>Private?</td><td>'.($extInfo['EM_CONF']['private']?'Yes':'').'</td>'.$this->helpCol('private').'</tr>';
1809 if (!$remote) $lines[]='<tr class="bgColor4"><td>Download password:</td><td>'.$extInfo['EM_CONF']['download_password'].'</td>'.$this->helpCol('download_password').'</tr>';
1810
1811 // Installation status:
1812 $lines[]='<tr><td>&nbsp;</td><td></td>'.$this->helpCol('').'</tr>';
1813 $lines[]='<tr class="bgColor5"><td colspan="2"><strong>Installation status:</strong></td>'.$this->helpCol('').'</tr>';
1814 if (!$remote) {
1815 $lines[]='<tr class="bgColor4"><td>Type of install:</td><td>'.$this->typeLabels[$extInfo['type']].' - <em>'.$this->typeDescr[$extInfo['type']].'</em></td>'.$this->helpCol('type').'</tr>';
1816 $lines[]='<tr class="bgColor4"><td>Double installs?</td><td>'.$this->extInformationArray_dbInst($extInfo['doubleInstall'],$extInfo['type']).'</td>'.$this->helpCol('doubleInstall').'</tr>';
1817 }
1818 if (is_array($extInfo['files'])) {
1819 sort($extInfo['files']);
1820 $lines[]='<tr class="bgColor4"><td>Root files:</td><td>'.implode('<br />',$extInfo['files']).'</td>'.$this->helpCol('rootfiles').'</tr>';
1821 }
1822
1823 if (!$remote) {
1824 $techInfo = $this->makeDetailedExtensionAnalysis($extKey,$extInfo,1);
1825 } else $techInfo = $extInfo['_TECH_INFO'];
1826 #debug($techInfo);
1827
1828 if ($techInfo['tables']||$techInfo['static']||$techInfo['fields']) {
1829 if (!$remote && t3lib_extMgm::isLoaded($extKey)) {
1830 $tableStatus = $GLOBALS['TBE_TEMPLATE']->rfw(($techInfo['tables_error']?'<strong>Table error!</strong><br />Probably one or more required fields/tables are missing in the database!':'').
1831 ($techInfo['static_error']?'<strong>Static table error!</strong><br />The static tables are missing or empty!':''));
1832 } else {
1833 $tableStatus = $techInfo['tables_error']||$techInfo['static_error'] ? 'The database will need to be updated when this extension is installed.' : 'All required tables are already in the database!';
1834 }
1835 }
1836
1837 $lines[]='<tr class="bgColor4"><td>Database requirements:</td><td>'.$this->extInformationArray_dbReq($techInfo,1).'</td>'.$this->helpCol('dbReq').'</tr>';
1838 if (!$remote) $lines[]='<tr class="bgColor4"><td>Database status:</td><td>'.$tableStatus.'</td>'.$this->helpCol('dbStatus').'</tr>';
1839 $lines[]='<tr class="bgColor4"><td>Flags:</td><td>'.(is_array($techInfo['flags'])?implode('<br />',$techInfo['flags']):'').'</td>'.$this->helpCol('flags').'</tr>';
1840 $lines[]='<tr class="bgColor4"><td>Config template?</td><td>'.($techInfo['conf']?'Yes':'').'</td>'.$this->helpCol('conf').'</tr>';
1841 $lines[]='<tr class="bgColor4"><td>TypoScript files:</td><td>'.(is_array($techInfo['TSfiles'])?implode('<br />',$techInfo['TSfiles']):'').'</td>'.$this->helpCol('TSfiles').'</tr>';
1842 $lines[]='<tr class="bgColor4"><td>Language files:</td><td>'.(is_array($techInfo['locallang'])?implode('<br />',$techInfo['locallang']):'').'</td>'.$this->helpCol('locallang').'</tr>';
1843 $lines[]='<tr class="bgColor4"><td>Upload folder:</td><td>'.($techInfo['uploadfolder']?$techInfo['uploadfolder']:'').'</td>'.$this->helpCol('uploadfolder').'</tr>';
1844 $lines[]='<tr class="bgColor4"><td>Create directories:</td><td>'.(is_array($techInfo['createDirs'])?implode('<br />',$techInfo['createDirs']):'').'</td>'.$this->helpCol('createDirs').'</tr>';
1845 $lines[]='<tr class="bgColor4"><td>Module names:</td><td>'.(is_array($techInfo['moduleNames'])?implode('<br />',$techInfo['moduleNames']):'').'</td>'.$this->helpCol('moduleNames').'</tr>';
1846 $lines[]='<tr class="bgColor4"><td>Class names:</td><td>'.(is_array($techInfo['classes'])?implode('<br />',$techInfo['classes']):'').'</td>'.$this->helpCol('classNames').'</tr>';
1847 $lines[]='<tr class="bgColor4"><td>Errors:</td><td>'.(is_array($techInfo['errors'])?$GLOBALS['TBE_TEMPLATE']->rfw(implode('<hr />',$techInfo['errors'])):'').'</td>'.$this->helpCol('errors').'</tr>';
1848 $lines[]='<tr class="bgColor4"><td>Naming errors:</td><td>'.(is_array($techInfo['NSerrors'])?
1849 (!t3lib_div::inList($this->nameSpaceExceptions,$extKey)?t3lib_div::view_array($techInfo['NSerrors']):$GLOBALS['TBE_TEMPLATE']->dfw('[exception]'))
1850 :'').'</td>'.$this->helpCol('NSerrors').'</tr>';
1851
1852
1853 if (!$remote) {
1854 $currentMd5Array = $this->serverExtensionMD5Array($extKey,$extInfo);
1855 $affectedFiles='';
1856
1857 $msgLines=array();
1858 # $msgLines[] = 'Files: '.count($currentMd5Array);
1859 if (strcmp($extInfo['EM_CONF']['_md5_values_when_last_written'],serialize($currentMd5Array))) {
1860 $msgLines[] = $GLOBALS['TBE_TEMPLATE']->rfw('<br /><strong>A difference between the originally installed version and the current was detected!</strong>');
1861 $affectedFiles = $this->findMD5ArrayDiff($currentMd5Array,unserialize($extInfo['EM_CONF']['_md5_values_when_last_written']));
1862 if (count($affectedFiles)) $msgLines[] = '<br /><strong>Modified files:</strong><br />'.$GLOBALS['TBE_TEMPLATE']->rfw(implode('<br />',$affectedFiles));
1863 }
1864 $lines[]='<tr class="bgColor4"><td>Files changed?</td><td>'.implode('<br />',$msgLines).'</td>'.$this->helpCol('filesChanged').'</tr>';
1865 }
1866
1867 return '<table border="0" cellpadding="1" cellspacing="2">
1868 '.implode('
1869 ',$lines).'
1870 </table>';
1871 }
1872
1873 /**
1874 * Returns HTML with information about database requirements
1875 *
1876 * @param array Technical information array
1877 * @param boolean Table header displayed
1878 * @return string HTML content.
1879 */
1880 function extInformationArray_dbReq($techInfo,$tableHeader=0) {
1881 return nl2br(trim((is_array($techInfo['tables'])?($tableHeader?"\n\n<strong>Tables:</strong>\n":'').implode(chr(10),$techInfo['tables']):'').
1882 (is_array($techInfo['static'])?"\n\n<strong>Static tables:</strong>\n".implode(chr(10),$techInfo['static']):'').
1883 (is_array($techInfo['fields'])?"\n\n<strong>Additional fields:</strong>\n".implode('<hr />',$techInfo['fields']):'')));
1884 }
1885
1886 /**
1887 * Double install warning.
1888 *
1889 * @param string Double-install string, eg. "LG" etc.
1890 * @param string Current scope, eg. "L" or "G" or "S"
1891 * @return string Message
1892 */
1893 function extInformationArray_dbInst($dbInst,$current) {
1894 if (strlen($dbInst)>1) {
1895 $others = array();
1896 for($a=0;$a<strlen($dbInst);$a++) {
1897 if (substr($dbInst,$a,1)!=$current) {
1898 $others[]='"'.$this->typeLabels[substr($dbInst,$a,1)].'"';
1899 }
1900 }
1901 return $GLOBALS['TBE_TEMPLATE']->rfw('A '.implode(' and ',$others).' extension with this key is also available on the server, but cannot be loaded because the "'.$this->typeLabels[$current].'" version takes precedence.');
1902 } else return '';
1903 }
1904
1905 /**
1906 * Prints the upload form for extensions
1907 *
1908 * @param string Extension key
1909 * @param array Extension information array
1910 * @return string HTML content.
1911 */
1912 function getRepositoryUploadForm($extKey,$extInfo) {
1913 $uArr = $this->makeUploadArray($extKey,$extInfo);
1914 if (is_array($uArr)) {
1915 $backUpData = $this->makeUploadDataFromArray($uArr);
1916
1917 #debug($this->decodeExchangeData($backUpData));
1918 $content.='Extension "'.$this->extensionTitleIconHeader($extKey,$extInfo).'" is ready to be uploaded.<br />
1919 The size of the upload is <strong>'.t3lib_div::formatSize(strlen($backUpData)).'</strong><br />
1920 ';
1921
1922 $b64data = base64_encode($backUpData);
1923 $content='</form><form action="'.$this->repositoryUrl.'" method="post" enctype="application/x-www-form-urlencoded">
1924 <input type="hidden" name="tx_extrep[upload][returnUrl]" value="'.htmlspecialchars($this->makeReturnUrl()).'" />
1925 <input type="hidden" name="tx_extrep[upload][data]" value="'.$b64data.'" />
1926 <input type="hidden" name="tx_extrep[upload][typo3ver]" value="'.$GLOBALS['TYPO_VERSION'].'" />
1927 <input type="hidden" name="tx_extrep[upload][os]" value="'.TYPO3_OS.'" />
1928 <input type="hidden" name="tx_extrep[upload][sapi]" value="'.php_sapi_name().'" />
1929 <input type="hidden" name="tx_extrep[upload][phpver]" value="'.phpversion().'" />
1930 <input type="hidden" name="tx_extrep[upload][gzcompressed]" value="'.$this->gzcompress.'" />
1931 <input type="hidden" name="tx_extrep[upload][data_md5]" value="'.md5($b64data).'" />
1932 <table border="0" cellpadding="2" cellspacing="1">
1933 <tr class="bgColor4">
1934 <td>Repository Username:</td>
1935 <td><input'.$this->doc->formWidth(20).' type="text" name="tx_extrep[user][fe_u]" value="'.$this->fe_user['username'].'" /></td>
1936 </tr>
1937 <tr class="bgColor4">
1938 <td>Repository Password:</td>
1939 <td><input'.$this->doc->formWidth(20).' type="password" name="tx_extrep[user][fe_p]" value="'.$this->fe_user['password'].'" /></td>
1940 </tr>
1941 <tr class="bgColor4">
1942 <td>Upload password for this extension:</td>
1943 <td><input'.$this->doc->formWidth(30).' type="password" name="tx_extrep[upload][upload_p]" value="'.$this->fe_user['uploadPass'].'" /></td>
1944 </tr>
1945 <tr class="bgColor4">
1946 <td>Changelog for upload:</td>
1947 <td><textarea'.$this->doc->formWidth(30,1).' rows="5" name="tx_extrep[upload][comment]"></textarea></td>
1948 </tr>
1949 <tr class="bgColor4">
1950 <td>Upload command:</td>
1951 <td nowrap="nowrap">
1952 <input type="radio" name="tx_extrep[upload][mode]" value="new_dev" checked="checked" /> New development version (latest x.x.<strong>'.$GLOBALS['TBE_TEMPLATE']->rfw('x+1').'</strong>)<br />
1953 <input type="radio" name="tx_extrep[upload][mode]" value="latest" /> Override <em>this</em> development version ('.$extInfo['EM_CONF']['version'].')<br />
1954 <input type="radio" name="tx_extrep[upload][mode]" value="new_sub" /> New sub version (latest x.<strong>'.$GLOBALS['TBE_TEMPLATE']->rfw('x+1').'</strong>.0)<br />
1955 <input type="radio" name="tx_extrep[upload][mode]" value="new_main" /> New main version (latest <strong>'.$GLOBALS['TBE_TEMPLATE']->rfw('x+1').'</strong>.0.0)<br />
1956 </td>
1957 </tr>
1958 <!-- Removing "private keys" since they are probably not used much. Better option for people is to distribute "private" extensions as files by emails.
1959 <tr class="bgColor4">
1960 <td>Private?</td>
1961 <td>
1962 <input type="checkbox" name="tx_extrep[upload][private]" value="1"'.($extInfo['EM_CONF']['private'] ? ' checked="checked"' : '').' />Yes, dont show <em>this upload</em> in the public list.<br />
1963 ("Private" uploads requires you to manually enter a special key (which will be shown to you after the upload has been completed) to be able to import and view details for the upload. This is nice when you are working on something internally which you do not want others to look at.)<br />
1964 <br /><strong>Additional import password:</strong><br />
1965 <input'.$this->doc->formWidth(20).' type="text" name="tx_extrep[upload][download_password]" value="'.htmlspecialchars(trim($extInfo['EM_CONF']['download_password'])).'" /> (Textfield!) <br />
1966 (Anybody who knows the "special key" assigned to the private upload will be able to import it. Specifying an import password allows you to give away the download key for private uploads and also require a password given in addition. The password can be changed later on.)<br />
1967 </td>
1968 </tr>
1969 -->
1970 <tr class="bgColor4">
1971 <td>&nbsp;</td>
1972 <td><input type="submit" name="submit" value="Upload extension" /><br />
1973 '.t3lib_div::formatSize(strlen($b64data)).($this->gzcompress?", compressed":"").', base64<br />
1974 <br />
1975
1976 </td>
1977 </tr>
1978 </table>
1979 ';
1980
1981 return $content;
1982 } else {
1983 return $uArr;
1984 }
1985 }
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996 /***********************************
1997 *
1998 * Extension list rendering
1999 *
2000 **********************************/
2001
2002 /**
2003 * Prints the header row for the various listings
2004 *
2005 * @param string Attributes for the <tr> tag
2006 * @param array Preset cells in the beginning of the row. Typically a blank cell with a clear-gif
2007 * @param boolean If set, the list is coming from remote server.
2008 * @return string HTML <tr> table row
2009 */
2010 function extensionListRowHeader($trAttrib,$cells,$import=0) {
2011 $cells[] = '<td></td>';
2012 $cells[] = '<td>Title:</td>';
2013
2014 if (!$this->MOD_SETTINGS['display_details']) {
2015 $cells[] = '<td>Description:</td>';
2016 $cells[] = '<td>Author:</td>';
2017 } elseif ($this->MOD_SETTINGS['display_details']==2) {
2018 $cells[] = '<td>Priority:</td>';
2019 $cells[] = '<td>Mod.Tables:</td>';
2020 $cells[] = '<td>Modules:</td>';
2021 $cells[] = '<td>Cl.Cache?</td>';
2022 $cells[] = '<td>Internal?</td>';
2023 $cells[] = '<td>Shy?</td>';
2024 } elseif ($this->MOD_SETTINGS['display_details']==3) {
2025 $cells[] = '<td>Tables/Fields:</td>';
2026 $cells[] = '<td>TS-files:</td>';
2027 $cells[] = '<td>Affects:</td>';
2028 $cells[] = '<td>Modules:</td>';
2029 $cells[] = '<td>Config?</td>';
2030 $cells[] = '<td>Errors:</td>';
2031 } elseif ($this->MOD_SETTINGS['display_details']==4) {
2032 $cells[] = '<td>locallang:</td>';
2033 $cells[] = '<td>Classes:</td>';
2034 $cells[] = '<td>Errors:</td>';
2035 $cells[] = '<td>NameSpace Errors:</td>';
2036 } elseif ($this->MOD_SETTINGS['display_details']==5) {
2037 $cells[] = '<td>Changed files:</td>';
2038 } else {
2039 $cells[] = '<td>Extension key:</td>';
2040 $cells[] = '<td>Version:</td>';
2041 if (!$import) {
2042 $cells[] = '<td>DL:</td>';
2043 $cells[] = '<td>Doc:</td>';
2044 $cells[] = '<td>Type:</td>';
2045 } else {
2046 $cells[] = '<td class="bgColor6"'.$this->labelInfo('Current version of the extension on this server. If colored red there is a newer version in repository! Then you should upgrade.').'>Cur. Ver:</td>';
2047 $cells[] = '<td class="bgColor6"'.$this->labelInfo('Current type of installation of the extension on this server.').'>Cur. Type:</td>';
2048 $cells[] = '<td'.$this->labelInfo('If blank, everyone has access to this extension. "Owner" means that you see it ONLY because you are the owner. "Member" means you see it ONLY because you are among the project members.').'>Access:</td>';
2049 $cells[] = '<td'.$this->labelInfo('TYPO3 version of last uploading server.').'>T3 ver:</td>';
2050 $cells[] = '<td'.$this->labelInfo('PHP version of last uploading server.').'>PHP:</td>';
2051 $cells[] = '<td'.$this->labelInfo('Size of extension, uncompressed / compressed').'>Size:</td>';
2052 $cells[] = '<td'.$this->labelInfo('Number of downloads, all versions/this version').'>DL:</td>';
2053 }
2054 $cells[] = '<td>State:</td>';
2055 $cells[] = '<td>Dependencies:</td>';
2056 }
2057 return '
2058 <tr'.$trAttrib.'>
2059 '.implode('
2060 ',$cells).'
2061 </tr>';
2062 }
2063
2064 /**
2065 * Prints a row with data for the various extension listings
2066 *
2067 * @param string Extension key
2068 * @param array Extension information array
2069 * @param array Preset table cells, eg. install/uninstall icons.
2070 * @param string <tr> tag class
2071 * @param array Array with installed extension keys (as keys)
2072 * @param boolean If set, the list is coming from remote server.
2073 * @param string Alternative link URL
2074 * @return string HTML <tr> content
2075 */
2076 function extensionListRow($extKey,$extInfo,$cells,$bgColorClass='',$inst_list=array(),$import=0,$altLinkUrl='') {
2077
2078 // Initialize:
2079 $style = t3lib_extMgm::isLoaded($extKey) ? '' : ' style="color:#666666;"';
2080
2081 // Icon:
2082 $imgInfo = @getImageSize($this->getExtPath($extKey,$extInfo['type']).'/ext_icon.gif');
2083 if (is_array($imgInfo)) {
2084 $cells[] = '<td><img src="'.$GLOBALS['BACK_PATH'].$this->typeRelPaths[$extInfo['type']].$extKey.'/ext_icon.gif'.'" '.$imgInfo[3].' alt="" /></td>';
2085 } elseif ($extInfo['_ICON']) {
2086 $cells[] = '<td>'.$extInfo['_ICON'].'</td>';
2087 } else {
2088 $cells[] = '<td><img src="clear.gif" width="1" height="1" alt="" /></td>';
2089 }
2090
2091 // Extension title:
2092 $cells[] = '<td nowrap="nowrap"><a href="'.htmlspecialchars($altLinkUrl?$altLinkUrl:'index.php?CMD[showExt]='.$extKey.'&SET[singleDetails]=info').'" title="'.$extKey.'"'.$style.'>'.t3lib_div::fixed_lgd($extInfo['EM_CONF']['title']?$extInfo['EM_CONF']['title']:'<em>'.$extKey.'</em>',40).'</a></td>';
2093
2094 // Unset extension key in installed keys array (for tracking)
2095 if (isset($inst_list[$extKey])) {
2096 unset($this->inst_keys[$extKey]);
2097 }
2098
2099 // Based on which display mode you will see more or less details:
2100 if (!$this->MOD_SETTINGS['display_details']) {
2101 $cells[] = '<td>'.htmlspecialchars(t3lib_div::fixed_lgd($extInfo['EM_CONF']['description'],400)).'<br /><img src="clear.gif" width="300" height="1" alt="" /></td>';
2102 $cells[] = '<td nowrap="nowrap">'.htmlspecialchars($extInfo['EM_CONF']['author'].($extInfo['EM_CONF']['author_company'] ? '<br />'.$extInfo['EM_CONF']['author_company'] : '')).'</td>';
2103 } elseif ($this->MOD_SETTINGS['display_details']==2) {
2104 $cells[] = '<td nowrap="nowrap">'.$extInfo['EM_CONF']['priority'].'</td>';
2105 $cells[] = '<td nowrap="nowrap">'.implode('<br />',t3lib_div::trimExplode(',',$extInfo['EM_CONF']['modify_tables'],1)).'</td>';
2106 $cells[] = '<td nowrap="nowrap">'.$extInfo['EM_CONF']['module'].'</td>';
2107 $cells[] = '<td nowrap="nowrap">'.($extInfo['EM_CONF']['clearCacheOnLoad'] ? 'Yes' : '').'</td>';
2108 $cells[] = '<td nowrap="nowrap">'.($extInfo['EM_CONF']['internal'] ? 'Yes' : '').'</td>';
2109 $cells[] = '<td nowrap="nowrap">'.($extInfo['EM_CONF']['shy'] ? 'Yes' : '').'</td>';
2110 } elseif ($this->MOD_SETTINGS['display_details']==3) {
2111 $techInfo = $this->makeDetailedExtensionAnalysis($extKey,$extInfo);
2112
2113 $cells[] = '<td>'.$this->extInformationArray_dbReq($techInfo).
2114 '</td>';
2115 $cells[] = '<td nowrap="nowrap">'.(is_array($techInfo['TSfiles']) ? implode('<br />',$techInfo['TSfiles']) : '').'</td>';
2116 $cells[] = '<td nowrap="nowrap">'.(is_array($techInfo['flags']) ? implode('<br />',$techInfo['flags']) : '').'</td>';
2117 $cells[] = '<td nowrap="nowrap">'.(is_array($techInfo['moduleNames']) ? implode('<br />',$techInfo['moduleNames']) : '').'</td>';
2118 $cells[] = '<td nowrap="nowrap">'.($techInfo['conf'] ? 'Yes' : '').'</td>';
2119 $cells[] = '<td>'.
2120 $GLOBALS['TBE_TEMPLATE']->rfw((t3lib_extMgm::isLoaded($extKey)&&$techInfo['tables_error']?'<strong>Table error!</strong><br />Probably one or more required fields/tables are missing in the database!':'').
2121 (t3lib_extMgm::isLoaded($extKey)&&$techInfo['static_error']?'<strong>Static table error!</strong><br />The static tables are missing or empty!':'')).
2122 '</td>';
2123 } elseif ($this->MOD_SETTINGS['display_details']==4) {
2124 $techInfo=$this->makeDetailedExtensionAnalysis($extKey,$extInfo,1);
2125
2126 $cells[] = '<td>'.(is_array($techInfo['locallang']) ? implode('<br />',$techInfo['locallang']) : '').'</td>';
2127 $cells[] = '<td>'.(is_array($techInfo['classes']) ? implode('<br />',$techInfo['classes']) : '').'</td>';
2128 $cells[] = '<td>'.(is_array($techInfo['errors']) ? $GLOBALS['TBE_TEMPLATE']->rfw(implode('<hr />',$techInfo['errors'])) : '').'</td>';
2129 $cells[] = '<td>'.(is_array($techInfo['NSerrors']) ? (!t3lib_div::inList($this->nameSpaceExceptions,$extKey) ? t3lib_div::view_array($techInfo['NSerrors']) : $GLOBALS['TBE_TEMPLATE']->dfw('[exception]')) :'').'</td>';
2130 } elseif ($this->MOD_SETTINGS['display_details']==5) {
2131 $currentMd5Array = $this->serverExtensionMD5Array($extKey,$extInfo);
2132 $affectedFiles = '';
2133 $msgLines = array();
2134 $msgLines[] = 'Files: '.count($currentMd5Array);
2135 if (strcmp($extInfo['EM_CONF']['_md5_values_when_last_written'],serialize($currentMd5Array))) {
2136 $msgLines[] = $GLOBALS['TBE_TEMPLATE']->rfw('<br /><strong>A difference between the originally installed version and the current was detected!</strong>');
2137 $affectedFiles = $this->findMD5ArrayDiff($currentMd5Array,unserialize($extInfo['EM_CONF']['_md5_values_when_last_written']));
2138 if (count($affectedFiles)) $msgLines[] = '<br /><strong>Modified files:</strong><br />'.$GLOBALS['TBE_TEMPLATE']->rfw(implode('<br />',$affectedFiles));
2139 }
2140 $cells[] = '<td>'.implode('<br />',$msgLines).'</td>';
2141 } else {
2142 // Default view:
2143 $verDiff = $inst_list[$extKey] && $this->versionDifference($extInfo['EM_CONF']['version'],$inst_list[$extKey]['EM_CONF']['version'],$this->versionDiffFactor);
2144
2145 $cells[] = '<td nowrap="nowrap"><em>'.$extKey.'</em></td>';
2146 $cells[] = '<td nowrap="nowrap">'.($verDiff ? '<strong>'.$GLOBALS['TBE_TEMPLATE']->rfw(htmlspecialchars($extInfo['EM_CONF']['version'])).'</strong>' : $extInfo['EM_CONF']['version']).'</td>';
2147 if (!$import) { // Listing extenson on LOCAL server:
2148 // Extension Download:
2149 $cells[] = '<td nowrap="nowrap"><a href="'.htmlspecialchars('index.php?CMD[doBackup]=1&SET[singleDetails]=backup&CMD[showExt]='.$extKey).'"><img src="download.png" width="13" height="12" title="Download" alt="" /></a></td>';
2150
2151 // Manual download
2152 $fileP = PATH_site.$this->typePaths[$extInfo['type']].$extKey.'/doc/manual.sxw';
2153 $cells[] = '<td nowrap="nowrap">'.
2154 ($this->typePaths[$extInfo['type']] && @is_file($fileP)?'<a href="'.htmlspecialchars(t3lib_div::resolveBackPath($this->doc->backPath.'../'.$this->typePaths[$extInfo['type']].$extKey.'/doc/manual.sxw')).'" target="_blank"><img src="oodoc.gif" width="13" height="16" title="Local Open Office Manual" alt="" /></a>':'').
2155 '</td>';
2156 $cells[] = '<td nowrap="nowrap">'.$this->typeLabels[$extInfo['type']].(strlen($extInfo['doubleInstall'])>1?'<strong> '.$GLOBALS['TBE_TEMPLATE']->rfw($extInfo['doubleInstall']).'</strong>':'').'</td>';
2157 } else { // Listing extensions from REMOTE repository:
2158 $inst_curVer = $inst_list[$extKey]['EM_CONF']['version'];
2159 if (isset($inst_list[$extKey])) {
2160 if ($verDiff) $inst_curVer = '<strong>'.$GLOBALS['TBE_TEMPLATE']->rfw($inst_curVer).'</strong>';
2161 }
2162 $cells[] = '<td nowrap="nowrap">'.$inst_curVer.'</td>';
2163 $cells[] = '<td nowrap="nowrap">'.$this->typeLabels[$inst_list[$extKey]['type']].(strlen($inst_list[$extKey]['doubleInstall'])>1?'<strong> '.$GLOBALS['TBE_TEMPLATE']->rfw($inst_list[$extKey]['doubleInstall']).'</strong>':'').'</td>';
2164 $cells[] = '<td nowrap="nowrap"><strong>'.$GLOBALS['TBE_TEMPLATE']->rfw($this->remoteAccess[$extInfo['_ACCESS']]).'</strong></td>';
2165 $cells[] = '<td nowrap="nowrap">'.$extInfo['EM_CONF']['_typo3_ver'].'</td>';
2166 $cells[] = '<td nowrap="nowrap">'.$extInfo['EM_CONF']['_php_ver'].'</td>';
2167 $cells[] = '<td nowrap="nowrap">'.$extInfo['EM_CONF']['_size'].'</td>';
2168 $cells[] = '<td nowrap="nowrap">'.($extInfo['_STAT_IMPORT']['extension_allversions']?$extInfo['_STAT_IMPORT']['extension_allversions']:'&nbsp;&nbsp;').'/'.($extInfo['_STAT_IMPORT']['extension_thisversion']?$extInfo['_STAT_IMPORT']['extension_thisversion']:'&nbsp;').'</td>';
2169 }
2170 $cells[] = '<td nowrap="nowrap">'.$this->states[$extInfo['EM_CONF']['state']].'</td>';
2171 $cells[] = '<td nowrap="nowrap">'.$extInfo['EM_CONF']['dependencies'].'</td>';
2172 }
2173
2174 $bgColor = ' class="'.($bgColorClass?$bgColorClass:'bgColor4').'"';
2175 return '
2176 <tr'.$bgColor.$style.'>
2177 '.implode('
2178 ',$cells).'
2179 </tr>';
2180 }
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191 /************************************
2192 *
2193 * Output helper functions
2194 *
2195 ************************************/
2196
2197 /**
2198 * Wrapping input string in a link tag with link to email address
2199 *
2200 * @param string Input string, being wrapped in <a> tags
2201 * @param string Email address for use in link.
2202 * @return string Output
2203 */
2204 function wrapEmail($str,$email) {
2205 if ($email) {
2206 $str = '<a href="mailto:'.htmlspecialchars($email).'">'.htmlspecialchars($str).'</a>';
2207 }
2208 return $str;
2209 }
2210
2211 /**
2212 * Returns help text if applicable.
2213 *
2214 * @param string Help text key
2215 * @return string HTML table cell
2216 */
2217 function helpCol($key) {
2218 global $BE_USER;
2219 if ($BE_USER->uc['edit_showFieldHelp']) {
2220 $hT = trim(t3lib_BEfunc::helpText($this->descrTable,'emconf_'.$key,$this->doc->backPath));
2221 return '<td>'.($hT?$hT:t3lib_BEfunc::helpTextIcon($this->descrTable,'emconf_'.$key,$this->doc->backPath)).'</td>';
2222 }
2223 }
2224
2225 /**
2226 * Returns title and style attribute for mouseover help text.
2227 *
2228 * @param string Help text.
2229 * @return string title="" attribute prepended with a single space
2230 */
2231 function labelInfo($str) {
2232 return ' title="'.htmlspecialchars($str).'" style="cursor:help;"';
2233 }
2234
2235 /**
2236 * Returns a header for an extensions including icon if any
2237 *
2238 * @param string Extension key
2239 * @param array Extension information array
2240 * @param string align-attribute value (for <img> tag)
2241 * @return string HTML; Extension title and image.
2242 */
2243 function extensionTitleIconHeader($extKey,$extInfo,$align='top') {
2244 $imgInfo = @getImageSize($this->getExtPath($extKey,$extInfo['type']).'/ext_icon.gif');
2245 $out = '';
2246 if (is_array($imgInfo)) {
2247 $out.= '<img src="'.$GLOBALS['BACK_PATH'].$this->typeRelPaths[$extInfo['type']].$extKey.'/ext_icon.gif" '.$imgInfo[3].' align="'.$align.'" alt="" />';
2248 }
2249 $out.= $extInfo['EM_CONF']['title'] ? htmlspecialchars(t3lib_div::fixed_lgd($extInfo['EM_CONF']['title'],40)) : '<em>'.$extKey.'</em>';
2250 return $out;
2251 }
2252
2253 /**
2254 * Returns image tag for "uninstall"
2255 *
2256 * @return string <img> tag
2257 */
2258 function removeButton() {
2259 return '<img src="uninstall.gif" width="16" height="16" title="Remove extension" align="top" alt="" />';
2260 }
2261
2262 /**
2263 * Returns image for "install"
2264 *
2265 * @return string <img> tag
2266 */
2267 function installButton() {
2268 return '<img src="install.gif" width="16" height="16" title="Install extension..." align="top" alt="" />';
2269 }
2270
2271 /**
2272 * Warning (<img> + text string) message about the impossibility to import extensions (both local and global locations are disabled...)
2273 *
2274 * @return string <img> + text string.
2275 */
2276 function noImportMsg() {
2277 return '<img src="'.$this->doc->backPath.'gfx/icon_warning2.gif" width="18" height="16" align="top" alt="" /><strong>Import to both local and global path is disabled in TYPO3_CONF_VARS!</strong>';
2278 }
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289 /********************************
2290 *
2291 * Read information about all available extensions
2292 *
2293 *******************************/
2294
2295 /**
2296 * Returns the list of available (installed) extensions
2297 *
2298 * @return array Array with two arrays, list array (all extensions with info) and category index
2299 * @see getInstExtList()
2300 */
2301 function getInstalledExtensions() {
2302 $list = array();
2303 $cat = $this->defaultCategories;
2304
2305 $path = PATH_site.TYPO3_mainDir.'sysext/';
2306 $this->getInstExtList($path,$list,$cat,'S');
2307
2308 $path = PATH_site.TYPO3_mainDir.'ext/';
2309 $this->getInstExtList($path,$list,$cat,'G');
2310
2311 $path = PATH_site.'typo3conf/ext/';
2312 $this->getInstExtList($path,$list,$cat,'L');
2313
2314 return array($list,$cat);
2315 }
2316
2317 /**
2318 * Gathers all extensions in $path
2319 *
2320 * @param string Absolute path to local, global or system extensions
2321 * @param array Array with information for each extension key found. Notice: passed by reference
2322 * @param array Categories index: Contains extension titles grouped by various criteria.
2323 * @param string Path-type: L, G or S
2324 * @return void "Returns" content by reference
2325 * @access private
2326 * @see getInstalledExtensions()
2327 */
2328 function getInstExtList($path,&$list,&$cat,$type) {
2329
2330 if (@is_dir($path)) {
2331 $extList = t3lib_div::get_dirs($path);
2332 if (is_array($extList)) {
2333 foreach($extList as $extKey) {
2334 if (@is_file($path.$extKey.'/ext_emconf.php')) {
2335 $emConf = $this->includeEMCONF($path.$extKey.'/ext_emconf.php', $extKey);
2336 if (is_array($emConf)) {
2337 # unset($emConf['_md5_values_when_last_written']); // Trying to save space - hope this doesn't break anything. Shaves of maybe 100K!
2338 # unset($emConf['description']); // Trying to save space - hope this doesn't break anything
2339 if (is_array($list[$extKey])) {
2340 $list[$extKey]=array('doubleInstall'=>$list[$extKey]['doubleInstall']);
2341 }
2342 $list[$extKey]['doubleInstall'].= $type;
2343 $list[$extKey]['type'] = $type;
2344 $list[$extKey]['EM_CONF'] = $emConf;
2345 # $list[$extKey]['files'] = array_keys(array_flip(t3lib_div::getFilesInDir($path.$extKey))); // Shaves off a little by using num-indexes
2346 $list[$extKey]['files'] = t3lib_div::getFilesInDir($path.$extKey);
2347
2348 $this->setCat($cat,$list[$extKey], $extKey);
2349 }
2350 }
2351 }
2352 }
2353 }
2354 }
2355
2356 /**
2357 * Maps remote extensions information into $cat/$list arrays for listing
2358 *
2359 * @param array List of extensions from remote repository
2360 * @return array List array and category index as key 0 / 1 in an array.
2361 */
2362 function getImportExtList($listArr) {
2363 $list = array();
2364 $cat = $this->defaultCategories;
2365
2366 if (is_array($listArr)) {
2367
2368 foreach($listArr as $dat) {
2369 $extKey = $dat['extension_key'];
2370 $list[$extKey]['type'] = '_';
2371 $list[$extKey]['extRepUid'] = $dat['uid'];
2372 $list[$extKey]['_STAT_IMPORT'] = $dat['_STAT_IMPORT'];
2373 $list[$extKey]['_ACCESS'] = $dat['_ACCESS'];
2374 $list[$extKey]['_ICON'] = $dat['_ICON'];
2375 $list[$extKey]['_MEMBERS_ONLY'] = $dat['_MEMBERS_ONLY'];
2376 $list[$extKey]['EM_CONF'] = array(
2377 'title' => $dat['emconf_title'],
2378 'description' => $dat['emconf_description'],
2379 'category' => $dat['emconf_category'],
2380 'shy' => $dat['emconf_shy'],
2381 'dependencies' => $dat['emconf_dependencies'],
2382 'state' => $dat['emconf_state'],
2383 'private' => $dat['emconf_private'],
2384 'uploadfolder' => $dat['emconf_uploadfolder'],
2385 'createDirs' => $dat['emconf_createDirs'],
2386 'modify_tables' => $dat['emconf_modify_tables'],
2387 'module' => $dat['emconf_module'],
2388 'lockType' => $dat['emconf_lockType'],
2389 'clearCacheOnLoad' => $dat['emconf_clearCacheOnLoad'],
2390 'priority' => $dat['emconf_priority'],
2391 'version' => $dat['version'],
2392 'internal' => $dat['emconf_internal'],
2393 'author' => $dat['emconf_author'],
2394 'author_company' => $dat['emconf_author_company'],
2395
2396 '_typo3_ver' => $dat['upload_typo3_version'],
2397 '_php_ver' => $dat['upload_php_version'],
2398 '_size' => t3lib_div::formatSize($dat['datasize']).'/'.t3lib_div::formatSize($dat['datasize_gz']),
2399 );
2400 $this->setCat($cat, $list[$extKey], $extKey);
2401 }
2402 }
2403 return array($list,$cat);
2404 }
2405
2406 /**
2407 * Set category array entries for extension
2408 *
2409 * @param array Category index array
2410 * @param array Part of list array for extension.
2411 * @param string Extension key
2412 * @return array Modified category index array
2413 */
2414 function setCat(&$cat,$listArrayPart,$extKey) {
2415
2416 // Getting extension title:
2417 $extTitle = $listArrayPart['EM_CONF']['title'];
2418
2419 // Category index:
2420 $index = $listArrayPart['EM_CONF']['category'];
2421 $cat['cat'][$index][$extKey] = $extTitle;
2422
2423 // Author index:
2424 $index = $listArrayPart['EM_CONF']['author'].($listArrayPart['EM_CONF']['author_company']?', '.$listArrayPart['EM_CONF']['author_company']:'');
2425 $cat['author_company'][$index][$extKey] = $extTitle;
2426
2427 // State index:
2428 $index = $listArrayPart['EM_CONF']['state'];
2429 $cat['state'][$index][$extKey] = $extTitle;
2430
2431 // Private index:
2432 $index = $listArrayPart['EM_CONF']['private'] ? 1 : 0;
2433 $cat['private'][$index][$extKey] = $extTitle;
2434
2435 // Type index:
2436 $index = $listArrayPart['type'];
2437 $cat['type'][$index][$extKey] = $extTitle;
2438
2439 // Dependencies:
2440 if ($list[$extKey]['EM_CONF']['dependencies']) {
2441 $depItems = t3lib_div::trimExplode(',', $list[$extKey]['EM_CONF']['dependencies'], 1);
2442 foreach($depItems as $depKey) {
2443 $cat['dep'][$depKey][$extKey] = $extTitle;
2444 }
2445 }
2446
2447 // Return categories:
2448 return $cat;
2449 }
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460 /*******************************
2461 *
2462 * Extension analyzing (detailed information)
2463 *
2464 ******************************/
2465
2466 /**
2467 * Perform a detailed, technical analysis of the available extension on server!
2468 * Includes all kinds of verifications
2469 * Takes some time to process, therfore use with care, in particular in listings.
2470 *
2471 * @param string Extension key
2472 * @param array Extension information
2473 * @param boolean If set, checks for validity of classes etc.
2474 * @return array Information in an array.
2475 */
2476 function makeDetailedExtensionAnalysis($extKey,$extInfo,$validity=0) {
2477
2478 // Get absolute path of the extension
2479 $absPath = $this->getExtPath($extKey,$extInfo['type']);
2480
2481 $infoArray = array();
2482
2483 $table_class_prefix = substr($extKey,0,5)=='user_' ? 'user_' : 'tx_'.str_replace('_','',$extKey).'_';
2484 $module_prefix = substr($extKey,0,5)=='user_' ? 'u' : 'tx'.str_replace('_','',$extKey);
2485
2486 // Database status:
2487 $dbInfo = $this->checkDBupdates($extKey,$extInfo,1);
2488
2489 // Database structure required:
2490 if (is_array($dbInfo['structure']['tables_fields'])) {
2491 $modify_tables = t3lib_div::trimExplode(',',$extInfo['EM_CONF']['modify_tables'],1);
2492 $infoArray['dump_tf'] = array();
2493
2494 foreach($dbInfo['structure']['tables_fields'] as $tN => $d) {
2495 if (in_array($tN,$modify_tables)) {
2496 $infoArray['fields'][] = $tN.': <i>'.
2497 (is_array($d['fields']) ? implode(', ',array_keys($d['fields'])) : '').
2498 (is_array($d['keys']) ? ' + '.count($d['keys']).' keys' : '').
2499 '</i>';
2500 if (is_array($d['fields'])) {
2501 reset($d['fields']);
2502 while(list($fN) = each($d['fields'])) {
2503 $infoArray['dump_tf'][] = $tN.'.'.$fN;
2504 if (!t3lib_div::isFirstPartOfStr($fN,$table_class_prefix)) {
2505 $infoArray['NSerrors']['fields'][$fN] = $fN;
2506 } else {
2507 $infoArray['NSok']['fields'][$fN] = $fN;
2508 }
2509 }
2510 }
2511 if (is_array($d['keys'])) {
2512 reset($d['keys']);
2513 while(list($fN)=each($d['keys'])) {
2514 $infoArray['dump_tf'][] = $tN.'.KEY:'.$fN;
2515 }
2516 }
2517 } else {
2518 $infoArray['dump_tf'][] = $tN;
2519 $infoArray['tables'][] = $tN;
2520 if (!t3lib_div::isFirstPartOfStr($tN,$table_class_prefix)) {
2521 $infoArray['NSerrors']['tables'][$tN] = $tN;
2522 } else $infoArray['NSok']['tables'][$tN] = $tN;
2523 }
2524 }
2525 if (count($dbInfo['structure']['diff']['diff']) || count($dbInfo['structure']['diff']['extra'])) {
2526 $msg = array();
2527 if (count($dbInfo['structure']['diff']['diff'])) $msg[] = 'missing';
2528 if (count($dbInfo['structure']['diff']['extra'])) $msg[] = 'of wrong type';
2529 $infoArray['tables_error'] = 1;
2530 if (t3lib_extMgm::isLoaded($extKey)) $infoArray['errors'][] = 'Some tables or fields are '.implode(' and ',$msg).'!';
2531 }
2532 }
2533
2534 // Static tables?
2535 if (is_array($dbInfo['static'])) {
2536 $infoArray['static'] = array_keys($dbInfo['static']);
2537
2538 foreach($dbInfo['static'] as $tN => $d) {
2539 if (!$d['exists']) {
2540 $infoArray['static_error'] = 1;
2541 if (t3lib_extMgm::isLoaded($extKey)) $infoArray['errors'][] = 'Static table(s) missing!';
2542 if (!t3lib_div::isFirstPartOfStr($tN,$table_class_prefix)) {
2543 $infoArray['NSerrors']['tables'][$tN] = $tN;
2544 } else $infoArray['NSok']['tables'][$tN] = $tN;
2545 }
2546 }
2547 }
2548
2549 // Backend Module-check:
2550 $knownModuleList = t3lib_div::trimExplode(',',$extInfo['EM_CONF']['module'],1);
2551 foreach($knownModuleList as $mod) {
2552 if (@is_dir($absPath.$mod)) {
2553 if (@is_file($absPath.$mod.'/conf.php')) {
2554 $confFileInfo = $this->modConfFileAnalysis($absPath.$mod.'/conf.php');
2555 if (is_array($confFileInfo['TYPO3_MOD_PATH'])) {
2556 $shouldBePath = $this->typeRelPaths[$extInfo['type']].$extKey.'/'.$mod.'/';
2557 if (strcmp($confFileInfo['TYPO3_MOD_PATH'][1][1],$shouldBePath)) {
2558 $infoArray['errors'][] = 'Configured TYPO3_MOD_PATH "'.$confFileInfo['TYPO3_MOD_PATH'][1][1].'" different from "'.$shouldBePath.'"';
2559 }
2560 } else $infoArray['errors'][] = 'No definition of TYPO3_MOD_PATH constant found inside!';
2561 if (is_array($confFileInfo['MCONF_name'])) {
2562 $mName = $confFileInfo['MCONF_name'][1][1];
2563 $mNameParts = explode('_',$mName);
2564 $infoArray['moduleNames'][] = $mName;
2565 if (!t3lib_div::isFirstPartOfStr($mNameParts[0],$module_prefix) &&
2566 (!$mNameParts[1] || !t3lib_div::isFirstPartOfStr($mNameParts[1],$module_prefix))) {
2567 $infoArray['NSerrors']['modname'][] = $mName;
2568 } else $infoArray['NSok']['modname'][] = $mName;
2569 } else $infoArray['errors'][] = 'No definition of MCONF[name] variable found inside!';
2570 } else $infoArray['errors'][] = 'Backend module conf file "'.$mod.'/conf.php" should exist but does not!';
2571 } else $infoArray['errors'][] = 'Backend module folder "'.$mod.'/" should exist but does not!';
2572 }
2573 $dirs = t3lib_div::get_dirs($absPath);
2574 if (is_array($dirs)) {
2575 reset($dirs);
2576 while(list(,$mod) = each($dirs)) {
2577 if (!in_array($mod,$knownModuleList) && @is_file($absPath.$mod.'/conf.php')) {
2578 $confFileInfo = $this->modConfFileAnalysis($absPath.$mod.'/conf.php');
2579 if (is_array($confFileInfo)) {
2580 $infoArray['errors'][] = 'It seems like there is a backend module in "'.$mod.'/conf.php" which is not configured in ext_emconf.php';
2581 }
2582 }
2583 }
2584 }
2585
2586 // ext_tables.php:
2587 if (@is_file($absPath.'ext_tables.php')) {
2588 $content = t3lib_div::getUrl($absPath.'ext_tables.php');
2589 if (eregi('t3lib_extMgm::addModule',$content)) $infoArray['flags'][] = 'Module';
2590 if (eregi('t3lib_extMgm::insertModuleFunction',$content)) $infoArray['flags'][] = 'Module+';
2591 if (stristr($content,'t3lib_div::loadTCA')) $infoArray['flags'][] = 'loadTCA';
2592 if (stristr($content,'$TCA[')) $infoArray['flags'][] = 'TCA';
2593 if (eregi('t3lib_extMgm::addPlugin',$content)) $infoArray['flags'][] = 'Plugin';
2594 }
2595
2596 // ext_localconf.php:
2597 if (@is_file($absPath.'ext_localconf.php')) {
2598 $content = t3lib_div::getUrl($absPath.'ext_localconf.php');
2599 if (eregi('t3lib_extMgm::addPItoST43',$content)) $infoArray['flags'][]='Plugin/ST43';
2600 if (eregi('t3lib_extMgm::addPageTSConfig',$content)) $infoArray['flags'][]='Page-TSconfig';
2601 if (eregi('t3lib_extMgm::addUserTSConfig',$content)) $infoArray['flags'][]='User-TSconfig';
2602 if (eregi('t3lib_extMgm::addTypoScriptSetup',$content)) $infoArray['flags'][]='TS/Setup';
2603 if (eregi('t3lib_extMgm::addTypoScriptConstants',$content)) $infoArray['flags'][]='TS/Constants';
2604 }
2605
2606 if (@is_file($absPath.'ext_typoscript_constants.txt')) {
2607 $infoArray['TSfiles'][] = 'Constants';
2608 }
2609 if (@is_file($absPath.'ext_typoscript_setup.txt')) {
2610 $infoArray['TSfiles'][] = 'Setup';
2611 }
2612 if (@is_file($absPath.'ext_conf_template.txt')) {
2613 $infoArray['conf'] = 1;
2614 }
2615
2616 // Classes:
2617 if ($validity) {
2618 $filesInside = $this->getClassIndexLocallangFiles($absPath,$table_class_prefix,$extKey);
2619 if (is_array($filesInside['errors'])) $infoArray['errors'] = array_merge((array)$infoArray['errors'],$filesInside['errors']);
2620 if (is_array($filesInside['NSerrors'])) $infoArray['NSerrors'] = array_merge((array)$infoArray['NSerrors'],$filesInside['NSerrors']);
2621 if (is_array($filesInside['NSok'])) $infoArray['NSok'] = array_merge((array)$infoArray['NSok'],$filesInside['NSok']);
2622 $infoArray['locallang'] = $filesInside['locallang'];