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