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