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