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