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