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