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