| [ Index ] |
|
Code source de Typo3 4.1.3 |
1 <?php 2 /*************************************************************** 3 * Copyright notice 4 * 5 * (c) 1999-2005 Kasper Skaarhoj (kasperYYYY@typo3.com) 6 * (c) 2005-2006 Karsten Dambekalns <karsten@typo3.org> 7 * All rights reserved 8 * 9 * This script is part of the TYPO3 project. The TYPO3 project is 10 * free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or 13 * (at your option) any later version. 14 * 15 * The GNU General Public License can be found at 16 * http://www.gnu.org/copyleft/gpl.html. 17 * A copy is found in the textfile GPL.txt and important notices to the license 18 * from the author is found in LICENSE.txt distributed with these scripts. 19 * 20 * 21 * This script is distributed in the hope that it will be useful, 22 * but WITHOUT ANY WARRANTY; without even the implied warranty of 23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 24 * GNU General Public License for more details. 25 * 26 * This copyright notice MUST APPEAR in all copies of the script! 27 ***************************************************************/ 28 /** 29 * Module: Extension manager 30 * 31 * $Id: class.em_index.php 2464 2007-08-29 10:59:27Z mundaun $ 32 * 33 * @author Kasper Skaarhoj <kasperYYYY@typo3.com> 34 * @author Karsten Dambekalns <karsten@typo3.org> 35 */ 36 /** 37 * [CLASS/FUNCTION INDEX of SCRIPT] 38 * 39 * 40 * 41 * 194: class SC_mod_tools_em_index extends t3lib_SCbase 42 * 43 * SECTION: Standard module initialization 44 * 337: function init() 45 * 417: function handleExternalFunctionValue($MM_key='function', $MS_value=NULL) 46 * 431: function menuConfig() 47 * 508: function main() 48 * 584: function printContent() 49 * 50 * SECTION: Function Menu Applications 51 * 609: function extensionList_loaded() 52 * 664: function extensionList_installed() 53 * 736: function extensionList_import() 54 * 903: function alterSettings() 55 * 56 * SECTION: Command Applications (triggered by GET var) 57 * 1005: function importExtInfo($extKey, $version='') 58 * 1062: function fetchMetaData($metaType) 59 * 1125: function getMirrorURL() 60 * 1158: function installExtension($extKey, $version=null, $mode=EM_INSTALL_VERSION_MIN) 61 * 1279: function importExtFromRep($extKey,$version,$loc,$uploadFlag=0,$dontDelete=0,$directInput='') 62 * 1425: function showExtDetails($extKey) 63 * 64 * SECTION: Application Sub-functions (HTML parts) 65 * 1737: function updatesForm($extKey,$extInfo,$notSilent=0,$script='',$addFields='') 66 * 1768: function extDumpTables($extKey,$extInfo) 67 * 1835: function getFileListOfExtension($extKey,$conf) 68 * 1889: function extDelete($extKey,$extInfo) 69 * 1920: function extUpdateEMCONF($extKey,$extInfo) 70 * 1940: function extBackup($extKey,$extInfo) 71 * 1987: function extBackup_dumpDataTablesLine($tablesArray,$extKey) 72 * 2015: function extInformationArray($extKey,$extInfo,$remote=0) 73 * 2097: function extInformationArray_dbReq($techInfo,$tableHeader=0) 74 * 2110: function extInformationArray_dbInst($dbInst,$current) 75 * 2129: function getRepositoryUploadForm($extKey,$extInfo) 76 * 77 * SECTION: Extension list rendering 78 * 2190: function extensionListRowHeader($trAttrib,$cells,$import=0) 79 * 2251: function extensionListRow($extKey,$extInfo,$cells,$bgColorClass='',$inst_list=array(),$import=0,$altLinkUrl='') 80 * 81 * SECTION: Output helper functions 82 * 2367: function wrapEmail($str,$email) 83 * 2380: function helpCol($key) 84 * 2396: function labelInfo($str) 85 * 2408: function extensionTitleIconHeader($extKey,$extInfo,$align='top') 86 * 2423: function removeButton() 87 * 2432: function installButton() 88 * 2441: function noImportMsg() 89 * 2454: function depToString($dep,$type='depends') 90 * 2473: function stringToDep($dep) 91 * 92 * SECTION: Read information about all available extensions 93 * 2503: function getInstalledExtensions() 94 * 2530: function getInstExtList($path,&$list,&$cat,$type) 95 * 2561: function fixEMCONF($emConf) 96 * 2600: function splitVersionRange($ver) 97 * 2616: function prepareImportExtList() 98 * 2660: function setCat(&$cat,$listArrayPart,$extKey) 99 * 100 * SECTION: Extension analyzing (detailed information) 101 * 2710: function makeDetailedExtensionAnalysis($extKey,$extInfo,$validity=0) 102 * 2892: function getClassIndexLocallangFiles($absPath,$table_class_prefix,$extKey) 103 * 2962: function modConfFileAnalysis($confFilePath) 104 * 2990: function serverExtensionMD5Array($extKey,$conf) 105 * 3015: function findMD5ArrayDiff($current,$past) 106 * 107 * SECTION: File system operations 108 * 3047: function createDirsInPath($dirs,$extDirPath) 109 * 3065: function removeExtDirectory($removePath,$removeContentOnly=0) 110 * 3128: function clearAndMakeExtensionDir($importedData,$type,$dontDelete=0) 111 * 3182: function removeCacheFiles() 112 * 3192: function extractDirsFromFileList($files) 113 * 3218: function getExtPath($extKey,$type) 114 * 115 * SECTION: Writing to "conf.php" and "localconf.php" files 116 * 3252: function writeTYPO3_MOD_PATH($confFilePath,$type,$mP) 117 * 3289: function writeNewExtensionList($newExtList) 118 * 3312: function writeTsStyleConfig($extKey,$arr) 119 * 3334: function updateLocalEM_CONF($extKey,$extInfo) 120 * 121 * SECTION: Compiling upload information, emconf-file etc. 122 * 3376: function construct_ext_emconf_file($extKey,$EM_CONF) 123 * 3407: function arrayToCode($array, $level=0) 124 * 3433: function makeUploadArray($extKey,$conf) 125 * 3502: function getSerializedLocalLang($file,$content) 126 * 127 * SECTION: Managing dependencies, conflicts, priorities, load order of extension keys 128 * 3538: function addExtToList($extKey,$instExtInfo) 129 * 3569: function checkDependencies($extKey, $conf, $instExtInfo) 130 * 3709: function removeExtFromList($extKey,$instExtInfo) 131 * 3746: function removeRequiredExtFromListArr($listArr) 132 * 3761: function managesPriorities($listArr,$instExtInfo) 133 * 134 * SECTION: System Update functions (based on extension requirements) 135 * 3813: function checkClearCache($extInfo) 136 * 3840: function checkUploadFolder($extKey,$extInfo) 137 * 3925: function checkDBupdates($extKey,$extInfo,$infoOnly=0) 138 * 4022: function forceDBupdates($extKey, $extInfo) 139 * 4080: function tsStyleConfigForm($extKey,$extInfo,$output=0,$script='',$addFields='') 140 * 141 * SECTION: Dumping database (MySQL compliant) 142 * 4175: function dumpTableAndFieldStructure($arr) 143 * 4200: function dumpStaticTables($tableList) 144 * 4229: function dumpHeader() 145 * 4246: function dumpTableHeader($table,$fieldKeyInfo,$dropTableIfExists=0) 146 * 4288: function dumpTableContent($table,$fieldStructure) 147 * 4323: function getTableAndFieldStructure($parts) 148 * 149 * SECTION: TER Communication functions 150 * 4373: function uploadExtensionToTER($em) 151 * 152 * SECTION: Various helper functions 153 * 4411: function listOrderTitle($listOrder,$key) 154 * 4436: function makeVersion($v,$mode) 155 * 4448: function renderVersion($v,$raise='') 156 * 4485: function ulFolder($extKey) 157 * 4494: function importAtAll() 158 * 4505: function importAsType($type,$lockType='') 159 * 4527: function deleteAsType($type) 160 * 4548: function versionDifference($v1,$v2,$div=1) 161 * 4560: function first_in_array($str,$array,$caseInsensitive=FALSE) 162 * 4578: function includeEMCONF($path,$_EXTKEY) 163 * 4593: function searchExtension($extKey,$row) 164 * 165 * TOTAL FUNCTIONS: 90 166 * (This index is automatically created/updated by the extension "extdeveval") 167 * 168 */ 169 170 // Include classes needed: 171 require_once(PATH_t3lib.'class.t3lib_tcemain.php'); 172 require_once(PATH_t3lib.'class.t3lib_install.php'); 173 require_once(PATH_t3lib.'class.t3lib_tsstyleconfig.php'); 174 require_once(PATH_t3lib.'class.t3lib_scbase.php'); 175 176 require_once ('class.em_xmlhandler.php'); 177 require_once ('class.em_terconnection.php'); 178 require_once ('class.em_unzip.php'); 179 180 // from tx_ter by Robert Lemke 181 define('TX_TER_RESULT_EXTENSIONSUCCESSFULLYUPLOADED', '10504'); 182 183 define('EM_INSTALL_VERSION_MIN', 1); 184 define('EM_INSTALL_VERSION_MAX', 2); 185 define('EM_INSTALL_VERSION_STRICT', 3); 186 187 /** 188 * Module: Extension manager 189 * 190 * @author Kasper Skaarhoj <kasperYYYY@typo3.com> 191 * @author Karsten Dambekalns <karsten@typo3.org> 192 * @package TYPO3 193 * @subpackage core 194 */ 195 class SC_mod_tools_em_index extends t3lib_SCbase { 196 197 // Internal, static: 198 var $versionDiffFactor = 1; // This means that version difference testing for import is detected for sub-versions only, not dev-versions. Default: 1000 199 var $systemInstall = 0; // If "1" then installs in the sysext directory is allowed. Default: 0 200 var $requiredExt = ''; // List of required extension (from TYPO3_CONF_VARS) 201 var $maxUploadSize = 31457280; // Max size in bytes of extension upload to repository 202 var $kbMax = 500; // Max size in kilobytes for files to be edited. 203 var $doPrintContent = true; // If set (default), the function printContent() will echo the content which was collected in $this->content. You can set this to FALSE in order to echo content from elsewhere, fx. when using outbut buffering 204 var $listingLimit = 500; // List that many extension maximally at one time (fixing memory problems) 205 var $listingLimitAuthor = 250; // List that many extension maximally at one time (fixing memory problems) 206 207 /** 208 * Internal variable loaded with extension categories (for display/listing). Should reflect $categories above 209 * Dynamic var. 210 */ 211 var $defaultCategories = Array( 212 'cat' => Array ( 213 'be' => array(), 214 'module' => array(), 215 'fe' => array(), 216 'plugin' => array(), 217 'misc' => array(), 218 'services' => array(), 219 'templates' => array(), 220 'example' => array(), 221 'doc' => array() 222 ) 223 ); 224 225 /** 226 * Extension Categories (static var) 227 * Content must be redundant with the same internal variable as in class.tx_extrep.php! 228 */ 229 var $categories = Array( 230 'be' => 'Backend', 231 'module' => 'Backend Modules', 232 'fe' => 'Frontend', 233 'plugin' => 'Frontend Plugins', 234 'misc' => 'Miscellaneous', 235 'services' => 'Services', 236 'templates' => 'Templates', 237 'example' => 'Examples', 238 'doc' => 'Documentation' 239 ); 240 241 /** 242 * Extension States 243 * Content must be redundant with the same internal variable as in class.tx_extrep.php! 244 */ 245 var $states = Array ( 246 'alpha' => 'Alpha', 247 'beta' => 'Beta', 248 'stable' => 'Stable', 249 'experimental' => 'Experimental', 250 'test' => 'Test', 251 'obsolete' => 'Obsolete', 252 ); 253 254 /** 255 * Colors for extension states 256 */ 257 var $stateColors = Array ( 258 'alpha' => '#d12438', 259 'beta' => '#97b17e', 260 'stable' => '#3bb65c', 261 'experimental' => '#007eba', 262 'test' => '#979797', 263 'obsolete' => '#000000', 264 ); 265 266 /** 267 * "TYPE" information; labels, paths, description etc. 268 */ 269 var $typeLabels = Array ( 270 'S' => 'System', 271 'G' => 'Global', 272 'L' => 'Local', 273 ); 274 var $typeDescr = Array ( 275 'S' => 'System extension (typo3/sysext/) - Always distributed with source code (Static).', 276 'G' => 'Global extensions (typo3/ext/) - Available for shared source on server (Dynamic).', 277 'L' => 'Local extensions (typo3conf/ext/) - Local for this TYPO3 installation only (Dynamic).', 278 ); 279 var $typePaths = Array(); // Also static, set in init() 280 var $typeBackPaths = Array(); // Also static, set in init() 281 282 var $typeRelPaths = Array ( 283 'S' => 'sysext/', 284 'G' => 'ext/', 285 'L' => '../typo3conf/ext/', 286 ); 287 288 var $detailCols = Array ( 289 0 => 2, 290 1 => 5, 291 2 => 6, 292 3 => 6, 293 4 => 4, 294 5 => 1 295 ); 296 297 var $fe_user = array( 298 'username' => '', 299 'password' => '', 300 ); 301 302 var $privacyNotice = 'When you interact with the online repository, server information may be sent and stored in the repository for statistics.'; 303 var $securityHint = '<strong>Found a security problem? Please get in touch with us!</strong><br />If you think you have found a security issue in TYPO3 or an extension, please contact the <a href="http://typo3.org/teams/security/" target="_blank">TYPO3 security team</a>! Thank you!'; 304 var $editTextExtensions = 'html,htm,txt,css,tmpl,inc,php,sql,conf,cnf,pl,pm,sh,xml,ChangeLog'; 305 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,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,adodb'; 306 307 308 309 310 311 // Default variables for backend modules 312 var $MCONF = array(); // Module configuration 313 var $MOD_MENU = array(); // Module menu items 314 var $MOD_SETTINGS = array(); // Module session settings 315 var $doc; // Document Template Object 316 var $content; // Accumulated content 317 318 var $inst_keys = array(); // Storage of installed extensions 319 var $gzcompress = 0; // Is set true, if system support compression. 320 321 var $terConnection; // instance of TER connection handler 322 323 // GPvars: 324 var $CMD = array(); // CMD array 325 var $listRemote; // If set, connects to remote repository 326 var $lookUpStr; // Search string when listing local extensions 327 328 329 330 331 /********************************* 332 * 333 * Standard module initialization 334 * 335 *********************************/ 336 337 /** 338 * Standard init function of a module. 339 * 340 * @return void 341 */ 342 function init() { 343 global $BE_USER,$LANG,$BACK_PATH,$TYPO3_CONF_VARS; 344 345 // Setting paths of install scopes: 346 $this->typePaths = Array ( 347 'S' => TYPO3_mainDir.'sysext/', 348 'G' => TYPO3_mainDir.'ext/', 349 'L' => 'typo3conf/ext/' 350 ); 351 $this->typeBackPaths = Array ( 352 'S' => '../../../', 353 'G' => '../../../', 354 'L' => '../../../../'.TYPO3_mainDir 355 ); 356 357 $this->excludeForPackaging = $GLOBALS['TYPO3_CONF_VARS']['EXT']['excludeForPackaging']; 358 359 // Setting module configuration: 360 $this->MCONF = $GLOBALS['MCONF']; 361 362 // Setting GPvars: 363 $this->CMD = t3lib_div::_GP('CMD'); 364 $this->lookUpStr = trim(t3lib_div::_GP('_lookUp')); 365 $this->listRemote = t3lib_div::_GP('ter_connect'); 366 $this->listRemote_search = trim(t3lib_div::_GP('ter_search')); 367 368 369 // Configure menu 370 $this->menuConfig(); 371 372 // Setting internal static: 373 if ($TYPO3_CONF_VARS['EXT']['allowSystemInstall']) $this->systemInstall = 1; 374 $this->requiredExt = t3lib_div::trimExplode(',',$TYPO3_CONF_VARS['EXT']['requiredExt'],1); 375 376 377 // Initialize helper object 378 $this->terConnection = t3lib_div::makeInstance('SC_mod_tools_em_terconnection'); 379 $this->terConnection->emObj =& $this; 380 $this->terConnection->wsdlURL = $TYPO3_CONF_VARS['EXT']['em_wsdlURL']; 381 $this->xmlhandler = t3lib_div::makeInstance('SC_mod_tools_em_xmlhandler'); 382 $this->xmlhandler->emObj =& $this; 383 $this->xmlhandler->useUnchecked = $this->MOD_SETTINGS['display_unchecked']; 384 $this->xmlhandler->useObsolete = $this->MOD_SETTINGS['display_obsolete']; 385 386 // Initialize Document Template object: 387 $this->doc = t3lib_div::makeInstance('noDoc'); 388 $this->doc->backPath = $BACK_PATH; 389 $this->doc->docType = 'xhtml_trans'; 390 391 // JavaScript 392 $this->doc->JScode = $this->doc->wrapScriptTags(' 393 script_ended = 0; 394 function jumpToUrl(URL) { // 395 window.location.href = URL; 396 } 397 '); 398 $this->doc->form = '<form action="index.php" method="post" name="pageform">'; 399 400 // Descriptions: 401 $this->descrTable = '_MOD_'.$this->MCONF['name']; 402 if ($BE_USER->uc['edit_showFieldHelp']) { 403 $LANG->loadSingleTableDescription($this->descrTable); 404 } 405 406 // Setting username/password etc. for upload-user: 407 $this->fe_user['username'] = $this->MOD_SETTINGS['fe_u']; 408 $this->fe_user['password'] = $this->MOD_SETTINGS['fe_p']; 409 parent::init(); 410 $this->handleExternalFunctionValue('singleDetails'); 411 } 412 413 /** 414 * This function is a copy of the same function in t3lib_SCbase with one modification: 415 * In contrast to t3lib_SCbase::handleExternalFunctionValue() this function merges the $this->extClassConf array 416 * instead of overwriting it. That was necessary for including the Kickstarter as a submodule into the 'singleDetails' 417 * selectorbox as well as in the main 'function' selectorbox. 418 * 419 * @param string Mod-setting array key 420 * @param string Mod setting value, overriding the one in the key 421 * @return void 422 * @see t3lib_SCbase::handleExternalFunctionValue() 423 */ 424 function handleExternalFunctionValue($MM_key='function', $MS_value=NULL) { 425 $MS_value = is_null($MS_value) ? $this->MOD_SETTINGS[$MM_key] : $MS_value; 426 $externalItems = $this->getExternalItemConfig($this->MCONF['name'],$MM_key,$MS_value); 427 if (is_array($externalItems)) $this->extClassConf = array_merge($externalItems,is_array($this->extClassConf)?$this->extClassConf:array()); 428 if (is_array($this->extClassConf) && $this->extClassConf['path']) { 429 $this->include_once[]=$this->extClassConf['path']; 430 } 431 } 432 433 /** 434 * Configuration of which mod-menu items can be used 435 * 436 * @return void 437 */ 438 function menuConfig() { 439 global $BE_USER, $TYPO3_CONF_VARS; 440 441 // MENU-ITEMS: 442 $this->MOD_MENU = array( 443 'function' => array( 444 0 => 'Loaded extensions', 445 1 => 'Install extensions', 446 2 => 'Import extensions', 447 4 => 'Translation handling', 448 3 => 'Settings', 449 ), 450 'listOrder' => array( 451 'cat' => 'Category', 452 'author_company' => 'Author', 453 'state' => 'State', 454 'type' => 'Type' 455 ), 456 'display_details' => array( 457 1 => 'Details', 458 0 => 'Description', 459 2 => 'More details', 460 461 3 => 'Technical (takes time!)', 462 4 => 'Validating (takes time!)', 463 5 => 'Changed? (takes time!)', 464 ), 465 'display_shy' => '', 466 'display_own' => '', 467 'display_unchecked' => '', 468 'display_obsolete' => '', 469 470 'singleDetails' => array( 471 'info' => 'Information', 472 'edit' => 'Edit files', 473 'backup' => 'Backup/Delete', 474 'dump' => 'Dump DB', 475 'upload' => 'Upload to TER', 476 'updateModule' => 'UPDATE!', 477 ), 478 'fe_u' => '', 479 'fe_p' => '', 480 481 'mirrorListURL' => '', 482 'rep_url' => '', 483 'extMirrors' => '', 484 'selectedMirror' => '', 485 486 'selectedLanguages' => '' 487 ); 488 489 $this->MOD_MENU['singleDetails'] = $this->mergeExternalItems($this->MCONF['name'],'singleDetails',$this->MOD_MENU['singleDetails']); 490 491 // page/be_user TSconfig settings and blinding of menu-items 492 if (!$BE_USER->getTSConfigVal('mod.'.$this->MCONF['name'].'.allowTVlisting')) { 493 unset($this->MOD_MENU['display_details'][3]); 494 unset($this->MOD_MENU['display_details'][4]); 495 unset($this->MOD_MENU['display_details'][5]); 496 } 497 498 // CLEANSE SETTINGS 499 $this->MOD_SETTINGS = t3lib_BEfunc::getModuleData($this->MOD_MENU, t3lib_div::_GP('SET'), $this->MCONF['name']); 500 501 if ($this->MOD_SETTINGS['function']==2) { 502 // If listing from online repository, certain items are removed though: 503 unset($this->MOD_MENU['listOrder']['type']); 504 unset($this->MOD_MENU['display_details'][2]); 505 unset($this->MOD_MENU['display_details'][3]); 506 unset($this->MOD_MENU['display_details'][4]); 507 unset($this->MOD_MENU['display_details'][5]); 508 $this->MOD_SETTINGS = t3lib_BEfunc::getModuleData($this->MOD_MENU, t3lib_div::_GP('SET'), $this->MCONF['name']); 509 } 510 parent::menuConfig(); 511 } 512 513 /** 514 * Main function for Extension Manager module. 515 * 516 * @return void 517 */ 518 function main() { 519 global $BE_USER,$LANG,$TYPO3_CONF_VARS; 520 521 if (empty($this->MOD_SETTINGS['mirrorListURL'])) $this->MOD_SETTINGS['mirrorListURL'] = $TYPO3_CONF_VARS['EXT']['em_mirrorListURL']; 522 523 // Starting page: 524 $this->content.=$this->doc->startPage('Extension Manager'); 525 $this->content.=$this->doc->header('Extension Manager'); 526 $this->content.=$this->doc->spacer(5); 527 528 // Commands given which is executed regardless of main menu setting: 529 if ($this->CMD['showExt']) { // Show details for a single extension 530 $this->showExtDetails($this->CMD['showExt']); 531 } elseif ($this->CMD['requestInstallExtensions']) { // Show details for a single extension 532 $this->requestInstallExtensions($this->CMD['requestInstallExtensions']); 533 } elseif ($this->CMD['importExt'] || $this->CMD['uploadExt']) { // Imports an extension from online rep. 534 $err = $this->importExtFromRep($this->CMD['importExt'],$this->CMD['extVersion'],$this->CMD['loc'],$this->CMD['uploadExt']); 535 if ($err) { 536 $this->content.=$this->doc->section('',$GLOBALS['TBE_TEMPLATE']->rfw($err)); 537 } 538 if(!$err && $this->CMD['importExt']) { 539 $this->installTranslationsForExtension($this->CMD['importExt'], $this->getMirrorURL()); 540 } 541 } elseif ($this->CMD['importExtInfo']) { // Gets detailed information of an extension from online rep. 542 $this->importExtInfo($this->CMD['importExtInfo'],$this->CMD['extVersion']); 543 } else { // No command - we show what the menu setting tells us: 544 545 $menu = $LANG->sL('LLL:EXT:lang/locallang_core.php:labels.menu').' '. 546 t3lib_BEfunc::getFuncMenu(0,'SET[function]',$this->MOD_SETTINGS['function'],$this->MOD_MENU['function']); 547 548 if (t3lib_div::inList('0,1,2',$this->MOD_SETTINGS['function'])) { 549 $menu.=' Group by: '.t3lib_BEfunc::getFuncMenu(0,'SET[listOrder]',$this->MOD_SETTINGS['listOrder'],$this->MOD_MENU['listOrder']). 550 ' Show: '.t3lib_BEfunc::getFuncMenu(0,'SET[display_details]',$this->MOD_SETTINGS['display_details'],$this->MOD_MENU['display_details']).'<br />'; 551 } 552 if (t3lib_div::inList('0,1',$this->MOD_SETTINGS['function'])) { 553 $menu.='<label for="checkDisplayShy">Display shy extensions:</label> '.t3lib_BEfunc::getFuncCheck(0,'SET[display_shy]',$this->MOD_SETTINGS['display_shy'],'','','id="checkDisplayShy"'); 554 } 555 if (t3lib_div::inList('2',$this->MOD_SETTINGS['function']) && strlen($this->fe_user['username'])) { 556 $menu.='<label for="checkDisplayOwn">Only my extensions:</label> '.t3lib_BEfunc::getFuncCheck(0,'SET[display_own]',$this->MOD_SETTINGS['display_own'],'','','id="checkDisplayOwn"'); 557 } 558 if (t3lib_div::inList('0,1,2',$this->MOD_SETTINGS['function'])) { 559 $menu.=' <label for="checkDisplayObsolete">Show obsolete:</label> '.t3lib_BEfunc::getFuncCheck(0,'SET[display_obsolete]',$this->MOD_SETTINGS['display_obsolete'],'','','id="checkDisplayObsolete"'); 560 } 561 562 $this->content.=$this->doc->section('','<span class="nobr">'.$menu.'</span>'); 563 $this->content.=$this->doc->spacer(10); 564 565 switch((string)$this->MOD_SETTINGS['function']) { 566 case '0': 567 // Lists loaded (installed) extensions 568 $this->extensionList_loaded(); 569 break; 570 case '1': 571 // Lists the installed (available) extensions 572 $this->extensionList_installed(); 573 break; 574 case '2': 575 // Lists the extensions available from online rep. 576 $this->extensionList_import(); 577 break; 578 case '3': 579 // Shows the settings screen 580 $this->alterSettings(); 581 break; 582 case '4': 583 // Allows to set the translation preferences and check the status 584 $this->translationHandling(); 585 break; 586 default: 587 $this->extObjContent(); 588 break; 589 } 590 } 591 592 // Shortcuts: 593 if ($BE_USER->mayMakeShortcut()) { 594 $this->content.=$this->doc->spacer(20).$this->doc->section('',$this->doc->makeShortcutIcon('CMD','function',$this->MCONF['name'])); 595 } 596 } 597 598 /** 599 * Print module content. Called as last thing in the global scope. 600 * 601 * @return void 602 */ 603 function printContent() { 604 if ($this->doPrintContent) { 605 $this->content.= $this->doc->endPage(); 606 echo $this->content; 607 } 608 } 609 610 611 612 613 614 615 616 617 618 619 /********************************* 620 * 621 * Function Menu Applications 622 * 623 *********************************/ 624 625 /** 626 * Listing of loaded (installed) extensions 627 * 628 * @return void 629 */ 630 function extensionList_loaded() { 631 global $TYPO3_LOADED_EXT; 632 633 list($list,$cat) = $this->getInstalledExtensions(); 634 635 // Loaded extensions 636 $content = ''; 637 $lines = array(); 638 639 // Available extensions 640 if (is_array($cat[$this->MOD_SETTINGS['listOrder']])) { 641 $content=''; 642 $lines=array(); 643 $lines[] = $this->extensionListRowHeader(' class="bgColor5"',array('<td><img src="clear.gif" width="1" height="1" alt="" /></td>')); 644 645 foreach($cat[$this->MOD_SETTINGS['listOrder']] as $catName => $extEkeys) { 646 natcasesort($extEkeys); 647 reset($extEkeys); 648 $extensions = array(); 649 while(list($extKey)=each($extEkeys)) { 650 if (array_key_exists($extKey,$TYPO3_LOADED_EXT) && ($this->MOD_SETTINGS['display_shy'] || !$list[$extKey]['EM_CONF']['shy']) && $this->searchExtension($extKey,$list[$extKey])) { 651 if (in_array($extKey, $this->requiredExt)) { 652 $loadUnloadLink = '<strong>'.$GLOBALS['TBE_TEMPLATE']->rfw('Rq').'</strong>'; 653 } else { 654 $loadUnloadLink = '<a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[remove]=1').'">'.$this->removeButton().'</a>'; 655 } 656 657 $extensions[] = $this->extensionListRow($extKey,$list[$extKey],array('<td class="bgColor">'.$loadUnloadLink.'</td>')); 658 } 659 } 660 if(count($extensions)) { 661 $lines[]='<tr><td colspan="'.(3+$this->detailCols[$this->MOD_SETTINGS['display_details']]).'"><br /></td></tr>'; 662 $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>'; 663 $lines[] = implode(chr(10),$extensions); 664 } 665 } 666 } 667 668 $content.= t3lib_BEfunc::cshItem('_MOD_tools_em', 'loaded', $GLOBALS['BACK_PATH'],''); 669 670 $content.= '<label for="_lookUp">Look up:</label> <input type="text" id="_lookUp" name="_lookUp" value="'.htmlspecialchars($this->lookUpStr).'" /><input type="submit" value="Search"/><br/><br/>'; 671 672 $content.= ' 673 674 <!-- Loaded Extensions List --> 675 <table border="0" cellpadding="2" cellspacing="1">'.implode('',$lines).'</table>'; 676 677 $this->content.=$this->doc->section('Loaded Extensions',$content,0,1); 678 } 679 680 /** 681 * Listing of available (installed) extensions 682 * 683 * @return void 684 */ 685 function extensionList_installed() { 686 global $TYPO3_LOADED_EXT; 687 688 list($list,$cat)=$this->getInstalledExtensions(); 689 690 // Available extensions 691 if (is_array($cat[$this->MOD_SETTINGS['listOrder']])) { 692 $content=''; 693 $lines=array(); 694 $lines[]=$this->extensionListRowHeader(' class="bgColor5"',array('<td><img src="clear.gif" width="18" height="1" alt="" /></td>')); 695 696 $allKeys=array(); 697 foreach($cat[$this->MOD_SETTINGS['listOrder']] as $catName => $extEkeys) { 698 if(!$this->MOD_SETTINGS['display_obsolete'] && $catName=='obsolete') continue; 699 700 $allKeys[]=''; 701 $allKeys[]='TYPE: '.$catName; 702 703 natcasesort($extEkeys); 704 reset($extEkeys); 705 $extensions = array(); 706 while(list($extKey)=each($extEkeys)) { 707 $allKeys[]=$extKey; 708 if ((!$list[$extKey]['EM_CONF']['shy'] || $this->MOD_SETTINGS['display_shy']) && 709 ($list[$extKey]['EM_CONF']['state']!='obsolete' || $this->MOD_SETTINGS['display_obsolete']) 710 && $this->searchExtension($extKey,$list[$extKey])) { 711 $loadUnloadLink = t3lib_extMgm::isLoaded($extKey)? 712 '<a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[remove]=1&CMD[clrCmd]=1&SET[singleDetails]=info').'">'.$this->removeButton().'</a>': 713 '<a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[load]=1&CMD[clrCmd]=1&SET[singleDetails]=info').'">'.$this->installButton().'</a>'; 714 if (in_array($extKey,$this->requiredExt)) { 715 $loadUnloadLink='<strong>'.$GLOBALS['TBE_TEMPLATE']->rfw('Rq').'</strong>'; 716 } 717 $theRowClass = t3lib_extMgm::isLoaded($extKey)? 'em-listbg1' : 'em-listbg2'; 718 $extensions[]=$this->extensionListRow($extKey,$list[$extKey],array('<td class="bgColor">'.$loadUnloadLink.'</td>'),$theRowClass); 719 } 720 } 721 if(count($extensions)) { 722 $lines[]='<tr><td colspan="'.(3+$this->detailCols[$this->MOD_SETTINGS['display_details']]).'"><br /></td></tr>'; 723 $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>'; 724 $lines[] = implode(chr(10),$extensions); 725 } 726 } 727 728 $content.=' 729 730 731 <!-- 732 EXTENSION KEYS: 733 734 '.trim(implode(chr(10),$allKeys)).' 735 736 --> 737 738 '; 739 740 $content.= t3lib_BEfunc::cshItem('_MOD_tools_em', 'avail', $GLOBALS['BACK_PATH'],'|<br/>'); 741 $content.= 'If you want to use an extension in TYPO3, you should simply click the "plus" button '.$this->installButton().' . <br /> 742 Installed extensions can also be removed again - just click the remove button '.$this->removeButton().' .<br /><br />'; 743 744 $content.= '<label for="_lookUp">Look up:</label> <input type="text" id="_lookUp" name="_lookUp" value="'.htmlspecialchars($this->lookUpStr).'" /><input type="submit" value="Search"/><br/><br/>'; 745 $content.= $this->securityHint.'<br /><br />'; 746 747 $content.= '<table border="0" cellpadding="2" cellspacing="1">'.implode('',$lines).'</table>'; 748 749 $this->content.=$this->doc->section('Available Extensions - Grouped by: '.$this->MOD_MENU['listOrder'][$this->MOD_SETTINGS['listOrder']],$content,0,1); 750 } 751 } 752 753 /** 754 * Listing remote extensions from online repository 755 * 756 * @return void 757 */ 758 function extensionList_import() { 759 global $TYPO3_LOADED_EXT; 760 $content=''; 761 762 // Listing from online repository: 763 if ($this->listRemote) { 764 list($inst_list,) = $this->getInstalledExtensions(); 765 $this->inst_keys = array_flip(array_keys($inst_list)); 766 767 $this->detailCols[1]+=6; 768 769 // see if we have an extensionlist at all 770 $this->extensionCount = $this->xmlhandler->countExtensions(); 771 if (!$this->extensionCount) { 772 $content .= $this->fetchMetaData('extensions'); 773 } 774 775 if($this->MOD_SETTINGS['listOrder']=='author_company') { 776 $this->listingLimit = $this->listingLimitAuthor; 777 } 778 779 $this->pointer = intval(t3lib_div::_GP('pointer')); 780 $offset = $this->listingLimit*$this->pointer; 781 782 if($this->MOD_SETTINGS['display_own'] && strlen($this->fe_user['username'])) { 783 $this->xmlhandler->searchExtensionsXML($this->listRemote_search, $this->fe_user['username'], $this->MOD_SETTINGS['listOrder']); 784 } else { 785 $this->xmlhandler->searchExtensionsXML($this->listRemote_search, '', $this->MOD_SETTINGS['listOrder'], false, false, $offset, $this->listingLimit); 786 } 787 if (count($this->xmlhandler->extensionsXML)) { 788 list($list,$cat) = $this->prepareImportExtList(true); 789 790 // Available extensions 791 if (is_array($cat[$this->MOD_SETTINGS['listOrder']])) { 792 $lines=array(); 793 $lines[]=$this->extensionListRowHeader(' class="bgColor5"',array('<td><img src="clear.gif" width="18" height="1" alt="" /></td>'),1); 794 795 foreach($cat[$this->MOD_SETTINGS['listOrder']] as $catName => $extEkeys) { 796 if (count($extEkeys)) { 797 $lines[]='<tr><td colspan="'.(3+$this->detailCols[$this->MOD_SETTINGS['display_details']]).'"><br /></td></tr>'; 798 $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>'; 799 800 natcasesort($extEkeys); 801 reset($extEkeys); 802 while(list($extKey)=each($extEkeys)) { 803 $version = array_keys($list[$extKey]['versions']); 804 $version = end($version); 805 $ext = $list[$extKey]['versions'][$version]; 806 $ext['downloadcounter_all'] = $list[$extKey]['downloadcounter']; 807 $ext['_ICON'] = $list[$extKey]['_ICON']; 808 $loadUnloadLink=''; 809 if ($inst_list[$extKey]['type']!='S' && (!isset($inst_list[$extKey]) || $this->versionDifference($version,$inst_list[$extKey]['EM_CONF']['version'],$this->versionDiffFactor))) { 810 if (isset($inst_list[$extKey])) { 811 // update 812 $loc= ($inst_list[$extKey]['type']=='G'?'G':'L'); 813 $aUrl = 'index.php?CMD[importExt]='.$extKey.'&CMD[extVersion]='.$version.'&CMD[loc]='.$loc; 814 $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>'; 815 } else { 816 // import 817 $aUrl = 'index.php?CMD[importExt]='.$extKey.'&CMD[extVersion]='.$version.'&CMD[loc]=L'; 818 $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>'; 819 } 820 } else { 821 $loadUnloadLink = ' '; 822 } 823 824 if (isset($inst_list[$extKey])) { 825 $theRowClass = t3lib_extMgm::isLoaded($extKey) ? 'em-listbg1' : 'em-listbg2'; 826 } else { 827 $theRowClass = 'em-listbg3'; 828 } 829 830 $lines[]=$this->extensionListRow($extKey,$ext,array('<td class="bgColor">'.$loadUnloadLink.'</td>'),$theRowClass,$inst_list,1,'index.php?CMD[importExtInfo]='.rawurlencode($extKey)); 831 unset($list[$extKey]); 832 } 833 } 834 } 835 unset($list); 836 837 // CSH: 838 $content.= t3lib_BEfunc::cshItem('_MOD_tools_em', 'import_ter', $GLOBALS['BACK_PATH'],'|<br/>'); 839 $onsubmit = "window.location.href='index.php?ter_connect=1&ter_search='+escape(this.elements['_lookUp'].value);return false;"; 840 $content.= '</form><form action="index.php" method="post" onsubmit="'.htmlspecialchars($onsubmit).'"><label for="_lookUp">List or look up <strong'.($this->MOD_SETTINGS['display_unchecked']?' style="color:#900;">all':' style="color:#090;">reviewed').'</strong> extensions</label><br /> 841 <input type="text" id="_lookUp" name="_lookUp" value="'.htmlspecialchars($this->listRemote_search).'" /> <input type="submit" value="Look up" /><br /><br />'; 842 843 $content .= $this->browseLinks(); 844 845 $content.= ' 846 847 <!-- TER Extensions list --> 848 <table border="0" cellpadding="2" cellspacing="1">'.implode(chr(10),$lines).'</table>'; 849 $content .= '<br />'.$this->browseLinks(); 850 $content.= '<br /><br />'.$this->securityHint; 851 $content.= '<br /><br /><strong>PRIVACY NOTICE:</strong><br /> '.$this->privacyNotice; 852 853 $this->content.=$this->doc->section('Extensions in TYPO3 Extension Repository (online) - Grouped by: '.$this->MOD_MENU['listOrder'][$this->MOD_SETTINGS['listOrder']],$content,0,1); 854 855 // Plugins which are NOT uploaded to repository but present on this server. 856 $content=''; 857 $lines=array(); 858 if (count($this->inst_keys)) { 859 reset($this->inst_keys); 860 while(list($extKey)=each($this->inst_keys)) { 861 $this->xmlhandler->searchExtensionsXML($extKey, '', '', true); 862 if((strlen($this->listRemote_search) && !stristr($extKey,$this->listRemote_search)) || isset($this->xmlhandler->extensionsXML[$extKey])) continue; 863 864 $loadUnloadLink = t3lib_extMgm::isLoaded($extKey)? 865 '<a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[remove]=1&CMD[clrCmd]=1&SET[singleDetails]=info').'">'.$this->removeButton().'</a>': 866 '<a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[load]=1&CMD[clrCmd]=1&SET[singleDetails]=info').'">'.$this->installButton().'</a>'; 867 if (in_array($extKey,$this->requiredExt)) $loadUnloadLink='<strong>'.$GLOBALS['TBE_TEMPLATE']->rfw('Rq').'</strong>'; 868 $lines[]=$this->extensionListRow($extKey,$inst_list[$extKey],array('<td class="bgColor">'.$loadUnloadLink.'</td>'),t3lib_extMgm::isLoaded($extKey)?'em-listbg1':'em-listbg2'); 869 } 870 } 871 if(count($lines)) { 872 $content.= 'This is the list of extensions which are available locally, but not in the repository.<br />They might be user-defined and should be prepended user_ then.<br /><br />'; 873 $content.= '<table border="0" cellpadding="2" cellspacing="1">'. 874 $this->extensionListRowHeader(' class="bgColor5"',array('<td><img src="clear.gif" width="18" height="1" alt="" /></td>')). 875 implode('',$lines).'</table>'; 876 $this->content.=$this->doc->spacer(20); 877 $this->content.=$this->doc->section('Extensions found only on this server',$content,0,1); 878 } 879 } 880 } else { 881 $content.= t3lib_BEfunc::cshItem('_MOD_tools_em', 'import_ter', $GLOBALS['BACK_PATH'],'|<br/>'); 882 $onsubmit = "window.location.href='index.php?ter_connect=1&ter_search='+escape(this.elements['_lookUp'].value);return false;"; 883 $content.= '</form><form action="index.php" method="post" onsubmit="'.htmlspecialchars($onsubmit).'"><label for="_lookUp">List or look up <strong'.($this->MOD_SETTINGS['display_unchecked']?' style="color:#900;">all':' style="color:#090;">reviewed').'</strong> extensions</label><br /> 884 <input type="text" id="_lookUp" name="_lookUp" value="'.htmlspecialchars($this->listRemote_search).'" /> <input type="submit" value="Look up" /><br /><br />'; 885 886 $content.= '<p><strong>No matching extensions found.</strong></p>'; 887 888 $content.= '<br /><br /><strong>PRIVACY NOTICE:</strong><br /> '.$this->privacyNotice; 889 $this->content.=$this->doc->section('Extensions in TYPO3 Extension Repository (online) - Grouped by: '.$this->MOD_MENU['listOrder'][$this->MOD_SETTINGS['listOrder']],$content,0,1); 890 } 891 } else { 892 // CSH 893 $content.= t3lib_BEfunc::cshItem('_MOD_tools_em', 'import', $GLOBALS['BACK_PATH'],'|<br/>'); 894 895 $onsubmit = "window.location.href='index.php?ter_connect=1&ter_search='+escape(this.elements['_lookUp'].value);return false;"; 896 $content.= '</form><form action="index.php" method="post" onsubmit="'.htmlspecialchars($onsubmit).'"><label for="_lookUp">List or look up <strong'.($this->MOD_SETTINGS['display_unchecked']?' style="color:#900;">all':' style="color:#090;">reviewed').'</strong> extensions</label><br /> 897 <input type="text" id="_lookUp" name="_lookUp" value="" /> <input type="submit" value="Look up" /><br /><br />'; 898 899 if ($this->CMD['fetchMetaData']) { // fetches mirror/extension data from online rep. 900 $content .= $this->fetchMetaData($this->CMD['fetchMetaData']); 901 } else { 902 $onCLick = "window.location.href='index.php?CMD[fetchMetaData]=extensions';return false;"; 903 $content.= 'Connect to the current mirror and retrieve the current list of available plugins from the TYPO3 Extension Repository.<br /> 904 <input type="submit" value="Retrieve/Update" onclick="'.htmlspecialchars($onCLick).'" />'; 905 if (is_file(PATH_site.'typo3temp/extensions.xml.gz')) { 906 $dateFormat = $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy']; 907 $timeFormat = $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm']; 908 $content.= ' (last update: '.date($dateFormat.' '.$timeFormat,filemtime(PATH_site.'typo3temp/extensions.xml.gz')).')'; 909 } 910 } 911 $content.= '<br /><br />'.$this->securityHint; 912 $content.= '<br /><br /><strong>PRIVACY NOTICE:</strong><br />'.$this->privacyNotice; 913 914 $this->content.=$this->doc->section('Extensions in TYPO3 Extension Repository',$content,0,1); 915 } 916 917 // Upload: 918 if ($this->importAtAll()) { 919 $content= '</form><form action="index.php" enctype="'.$GLOBALS['TYPO3_CONF_VARS']['SYS']['form_enctype'].'" method="post"> 920 <label for="upload_ext_file">Upload extension file (.t3x):</label><br /> 921 <input type="file" size="60" id="upload_ext_file" name="upload_ext_file" /><br /> 922 ... to location:<br /> 923 <select name="CMD[loc]">'; 924 if ($this->importAsType('L')) $content.='<option value="L">Local (../typo3conf/ext/)</option>'; 925 if ($this->importAsType('G')) $content.='<option value="G">Global (typo3/ext/)</option>'; 926 if ($this->importAsType('S')) $content.='<option value="S">System (typo3/sysext/)</option>'; 927 $content.='</select><br /> 928 <input type="checkbox" value="1" name="CMD[uploadOverwrite]" id="checkUploadOverwrite" /> <label for="checkUploadOverwrite">Overwrite any existing extension!</label><br /> 929 <input type="submit" name="CMD[uploadExt]" value="Upload extension file" /><br /> 930 '; 931 } else $content=$this->noImportMsg(); 932 933 $this->content.=$this->doc->spacer(20); 934 $this->content.=$this->doc->section('Upload extension file directly (.t3x):',$content,0,1); 935 } 936 937 /** 938 * Generates a link to the next page of extensions 939 * 940 * @return void 941 */ 942 function browseLinks() { 943 $content = ''; 944 if ($this->pointer) { 945 $content .= '<a href="'.t3lib_div::linkThisScript(array('pointer' => $this->pointer-1)).'" class="typo3-prevPage"><img'.t3lib_iconWorks::skinImg($GLOBALS['BACK_PATH'],'gfx/pilleft_n.gif','width="14" height="14"').' alt="Prev page" /> Prev page</a>'; 946 } 947 if ($content) $content .= ' '; 948 if (intval($this->xmlhandler->matchingCount/$this->listingLimit)>$this->pointer) { 949 $content .= '<a href="'.t3lib_div::linkThisScript(array('pointer' => $this->pointer+1)).'" class="typo3-nextPage"><img'.t3lib_iconWorks::skinImg($GLOBALS['BACK_PATH'],'gfx/pilright_n.gif','width="14" height="14"').' alt="Next page" /> Next page</a>'; 950 } 951 $upper = (($this->pointer+1)*$this->listingLimit); 952 if ($upper>$this->xmlhandler->matchingCount) { 953 $upper = $this->xmlhandler->matchingCount; 954 } 955 if ($content) $content .= '<br /><br />Showing extensions <strong>'.($this->pointer*$this->listingLimit+1).'</strong> to <strong>'.$upper.'</strong>'; 956 if ($content) $content .= '<br /><br />'; 957 return $content; 958 } 959 960 /** 961 * Allows changing of settings 962 * 963 * @return void 964 */ 965 function alterSettings() { 966 967 // Prepare the HTML output: 968 $content.= ' 969 '.t3lib_BEfunc::cshItem('_MOD_tools_em', 'settings', $GLOBALS['BACK_PATH'],'|<br/>').' 970 <fieldset><legend>Security Settings</legend> 971 <table border="0" cellpadding="2" cellspacing="2"> 972 <tr class="bgColor4"> 973 <td><label for="display_unchecked">Enable extensions without review (basic security check):</label></td> 974 <td>'.t3lib_BEfunc::getFuncCheck(0,'SET[display_unchecked]',$this->MOD_SETTINGS['display_unchecked'],'','','id="display_unchecked"').'</td> 975 </tr> 976 </table> 977 <strong>Notice:</strong> Make sure you know what consequences enabling this checkbox might have. Check the <a href="http://typo3.org/extensions/what-are-reviews/" target="_blank">information on typo3.org about security reviewing</a>! 978 </fieldset> 979 <br /> 980 <br /> 981 <fieldset><legend>User Settings</legend> 982 <table border="0" cellpadding="2" cellspacing="2"> 983 <tr class="bgColor4"> 984 <td><label for="set_fe_u">Enter repository username:</label></td> 985 <td><input type="text" id="set_fe_u" name="SET[fe_u]" value="'.htmlspecialchars($this->MOD_SETTINGS['fe_u']).'" /></td> 986 </tr> 987 <tr class="bgColor4"> 988 <td><label for="set_fe_p">Enter repository password:</label></td> 989 <td><input type="password" id="set_fe_p" name="SET[fe_p]" value="'.htmlspecialchars($this->MOD_SETTINGS['fe_p']).'" /></td> 990 </tr> 991 </table> 992 <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! 993 </fieldset> 994 <br /> 995 <br /> 996 <fieldset><legend>Mirror selection</legend> 997 <table border="0" cellpadding="2" cellspacing="2"> 998 <tr class="bgColor4"> 999 <td><label for="set_mirror_list_url">Enter mirror list URL:</label></a></td> 1000 <td><input type="text" size="50" id="set_mirror_list_url" name="SET[mirrorListURL]" value="'.htmlspecialchars($this->MOD_SETTINGS['mirrorListURL']).'" /></td> 1001 </tr> 1002 </table> 1003 <br /> 1004 <p>Select a mirror from below. This list is built from the online mirror list retrieved from the URL above.<br /><br /></p> 1005 <fieldset><legend>Mirror list</legend>'; 1006 if(!empty($this->MOD_SETTINGS['mirrorListURL'])) { 1007 if ($this->CMD['fetchMetaData']) { // fetches mirror/extension data from online rep. 1008 $content .= $this->fetchMetaData($this->CMD['fetchMetaData']); 1009 } else { 1010 $content.= '<a href="index.php?CMD[fetchMetaData]=mirrors">Click here to reload the list.</a>'; 1011 } 1012 } 1013 $content .= '<br /> 1014 <table cellspacing="4" style="text-align:left; vertical-alignment:top;"> 1015 <tr><td>Use</td><td>Name</td><td>URL</td><td>Country</td><td>Sponsored by</td></tr> 1016 '; 1017 1018 if (!strlen($this->MOD_SETTINGS['extMirrors'])) $this->fetchMetaData('mirrors'); 1019 $extMirrors = unserialize($this->MOD_SETTINGS['extMirrors']); 1020 $extMirrors[''] = array('title'=>'Random (recommended!)'); 1021 ksort($extMirrors); 1022 if(is_array($extMirrors)) { 1023 foreach($extMirrors as $k => $v) { 1024 if(isset($v['sponsor'])) { 1025 $sponsor = '<a href="'.htmlspecialchars($v['sponsor']['link']).'" target="_new"><img src="'.$v['sponsor']['logo'].'" title="'.htmlspecialchars($v['sponsor']['name']).'" alt="'.htmlspecialchars($v['sponsor']['name']).'" /></a>'; 1026 } 1027 $selected = ($this->MOD_SETTINGS['selectedMirror']==$k) ? 'checked="checked"' : ''; 1028 $content.='<tr class="bgColor4"> 1029 <td><input type="radio" name="SET[selectedMirror]" id="selectedMirror'.$k.'" value="'.$k.'" '.$selected.'/></td><td><label for="selectedMirror'.$k.'">'.htmlspecialchars($v['title']).'</label></td><td>'.htmlspecialchars($v['host'].$v['path']).'</td><td>'.$v['country'].'</td><td>'.$sponsor.'</td></tr>'; 1030 } 1031 } 1032 $content.= ' 1033 </table> 1034 </fieldset> 1035 <br /> 1036 <table border="0" cellpadding="2" cellspacing="2"> 1037 <tr class="bgColor4"> 1038 <td><label for="set_rep_url">Enter repository URL:</label></td> 1039 <td><input type="text" size="50" id="set_rep_url" name="SET[rep_url]" value="'.htmlspecialchars($this->MOD_SETTINGS['rep_url']).'" /></td> 1040 </tr> 1041 </table> 1042 1043 If you set a repository URL, this overrides the use of a mirror. Use this to select a specific (private) repository.<br /> 1044 </fieldset> 1045 <br /> 1046 <input type="submit" value="Update" /> 1047 '; 1048 1049 $this->content.=$this->doc->section('Repository settings',$content,0,1); 1050 } 1051 1052 /** 1053 * Allows to set the translation preferences and check the status 1054 * 1055 * @return void 1056 */ 1057 function translationHandling() { 1058 global $LANG, $TYPO3_LOADED_EXT; 1059 $LANG->includeLLFile('EXT:setup/mod/locallang.xml'); 1060 1061 $incoming = t3lib_div::_POST('SET'); 1062 if(isset($incoming['selectedLanguages']) && is_array($incoming['selectedLanguages'])) { 1063 t3lib_BEfunc::getModuleData($this->MOD_MENU, array('selectedLanguages' => serialize($incoming['selectedLanguages'])), $this->MCONF['name'], '', 'selectedLanguages'); 1064 $this->MOD_SETTINGS['selectedLanguages'] = serialize($incoming['selectedLanguages']); 1065 } 1066 1067 $selectedLanguages = unserialize($this->MOD_SETTINGS['selectedLanguages']); 1068 if(count($selectedLanguages)==1 && empty($selectedLanguages[0])) $selectedLanguages = array(); 1069 $theLanguages = t3lib_div::trimExplode('|',TYPO3_languages); 1070 foreach($theLanguages as $val) { 1071 if ($val!='default') { 1072 $localLabel = ' - ['.htmlspecialchars($GLOBALS['LOCAL_LANG']['default']['lang_'.$val]).']'; 1073 $selected = (is_array($selectedLanguages) && in_array($val, $selectedLanguages)) ? ' selected="selected"' : ''; 1074 $opt[$GLOBALS['LOCAL_LANG']['default']['lang_'.$val].'--'.$val]=' 1075 <option value="'.$val.'"'.$selected.'>'.$LANG->getLL('lang_'.$val,1).$localLabel.'</option>'; 1076 } 1077 } 1078 ksort($opt); 1079 1080 // Prepare the HTML output: 1081 $content.= ' 1082 '.t3lib_BEfunc::cshItem('_MOD_tools_em', 'translation', $GLOBALS['BACK_PATH'],'|<br/>').' 1083 <fieldset><legend>Translation Settings</legend> 1084 <table border="0" cellpadding="2" cellspacing="2"> 1085 <tr class="bgColor4"> 1086 <td>Languages to fetch:</td> 1087 <td> 1088 <select name="SET[selectedLanguages][]" multiple="multiple" size="10"> 1089 <option></option>'. 1090 implode('',$opt).' 1091 </select> 1092 </td> 1093 </tr> 1094 </table> 1095 <br /> 1096 <p>For the selected languages the EM tries to download and install translation files if available, whenever an extension is installed. (This replaces the <code>csh_*</code> extensions that were used to install core translations before TYPO3 version 4!)<br /> 1097 <br />To request an update/install for already loaded extensions, see below.</p> 1098 </fieldset> 1099 <br /> 1100 <input type="submit" value="Save selection" /> 1101 <br /> 1102 </fieldset>'; 1103 1104 $this->content.=$this->doc->section('Translation settings',$content,0,1); 1105 1106 if(count($selectedLanguages)>0) { 1107 $mirrorURL = $this->getMirrorURL(); 1108 $content = '<input type="button" value="Check status against repository" onclick="document.location.href=\''.t3lib_div::linkThisScript(array('l10n'=>'check')).'\'" /> <input type="button" value="Update from repository" onclick="document.location.href=\''.t3lib_div::linkThisScript(array('l10n'=>'update')).'\'" />'; 1109 1110 if(t3lib_div::_GET('l10n') == 'check') { 1111 $loadedExtensions = array_keys($TYPO3_LOADED_EXT); 1112 $loadedExtensions = array_diff($loadedExtensions,array('_CACHEFILE')); 1113 1114 // Override content output - we now do that ourself: 1115 echo ($this->content . $this->doc->section('Translation status',$content,0,1)); 1116 $this->doPrintContent = FALSE; 1117 flush(); 1118 1119 echo ' 1120 <br /> 1121 <br /> 1122 <p id="progress-message"> 1123 Checking translation status, please wait ... 1124 </p> 1125 <br /> 1126 <div style="width:100%; height:20px; border: 1px solid black;"> 1127 <div id="progress-bar" style="float: left; width: 0%; height: 20px; background-color:green;"> </div> 1128 <div id="transparent-bar" style="float: left; width: 100%; height: 20px; background-color:'.$this->doc->bgColor2.';"> </div> 1129 </div> 1130 <br /> 1131 <br /><p>This table shows the status of the loaded extension\'s translations.</p><br /> 1132 <table border="0" cellpadding="2" cellspacing="2"> 1133 <tr class="bgColor2"><td>Extension key</td> 1134 '; 1135 1136 foreach($selectedLanguages as $lang) { 1137 echo ('<td>'.$LANG->getLL('lang_'.$lang,1).'</td>'); 1138 } 1139 echo ('</tr>'); 1140 1141 $counter = 1; 1142 foreach($loadedExtensions as $extKey) { 1143 1144 $percentDone = intval (($counter / count($loadedExtensions)) * 100); 1145 echo (' 1146 <script> 1147 document.getElementById("progress-bar").style.width = "'.$percentDone.'%"; 1148 document.getElementById("transparent-bar").style.width = "'.(100-$percentDone).'%"; 1149 document.getElementById("progress-message").firstChild.data="Checking translation status for extension \"'.$extKey.'\" ..."; 1150 </script> 1151 '); 1152 1153 flush(); 1154 $translationStatusArr = $this->terConnection->fetchTranslationStatus($extKey,$mirrorURL); 1155 1156 echo ('<tr class="bgColor4"><td>'.$extKey.'</td>'); 1157 foreach($selectedLanguages as $lang) { 1158 // remote unknown -> keine l10n 1159 if(!isset($translationStatusArr[$lang])) { 1160 echo ('<td title="No translation available">N/A</td>'); 1161 continue; 1162 } 1163 // determine local md5 from zip 1164 if(is_file(PATH_site.'typo3temp/'.$extKey.'-l10n-'.$lang.'.zip')) { 1165 $localmd5 = md5_file(PATH_site.'typo3temp/'.$extKey.'-l10n-'.$lang.'.zip'); 1166 } else { 1167 echo ('<td title="Not installed / Unknown" style="background-color:#ff0">???</td>'); 1168 continue; 1169 } 1170 // local!=remote -> needs update 1171 if($localmd5 != $translationStatusArr[$lang]['md5']) { 1172 echo ('<td title="Needs update" style="background-color:#ff0">UPD</td>'); 1173 continue; 1174 } 1175 echo ('<td title="Is up to date" style="background-color:#69a550">OK</td>'); 1176 } 1177 echo ('</tr>'); 1178 1179 $counter ++; 1180 } 1181 echo '</table> 1182 <script> 1183 document.getElementById("progress-message").firstChild.data="Check done."; 1184 </script> 1185 '; 1186 echo $this->doc->endPage(); 1187 return ''; 1188 1189 } elseif(t3lib_div::_GET('l10n') == 'update') { 1190 $loadedExtensions = array_keys($TYPO3_LOADED_EXT); 1191 $loadedExtensions = array_diff($loadedExtensions,array('_CACHEFILE')); 1192 1193 // Override content output - we now do that ourself: 1194 echo ($this->content . $this->doc->section('Translation status',$content,0,1)); 1195 $this->doPrintContent = FALSE; 1196 flush(); 1197 1198 echo (' 1199 <br /> 1200 <br /> 1201 <p id="progress-message"> 1202 Updating translations, please wait ... 1203 </p> 1204 <br /> 1205 <div style="width:100%; height:20px; border: 1px solid black;"> 1206 <div id="progress-bar" style="float: left; width: 0%; height: 20px; background-color:green;"> </div> 1207 <div id="transparent-bar" style="float: left; width: 100%; height: 20px; background-color:'.$this->doc->bgColor2.';"> </div> 1208 </div> 1209 <br /> 1210 <br /><p>This table shows the update results of the loaded extension\'s translations.<br /> 1211 <em>If you want to force a full check/update, delete the l10n zip-files from the typo3temp folder.</em></p><br /> 1212 <table border="0" cellpadding="2" cellspacing="2"> 1213 <tr class="bgColor2"><td>Extension key</td> 1214 '); 1215 1216 foreach($selectedLanguages as $lang) { 1217 echo '<td>'.$LANG->getLL('lang_'.$lang,1).'</td>'; 1218 } 1219 echo '</tr>'; 1220 1221 $counter = 1; 1222 foreach($loadedExtensions as $extKey) { 1223 $percentDone = intval (($counter / count($loadedExtensions)) * 100); 1224 echo (' 1225 <script> 1226 document.getElementById("progress-bar").style.width = "'.$percentDone.'%"; 1227 document.getElementById("transparent-bar").style.width = "'.(100-$percentDone).'%"; 1228 document.getElementById("progress-message").firstChild.data="Updating translation for extension \"'.$extKey.'\" ..."; 1229 </script> 1230 '); 1231 1232 flush(); 1233 $translationStatusArr = $this->terConnection->fetchTranslationStatus($extKey,$mirrorURL); 1234 1235 echo ('<tr class="bgColor4"><td>'.$extKey.'</td>'); 1236 if(is_array($translationStatusArr)) { 1237 foreach($selectedLanguages as $lang) { 1238 // remote unknown -> no l10n available 1239 if(!isset($translationStatusArr[$lang])) { 1240 echo ('<td title="No translation available">N/A</td>'); 1241 continue; 1242 } 1243 // determine local md5 from zip 1244 if(is_file(PATH_site.'typo3temp/'.$extKey.'-l10n-'.$lang.'.zip')) { 1245 $localmd5 = md5_file(PATH_site.'typo3temp/'.$extKey.'-l10n-'.$lang.'.zip'); 1246 } else { 1247 $localmd5 = 'zzz'; 1248 } 1249 // local!=remote or not installed -> needs update 1250 if($localmd5 != $translationStatusArr[$lang]['md5']) { 1251 $ret = $this->updateTranslation($extKey, $lang, $mirrorURL); 1252 if($ret === true) { 1253 echo ('<td title="Has been updated" style="background-color:#69a550">UPD</td>'); 1254 } else { 1255 echo ('<td title="'.htmlspecialchars($ret).'" style="background-color:#cb3352">ERR</td>'); 1256 } 1257 continue; 1258 } 1259 echo ('<td title="Is up to date" style="background-color:#69a550">OK</td>'); 1260 } 1261 } else { 1262 echo ('<td colspan="'.count($selectedLanguages).'" title="Possible reasons: network problems, allow_url_fopen off, curl not enabled in Install tool.">Could not fetch translation status</td>'); 1263 } 1264 echo ('</tr>'); 1265 $counter++; 1266 } 1267 echo '</table> 1268 <script> 1269 document.getElementById("progress-message").firstChild.data="Update done."; 1270 </script> 1271 '; 1272 echo $this->doc->endPage(); 1273 return ''; 1274 } 1275 1276 $this->content.=$this->doc->section('Translation status',$content,0,1); 1277 } 1278 } 1279 1280 /** 1281 * Install translations for all selected languages for an extension 1282 * 1283 * @param string $extKey The extension key to install the translations for 1284 * @param string $lang Language code of translation to fetch 1285 * @param string $mirrorURL Mirror URL to fetch data from 1286 * @return mixed true on success, error string on fauilure 1287 */ 1288 function updateTranslation($extKey, $lang, $mirrorURL) { 1289 $l10n = $this->terConnection->fetchTranslation($extKey, $lang, $mirrorURL); 1290 if(is_array($l10n)) { 1291 $file = PATH_site.'typo3temp/'.$extKey.'-l10n-'.$lang.'.zip'; 1292 $path = 'l10n/'.$lang.'/'; 1293 if(!is_dir(PATH_typo3conf.$path)) t3lib_div::mkdir_deep(PATH_typo3conf,$path); 1294 t3lib_div::writeFile($file, $l10n[0]); 1295 if($this->unzip($file, PATH_typo3conf.$path)) { 1296 return true; 1297 } else { 1298 return 'Unpacking the language pack failed!'; 1299 } 1300 } else { 1301 return $l10n; 1302 } 1303 } 1304 1305 /** 1306 * Install translations for all selected languages for an extension 1307 * 1308 * @param string $extKey The extension key to install the translations for 1309 * @param string $mirrorURL Mirror URL to fetch data from 1310 * @return mixed true on success, error string on fauilure 1311 */ 1312 function installTranslationsForExtension($extKey, $mirrorURL) { 1313 $selectedLanguages = unserialize($this->MOD_SETTINGS['selectedLanguages']); 1314 if(!is_array($selectedLanguages)) $selectedLanguages = array(); 1315 foreach($selectedLanguages as $lang) { 1316 $l10n = $this->terConnection->fetchTranslation($extKey, $lang, $mirrorURL); 1317 if(is_array($l10n)) { 1318 $file = PATH_typo3conf.'l10n/'.$extKey.'-l10n-'.$lang.'.zip'; 1319 $path = 'l10n/'.$lang.'/'.$extKey; 1320 t3lib_div::writeFile($file, $l10n[0]); 1321 if(!is_dir(PATH_typo3conf.$path)) t3lib_div::mkdir_deep(PATH_typo3conf,$path); 1322 if($this->unzip($file, PATH_typo3conf.$path)) { 1323 return true; 1324 } else { 1325 return 'Unpacking the language pack failed!'; 1326 } 1327 } else { 1328 return $l10n; 1329 } 1330 } 1331 } 1332 1333 /** 1334 * Unzips a zip file in the given path. 1335 * 1336 * Uses unzip binary if available, otherwise a pure PHP unzip is used. 1337 * 1338 * @param string $file Full path to zip file 1339 * @param string $path Path to change to before extracting 1340 * @return boolean True on success, false in failure 1341 */ 1342 function unzip($file, $path) { 1343 if(strlen($GLOBALS['TYPO3_CONF_VARS']['BE']['unzip_path'])) { 1344 chdir($path); 1345 $cmd = $GLOBALS['TYPO3_CONF_VARS']['BE']['unzip_path'].' -o '.escapeshellarg($file); 1346 exec($cmd, $list, $ret); 1347 return ($ret === 0); 1348 } else { 1349 // we use a pure PHP unzip 1350 $unzip = new em_unzip($file); 1351 $ret = $unzip->extract(array('add_path'=>$path)); 1352 return (is_array($ret)); 1353 } 1354 } 1355 1356 1357 1358 /********************************* 1359 * 1360 * Command Applications (triggered by GET var) 1361 * 1362 *********************************/ 1363 1364 /** 1365 * Returns detailed info about an extension in the online repository 1366 * 1367 * @param string Extension repository uid + optional "private key": [uid]-[key]. 1368 * @param [type] $version: ... 1369 * @return void 1370 */ 1371 function importExtInfo($extKey, $version='') { 1372 1373 // "Go back" link 1374 $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>'; 1375 $this->content.= $this->doc->section('',$content); 1376 $content = ''; 1377 1378 // Fetch remote data: 1379 $this->xmlhandler->searchExtensionsXML($extKey, '', '', true, true); 1380 list($fetchData,) = $this->prepareImportExtList(true); 1381 1382 $versions = array_keys($fetchData[$extKey]['versions']); 1383 $version = ($version == '') ? end($versions) : $version; 1384 1385 $opt = array(); 1386 foreach(array_keys($fetchData[$extKey]['versions']) as $ver) { 1387 $opt[]='<option value="'.$ver.'"'.(($version == $ver) ? ' selected="selected"' : '').'>'.$ver.'</option>'; 1388 } 1389 1390 // "Select version" box: 1391 $onClick = 'window.location.href=\'index.php?CMD[importExtInfo]='.$extKey.'&CMD[extVersion]=\'+document.pageform.extVersion.options[document.pageform.extVersion.selectedIndex].value; return false;'; 1392 $select='<select name="extVersion">'.implode('',$opt).'</select> <input type="submit" value="Load details" onclick="'.htmlspecialchars($onClick).'" /> or<br /><br />'; 1393 1394 if ($this->importAtAll()) { 1395 $onClick = ' 1396 window.location.href=\'index.php?CMD[importExt]='.$extKey.'\' 1397 +\'&CMD[extVersion]=\'+document.pageform.extVersion.options[document.pageform.extVersion.selectedIndex].value 1398 +\'&CMD[loc]=\'+document.pageform.loc.options[document.pageform.loc.selectedIndex].value; 1399 return false;'; 1400 $select.=' 1401 <input type="submit" value="Import/Update" onclick="'.htmlspecialchars($onClick).'"> to: 1402 <select name="loc">'. 1403 ($this->importAsType('G',$fetchData['emconf_lockType'])?'<option value="G">Global: '.$this->typePaths['G'].$extKey.'/'.(@is_dir(PATH_site.$this->typePaths['G'].$extKey)?' (OVERWRITE)':' (empty)').'</option>':''). 1404 ($this->importAsType('L',$fetchData['emconf_lockType'])?'<option value="L">Local: '.$this->typePaths['L'].$extKey.'/'.(@is_dir(PATH_site.$this->typePaths['L'].$extKey)?' (OVERWRITE)':' (empty)').'</option>':''). 1405 ($this->importAsType('S',$fetchData['emconf_lockType'])?'<option value="S">System: '.$this->typePaths['S'].$extKey.'/'.(@is_dir(PATH_site.$this->typePaths['S'].$extKey)?' (OVERWRITE)':' (empty)').'</option>':''). 1406 '</select>'; 1407 } else $select.= $this->noImportMsg(); 1408 $content.= $select; 1409 $this->content.= $this->doc->section('Select command',$content,0,1); 1410 1411 // Details: 1412 $eInfo = $fetchData[$extKey]['versions'][$version]; 1413 $content='<strong>'.$fetchData[$extKey]['_ICON'].' '.$eInfo['EM_CONF']['title'].' ('.$extKey.', '.$version.')</strong><br /><br />'; 1414 $content.=$this->extInformationArray($extKey,$eInfo,1); 1415 $this->content.=$this->doc->spacer(10); 1416 $this->content.=$this->doc->section('Remote Extension Details',$content,0,1); 1417 } 1418 1419 /** 1420 * Fetches metadata and stores it to the corresponding place. This includes the mirror list, 1421 * extension XML files. 1422 * 1423 * @param string Type of data to fetch: (mirrors) 1424 * @param boolean If true the method doesn't produce any output 1425 * @return void 1426 */ 1427 function fetchMetaData($metaType) { 1428 global $TYPO3_CONF_VARS; 1429 1430 switch($metaType) { 1431 case 'mirrors': 1432 $mfile = t3lib_div::tempnam('mirrors'); 1433 $mirrorsFile = t3lib_div::getURL($this->MOD_SETTINGS['mirrorListURL']); 1434 if($mirrorsFile===false) { 1435 t3lib_div::unlink_tempfile($mfile); 1436 $content = '<p>The mirror list was not updated, it could not be fetched from '.$this->MOD_SETTINGS['mirrorListURL'].'. Possible reasons: network problems, allow_url_fopen is off, curl is not enabled in Install tool.</p>'; 1437 } else { 1438 t3lib_div::writeFile($mfile, $mirrorsFile); 1439 $mirrors = implode('',gzfile($mfile)); 1440 t3lib_div::unlink_tempfile($mfile); 1441 1442 $mirrors = $this->xmlhandler->parseMirrorsXML($mirrors); 1443 if(is_array($mirrors) && count($mirrors)) { 1444 t3lib_BEfunc::getModuleData($this->MOD_MENU, array('extMirrors' => serialize($mirrors)), $this->MCONF['name'], '', 'extMirrors'); 1445 $this->MOD_SETTINGS['extMirrors'] = serialize($mirrors); 1446 $content = '<p>The mirror list has been updated and now contains '.count($mirrors).' entries.</p>'; 1447 } 1448 else { 1449 $content = '<p>'.$mirrors.'<br />The mirror list was not updated as it contained no entries.</p>'; 1450 } 1451 } 1452 break; 1453 case 'extensions': 1454 $this->fetchMetaData('mirrors'); // if we fetch the extensions anyway, we can as well keep this up-to-date 1455 1456 $mirror = $this->getMirrorURL(); 1457 $extfile = $mirror.'extensions.xml.gz'; 1458 $extmd5 = t3lib_div::getURL($mirror.'extensions.md5'); 1459 if(is_file(PATH_site.'typo3temp/extensions.xml.gz')) $localmd5 = md5_file(PATH_site.'typo3temp/extensions.xml.gz'); 1460 1461 if($extmd5 === false) { 1462 $content .= '<p>Error: The extension MD5 sum could not be fetched from '.$mirror.'extensions.md5. Possible reasons: network problems, allow_url_fopen is off, curl is not enabled in Install tool.</p>'; 1463 } elseif($extmd5 == $localmd5) { 1464 $content .= '<p>The extension list has not changed remotely, it has thus not been fetched.</p>'; 1465 } else { 1466 $extXML = t3lib_div::getURL($extfile); 1467 if($extXML === false) { 1468 $content .= '<p>Error: The extension list could not be fetched from '.$extfile.'. Possible reasons: network problems, allow_url_fopen is off, curl is not enabled in Install tool.</p>'; 1469 } else { 1470 t3lib_div::writeFile(PATH_site.'typo3temp/extensions.xml.gz', $extXML); 1471 $content .= $this->xmlhandler->parseExtensionsXML(PATH_site.'typo3temp/extensions.xml.gz'); 1472 } 1473 } 1474 break; 1475 } 1476 1477 return $content; 1478 } 1479 1480 /** 1481 * Returns the base URL for the slected or a random mirror. 1482 * 1483 * @return string The URL for the selected or a random mirror 1484 */ 1485 function getMirrorURL() { 1486 if(strlen($this->MOD_SETTINGS['rep_url'])) return $this->MOD_SETTINGS['rep_url']; 1487 1488 $mirrors = unserialize($this->MOD_SETTINGS['extMirrors']); 1489 if(!is_array($mirrors)) { 1490 $this->fetchMetaData('mirrors'); 1491 $mirrors = unserialize($this->MOD_SETTINGS['extMirrors']); 1492 if(!is_array($mirrors)) return false; 1493 } 1494 if($this->MOD_SETTINGS['selectedMirror']=='') { 1495 srand((float) microtime() * 10000000); // not needed after PHP 4.2.0... 1496 $rand = array_rand($mirrors); 1497 $url = 'http://'.$mirrors[$rand]['host'].$mirrors[$rand]['path']; 1498 } 1499 else { 1500 $url = 'http://'.$mirrors[$this->MOD_SETTINGS['selectedMirror']]['host'].$mirrors[$this->MOD_SETTINGS['selectedMirror']]['path']; 1501 } 1502 1503 return $url; 1504 } 1505 1506 1507 1508 /** 1509 * Installs (activates) an extension 1510 * 1511 * For $mode use the three constants EM_INSTALL_VERSION_MIN, EM_INSTALL_VERSION_MAX, EM_INSTALL_VERSION_STRICT 1512 * 1513 * If an extension is loaded or imported already and the version requirement is matched, it will not be 1514 * fetched from the repository. This means, if you use EM_INSTALL_VERSION_MIN, you will not always get the latest 1515 * version of an extension! 1516 * 1517 * @param string $extKey The extension key to install 1518 * @param string $version A version number that should be installed 1519 * @param int $mode If a version is requested, this determines if it is the min, max or strict version requested 1520 * @return [type] ... 1521 * @todo Make the method able to handle needed interaction somehow (unmatched dependencies) 1522 */ 1523 function installExtension($extKey, $version=null, $mode=EM_INSTALL_VERSION_MIN) { 1524 list($inst_list,) = $this->getInstalledExtensions(); 1525 1526 // check if it is already installed and loaded with sufficient version 1527 if(isset($inst_list[$extKey])) { 1528 $currentVersion = $inst_list[$extKey]['EM_CONF']['version']; 1529 1530 if(t3lib_extMgm::isLoaded($extKey)) { 1531 if($version===null) { 1532 return array(true, 'Extension already installed and loaded.'); 1533 } else { 1534 switch($mode) { 1535 case EM_INSTALL_VERSION_STRICT: 1536 if ($currentVersion == $version) { 1537 return array(true, 'Extension already installed and loaded.'); 1538 } 1539 break; 1540 case EM_INSTALL_VERSION_MIN: 1541 if (version_compare($currentVersion, $version, '>=')) { 1542 return array(true, 'Extension already installed and loaded.'); 1543 } 1544 break; 1545 case EM_INSTALL_VERSION_MAX: 1546 if (version_compare($currentVersion, $version, '<=')) { 1547 return array(true, 'Extension already installed and loaded.'); 1548 } 1549 break; 1550 } 1551 } 1552 } else { 1553 if (!t3lib_extMgm::isLocalconfWritable()) { 1554 return array(false, 'localconf.php is not writable!'); 1555 } 1556 $newExtList = -1; 1557 switch($mode) { 1558 case EM_INSTALL_VERSION_STRICT: 1559 if ($currentVersion == $version) { 1560 $newExtList = $this->addExtToList($extKey, $inst_list); 1561 } 1562 break; 1563 case EM_INSTALL_VERSION_MIN: 1564 if (version_compare($currentVersion, $version, '>=')) { 1565 $newExtList = $this->addExtToList($extKey, $inst_list); 1566 } 1567 break; 1568 case EM_INSTALL_VERSION_MAX: 1569 if (version_compare($currentVersion, $version, '<=')) { 1570 $newExtList = $this->addExtToList($extKey, $inst_list); 1571 } 1572 break; 1573 } 1574 if ($newExtList!=-1) { 1575 $this->writeNewExtensionList($newExtList); 1576 $this->refreshGlobalExtList(); 1577 $this->forceDBupdates($extKey, $inst_list[$extKey]); 1578 return array(true, 'Extension was already installed, it has been loaded.'); 1579 } 1580 } 1581 } 1582 1583 // at this point we know we need to import (a matching version of) the extension from TER2 1584 1585 // see if we have an extensionlist at all 1586 if (!$this->xmlhandler->countExtensions()) { 1587 $this->fetchMetaData('extensions'); 1588 } 1589 $this->xmlhandler->searchExtensionsXML($extKey, '', '', true); 1590 1591 // check if extension can be fetched 1592 if(isset($this->xmlhandler->extensionsXML[$extKey])) { 1593 $versions = array_keys($this->xmlhandler->extensionsXML[$extKey]['versions']); 1594 $latestVersion = end($versions); 1595 switch($mode) { 1596 case EM_INSTALL_VERSION_STRICT: 1597 if(!isset($this->xmlhandler->extensionsXML[$extKey]['versions'][$version])) { 1598 return array(false, 'Extension not available in matching version'); 1599 } 1600 break; 1601 case EM_INSTALL_VERSION_MIN: 1602 if (version_compare($latestVersion, $version, '>=')) { 1603 $version = $latestVersion; 1604 } else { 1605 return array(false, 'Extension not available in matching version'); 1606 } 1607 break; 1608 case EM_INSTALL_VERSION_MAX: 1609 while (($v = array_pop($versions)) && version_compare($v, $version, '>=')) { 1610 // Loop until a version is found 1611 } 1612 1613 if ($v !== null && version_compare($v, $version, '<=')) { 1614 $version = $v; 1615 } else { 1616 return array(false, 'Extension not available in matching version'); 1617 } 1618 break; 1619 } 1620 $this->importExtFromRep($extKey, $version, 'L'); 1621 $newExtList = $this->addExtToList($extKey, $inst_list); 1622 if ($newExtList!=-1) { 1623 $this->writeNewExtensionList($newExtList); 1624 $this->refreshGlobalExtList(); 1625 $this->forceDBupdates($extKey, $inst_list[$extKey]); 1626 $this->installTranslationsForExtension($extKey, $this->getMirrorURL()); 1627 return array(true, 'Extension has been imported from repository and loaded.'); 1628 } else { 1629 return array(false, 'Extension is in repository, but could not be loaded.'); 1630 } 1631 } else { 1632 return array(false, 'Extension not available in repository'); 1633 } 1634 } 1635 1636 function refreshGlobalExtList() { 1637 global $TYPO3_LOADED_EXT; 1638 1639 $TYPO3_LOADED_EXT = t3lib_extMgm::typo3_loadExtensions(); 1640 if ($TYPO3_LOADED_EXT['_CACHEFILE']) { 1641 require(PATH_typo3conf.$TYPO3_LOADED_EXT['_CACHEFILE'].'_ext_localconf.php'); 1642 } 1643 return; 1644 1645 $GLOBALS['TYPO3_LOADED_EXT'] = t3lib_extMgm::typo3_loadExtensions(); 1646 if ($TYPO3_LOADED_EXT['_CACHEFILE']) { 1647 require(PATH_typo3conf.$TYPO3_LOADED_EXT['_CACHEFILE'].'_ext_localconf.php'); 1648 } else { 1649 $temp_TYPO3_LOADED_EXT = $TYPO3_LOADED_EXT; 1650 reset($temp_TYPO3_LOADED_EXT); 1651 while(list($_EXTKEY,$temp_lEDat)=each($temp_TYPO3_LOADED_EXT)) { 1652 if (is_array($temp_lEDat) && $temp_lEDat['ext_localconf.php']) { 1653 $_EXTCONF = $TYPO3_CONF_VARS['EXT']['extConf'][$_EXTKEY]; 1654 require($temp_lEDat['ext_localconf.php']); 1655 } 1656 } 1657 } 1658 } 1659 1660 1661 /** 1662 * Imports an extensions from the online repository 1663 * NOTICE: in version 4.0 this changed from "importExtFromRep_old($extRepUid,$loc,$uploadFlag=0,$directInput='',$recentTranslations=0,$incManual=0,$dontDelete=0)" 1664 * 1665 * @param string Extension key 1666 * @param string Version 1667 * @param string Install scope: "L" or "G" or "S" 1668 * @param boolean If true, extension is uploaded as file 1669 * @param boolean If true, extension directory+files will not be deleted before writing the new ones. That way custom files stored in the extension folder will be kept. 1670 * @param array Direct input array (like from kickstarter) 1671 * @return string Return false on success, returns error message if error. 1672 */ 1673 function importExtFromRep($extKey,$version,$loc,$uploadFlag=0,$dontDelete=0,$directInput='') { 1674 1675 $uploadSucceed = false; 1676 $uploadedTempFile = ''; 1677 if (is_array($directInput)) { 1678 $fetchData = array($directInput,''); 1679 $loc = ($loc==='G'||$loc==='S') ? $loc : 'L'; 1680 } elseif ($uploadFlag) { 1681 if (($uploadedTempFile = $this->CMD['alreadyUploaded']) || $_FILES['upload_ext_file']['tmp_name']) { 1682 1683 // Read uploaded file: 1684 if (!$uploadedTempFile) { 1685 if (!is_uploaded_file($_FILES['upload_ext_file']['tmp_name'])) { 1686 t3lib_div::sysLog('Possible file upload attack: '.$_FILES['upload_ext_file']['tmp_name'], 'Extension Manager', 3); 1687 1688 return 'File was not uploaded?!?'; 1689 } 1690 1691 $uploadedTempFile = t3lib_div::upload_to_tempfile($_FILES['upload_ext_file']['tmp_name']); 1692 } 1693 $fileContent = t3lib_div::getUrl($uploadedTempFile); 1694 1695 if (!$fileContent) return 'File is empty!'; 1696 1697 // Decode file data: 1698 $fetchData = $this->terConnection->decodeExchangeData($fileContent); 1699 1700 if (is_array($fetchData)) { 1701 $extKey = $fetchData[0]['extKey']; 1702 if ($extKey) { 1703 if (!$this->CMD['uploadOverwrite']) { 1704 $loc = ($loc==='G'||$loc==='S') ? $loc : 'L'; 1705 $comingExtPath = PATH_site.$this->typePaths[$loc].$extKey.'/'; 1706 if (@is_dir($comingExtPath)) { 1707 return 'Extension was already present in "'.$comingExtPath.'" - and the overwrite flag was not set! So nothing done...'; 1708 } // ... else go on, install... 1709 } // ... else go on, install... 1710 } else return 'No extension key in file. Strange...'; 1711 } else return 'Wrong file format. No data recognized, '.$fetchData; 1712 } else return 'No file uploaded! Probably the file was too large for PHPs internal limit for uploadable files.'; 1713 } else { 1714 $this->xmlhandler->searchExtensionsXML($extKey, '', '', true, true); 1715 1716 // Fetch extension from TER: 1717 if(!strlen($version)) { 1718 $versions = array_keys($this->xmlhandler->extensionsXML[$extKey]['versions']); 1719 $version = end($versions); 1720 } 1721 $fetchData = $this->terConnection->fetchExtension($extKey, $version, $this->xmlhandler->extensionsXML[$extKey]['versions'][$version]['t3xfilemd5'], $this->getMirrorURL()); 1722 } 1723 1724 // At this point the extension data should be present; so we want to write it to disc: 1725 if ($this->importAsType($loc)) { 1726 if (is_array($fetchData)) { // There was some data successfully transferred 1727 if ($fetchData[0]['extKey'] && is_array($fetchData[0]['FILES'])) { 1728 $extKey = $fetchData[0]['extKey']; 1729 if(!isset($fetchData[0]['EM_CONF']['constraints'])) $fetchData[0]['EM_CONF']['constraints'] = $this->xmlhandler->extensionsXML[$extKey]['versions'][$version]['dependencies']; 1730 $EM_CONF = $this->fixEMCONF($fetchData[0]['EM_CONF']); 1731 if (!$EM_CONF['lockType'] || !strcmp($EM_CONF['lockType'],$loc)) { 1732 // check dependencies, act accordingly if ext is loaded 1733 list($instExtInfo,)=$this->getInstalledExtensions(); 1734 $depStatus = $this->checkDependencies($extKey, $EM_CONF, $instExtInfo); 1735 if(t3lib_extMgm::isLoaded($extKey) && !$depStatus['returnCode']) { 1736 $this->content .= $depStatus['html']; 1737 if ($uploadedTempFile) { 1738 $this->content .= '<input type="hidden" name="CMD[alreadyUploaded]" value="'.$uploadedTempFile.'" />'; 1739 } 1740 } else { 1741 $res = $this->clearAndMakeExtensionDir($fetchData[0],$loc,$dontDelete); 1742 if (is_array($res)) { 1743 $extDirPath = trim($res[0]); 1744 if ($extDirPath && @is_dir($extDirPath) && substr($extDirPath,-1)=='/') { 1745 1746 $emConfFile = $this->construct_ext_emconf_file($extKey,$EM_CONF); 1747 $dirs = $this->extractDirsFromFileList(array_keys($fetchData[0]['FILES'])); 1748 1749 $res = $this->createDirsInPath($dirs,$extDirPath); 1750 if (!$res) { 1751 $writeFiles = $fetchData[0]['FILES']; 1752 $writeFiles['ext_emconf.php']['content'] = $emConfFile; 1753 $writeFiles['ext_emconf.php']['content_md5'] = md5($emConfFile); 1754 1755 // Write files: 1756 foreach($writeFiles as $theFile => $fileData) { 1757 t3lib_div::writeFile($extDirPath.$theFile,$fileData['content']); 1758 if (!@is_file($extDirPath.$theFile)) { 1759 $content.='Error: File "'.$extDirPath.$theFile.'" could not be created!!!<br />'; 1760 } elseif (md5(t3lib_div::getUrl($extDirPath.$theFile)) != $fileData['content_md5']) { 1761 $content.='Error: File "'.$extDirPath.$theFile.'" MD5 was different from the original files MD5 - so the file is corrupted!<br />'; 1762 } 1763 } 1764 1765 // No content, no errors. Create success output here: 1766 if (!$content) { 1767 $content='SUCCESS: '.$extDirPath.'<br />'; 1768 1769 $uploadSucceed = true; 1770 1771 // Fix TYPO3_MOD_PATH for backend modules in extension: 1772 $modules = t3lib_div::trimExplode(',',$EM_CONF['module'],1); 1773 if (count($modules)) { 1774 foreach($modules as $mD) { 1775 $confFileName = $extDirPath.$mD.'/conf.php'; 1776 if (@is_file($confFileName)) { 1777 $content.= $this->writeTYPO3_MOD_PATH($confFileName,$loc,$extKey.'/'.$mD.'/').'<br />'; 1778 } else $content.='Error: Couldn\'t find "'.$confFileName.'"<br />'; 1779 } 1780 } 1781 // 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. 1782 // But this order of the code works.... (using the empty Array with type, EMCONF and files hereunder). 1783 1784 // Writing to ext_emconf.php: 1785 $sEMD5A = $this->serverExtensionMD5Array($extKey,array('type' => $loc, 'EM_CONF' => array(), 'files' => array())); 1786 $EM_CONF['_md5_values_when_last_written'] = serialize($sEMD5A); 1787 $emConfFile = $this->construct_ext_emconf_file($extKey,$EM_CONF); 1788 t3lib_div::writeFile($extDirPath.'ext_emconf.php',$emConfFile); 1789 1790 $content.='ext_emconf.php: '.$extDirPath.'ext_emconf.php<br />'; 1791 $content.='Type: '.$loc.'<br />'; 1792 1793 // Remove cache files: 1794 if (t3lib_extMgm::isLoaded($extKey)) { 1795 if ($this->removeCacheFiles()) { 1796 $content.='Cache-files are removed and will be re-written upon next hit<br />'; 1797 } 1798 1799 list($new_list)=$this->getInstalledExtensions(); 1800 $content.=$this->updatesForm($extKey,$new_list[$extKey],1,'index.php?CMD[showExt]='.$extKey.'&SET[singleDetails]=info'); 1801 } 1802 1803 // Install / Uninstall: 1804 if(!$this->CMD['standAlone']) { 1805 $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><br />'.$content; 1806 $content.='<h3>Install / Uninstall Extension:</h3>'; 1807 $content.= $new_list[$extKey] ? 1808 '<a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[remove]=1&CMD[clrCmd]=1&SET[singleDetails]=info').'">'.$this->removeButton().' Uninstall extension</a>' : 1809 '<a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[load]=1&CMD[clrCmd]=1&SET[singleDetails]=info').'">'.$this->installButton().' Install extension</a>'; 1810 } else { 1811 $content = 'Extension has been imported.<br /><br /><a href="javascript:opener.top.content.document.forms[0].submit();window.close();">Close window and recheck dependencies</a>'; 1812 } 1813 1814 } 1815 } else $content = $res; 1816 } else $content = 'Error: The extension path "'.$extDirPath.'" was different than expected...'; 1817 } else $content = $res; 1818 } 1819 } else $content = 'Error: The extension can only be installed in the path '.$this->typePaths[$EM_CONF['lockType']].' (lockType='.$EM_CONF['lockType'].')'; 1820 } else $content = 'Error: No extension key!!! Why? - nobody knows... (Or no files in the file-array...)'; 1821 } else $content = 'Error: The datatransfer did not succeed. '.$fetchData; 1822 } else $content = 'Error: Installation is not allowed in this path ('.$this->typePaths[$loc].')'; 1823 1824 $this->content.=$this->doc->section('Extension import results',$content,0,1); 1825 1826 if ($uploadSucceed && $uploadedTempFile) { 1827 t3lib_div::unlink_tempfile($uploadedTempFile); 1828 } 1829 1830 return false; 1831 } 1832 1833 /** 1834 * Display extensions details. 1835 * 1836 * @param string Extension key 1837 * @return void Writes content to $this->content 1838 */ 1839 function showExtDetails($extKey) { 1840 global $TYPO3_LOADED_EXT; 1841 1842 list($list,)=$this->getInstalledExtensions(); 1843 $absPath = $this->getExtPath($extKey,$list[$extKey]['type']); 1844 1845 // Check updateModule: 1846 if (@is_file($absPath.'class.ext_update.php')) { 1847 require_once($absPath.'class.ext_update.php'); 1848 $updateObj = new ext_update; 1849 if (!$updateObj->access()) { 1850 unset($this->MOD_MENU['singleDetails']['updateModule']); 1851 } 1852 } else { 1853 unset($this->MOD_MENU['singleDetails']['updateModule']); 1854 } 1855 1856 if($this->CMD['doDelete']) { 1857 $this->MOD_MENU['singleDetails'] = array(); 1858 } 1859 1860 // Function menu here: 1861 if(!$this->CMD['standAlone'] && !t3lib_div::_GP('standAlone')) { 1862 $content = ' 1863 <table border="0" cellpadding="0" cellspacing="0" width="100%"> 1864 <tr> 1865 <td nowrap="nowrap">Extension: <strong>'.$this->extensionTitleIconHeader($extKey,$list[$extKey]).'</strong> ('.$extKey.')</td> 1866 <td align="right" nowrap="nowrap">'. 1867 t3lib_BEfunc::getFuncMenu(0,'SET[singleDetails]',$this->MOD_SETTINGS['singleDetails'],$this->MOD_MENU['singleDetails'],'','&CMD[showExt]='.$extKey).' '. 1868 '<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> 1869 </tr> 1870 </table>'; 1871 $this->content.=$this->doc->section('',$content); 1872 } 1873 1874 // Show extension details: 1875 if ($list[$extKey]) { 1876 1877 // Checking if a command for install/uninstall is executed: 1878 if (($this->CMD['remove'] || $this->CMD['load']) && !in_array($extKey,$this->requiredExt)) { 1879 1880 // Install / Uninstall extension here: 1881 if (t3lib_extMgm::isLocalconfWritable()) { 1882 // Check dependencies: 1883 $depStatus = $this->checkDependencies($extKey, $list[$extKey]['EM_CONF'], $list); 1884 if(!$this->CMD['remove'] && !$depStatus['returnCode']) { 1885 $this->content .= $depStatus['html']; 1886 $newExtList = -1; 1887 } elseif ($this->CMD['remove']) { 1888 $newExtList = $this->removeExtFromList($extKey,$list); 1889 } else { 1890 $newExtList = $this->addExtToList($extKey,$list); 1891 } 1892 1893 // Success-installation: 1894 if ($newExtList!=-1) { 1895 $updates = ''; 1896 if ($this->CMD['load']) { 1897 if($_SERVER['REQUEST_METHOD'] == 'POST') { 1898 $script = t3lib_div::linkThisScript(array('CMD[showExt]' => $extKey, 'CMD[load]' => 1, 'CMD[clrCmd]' => $this->CMD['clrCmd'], 'SET[singleDetails]' => 'info')); 1899 } else { 1900 $script = ''; 1901 } 1902 $updates = $this->updatesForm($extKey,$list[$extKey],1,$script,'<input type="hidden" name="_do_install" value="1" /><input type="hidden" name="_clrCmd" value="'.$this->CMD['clrCmd'].'" />'); 1903 if ($updates) { 1904 $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; 1905 if($this->CMD['standAlone']) $updates .= '<input type="hidden" name="standAlone" value="1" />'; 1906 $depsolver = t3lib_div::_POST('depsolver'); 1907 if(is_array($depsolver['ignore'])) { 1908 foreach($depsolver['ignore'] as $depK => $depV) { 1909 $updates .= '<input type="hidden" name="depsolver[ignore]['.$depK.']" value="1" />'; 1910 } 1911 } 1912 1913 $this->content.=$this->doc->section('Installing '.$this->extensionTitleIconHeader($extKey,$list[$extKey]).strtoupper(': Database needs to be updated'),$updates,1,1,1,1); 1914 } 1915 } elseif ($this->CMD['remove']) { 1916 $updates.= $this->checkClearCache($list[$extKey]); 1917 if ($updates) { 1918 $updates = ' 1919 </form><form action="'.t3lib_div::linkThisScript().'" method="post">'.$updates.' 1920 <br /><input type="submit" name="write" value="Remove extension" /> 1921 <input type="hidden" name="_do_install" value="1" /> 1922 <input type="hidden" name="_clrCmd" value="'.$this->CMD['clrCmd'].'" /> 1923 <input type="hidden" name="standAlone" value="'.$this->CMD['standAlone'].'" /> 1924 '; 1925 $this->content.=$this->doc->section('Removing '.$this->extensionTitleIconHeader($extKey,$list[$extKey]).strtoupper(': Database needs to be updated'),$updates,1,1,1,1); 1926 } 1927 } 1928 if (!$updates || t3lib_div::_GP('_do_install')) { 1929 $this->writeNewExtensionList($newExtList); 1930 $GLOBALS['BE_USER']->writelog(5,1,0,0,'Extension list has been changed, extension %s has been %s',array($extKey,($this->CMD['load']?'installed':'removed'))); 1931 if ($this->CMD['clrCmd'] || t3lib_div::_GP('_clrCmd')) { 1932 $vA = array('CMD'=>''); 1933 } else { 1934 $vA = array('CMD'=>Array('showExt'=>$extKey)); 1935 } 1936 if($this->CMD['standAlone'] || t3lib_div::_GP('standAlone')) { 1937 $this->content .= 'Extension has been '.($this->CMD['load'] ? 'installed' : 'removed').'.<br /><br /><a href="javascript:opener.top.content.document.forms[0].submit();window.close();">Close window and recheck dependencies</a>'; 1938 } else { 1939 header('Location: '.t3lib_div::linkThisScript($vA)); 1940 } 1941 } 1942 } 1943 } else { 1944 $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); 1945 } 1946 1947 } elseif ($this->CMD['downloadFile'] && !in_array($extKey,$this->requiredExt)) { 1948 1949 // Link for downloading extension has been clicked - deliver content stream: 1950 $dlFile = $this->CMD['downloadFile']; 1951 if (t3lib_div::isFirstPartOfStr($dlFile,PATH_site) && t3lib_div::isFirstPartOfStr($dlFile,$absPath) && @is_file($dlFile)) { 1952 $mimeType = 'application/octet-stream'; 1953 Header('Content-Type: '.$mimeType); 1954 Header('Content-Disposition: attachment; filename='.basename($dlFile)); 1955 echo t3lib_div::getUrl($dlFile); 1956 exit; 1957 } else die('Error while trying to download extension file...'); 1958 1959 } elseif ($this->CMD['editFile'] && !in_array($extKey,$this->requiredExt)) { 1960 1961 // Editing extension file: 1962 $editFile = $this->CMD['editFile']; 1963 if (t3lib_div::isFirstPartOfStr($editFile,PATH_site) && t3lib_div::isFirstPartOfStr($editFile,$absPath)) { // Paranoia... 1964 1965 $fI = t3lib_div::split_fileref($editFile); 1966 if (@is_file($editFile) && t3lib_div::inList($this->editTextExtensions,($fI['fileext']?$fI['fileext']:$fI['filebody']))) { 1967 if (filesize($editFile)<($this->kbMax*1024)) { 1968 $outCode = ''; 1969 $info = ''; 1970 $submittedContent = t3lib_div::_POST('edit'); 1971 $saveFlag = 0; 1972 1973 if(isset($submittedContent['file']) && !$GLOBALS['TYPO3_CONF_VARS']['EXT']['noEdit']) { // Check referer here? 1974 $oldFileContent = t3lib_div::getUrl($editFile); 1975 if($oldFileContent != $submittedContent['file']) { 1976 $oldMD5 = md5(str_replace(chr(13),'',$oldFileContent)); 1977 $info.= 'MD5: <b>'.$oldMD5.'</b> (Previous File)<br />'; 1978 t3lib_div::writeFile($editFile,$submittedContent['file']); 1979 $saveFlag = 1; 1980 } else { 1981 $info .= 'No changes to the file detected!<br />'; 1982 } 1983 } 1984 1985 $fileContent = t3lib_div::getUrl($editFile); 1986 1987 $outCode.= 'File: <b>'.substr($editFile,strlen($absPath)).'</b> ('.t3lib_div::formatSize(filesize($editFile)).')<br />'; 1988 $fileMD5 = md5(str_replace(chr(13),'',$fileContent)); 1989 $info.= 'MD5: <b>'.$fileMD5.'</b> (Current File)<br />'; 1990 if($saveFlag) { 1991 $saveMD5 = md5(str_replace(chr(13),'',$submittedContent['file'])); 1992 $info.= 'MD5: <b>'.$saveMD5.'</b> (Submitted)<br />'; 1993 if($fileMD5!=$saveMD5) $info .= $GLOBALS['TBE_TEMPLATE']->rfw('<br /><strong>Saving failed, the content was not correctly written to disk. Changes have been lost!</strong>').'<br />'; 1994 else $info.= $GLOBALS['TBE_TEMPLATE']->rfw('<br /><strong>File saved.</strong>').'<br />'; 1995 } 1996 1997 $outCode.= '<textarea name="edit[file]" rows="35" wrap="off"'.$this->doc->formWidthText(48,'width:98%;height:70%','off').' class="fixed-font enable-tab">'.t3lib_div::formatForTextarea($fileContent).'</textarea>'; 1998 $outCode.= '<input type="hidden" name="edit[filename]" value="'.$editFile.'" />'; 1999 $outCode.= '<input type="hidden" name="CMD[editFile]" value="'.htmlspecialchars($editFile).'" />'; 2000 $outCode.= '<input type="hidden" name="CMD[showExt]" value="'.$extKey.'" />'; 2001 $outCode.= $info; 2002 2003 if (!$GLOBALS['TYPO3_CONF_VARS']['EXT']['noEdit']) { 2004 $outCode.='<br /><input type="submit" name="save_file" value="Save file" />'; 2005 } else $outCode.=$GLOBALS['TBE_TEMPLATE']->rfw('<br />[SAVING IS DISABLED - can be enabled by the $TYPO3_CONF_VARS[\'EXT\'][\'noEdit\']-flag] '); 2006 2007 $onClick = 'window.location.href=\'index.php?CMD[showExt]='.$extKey.'\';return false;'; 2008 $outCode.='<input type="submit" name="cancel" value="Cancel" onclick="'.htmlspecialchars($onClick).'" />'; 2009 2010 $theOutput.=$this->doc->spacer(15); 2011 $theOutput.=$this->doc->section('Edit file:','',0,1); 2012 $theOutput.=$this->doc->sectionEnd().$outCode; 2013 $this->content.=$theOutput; 2014 } else { 2015 $theOutput.=$this->doc->spacer(15); 2016 $theOutput.=$this->doc->section('Filesize exceeded '.$this->kbMax.' Kbytes','Files larger than '.$this->kbMax.' KBytes are not allowed to be edited.'); 2017 } 2018 } 2019 } else die('Fatal Edit error: File "'.$editFile.'" was not inside the correct path of the TYPO3 Extension!'); 2020 } else { 2021 2022 // MAIN: 2023 switch((string)$this->MOD_SETTINGS['singleDetails']) { 2024 case 'info': 2025 // Loaded / Not loaded: 2026 if (!in_array($extKey,$this->requiredExt)) { 2027 if ($TYPO3_LOADED_EXT[$extKey]) { 2028 $content = '<strong>The extension is installed (loaded and running)!</strong><br />'. 2029 '<a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[remove]=1').'">Click here to remove the extension: '.$this->removeButton().'</a>'; 2030 } else { 2031 $content = 'The extension is <strong>not</strong> installed yet.<br />'. 2032 '<a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[load]=1').'">Click here to install the extension: '.$this->installButton().'</a>'; 2033 } 2034 } else { 2035 $content = 'This extension is entered in the TYPO3_CONF_VARS[SYS][requiredExt] list and is therefore always loaded.'; 2036 } 2037 $this->content.=$this->doc->spacer(10); 2038 $this->content.=$this->doc->section('Active status:',$content,0,1); 2039 2040 if (t3lib_extMgm::isLoaded($extKey)) { 2041 $updates=$this->updatesForm($extKey,$list[$extKey]); 2042 if ($updates) { 2043 $this->content.=$this->doc->spacer(10); 2044 $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); 2045 } 2046 } 2047 2048 // Config: 2049 if (@is_file($absPath.'ext_conf_template.txt')) { 2050 $this->content.=$this->doc->spacer(10); 2051 $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); 2052 $this->tsStyleConfigForm($extKey,$list[$extKey]); 2053 } 2054 2055 // Show details: 2056 $content = t3lib_BEfunc::cshItem('_MOD_tools_em', 'info', $GLOBALS['BACK_PATH'],'|<br/>'); 2057 $content.= $this->extInformationArray($extKey,$list[$extKey]); 2058 2059 $this->content.=$this->doc->spacer(10); 2060 $this->content.=$this->doc->section('Details:',$content,0,1); 2061 break; 2062 case 'upload': 2063 $em = t3lib_div::_POST('em'); 2064 if($em['action'] == 'doUpload') { 2065 $em['extKey'] = $extKey; 2066 $em['extInfo'] = $list[$extKey]; 2067 $content = $this->uploadExtensionToTER($em); 2068 $content .= $this->doc->spacer(10); 2069 // Must reload this, because EM_CONF information has been updated! 2070 list($list,)=$this->getInstalledExtensions(); 2071 } else { 2072 // CSH: 2073 $content = t3lib_BEfunc::cshItem('_MOD_tools_em', 'upload', $GLOBALS['BACK_PATH'],'|<br/>'); 2074 2075 // Upload: 2076 if (substr($extKey,0,5)!='user_') { 2077 $content.= $this->getRepositoryUploadForm($extKey,$list[$extKey]); 2078 $eC=0; 2079 } else { 2080 $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.'; 2081 $eC=2; 2082 } 2083 if (!$this->fe_user['username']) { 2084 $content.= '<br /><br /><img src="'.$GLOBALS['BACK_PATH'].'gfx/icon_note.gif" width="18" height="16" align="top" alt="" />You have not configured a default username/password yet. <a href="index.php?SET[function]=3">Go to "Settings"</a> if you want to do that.<br />'; 2085 } 2086 } 2087 $this->content.=$this->doc->section('Upload extension to repository',$content,0,1,$eC); 2088 break; 2089 case 'backup': 2090 if($this->CMD['doDelete']) { 2091 $content = $this->extDelete($extKey,$list[$extKey]); 2092 $this->content.=$this->doc->section('Delete',$content,0,1); 2093 } else { 2094 $content = t3lib_BEfunc::cshItem('_MOD_tools_em', 'backup_delete', $GLOBALS['BACK_PATH'],'|<br/>'); 2095 $content.= $this->extBackup($extKey,$list[$extKey]); 2096 $this->content.=$this->doc->section('Backup',$content,0,1); 2097 2098 $content = $this->extDelete($extKey,$list[$extKey]); 2099 $this->content.=$this->doc->section('Delete',$content,0,1); 2100 2101 $content = $this->extUpdateEMCONF($extKey,$list[$extKey]); 2102 $this->content.=$this->doc->section('Update EM_CONF',$content,0,1); 2103 } 2104 break; 2105 case 'dump': 2106 $this->extDumpTables($extKey,$list[$extKey]); 2107 break; 2108 case 'edit': 2109 $content = t3lib_BEfunc::cshItem('_MOD_tools_em', 'editfiles', $GLOBALS['BACK_PATH'],'|<br/>'); 2110 $content.= $this->getFileListOfExtension($extKey,$list[$extKey]); 2111 2112 $this->content.=$this->doc->section('Extension files',$content,0,1); 2113 break; 2114 case 'updateModule': 2115 $this->content.=$this->doc->section('Update:',is_object($updateObj) ? $updateObj->main() : 'No update object',0,1); 2116 break; 2117 default: 2118 $this->extObjContent(); 2119 break; 2120 } 2121 } 2122 } 2123 } 2124 2125 /** 2126 * Outputs a screen from where you can install multiple extensions in one go 2127 * This can be called from external modules with "...index.php?CMD[requestInstallExtensions]= 2128 * 2129 * @param string Comma list of extension keys to install. Renders a screen with checkboxes for all extensions not already imported or installed 2130 * @return void 2131 */ 2132 function requestInstallExtensions($extList) { 2133 2134 // Return URL: 2135 $returnUrl = t3lib_div::_GP('returnUrl'); 2136 $installOrImportExtension = t3lib_div::_POST('installOrImportExtension'); 2137 2138 // Extension List: 2139 $extArray = explode(',',$extList); 2140 $outputRow = array(); 2141 $outputRow[] = ' 2142 <tr class="bgColor5 tableheader"> 2143 <td>Install/Import:</td> 2144 <td>Extension Key:</td> 2145 </tr> 2146 '; 2147 2148 foreach($extArray as $extKey) { 2149 2150 // Check for the request: 2151 if ($installOrImportExtension[$extKey]) { 2152 $this->installExtension($extKey); 2153 } 2154 2155 // Display: 2156 if (!t3lib_extMgm::isLoaded($extKey)) { 2157 $outputRow[] = ' 2158 <tr class="bgColor4"> 2159 <td><input type="checkbox" name="'.htmlspecialchars('installOrImportExtension['.$extKey.']').'" value="1" checked="checked" id="check_'.$extKey.'" /></td> 2160 <td><label for="check_'.$extKey.'">'.htmlspecialchars($extKey).'</label></td> 2161 </tr> 2162 '; 2163 } 2164 } 2165 2166 if (count($outputRow)>1 || !$returnUrl) { 2167 $content = ' 2168 </form> <!-- ending page form ... --> 2169 <form action="'.htmlspecialchars(t3lib_div::getIndpEnv('REQUEST_URI')).'" method="post"> 2170 <table border="0" cellpadding="1" cellspacing="1">'.implode('',$outputRow).'</table> 2171 <input type="submit" name="_" value="Import and Install selected" /> 2172 </form> 2173 <form> <!-- continuing page form... -->'; 2174 2175 if ($returnUrl) { 2176 $content.= ' 2177 <br/> 2178 <br/> 2179 <a href="'.htmlspecialchars($returnUrl).'">Return</a> 2180 '; 2181 } 2182 2183 $this->content.= $this->doc->section('Import/Install Extensions:',$content,0,1); 2184 } else { 2185 header('Location: '.t3lib_div::locationHeaderUrl($returnUrl)); 2186 } 2187 } 2188 2189 2190 2191 2192 2193 2194 2195 2196 /*********************************** 2197 * 2198 * Application Sub-functions (HTML parts) 2199 * 2200 **********************************/ 2201 2202 /** 2203 * Creates a form for an extension which contains all options for configuration, updates of database, clearing of cache etc. 2204 * This form is shown when 2205 * 2206 * @param string Extension key 2207 * @param array Extension information array 2208 * @param boolean If set, the form will ONLY show if fields/tables should be updated (suppressing forms like general configuration and cache clearing). 2209 * @param string Alternative action=""-script 2210 * @param string HTML: Additional form fields 2211 * @return string HTML 2212 */ 2213 function updatesForm($extKey,$extInfo,$notSilent=0,$script='',$addFields='') { 2214 $script = $script ? $script : t3lib_div::linkThisScript(); 2215 $updates.= $this->checkDBupdates($extKey,$extInfo); 2216 $uCache = $this->checkClearCache($extInfo); 2217 if ($notSilent) $updates.= $uCache; 2218 $updates.= $this->checkUploadFolder($extKey,$extInfo); 2219 2220 $absPath = $this->getExtPath($extKey,$extInfo['type']); 2221 if ($notSilent && @is_file($absPath.'ext_conf_template.txt')) { 2222 $cForm = $this->tsStyleConfigForm($extKey,$extInfo,1,$script,$updates.$addFields.'<br />'); 2223 } 2224 2225 if ($updates || $cForm) { 2226 if ($cForm) { 2227 $updates = '</form>'.$cForm.'<form>'; 2228 } else { 2229 $updates = '</form><form action="'.htmlspecialchars($script).'" method="post">'.$updates.$addFields.' 2230 <br /><input type="submit" name="write" value="Make updates" /> 2231 '; 2232 } 2233 } 2234 return $updates; 2235 } 2236 2237 /** 2238 * Creates view for dumping static tables and table/fields structures... 2239 * 2240 * @param string Extension key 2241 * @param array Extension information array 2242 * @return void 2243 */ 2244 function extDumpTables($extKey,$extInfo) { 2245 2246 // Get dbInfo which holds the structure known from the tables.sql file 2247 $techInfo = $this->makeDetailedExtensionAnalysis($extKey,$extInfo); 2248 $absPath = $this->getExtPath($extKey,$extInfo['type']); 2249 2250 // Static tables: 2251 if (is_array($techInfo['static'])) { 2252 if ($this->CMD['writeSTATICdump']) { // Writing static dump: 2253 $writeFile = $absPath.'ext_tables_static+adt.sql'; 2254 if (@is_file($writeFile)) { 2255 $dump_static = $this->dumpStaticTables(implode(',',$techInfo['static'])); 2256 t3lib_div::writeFile($writeFile,$dump_static); 2257 $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); 2258 } 2259 } else { // Showing info about what tables to dump - and giving the link to execute it. 2260 $msg = 'Dumping table content for static tables:<br />'; 2261 $msg.= '<br />'.implode('<br />',$techInfo['static']).'<br />'; 2262 2263 // ... then feed that to this function which will make new CREATE statements of the same fields but based on the current database content. 2264 $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); 2265 $this->content.=$this->doc->spacer(20); 2266 } 2267 } 2268 2269 // Table and field definitions: 2270 if (is_array($techInfo['dump_tf'])) { 2271 $dump_tf_array = $this->getTableAndFieldStructure($techInfo['dump_tf']); 2272 $dump_tf = $this->dumpTableAndFieldStructure($dump_tf_array); 2273 if ($this->CMD['writeTFdump']) { 2274 $writeFile = $absPath.'ext_tables.sql'; 2275 if (@is_file($writeFile)) { 2276 t3lib_div::writeFile($writeFile,$dump_tf); 2277 $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); 2278 } 2279 } else { 2280 $msg = 'Dumping current database structure for:<br />'; 2281 if (is_array($techInfo['tables'])) { 2282 $msg.= '<br /><strong>Tables:</strong><br />'.implode('<br />',$techInfo['tables']).'<br />'; 2283 } 2284 if (is_array($techInfo['fields'])) { 2285 $msg.= '<br /><strong>Solo-fields:</strong><br />'.implode('<br />',$techInfo['fields']).'<br />'; 2286 } 2287 2288 // ... then feed that to this function which will make new CREATE statements of the same fields but based on the current database content. 2289 $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 /> 2290 <pre>'.htmlspecialchars($dump_tf).'</pre>',0,1); 2291 2292 2293 $details = ' This dump is based on two factors:<br /> 2294 <ul> 2295 <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> 2296 <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> 2297 </ul> 2298 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 />'; 2299 $this->content.=$this->doc->section('',$details); 2300 } 2301 } 2302 } 2303 2304 /** 2305 * Returns file-listing of an extension 2306 * 2307 * @param string Extension key 2308 * @param array Extension information array 2309 * @return string HTML table. 2310 */ 2311 function getFileListOfExtension($extKey,$conf) { 2312 $content = ''; 2313 $extPath = $this->getExtPath($extKey,$conf['type']); 2314 2315 if ($extPath) { 2316 // Read files: 2317 $fileArr = array(); 2318 $fileArr = t3lib_div::getAllFilesAndFoldersInPath($fileArr,$extPath,'',0,99,$this->excludeForPackaging); 2319 2320 // Start table: 2321 $lines = array(); 2322 $totalSize = 0; 2323 2324 // Header: 2325 $lines[] = ' 2326 <tr class="bgColor5"> 2327 <td>File:</td> 2328 <td>Size:</td> 2329 <td>Edit:</td> 2330 </tr>'; 2331 2332 foreach($fileArr as $file) { 2333 $fI = t3lib_div::split_fileref($file); 2334 $lines[] = ' 2335 <tr class="bgColor4"> 2336 <td><a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[downloadFile]='.rawurlencode($file)).'" title="Download...">'.substr($file,strlen($extPath)).'</a></td> 2337 <td>'.t3lib_div::formatSize(filesize($file)).'</td> 2338 <td>'.(!in_array($extKey,$this->requiredExt)&&t3lib_div::inList($this->editTextExtensions,($fI['fileext']?$fI['fileext']:$fI['filebody']))?'<a href="'.htmlspecialchars('index.php?CMD[showExt]='.$extKey.'&CMD[editFile]='.rawurlencode($file)).'">Edit file</a>':'').'</td> 2339 </tr>'; 2340 $totalSize+=filesize($file); 2341 } 2342 2343 $lines[] = ' 2344 <tr class="bgColor6"> 2345 <td><strong>Total:</strong></td> 2346 <td><strong>'.t3lib_div::formatSize($totalSize).'</strong></td> 2347 <td> </td> 2348 </tr>'; 2349 2350 $content = ' 2351 Path: '.$extPath.'<br /><br /> 2352 <table border="0" cellpadding="1" cellspacing="2">'.implode('',$lines).'</table>'; 2353 } 2354 2355 return $content; 2356 } 2357 2358 /** 2359 * Delete extension from the file system 2360 * 2361 * @param string Extension key 2362 * @param array Extension info array 2363 * @return string Returns message string about the status of the operation 2364 */ 2365 function extDelete($extKey,$extInfo) { 2366 $absPath = $this->getExtPath($extKey,$extInfo['type']); 2367 if (t3lib_extMgm::isLoaded($extKey)) { 2368 return 'This extension is currently installed (loaded and active) and so cannot be deleted!'; 2369 } elseif (!$this->deleteAsType($extInfo['type'])) { 2370 return 'You cannot delete (and install/update) extensions in the '.$this->typeLabels[$extInfo['type']].' scope.'; 2371 } elseif (t3lib_div::inList('G,L',$extInfo['type'])) { 2372 if ($this->CMD['doDelete'] && !strcmp($absPath,$this->CMD['absPath'])) { 2373 $res = $this->removeExtDirectory($absPath); 2374 if ($res) { 2375 return 'ERROR: Could not remove extension directory "'.$absPath.'". Had the following errors:<br /><br />'. 2376 nl2br($res); 2377 } else { 2378 return 'Removed extension in path "'.$absPath.'"!'; 2379 } 2380 } else { 2381 $onClick = "if (confirm('Are you sure you want to delete this extension from the server?')) {window.location.href='index.php?CMD[showExt]=".$extKey.'&CMD[doDelete]=1&CMD[absPath]='.rawurlencode($absPath)."';}"; 2382 $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>'; 2383 $content.= '<br /><br />(Maybe you should make a backup first, see above.)'; 2384 return $content; 2385 } 2386 } else return 'Extension is not a global or local extension and cannot be removed.'; 2387 } 2388 2389 /** 2390 * Update extension EM_CONF... 2391 * 2392 * @param string Extension key 2393 * @param array Extension information array 2394 * @return string HTML content. 2395 */ 2396 function extUpdateEMCONF($extKey,$extInfo) { 2397 $absPath = $this->getExtPath($extKey,$extInfo['type']); 2398 if ($this->CMD['doUpdateEMCONF']) { 2399 return $this->updateLocalEM_CONF($extKey,$extInfo); 2400 } else { 2401 $onClick = "if (confirm('Are you sure you want to update EM_CONF?')) {window.location.href='index.php?CMD[showExt]=".$extKey."&CMD[doUpdateEMCONF]=1';}"; 2402 $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>'; 2403 $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 /> 2404 Updating this file will first of all reset this registration.'; 2405 return $content; 2406 } 2407 } 2408 2409 /** 2410 * Download extension as file / make backup 2411 * 2412 * @param string Extension key 2413 * @param array Extension information array 2414 * @return string HTML content 2415 */ 2416 function extBackup($extKey,$extInfo) { 2417 $uArr = $this->makeUploadArray($extKey,$extInfo); 2418 if (is_array($uArr)) { 2419 $backUpData = $this->terConnection->makeUploadDataFromArray($uArr); 2420 $filename = 'T3X_'.$extKey.'-'.str_replace('.','_',$extInfo['EM_CONF']['version']).'-z-'.date('YmdHi').'.t3x'; 2421 if (intval($this->CMD['doBackup'])==1) { 2422 header('Content-Type: application/octet-stream'); 2423 header('Content-Disposition: attachment; filename='.$filename); 2424 echo $backUpData; 2425 exit; 2426 } elseif ($this->CMD['dumpTables']) { 2427 $filename='T3X_'.$extKey; 2428 $cTables = count(explode(',',$this->CMD['dumpTables'])); 2429 if ($cTables>1) { 2430 $filename.='-'.$cTables.'tables'; 2431 } else { 2432 $filename.='-'.$this->CMD['dumpTables']; 2433 } 2434 $filename.='+adt.sql'; 2435 2436 header('Content-Type: application/octet-stream'); 2437 header('Content-Disposition: attachment; filename='.$filename); 2438 echo $this->dumpStaticTables($this->CMD['dumpTables']); 2439 exit; 2440 } else { 2441 $techInfo = $this->makeDetailedExtensionAnalysis($extKey,$extInfo); 2442 $lines=array(); 2443 $lines[]='<tr class="bgColor5"><td colspan="2"><strong>Make selection:</strong></td></tr>'; 2444 $lines[]='<tr class="bgColor4"><td><strong>Extension files:</strong></td><td>'. 2445 '<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 /></td></tr>'; 2446 2447 if (is_array($techInfo['tables'])) { $lines[]='<tr class="bgColor4"><td><strong>Data tables:</strong></td><td>'.$this->extBackup_dumpDataTablesLine($techInfo['tables'],$extKey).'</td></tr>'; } 2448 if (is_array($techInfo['static'])) { $lines[]='<tr class="bgColor4"><td><strong>Static tables:</strong></td><td>'.$this->extBackup_dumpDataTablesLine($techInfo['static'],$extKey).'</td></tr>'; } 2449 2450 $content = '<table border="0" cellpadding="2" cellspacing="2">'.implode('',$lines).'</table>'; 2451 return $content; 2452 } 2453 } else die('Error...'); 2454 } 2455 2456 /** 2457 * Link to dump of database tables 2458 * 2459 * @param string Extension key 2460 * @param array Extension information array 2461 * @return string HTML 2462 */ 2463 function extBackup_dumpDataTablesLine($tablesArray,$extKey) { 2464 $tables = array(); 2465 $tablesNA = array(); 2466 2467 foreach($tablesArray as $tN) { 2468 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('count(*)', $tN, ''); 2469 if (!$GLOBALS['TYPO3_DB']->sql_error()) { 2470 $row = $GLOBALS['TYPO3_DB']->sql_fetch_row($res); 2471 $tables[$tN]='<tr><td> </td><td><a href="'.htmlspecialchars('index.php?CMD[dumpTables]='.rawurlencode($tN).'&CMD[showExt]='.$extKey).'" title="Dump table \''.$tN.'\'">'.$tN.'</a></td><td> </td><td>'.$row[0].' records</td></tr>'; 2472 } else { 2473 $tablesNA[$tN]='<tr><td> </td><td>'.$tN.'</td><td> </td><td>Did not exist.</td></tr>'; 2474 } 2475 } 2476 $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... 2477 if (count($tables)) { 2478 $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; 2479 } else $label = 'Nothing to dump...<br /><br />'.$label; 2480 return $label; 2481 } 2482 2483 /** 2484 * Prints a table with extension information in it. 2485 * 2486 * @param string Extension key 2487 * @param array Extension information array 2488 * @param boolean If set, the information array shows information for a remote extension in TER, not a local one. 2489 * @return string HTML content. 2490 */ 2491 function extInformationArray($extKey,$extInfo,$remote=0) { 2492 $lines=array(); 2493 $lines[]='<tr class="bgColor5"><td colspan="2"><strong>General information:</strong></td>'.$this->helpCol('').'</tr>'; 2494 $lines[]='<tr class="bgColor4"><td>Title:</td><td>'.$extInfo['EM_CONF']['_icon'].$extInfo['EM_CONF']['title'].'</td>'.$this->helpCol('title').'</tr>'; 2495 $lines[]='<tr class="bgColor4"><td>Description:</td><td>'.nl2br(htmlspecialchars($extInfo['EM_CONF']['description'])).'</td>'.$this->helpCol('description').'</tr>'; 2496 $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']).($extInfo['EM_CONF']['author_company']?', '.$extInfo['EM_CONF']['author_company']:''). 2497 '</td>'.$this->helpCol('description').'</tr>'; 2498 2499 $lines[]='<tr class="bgColor4"><td>Version:</td><td>'.$extInfo['EM_CONF']['version'].'</td>'.$this->helpCol('version').'</tr>'; 2500 $lines[]='<tr class="bgColor4"><td>Category:</td><td>'.$this->categories[$extInfo['EM_CONF']['category']].'</td>'.$this->helpCol('category').'</tr>'; 2501 $lines[]='<tr class="bgColor4"><td>State:</td><td>'.$this->states[$extInfo['EM_CONF']['state']].'</td>'.$this->helpCol('state').'</tr>'; 2502 $lines[]='<tr class="bgColor4"><td>Shy?</td><td>'.($extInfo['EM_CONF']['shy']?'Yes':'').'</td>'.$this->helpCol('shy').'</tr>'; 2503 $lines[]='<tr class="bgColor4"><td>Internal?</td><td>'.($extInfo['EM_CONF']['internal']?'Yes':'').'</td>'.$this->helpCol('internal').'</tr>'; 2504 2505 $lines[]='<tr class="bgColor4"><td>Depends on:</td><td>'.$this->depToString($extInfo['EM_CONF']['constraints']).'</td>'.$this->helpCol('dependencies').'</tr>'; 2506 $lines[]='<tr class="bgColor4"><td>Conflicts with:</td><td>'.$this->depToString($extInfo['EM_CONF']['constraints'],'conflicts').'</td>'.$this->helpCol('dependencies').'</tr>'; 2507 $lines[]='<tr class="bgColor4"><td>Suggests:</td><td>'.$this->depToString($extInfo['EM_CONF']['constraints'],'suggests').'</td>'.$this->helpCol('dependencies').'</tr>'; 2508 if (!$remote) { 2509 $lines[]='<tr class="bgColor4"><td>Priority:</td><td>'.$extInfo['EM_CONF']['priority'].'</td>'.$this->helpCol('priority').'</tr>'; 2510 $lines[]='<tr class="bgColor4"><td>Clear cache?</td><td>'.($extInfo['EM_CONF']['clearCacheOnLoad']?'Yes':'').'</td>'.$this->helpCol('clearCacheOnLoad').'</tr>'; 2511 $lines[]='<tr class="bgColor4"><td>Includes modules:</td><td>'.$extInfo['EM_CONF']['module'].'</td>'.$this->helpCol('module').'</tr>'; 2512 $lines[]='<tr class="bgColor4"><td>Lock Type?</td><td>'.($extInfo['EM_CONF']['lockType']?$extInfo['EM_CONF']['lockType']:'').'</td>'.$this->helpCol('lockType').'</tr>'; 2513 $lines[]='<tr class="bgColor4"><td>Modifies tables:</td><td>'.$extInfo['EM_CONF']['modify_tables'].'</td>'.$this->helpCol('modify_tables').'</tr>'; 2514 2515 // Installation status: 2516 $techInfo = $this->makeDetailedExtensionAnalysis($extKey,$extInfo,1); 2517 $lines[]='<tr><td> </td><td></td>'.$this->helpCol('').'</tr>'; 2518 $lines[]='<tr class="bgColor5"><td colspan="2"><strong>Installation status:</strong></td>'.$this->helpCol('').'</tr>'; 2519 $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>'; 2520 $lines[]='<tr class="bgColor4"><td>Double installs?</td><td>'.$this->extInformationArray_dbInst($extInfo['doubleInstall'],$extInfo['type']).'</td>'.$this->helpCol('doubleInstall').'</tr>'; 2521 if (is_array($extInfo['files'])) { 2522 sort($extInfo['files']); 2523 $lines[]='<tr class="bgColor4"><td>Root files:</td><td>'.implode('<br />',$extInfo['files']).'</td>'.$this->helpCol('rootfiles').'</tr>'; 2524 } 2525 2526 if ($techInfo['tables']||$techInfo['static']||$techInfo['fields']) { 2527 if (!$remote && t3lib_extMgm::isLoaded($extKey)) { 2528 $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!':''). 2529 ($techInfo['static_error']?'<strong>Static table error!</strong><br />The static tables are missing or empty!':'')); 2530 } else { 2531 $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!'; 2532 } 2533 } 2534 2535 $lines[]='<tr class="bgColor4"><td>Database requirements:</td><td>'.$this->extInformationArray_dbReq($techInfo,1).'</td>'.$this->helpCol('dbReq').'</tr>'; 2536 $lines[]='<tr class="bgColor4"><td>Database status:</td><td>'.$tableStatus.'</td>'.$this->helpCol('dbStatus').'</tr>'; 2537 $lines[]='<tr class="bgColor4"><td>Flags:</td><td>'.(is_array($techInfo['flags'])?implode('<br />',$techInfo['flags']):'').'</td>'.$this->helpCol('flags').'</tr>'; 2538 $lines[]='<tr class="bgColor4"><td>Config template?</td><td>'.($techInfo['conf']?'Yes':'').'</td>'.$this->helpCol('conf').'</tr>'; 2539 $lines[]='<tr class="bgColor4"><td>TypoScript files:</td><td>'.(is_array($techInfo['TSfiles'])?implode('<br />',$techInfo['TSfiles']):'').'</td>'.$this->helpCol('TSfiles').'</tr>'; 2540 $lines[]='<tr class="bgColor4"><td>Language files:</td><td>'.(is_array($techInfo['locallang'])?implode('<br />',$techInfo['locallang']):'').'</td>'.$this->helpCol('locallang').'</tr>'; 2541 $lines[]='<tr class="bgColor4"><td>Upload folder:</td><td>'.($techInfo['uploadfolder']?$techInfo['uploadfolder']:'').'</td>'.$this->helpCol('uploadfolder').'</tr>'; 2542 $lines[]='<tr class="bgColor4"><td>Create directories:</td><td>'.(is_array($techInfo['createDirs'])?implode('<br />',$techInfo['createDirs']):'').'</td>'.$this->helpCol('createDirs').'</tr>'; 2543 $lines[]='<tr class="bgColor4"><td>Module names:</td><td>'.(is_array($techInfo['moduleNames'])?implode('<br />',$techInfo['moduleNames']):'').'</td>'.$this->helpCol('moduleNames').'</tr>'; 2544 $lines[]='<tr class="bgColor4"><td>Class names:</td><td>'.(is_array($techInfo['classes'])?implode('<br />',$techInfo['classes']):'').'</td>'.$this->helpCol('classNames').'</tr>'; 2545 $lines[]='<tr class="bgColor4"><td>Code warnings:<br />(developer-relevant)</td><td>'.(is_array($techInfo['errors'])?$GLOBALS['TBE_TEMPLATE']->rfw(implode('<br />',$techInfo['errors'])):'').'</td>'.$this->helpCol('errors').'</tr>'; 2546 $lines[]='<tr class="bgColor4"><td>Naming annoyances:<br />(developer-relevant)</td><td>'.(is_array($techInfo['NSerrors']) ? (!t3lib_div::inList($this->nameSpaceExceptions,$extKey)?t3lib_div::view_array($techInfo['NSerrors']):$GLOBALS['TBE_TEMPLATE']->dfw('[exception]')) : '').'</td>'.$this->helpCol('NSerrors').'</tr>'; 2547 2548 $currentMd5Array = $this->serverExtensionMD5Array($extKey,$extInfo); 2549 $affectedFiles=''; 2550 2551 $msgLines=array(); 2552 if (strcmp($extInfo['EM_CONF']['_md5_values_when_last_written'],serialize($currentMd5Array))) { 2553 $msgLines[] = $GLOBALS['TBE_TEMPLATE']->rfw('<br /><strong>A difference between the originally installed version and the current was detected!</strong>'); 2554 $affectedFiles = $this->findMD5ArrayDiff($currentMd5Array,unserialize($extInfo['EM_CONF']['_md5_values_when_last_written'])); 2555 if (count($affectedFiles)) $msgLines[] = '<br /><strong>Modified files:</strong><br />'.$GLOBALS['TBE_TEMPLATE']->rfw(implode('<br />',$affectedFiles)); 2556 } 2557 $lines[]='<tr class="bgColor4"><td>Files changed?</td><td>'.implode('<br />',$msgLines).'</td>'.$this->helpCol('filesChanged').'</tr>'; 2558 } 2559 2560 return '<table border="0" cellpadding="1" cellspacing="2"> 2561 '.implode(' 2562 ',$lines).' 2563 </table>'; 2564 } 2565 2566 /** 2567 * Returns HTML with information about database requirements 2568 * 2569 * @param array Technical information array 2570 * @param boolean Table header displayed 2571 * @return string HTML content. 2572 */ 2573 function extInformationArray_dbReq($techInfo,$tableHeader=0) { 2574 return nl2br(trim((is_array($techInfo['tables'])?($tableHeader?"\n\n<strong>Tables:</strong>\n":'').implode(chr(10),$techInfo['tables']):''). 2575 (is_array($techInfo['static'])?"\n\n<strong>Static tables:</strong>\n".implode(chr(10),$techInfo['static']):''). 2576 (is_array($techInfo['fields'])?"\n\n<strong>Additional fields:</strong>\n".implode('<hr />',$techInfo['fields']):''))); 2577 } 2578 2579 /** 2580 * Double install warning. 2581 * 2582 * @param string Double-install string, eg. "LG" etc. 2583 * @param string Current scope, eg. "L" or "G" or "S" 2584 * @return string Message 2585 */ 2586 function extInformationArray_dbInst($dbInst,$current) { 2587 if (strlen($dbInst)>1) { 2588 $others = array(); 2589 for($a=0;$a<strlen($dbInst);$a++) { 2590 if (substr($dbInst,$a,1)!=$current) { 2591 $others[]='"'.$this->typeLabels[substr($dbInst,$a,1)].'"'; 2592 } 2593 } 2594 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.'); 2595 } else return ''; 2596 } 2597 2598 /** 2599 * Prints the upload form for extensions 2600 * 2601 * @param string Extension key 2602 * @param array Extension information array 2603 * @return string HTML content. 2604 */ 2605 function getRepositoryUploadForm($extKey,$extInfo) { 2606 $content.=' 2607 <input type="hidden" name="CMD[showExt]" value="'.$extKey.'" /> 2608 <input type="hidden" name="em[action]" value="doUpload" /> 2609 <table border="0" cellpadding="2" cellspacing="1"> 2610 <tr class="bgColor4"> 2611 <td>Repository Username:</td> 2612 <td><input'.$this->doc->formWidth(20).' type="text" name="em[user][fe_u]" value="'.$this->fe_user['username'].'" /></td> 2613 </tr> 2614 <tr class="bgColor4"> 2615 <td>Repository Password:</td> 2616 <td><input'.$this->doc->formWidth(20).' type="password" name="em[user][fe_p]" value="'.$this->fe_user['password'].'" /></td> 2617 </tr> 2618 <tr class="bgColor4"> 2619 <td>Changelog for upload:</td> 2620 <td><textarea'.$this->doc->formWidth(30,1).' rows="5" name="em[upload][comment]"></textarea></td> 2621 </tr> 2622 <tr class="bgColor4"> 2623 <td>Upload command:</td> 2624 <td nowrap="nowrap"> 2625 <input type="radio" name="em[upload][mode]" id="new_dev" value="new_dev" checked="checked" /> <label for="new_dev">New development version (latest x.x.<strong>'.$GLOBALS['TBE_TEMPLATE']->rfw('x+1').'</strong>)</label><br /> 2626 <input type="radio" name="em[upload][mode]" id="latest" value="latest" /> <label for="latest">Override <em>this</em> development version ('.$extInfo['EM_CONF']['version'].')</label><br /> 2627 <input type="radio" name="em[upload][mode]" id="new_sub" value="new_sub" /> <label for="new_sub">New sub version (latest x.<strong>'.$GLOBALS['TBE_TEMPLATE']->rfw('x+1').'</strong>.0)</label><br /> 2628 <input type="radio" name="em[upload][mode]" id="new_main" value="new_main" /> <label for="new_main">New main version (latest <strong>'.$GLOBALS['TBE_TEMPLATE']->rfw('x+1').'</strong>.0.0)</label><br /> 2629 <input type="radio" name="em[upload][mode]" id="custom" value="custom" /> <label for="custom">This version: <input type="text" name="em[upload][version]" /></label><br /> 2630 </td> 2631 </tr> 2632 <tr class="bgColor4"> 2633 <td> </td> 2634 <td><input type="submit" name="submit" value="Upload extension" /> 2635 </td> 2636 </tr> 2637 </table> 2638 '; 2639 2640 return $content; 2641 } 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 /*********************************** 2653 * 2654 * Extension list rendering 2655 * 2656 **********************************/ 2657 2658 /** 2659 * Prints the header row for the various listings 2660 * 2661 * @param string Attributes for the <tr> tag 2662 * @param array Preset cells in the beginning of the row. Typically a blank cell with a clear-gif 2663 * @param boolean If set, the list is coming from remote server. 2664 * @return string HTML <tr> table row 2665 */ 2666 function extensionListRowHeader($trAttrib,$cells,$import=0) { 2667 $cells[] = '<td></td>'; 2668 $cells[] = '<td>Title:</td>'; 2669 2670 if (!$this->MOD_SETTINGS['display_details']) { 2671 $cells[] = '<td>Description:</td>'; 2672 $cells[] = '<td>Author:</td>'; 2673 } elseif ($this->MOD_SETTINGS['display_details']==2) { 2674 $cells[] = '<td>Priority:</td>'; 2675 $cells[] = '<td>Mod.Tables:</td>'; 2676 $cells[] = '<td>Modules:</td>'; 2677 $cells[] = '<td>Cl.Cache?</td>'; 2678 $cells[] = '<td>Internal?</td>'; 2679 $cells[] = '<td>Shy?</td>'; 2680 } elseif ($this->MOD_SETTINGS['display_details']==3) { 2681 $cells[] = '<td>Tables/Fields:</td>'; 2682 $cells[] = '<td>TS-files:</td>'; 2683 $cells[] = '<td>Affects:</td>'; 2684 $cells[] = '<td>Modules:</td>'; 2685 $cells[] = '<td>Config?</td>'; 2686 $cells[] = '<td>Code warnings:</td>'; 2687 } elseif ($this->MOD_SETTINGS['display_details']==4) { 2688 $cells[] = '<td>locallang:</td>'; 2689 $cells[] = '<td>Classes:</td>'; 2690 $cells[] = '<td>Code warnings:</td>'; 2691 $cells[] = '<td>Nameing annoyances:</td>'; 2692 } elseif ($this->MOD_SETTINGS['display_details']==5) { 2693 $cells[] = '<td>Changed files:</td>'; 2694 } else { 2695 $cells[] = '<td>Extension key:</td>'; 2696 $cells[] = '<td>Version:</td>'; 2697 if (!$import) { 2698 $cells[] = '<td>DL:</td>'; 2699 $cells[] = '<td>Doc:</td>'; 2700 $cells[] = '<td>Type:</td>'; 2701 } else { 2702 $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>'; 2703 $cells[] = '<td class="bgColor6"'.$this->labelInfo('Current type of installation of the extension on this server.').'>Cur. Type:</td>'; 2704 $cells[] = '<td'.$this->labelInfo('Number of downloads, all versions/this version').'>DL:</td>'; 2705 } 2706 $cells[] = '<td>State:</td>'; 2707 } 2708 return ' 2709 <tr'.$trAttrib.'> 2710 '.implode(' 2711 ',$cells).' 2712 </tr>'; 2713 } 2714 2715 /** 2716 * Prints a row with data for the various extension listings 2717 * 2718 * @param string Extension key 2719 * @param array Extension information array 2720 * @param array Preset table cells, eg. install/uninstall icons. 2721 * @param string <tr> tag class 2722 * @param array Array with installed extension keys (as keys) 2723 * @param boolean If set, the list is coming from remote server. 2724 * @param string Alternative link URL 2725 * @return string HTML <tr> content 2726 */ 2727 function extensionListRow($extKey,$extInfo,$cells,$bgColorClass='',$inst_list=array(),$import=0,$altLinkUrl='') { 2728 2729 // Icon: 2730 $imgInfo = @getImageSize($this->getExtPath($extKey,$extInfo['type']).'/ext_icon.gif'); 2731 if (is_array($imgInfo)) { 2732 $cells[] = '<td><img src="'.$GLOBALS['BACK_PATH'].$this->typeRelPaths[$extInfo['type']].$extKey.'/ext_icon.gif'.'" '.$imgInfo[3].' alt="" /></td>'; 2733 } elseif ($extInfo['_ICON']) { 2734 $cells[] = '<td>'.$extInfo['_ICON'].'</td>'; 2735 } else { 2736 $cells[] = '<td><img src="clear.gif" width="1" height="1" alt="" /></td>'; 2737 } 2738 2739 // Extension title: 2740 $cells[] = '<td nowrap="nowrap"><a href="'.htmlspecialchars($altLinkUrl?$altLinkUrl:'index.php?CMD[showExt]='.$extKey.'&SET[singleDetails]=info').'" title="'.$extKey.'"'/*.($extInfo['EM_CONF']['shy'] ? ' style="color:#666;" ' : '')*/.'>'.t3lib_div::fixed_lgd($extInfo['EM_CONF']['title']?$extInfo['EM_CONF']['title']:'<em>'.$extKey.'</em>',40).'</a></td>'; 2741 2742 // Based on which display mode you will see more or less details: 2743 if (!$this->MOD_SETTINGS['display_details']) { 2744 $cells[] = '<td>'.htmlspecialchars(t3lib_div::fixed_lgd($extInfo['EM_CONF']['description'],400)).'<br /><img src="clear.gif" width="300" height="1" alt="" /></td>'; 2745 $cells[] = '<td nowrap="nowrap">'.($extInfo['EM_CONF']['author_email'] ? '<a href="mailto:'.htmlspecialchars($extInfo['EM_CONF']['author_email']).'">' : '').htmlspecialchars($extInfo['EM_CONF']['author']).($extInfo['EM_CONF']['author_email'] ? '</a>' : '').($extInfo['EM_CONF']['author_company'] ? '<br />'.htmlspecialchars($extInfo['EM_CONF']['author_company']) : '').'</td>'; 2746 } elseif ($this->MOD_SETTINGS['display_details']==2) { 2747 $cells[] = '<td nowrap="nowrap">'.$extInfo['EM_CONF']['priority'].'</td>'; 2748 $cells[] = '<td nowrap="nowrap">'.implode('<br />',t3lib_div::trimExplode(',',$extInfo['EM_CONF']['modify_tables'],1)).'</td>'; 2749 $cells[] = '<td nowrap="nowrap">'.$extInfo['EM_CONF']['module'].'</td>'; 2750 $cells[] = '<td nowrap="nowrap">'.($extInfo['EM_CONF']['clearCacheOnLoad'] ? 'Yes' : '').'</td>'; 2751 $cells[] = '<td nowrap="nowrap">'.($extInfo['EM_CONF']['internal'] ? 'Yes' : '').'</td>'; 2752 $cells[] = '<td nowrap="nowrap">'.($extInfo['EM_CONF']['shy'] ? 'Yes' : '').'</td>'; 2753 } elseif ($this->MOD_SETTINGS['display_details']==3) { 2754 $techInfo = $this->makeDetailedExtensionAnalysis($extKey,$extInfo); 2755 2756 $cells[] = '<td>'.$this->extInformationArray_dbReq($techInfo). 2757 '</td>'; 2758 $cells[] = '<td nowrap="nowrap">'.(is_array($techInfo['TSfiles']) ? implode('<br />',$techInfo['TSfiles']) : '').'</td>'; 2759 $cells[] = '<td nowrap="nowrap">'.(is_array($techInfo['flags']) ? implode('<br />',$techInfo['flags']) : '').'</td>'; 2760 $cells[] = '<td nowrap="nowrap">'.(is_array($techInfo['moduleNames']) ? implode('<br />',$techInfo['moduleNames']) : '').'</td>'; 2761 $cells[] = '<td nowrap="nowrap">'.($techInfo['conf'] ? 'Yes' : '').'</td>'; 2762 $cells[] = '<td>'. 2763 $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!':''). 2764 (t3lib_extMgm::isLoaded($extKey)&&$techInfo['static_error']?'<strong>Static table error!</strong><br />The static tables are missing or empty!':'')). 2765 '</td>'; 2766 } elseif ($this->MOD_SETTINGS['display_details']==4) { 2767 $techInfo=$this->makeDetailedExtensionAnalysis($extKey,$extInfo,1); 2768 2769 $cells[] = '<td>'.(is_array($techInfo['locallang']) ? implode('<br />',$techInfo['locallang']) : '').'</td>'; 2770 $cells[] = '<td>'.(is_array($techInfo['classes']) ? implode('<br />',$techInfo['classes']) : '').'</td>'; 2771 $cells[] = '<td>'.(is_array($techInfo['errors']) ? $GLOBALS['TBE_TEMPLATE']->rfw(implode('<hr />',$techInfo['errors'])) : '').'</td>'; 2772 $cells[] = '<td>'.(is_array($techInfo['NSerrors']) ? (!t3lib_div::inList($this->nameSpaceExceptions,$extKey) ? t3lib_div::view_array($techInfo['NSerrors']) : $GLOBALS['TBE_TEMPLATE']->dfw('[exception]')) :'').'</td>'; 2773 } elseif ($this->MOD_SETTINGS['display_details']==5) { 2774 $currentMd5Array = $this->serverExtensionMD5Array($extKey,$extInfo); 2775 $affectedFiles = ''; 2776 $msgLines = array(); 2777 $msgLines[] = 'Files: '.count($currentMd5Array); 2778 if (strcmp($extInfo['EM_CONF']['_md5_values_when_last_written'],serialize($currentMd5Array))) { 2779 $msgLines[] = $GLOBALS['TBE_TEMPLATE']->rfw('<br /><strong>A difference between the originally installed version and the current was detected!</strong>'); 2780 $affectedFiles = $this->findMD5ArrayDiff($currentMd5Array,unserialize($extInfo['EM_CONF']['_md5_values_when_last_written'])); 2781 if (count($affectedFiles)) $msgLines[] = '<br /><strong>Modified files:</strong><br />'.$GLOBALS['TBE_TEMPLATE']->rfw(implode('<br />',$affectedFiles)); 2782 } 2783 $cells[] = '<td>'.implode('<br />',$msgLines).'</td>'; 2784 } else { 2785 // Default view: 2786 $verDiff = $inst_list[$extKey] && $this->versionDifference($extInfo['EM_CONF']['version'],$inst_list[$extKey]['EM_CONF']['version'],$this->versionDiffFactor); 2787 2788 $cells[] = '<td nowrap="nowrap"><em>'.$extKey.'</em></td>'; 2789 $cells[] = '<td nowrap="nowrap">'.($verDiff ? '<strong>'.$GLOBALS['TBE_TEMPLATE']->rfw(htmlspecialchars($extInfo['EM_CONF']['version'])).'</strong>' : $extInfo['EM_CONF']['version']).'</td>'; 2790 if (!$import) { // Listing extenson on LOCAL server: 2791 // Extension Download: 2792 $cells[] = '<td nowrap="nowrap"><a href="'.htmlspecialchars('index.php?CMD[doBackup]=1&SET[singleDetails]=backup&CMD[showExt]='.$extKey).'"><img src="download.png" width="13" height="12" title="Download" alt="" /></a></td>'; 2793 2794 // Manual download 2795 $fileP = PATH_site.$this->typePaths[$extInfo['type']].$extKey.'/doc/manual.sxw'; 2796 $cells[] = '<td nowrap="nowrap">'. 2797 ($this->typePaths[$extInfo['type']] && @is_file($fileP)?'<a href="'.htmlspecialchars(t3lib_div::resolveBackPath($this->doc->backPath.'../'.$this->typePaths[$extInfo['type']].$extKey.'/doc/manual.sxw')).'" target="_blank"><img src="oodoc.gif" width="13" height="16" title="Local Open Office Manual" alt="" /></a>':''). 2798 '</td>'; 2799 $cells[] = '<td nowrap="nowrap">'.$this->typeLabels[$extInfo['type']].(strlen($extInfo['doubleInstall'])>1?'<strong> '.$GLOBALS['TBE_TEMPLATE']->rfw($extInfo['doubleInstall']).'</strong>':'').'</td>'; 2800 } else { // Listing extensions from REMOTE repository: 2801 $inst_curVer = $inst_list[$extKey]['EM_CONF']['version']; 2802 if (isset($inst_list[$extKey])) { 2803 if ($verDiff) $inst_curVer = '<strong>'.$GLOBALS['TBE_TEMPLATE']->rfw($inst_curVer).'</strong>'; 2804 } 2805 $cells[] = '<td nowrap="nowrap">'.$inst_curVer.'</td>'; 2806 $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>'; 2807 $cells[] = '<td nowrap="nowrap">'.($extInfo['downloadcounter_all']?$extInfo['downloadcounter_all']:' ').'/'.($extInfo['downloadcounter']?$extInfo['downloadcounter']:' ').'</td>'; 2808 } 2809 $cells[] = '<td nowrap="nowrap" class="extstate" style="background-color:'.$this->stateColors[$extInfo['EM_CONF']['state']].';">'.$this->states[$extInfo['EM_CONF']['state']].'</td>'; 2810 } 2811 2812 if($this->xmlhandler->getReviewState($extKey,$extInfo['EM_CONF']['version'])<1) { 2813 $bgclass = ' class="unsupported-ext"'; 2814 } else { 2815 $bgclass = ' class="'.($bgColorClass?$bgColorClass:'bgColor4').'"'; 2816 } 2817 2818 return ' 2819 <tr'.$bgclass.'> 2820 '.implode(' 2821 ',$cells).' 2822 </tr>'; 2823 } 2824 2825 2826 2827 2828 2829 2830 /************************************ 2831 * 2832 * Output helper functions 2833 * 2834 ************************************/ 2835 2836 /** 2837 * Wrapping input string in a link tag with link to email address 2838 * 2839 * @param string Input string, being wrapped in <a> tags 2840 * @param string Email address for use in link. 2841 * @return string Output 2842 */ 2843 function wrapEmail($str,$email) { 2844 if ($email) { 2845 $str = '<a href="mailto:'.htmlspecialchars($email).'">'.htmlspecialchars($str).'</a>'; 2846 } 2847 return $str; 2848 } 2849 2850 /** 2851 * Returns help text if applicable. 2852 * 2853 * @param string Help text key 2854 * @return string HTML table cell 2855 */ 2856 function helpCol($key) { 2857 global $BE_USER; 2858 if ($BE_USER->uc['edit_showFieldHelp']) { 2859 $hT = trim(t3lib_BEfunc::helpText($this->descrTable,'emconf_'.$key,$this->doc->backPath)); 2860 return '<td>'.($hT?$hT:t3lib_BEfunc::helpTextIcon($this->descrTable,'emconf_'.$key,$this->doc->backPath)).'</td>'; 2861 } else { 2862 return ''; 2863 } 2864 } 2865 2866 /** 2867 * Returns title and style attribute for mouseover help text. 2868 * 2869 * @param string Help text. 2870 * @return string title="" attribute prepended with a single space 2871 */ 2872 function labelInfo($str) { 2873 return ' title="'.htmlspecialchars($str).'" style="cursor:help;"'; 2874 } 2875 2876 /** 2877 * Returns a header for an extensions including icon if any 2878 * 2879 * @param string Extension key 2880 * @param array Extension information array 2881 * @param string align-attribute value (for <img> tag) 2882 * @return string HTML; Extension title and image. 2883 */ 2884 function extensionTitleIconHeader($extKey,$extInfo,$align='top') { 2885 $imgInfo = @getImageSize($this->getExtPath($extKey,$extInfo['type']).'/ext_icon.gif'); 2886 $out = ''; 2887 if (is_array($imgInfo)) { 2888 $out.= '<img src="'.$GLOBALS['BACK_PATH'].$this->typeRelPaths[$extInfo['type']].$extKey.'/ext_icon.gif" '.$imgInfo[3].' align="'.$align.'" alt="" />'; 2889 } 2890 $out.= $extInfo['EM_CONF']['title'] ? htmlspecialchars(t3lib_div::fixed_lgd($extInfo['EM_CONF']['title'],40)) : '<em>'.$extKey.'</em>'; 2891 return $out; 2892 } 2893 2894 /** 2895 * Returns image tag for "uninstall" 2896 * 2897 * @return string <img> tag 2898 */ 2899 function removeButton() { 2900 return '<img src="uninstall.gif" width="16" height="16" title="Remove extension" align="top" alt="" />'; 2901 } 2902 2903 /** 2904 * Returns image for "install" 2905 * 2906 * @return string <img> tag 2907 */ 2908 function installButton() { 2909 return '<img src="install.gif" width="16" height="16" title="Install extension..." align="top" alt="" />'; 2910 } 2911 2912 /** 2913 * Warning (<img> + text string) message about the impossibility to import extensions (both local and global locations are disabled...) 2914 * 2915 * @return string <img> + text string. 2916 */ 2917 function noImportMsg() { 2918 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>'; 2919 } 2920 2921 /** 2922 * Checks whether the passed dependency is TER2-style (array) and returns a single string for displaying the dependencies. 2923 * 2924 * It leaves out all version numbers and the "php" and "typo3" dependencies, as they are implicit and of no interest without the version number. 2925 * 2926 * @param mixed $dep Either a string or an array listing dependencies. 2927 * @param string $type The dependency type to list if $dep is an array 2928 * @return string A simple dependency list for display 2929 */ 2930 function depToString($dep,$type='depends') { 2931 if(is_array($dep)) { 2932 unset($dep[$type]['php']); 2933 unset($dep[$type]['typo3']); 2934 $s = (count($dep[$type])) ? implode(',', array_keys($dep[$type])) : ''; 2935 return $s; 2936 } 2937 return ''; 2938 } 2939 2940 /** 2941 * Checks whether the passed dependency is TER-style (string) or TER2-style (array) and returns a single string for displaying the dependencies. 2942 * 2943 * It leaves out all version numbers and the "php" and "typo3" dependencies, as they are implicit and of no interest without the version number. 2944 * 2945 * @param mixed $dep Either a string or an array listing dependencies. 2946 * @param string $type The dependency type to list if $dep is an array 2947 * @return string A simple dependency list for display 2948 */ 2949 function stringToDep($dep) { 2950 $constraint = array(); 2951 if(is_string($dep) && strlen($dep)) { 2952 $dep = explode(',',$dep); 2953 foreach($dep as $v) { 2954 $constraint[$v] = ''; 2955 } 2956 } 2957 return $constraint; 2958 } 2959 2960 2961 2962 2963 2964 2965 2966 2967 /******************************** 2968 * 2969 * Read information about all available extensions 2970 * 2971 *******************************/ 2972 2973 /** 2974 * Returns the list of available (installed) extensions 2975 * 2976 * @return array Array with two arrays, list array (all extensions with info) and category index 2977 * @see getInstExtList() 2978 */ 2979 function getInstalledExtensions() { 2980 $list = array(); 2981 $cat = $this->defaultCategories; 2982 2983 $path = PATH_typo3.'sysext/'; 2984 $this->getInstExtList($path,$list,$cat,'S'); 2985 2986 $path = PATH_typo3.'ext/'; 2987 $this->getInstExtList($path,$list,$cat,'G'); 2988 2989 $path = PATH_typo3conf.'ext/'; 2990 $this->getInstExtList($path,$list,$cat,'L'); 2991 2992 return array($list,$cat); 2993 } 2994 2995 /** 2996 * Gathers all extensions in $path 2997 * 2998 * @param string Absolute path to local, global or system extensions 2999 * @param array Array with information for each extension key found. Notice: passed by reference 3000 * @param array Categories index: Contains extension titles grouped by various criteria. 3001 * @param string Path-type: L, G or S 3002 * @return void "Returns" content by reference 3003 * @access private 3004 * @see getInstalledExtensions() 3005 */ 3006 function getInstExtList($path,&$list,&$cat,$type) { 3007 3008 if (@is_dir($path)) { 3009 $extList = t3lib_div::get_dirs($path); 3010 if (is_array($extList)) { 3011 foreach($extList as $extKey) { 3012 if (@is_file($path.$extKey.'/ext_emconf.php')) { 3013 $emConf = $this->includeEMCONF($path.$extKey.'/ext_emconf.php', $extKey); 3014 if (is_array($emConf)) { 3015 if (is_array($list[$extKey])) { 3016 $list[$extKey]=array('doubleInstall'=>$list[$extKey]['doubleInstall']); 3017 } 3018 $list[$extKey]['doubleInstall'].= $type; 3019 $list[$extKey]['type'] = $type; 3020 $list[$extKey]['EM_CONF'] = $emConf; 3021 $list[$extKey]['files'] = t3lib_div::getFilesInDir($path.$extKey, '', 0, '', $this->excludeForPackaging); 3022 3023 $this->setCat($cat,$list[$extKey], $extKey); 3024 } 3025 } 3026 } 3027 } 3028 } 3029 } 3030 3031 /** 3032 * Fixes an old style ext_emconf.php array by adding constraints if needed and removing deprecated keys 3033 * 3034 * @param array $emConf 3035 * @return array 3036 */ 3037 function fixEMCONF($emConf) { 3038 if(!isset($emConf['constraints']) || !isset($emConf['constraints']['depends']) || !isset($emConf['constraints']['conflicts']) || !isset($emConf['constraints']['suggests'])) { 3039 if(!isset($emConf['constraints']) || !isset($emConf['constraints']['depends'])) { 3040 $emConf['constraints']['depends'] = $this->stringToDep($emConf['dependencies']); 3041 if(strlen($emConf['PHP_version'])) { 3042 $versionRange = $this->splitVersionRange($emConf['PHP_version']); 3043 if (version_compare($versionRange[0],'3.0.0','<')) $versionRange[0] = '3.0.0'; 3044 if (version_compare($versionRange[1],'3.0.0','<')) $versionRange[1] = '0.0.0'; 3045 $emConf['constraints']['depends']['php'] = implode('-',$versionRange); 3046 } 3047 if(strlen($emConf['TYPO3_version'])) { 3048 $versionRange = $this->splitVersionRange($emConf['TYPO3_version']); 3049 if (version_compare($versionRange[0],'3.5.0','<')) $versionRange[0] = '3.5.0'; 3050 if (version_compare($versionRange[1],'3.5.0','<')) $versionRange[1] = '0.0.0'; 3051 $emConf['constraints']['depends']['typo3'] = implode('-',$versionRange); 3052 } 3053 } 3054 if(!isset($emConf['constraints']) || !isset($emConf['constraints']['conflicts'])) { 3055 $emConf['constraints']['conflicts'] = $this->stringToDep($emConf['conflicts']); 3056 } 3057 if(!isset($emConf['constraints']) || !isset($emConf['constraints']['suggests'])) { 3058 $emConf['constraints']['suggests'] = array(); 3059 } 3060 } elseif (isset($emConf['constraints']) && isset($emConf['dependencies'])) { 3061 $emConf['suggests'] = isset($emConf['suggests']) ? $emConf['suggests'] : array(); 3062 $emConf['dependencies'] = $this->depToString($emConf['constraints']); 3063 $emConf['conflicts'] = $this->depToString($emConf['constraints'], 'conflicts'); 3064 } 3065 3066 // sanity check for version numbers, intentionally only checks php and typo3 3067 if(isset($emConf['constraints']['depends']) && isset($emConf['constraints']['depends']['php'])) { 3068 $versionRange = $this->splitVersionRange($emConf['constraints']['depends']['php']); 3069 if (version_compare($versionRange[0],'3.0.0','<')) $versionRange[0] = '3.0.0'; 3070 if (version_compare($versionRange[1],'3.0.0','<')) $versionRange[1] = '0.0.0'; 3071 $emConf['constraints']['depends']['php'] = implode('-',$versionRange); 3072 } 3073 if(isset($emConf['constraints']['depends']) && isset($emConf['constraints']['depends']['typo3'])) { 3074 $versionRange = $this->splitVersionRange($emConf['constraints']['depends']['typo3']); 3075 if (version_compare($versionRange[0],'3.5.0','<')) $versionRange[0] = '3.5.0'; 3076 if (version_compare($versionRange[1],'3.5.0','<')) $versionRange[1] = '0.0.0'; 3077 $emConf['constraints']['depends']['typo3'] = implode('-',$versionRange); 3078 } 3079 3080 unset($emConf['private']); 3081 unset($emConf['download_password']); 3082 unset($emConf['TYPO3_version']); 3083 unset($emConf['PHP_version']); 3084 3085 return $emConf; 3086 } 3087 3088 /** 3089 * Splits a version range into an array. 3090 * 3091 * If a single version number is given, it is considered a minimum value. 3092 * If a dash is found, the numbers left and right are considered as minimum and maximum. Empty values are allowed. 3093 * 3094 * @param string $ver A string with a version range. 3095 * @return array 3096 */ 3097 function splitVersionRange($ver) { 3098 $versionRange = array(); 3099 if (strstr($ver, '-')) { 3100 $versionRange = explode('-', $ver, 2); 3101 } else { 3102 $versionRange[0] = $ver; 3103 $versionRange[1] = ''; 3104 } 3105 3106 if (!$versionRange[0]) { $versionRange[0] = '0.0.0'; } 3107 if (!$versionRange[1]) { $versionRange[1] = '0.0.0'; } 3108 3109 return $versionRange; 3110 } 3111 3112 /** 3113 * Maps remote extensions information into $cat/$list arrays for listing 3114 * 3115 * @param boolean If set the info in the internal extensionsXML array will be unset before returning the result. 3116 * @return array List array and category index as key 0 / 1 in an array. 3117 */ 3118 function prepareImportExtList($unsetProc = false) { 3119 $list = array(); 3120 $cat = $this->defaultCategories; 3121 $filepath = $this->getMirrorURL(); 3122 3123 reset($this->xmlhandler->extensionsXML); 3124 while (list($extKey, $data) = each($this->xmlhandler->extensionsXML)) { 3125 $GLOBALS['LANG']->csConvObj->convArray($data,'utf-8',$GLOBALS['LANG']->charSet); // is there a better place for conversion? 3126 $list[$extKey]['type'] = '_'; 3127 $version = array_keys($data['versions']); 3128 $list[$extKey]['_ICON'] = '<img alt="" src="'.$filepath.$extKey{0}.'/'.$extKey{1}.'/'.$extKey.'_'.end($version).'.gif" />'; 3129 $list[$extKey]['downloadcounter'] = $data['downloadcounter']; 3130 3131 foreach(array_keys($data['versions']) as $version) { 3132 $list[$extKey]['versions'][$version]['downloadcounter'] = $data['versions'][$version]['downloadcounter']; 3133 3134 $list[$extKey]['versions'][$version]['EM_CONF'] = array( 3135 'version' => $version, 3136 'title' => $data['versions'][$version]['title'], 3137 'description' => $data['versions'][$version]['description'], 3138 'category' => $data['versions'][$version]['category'], 3139 'constraints' => $data['versions'][$version]['dependencies'], 3140 'state' => $data['versions'][$version]['state'], 3141 'reviewstate' => $data['versions'][$version]['reviewstate'], 3142 'lastuploaddate' => $data['versions'][$version]['lastuploaddate'], 3143 'author' => $data['versions'][$version]['authorname'], 3144 'author_email' => $data['versions'][$version]['authoremail'], 3145 'author_company' => $data['versions'][$version]['authorcompany'], 3146 ); 3147 } 3148 $this->setCat($cat, $list[$extKey]['versions'][$version], $extKey); 3149 if ($unsetProc) { 3150 unset($this->xmlhandler->extensionsXML[$extKey]); 3151 } 3152 } 3153 3154 return array($list,$cat); 3155 } 3156 3157 /** 3158 * Set category array entries for extension 3159 * 3160 * @param array Category index array 3161 * @param array Part of list array for extension. 3162 * @param string Extension key 3163 * @return array Modified category index array 3164 */ 3165 function setCat(&$cat,$listArrayPart,$extKey) { 3166 3167 // Getting extension title: 3168 $extTitle = $listArrayPart['EM_CONF']['title']; 3169 3170 // Category index: 3171 $index = $listArrayPart['EM_CONF']['category']; 3172 $cat['cat'][$index][$extKey] = $extTitle; 3173 3174 // Author index: 3175 $index = $listArrayPart['EM_CONF']['author'].($listArrayPart['EM_CONF']['author_company']?', '.$listArrayPart['EM_CONF']['author_company']:''); 3176 $cat['author_company'][$index][$extKey] = $extTitle; 3177 3178 // State index: 3179 $index = $listArrayPart['EM_CONF']['state']; 3180 $cat['state'][$index][$extKey] = $extTitle; 3181 3182 // Type index: 3183 $index = $listArrayPart['type']; 3184 $cat['type'][$index][$extKey] = $extTitle; 3185 3186 // Return categories: 3187 return $cat; 3188 } 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 /******************************* 3200 * 3201 * Extension analyzing (detailed information) 3202 * 3203 ******************************/ 3204 3205 /** 3206 * Perform a detailed, technical analysis of the available extension on server! 3207 * Includes all kinds of verifications 3208 * Takes some time to process, therfore use with care, in particular in listings. 3209 * 3210 * @param string Extension key 3211 * @param array Extension information 3212 * @param boolean If set, checks for validity of classes etc. 3213 * @return array Information in an array. 3214 */ 3215 function makeDetailedExtensionAnalysis($extKey,$extInfo,$validity=0) { 3216 3217 // Get absolute path of the extension 3218 $absPath = $this->getExtPath($extKey,$extInfo['type']); 3219 3220 $infoArray = array(); 3221 3222 $table_class_prefix = substr($extKey,0,5)=='user_' ? 'user_' : 'tx_'.str_replace('_','',$extKey).'_'; 3223 $module_prefix = substr($extKey,0,5)=='user_' ? 'u' : 'tx'.str_replace('_','',$extKey); 3224 3225 // Database status: 3226 $dbInfo = $this->checkDBupdates($extKey,$extInfo,1); 3227 3228 // Database structure required: 3229 if (is_array($dbInfo['structure']['tables_fields'])) { 3230 $modify_tables = t3lib_div::trimExplode(',',$extInfo['EM_CONF']['modify_tables'],1); 3231 $infoArray['dump_tf'] = array(); 3232 3233 foreach($dbInfo['structure']['tables_fields'] as $tN => $d) { 3234 if (in_array($tN,$modify_tables)) { 3235 $infoArray['fields'][] = $tN.': <i>'. 3236 (is_array($d['fields']) ? implode(', ',array_keys($d['fields'])) : ''). 3237 (is_array($d['keys']) ? ' + '.count($d['keys']).' keys' : ''). 3238 '</i>'; 3239 if (is_array($d['fields'])) { 3240 reset($d['fields']); 3241 while(list($fN) = each($d['fields'])) { 3242 $infoArray['dump_tf'][] = $tN.'.'.$fN; 3243 if (!t3lib_div::isFirstPartOfStr($fN,$table_class_prefix)) { 3244 $infoArray['NSerrors']['fields'][$fN] = $fN; 3245 } else { 3246 $infoArray['NSok']['fields'][$fN] = $fN; 3247 } 3248 } 3249 } 3250 if (is_array($d['keys'])) { 3251 reset($d['keys']); 3252 while(list($fN)=each($d['keys'])) { 3253 $infoArray['dump_tf'][] = $tN.'.KEY:'.$fN; 3254 } 3255 } 3256 } else { 3257 $infoArray['dump_tf'][] = $tN; 3258 $infoArray['tables'][] = $tN; 3259 if (!t3lib_div::isFirstPartOfStr($tN,$table_class_prefix)) { 3260 $infoArray['NSerrors']['tables'][$tN] = $tN; 3261 } else $infoArray['NSok']['tables'][$tN] = $tN; 3262 } 3263 } 3264 if (count($dbInfo['structure']['diff']['diff']) || count($dbInfo['structure']['diff']['extra'])) { 3265 $msg = array(); 3266 if (count($dbInfo['structure']['diff']['diff'])) $msg[] = 'missing'; 3267 if (count($dbInfo['structure']['diff']['extra'])) $msg[] = 'of wrong type'; 3268 $infoArray['tables_error'] = 1; 3269 if (t3lib_extMgm::isLoaded($extKey)) $infoArray['errors'][] = 'Some tables or fields are '.implode(' and ',$msg).'!'; 3270 } 3271 } 3272 3273 // Static tables? 3274 if (is_array($dbInfo['static'])) { 3275 $infoArray['static'] = array_keys($dbInfo['static']); 3276 3277 foreach($dbInfo['static'] as $tN => $d) { 3278 if (!$d['exists']) { 3279 $infoArray['static_error'] = 1; 3280 if (t3lib_extMgm::isLoaded($extKey)) $infoArray['errors'][] = 'Static table(s) missing!'; 3281 if (!t3lib_div::isFirstPartOfStr($tN,$table_class_prefix)) { 3282 $infoArray['NSerrors']['tables'][$tN] = $tN; 3283 } else $infoArray['NSok']['tables'][$tN] = $tN; 3284 } 3285 } 3286 } 3287 3288 // Backend Module-check: 3289 $knownModuleList = t3lib_div::trimExplode(',',$extInfo['EM_CONF']['module'],1); 3290 foreach($knownModuleList as $mod) { 3291 if (@is_dir($absPath.$mod)) { 3292 if (@is_file($absPath.$mod.'/conf.php')) { 3293 $confFileInfo = $this->modConfFileAnalysis($absPath.$mod.'/conf.php'); 3294 if (is_array($confFileInfo['TYPO3_MOD_PATH'])) { 3295 $shouldBePath = $this->typeRelPaths[$extInfo['type']].$extKey.'/'.$mod.'/'; 3296 if (strcmp($confFileInfo['TYPO3_MOD_PATH'][1][1],$shouldBePath)) { 3297 $infoArray['errors'][] = 'Configured TYPO3_MOD_PATH "'.$confFileInfo['TYPO3_MOD_PATH'][1][1].'" different from "'.$shouldBePath.'"'; 3298 } 3299 } else $infoArray['errors'][] = 'No definition of TYPO3_MOD_PATH constant found inside!'; 3300 if (is_array($confFileInfo['MCONF_name'])) { 3301 $mName = $confFileInfo['MCONF_name'][1][1]; 3302 $mNameParts = explode('_',$mName); 3303 $infoArray['moduleNames'][] = $mName; 3304 if (!t3lib_div::isFirstPartOfStr($mNameParts[0],$module_prefix) && 3305 (!$mNameParts[1] || !t3lib_div::isFirstPartOfStr($mNameParts[1],$module_prefix))) { 3306 $infoArray['NSerrors']['modname'][] = $mName; 3307 } else $infoArray['NSok']['modname'][] = $mName; 3308 } else $infoArray['errors'][] = 'No definition of MCONF[name] variable found inside!'; 3309 } else $infoArray['errors'][] = 'Backend module conf file "'.$mod.'/conf.php" should exist but does not!'; 3310 } else $infoArray['errors'][] = 'Backend module folder "'.$mod.'/" should exist but does not!'; 3311 } 3312 $dirs = t3lib_div::get_dirs($absPath); 3313 if (is_array($dirs)) { 3314 reset($dirs); 3315 while(list(,$mod) = each($dirs)) { 3316 if (!in_array($mod,$knownModuleList) && @is_file($absPath.$mod.'/conf.php')) { 3317 $confFileInfo = $this->modConfFileAnalysis($absPath.$mod.'/conf.php'); 3318 if (is_array($confFileInfo)) { 3319 $infoArray['errors'][] = 'It seems like there is a backend module in "'.$mod.'/conf.php" which is not configured in ext_emconf.php'; 3320 } 3321 } 3322 } 3323 } 3324 3325 // ext_tables.php: 3326 if (@is_file($absPath.'ext_tables.php')) { 3327 $content = t3lib_div::getUrl($absPath.'ext_tables.php'); 3328 if (stristr($content,'t3lib_extMgm::addModule')) $infoArray['flags'][] = 'Module'; 3329 if (stristr($content,'t3lib_extMgm::insertModuleFunction')) $infoArray['flags'][] = 'Module+'; 3330 if (stristr($content,'t3lib_div::loadTCA')) $infoArray['flags'][] = 'loadTCA'; 3331 if (stristr($content,'$TCA[')) $infoArray['flags'][] = 'TCA'; 3332 if (stristr($content,'t3lib_extMgm::addPlugin')) $infoArray['flags'][] = 'Plugin'; 3333 } 3334 3335 // ext_localconf.php: 3336 if (@is_file($absPath.'ext_localconf.php')) { 3337 $content = t3lib_div::getUrl($absPath.'ext_localconf.php'); 3338 if (stristr($content,'t3lib_extMgm::addPItoST43')) $infoArray['flags'][]='Plugin/ST43'; 3339 if (stristr($content,'t3lib_extMgm::addPageTSConfig')) $infoArray['flags'][]='Page-TSconfig'; 3340 if (stristr($content,'t3lib_extMgm::addUserTSConfig')) $infoArray['flags'][]='User-TSconfig'; 3341 if (stristr($content,'t3lib_extMgm::addTypoScriptSetup')) $infoArray['flags'][]='TS/Setup'; 3342 if (stristr($content,'t3lib_extMgm::addTypoScriptConstants')) $infoArray['flags'][]='TS/Constants'; 3343 } 3344 3345 if (@is_file($absPath.'ext_typoscript_constants.txt')) { 3346 $infoArray['TSfiles'][] = 'Constants'; 3347 } 3348 if (@is_file($absPath.'ext_typoscript_setup.txt')) { 3349 $infoArray['TSfiles'][] = 'Setup'; 3350 } 3351 if (@is_file($absPath.'ext_conf_template.txt')) { 3352 $infoArray['conf'] = 1; 3353 } 3354 3355 // Classes: 3356 if ($validity) { 3357 $filesInside = $this->getClassIndexLocallangFiles($absPath,$table_class_prefix,$extKey); 3358 if (is_array($filesInside['errors'])) $infoArray['errors'] = array_merge((array)$infoArray['errors'],$filesInside['errors']); 3359 if (is_array($filesInside['NSerrors'])) $infoArray['NSerrors'] = array_merge((array)$infoArray['NSerrors'],$filesInside['NSerrors']); 3360 if (is_array($filesInside['NSok'])) $infoArray['NSok'] = array_merge((array)$infoArray['NSok'],$filesInside['NSok']); 3361 $infoArray['locallang'] = $filesInside['locallang']; 3362 $infoArray['classes'] = $filesInside['classes']; 3363 } 3364 3365 // Upload folders 3366 if ($extInfo['EM_CONF']['uploadfolder']) { 3367 $infoArray['uploadfolder'] = $this->ulFolder($extKey); 3368 if (!@is_dir(PATH_site.$infoArray['uploadfolder'])) { 3369 $infoArray['errors'][] = 'Error: Upload folder "'.$infoArray['uploadfolder'].'" did not exist!'; 3370 $infoArray['uploadfolder'] = ''; 3371 } 3372 } 3373 3374 // Create directories: 3375 if ($extInfo['EM_CONF']['createDirs']) { 3376 $infoArray['createDirs'] = array_unique(t3lib_div::trimExplode(',',$extInfo['EM_CONF']['createDirs'],1)); 3377 foreach($infoArray['createDirs'] as $crDir) { 3378 if (!@is_dir(PATH_site.$crDir)) { 3379 $infoArray['errors'][]='Error: Upload folder "'.$crDir.'" did not exist!'; 3380 } 3381 } 3382 } 3383 3384 // Return result array: 3385 return $infoArray; 3386 } 3387 3388 /** 3389 * Analyses the php-scripts of an available extension on server 3390 * 3391 * @param string Absolute path to extension 3392 * @param string Prefix for tables/classes. 3393 * @param string Extension key 3394 * @return array Information array. 3395 * @see makeDetailedExtensionAnalysis() 3396 */ 3397 function getClassIndexLocallangFiles($absPath,$table_class_prefix,$extKey) { 3398 $filesInside = t3lib_div::removePrefixPathFromList(t3lib_div::getAllFilesAndFoldersInPath(array(),$absPath,'php,inc',0,99,$this->excludeForPackaging),$absPath); 3399 $out = array(); 3400 3401 foreach($filesInside as $fileName) { 3402 if (substr($fileName,0,4)!='ext_' && substr($fileName,0,6)!='tests/') { // ignore supposed-to-be unit tests as well 3403 $baseName = basename($fileName); 3404 if (substr($baseName,0,9)=='locallang' && substr($baseName,-4)=='.php') { 3405 $out['locallang'][] = $fileName; 3406 } elseif ($baseName!='conf.php') { 3407 if (filesize($absPath.$fileName)<500*1024) { 3408 $fContent = t3lib_div::getUrl($absPath.$fileName); 3409 unset($reg); 3410 if (preg_match('/\n[[:space:]]*class[[:space:]]*([[:alnum:]_]+)([[:alnum:][:space:]_]*)/',$fContent,$reg)) { 3411 3412 // Find classes: 3413 $lines = explode(chr(10),$fContent); 3414 foreach($lines as $l) { 3415 $line = trim($l); 3416 unset($reg); 3417 if (preg_match('/^class[[:space:]]*([[:alnum:]_]+)([[:alnum:][:space:]_]*)/',$line,$reg)) { 3418 $out['classes'][] = $reg[1]; 3419 $out['files'][$fileName]['classes'][] = $reg[1]; 3420 if ($reg[1]!=='ext_update' && substr($reg[1],0,3)!='ux_' && !t3lib_div::isFirstPartOfStr($reg[1],$table_class_prefix) && strcmp(substr($table_class_prefix,0,-1),$reg[1])) { 3421 $out['NSerrors']['classname'][] = $reg[1]; 3422 } else $out['NSok']['classname'][] = $reg[1]; 3423 } 3424 } 3425 // If class file prefixed 'class.'.... 3426 if (substr($baseName,0,6)=='class.') { 3427 $fI = pathinfo($baseName); 3428 $testName=substr($baseName,6,-(1+strlen($fI['extension']))); 3429 if ($testName!=='ext_update' && substr($testName,0,3)!='ux_' && !t3lib_div::isFirstPartOfStr($testName,$table_class_prefix) && strcmp(substr($table_class_prefix,0,-1),$testName)) { 3430 $out['NSerrors']['classfilename'][] = $baseName; 3431 } else { 3432 $out['NSok']['classfilename'][] = $baseName; 3433 if (is_array($out['files'][$fileName]['classes']) && $this->first_in_array($testName,$out['files'][$fileName]['classes'],1)) { 3434 $out['msg'][] = 'Class filename "'.$fileName.'" did contain the class "'.$testName.'" just as it should.'; 3435 } else $out['errors'][] = 'Class filename "'.$fileName.'" did NOT contain the class "'.$testName.'"!'; 3436 } 3437 } 3438 // 3439 $XclassParts = split('if \(defined\([\'"]TYPO3_MODE[\'"]\) && \$TYPO3_CONF_VARS\[TYPO3_MODE\]\[[\'"]XCLASS[\'"]\]',$fContent,2); 3440 if (count($XclassParts)==2) { 3441 unset($reg); 3442 preg_match('/^\[[\'"]([[:alnum:]_\/\.]*)[\'"]\]/',$XclassParts[1],$reg); 3443 if ($reg[1]) { 3444 $cmpF = 'ext/'.$extKey.'/'.$fileName; 3445 if (!strcmp($reg[1],$cmpF)) { 3446 if (preg_match('/_once[[:space:]]*\(\$TYPO3_.ONF_VARS\[TYPO3_MODE\]\[[\'"]XCLASS[\'"]\]\[[\'"]'.preg_quote($cmpF,'/').'[\'"]\]\);/', $XclassParts[1])) { 3447 $out['msg'][] = 'XCLASS OK in '.$fileName; 3448 } else $out['errors'][] = 'Couldn\'t find the include_once statement for XCLASS!'; 3449 } else $out['errors'][] = 'The XCLASS filename-key "'.$reg[1].'" was different from "'.$cmpF.'" which it should have been!'; 3450 } else $out['errors'][] = 'No XCLASS filename-key found in file "'.$fileName.'". Maybe a regex coding error here...'; 3451 } elseif (!$this->first_in_array('ux_',$out['files'][$fileName]['classes'])) $out['errors'][] = 'No XCLASS inclusion code found in file "'.$fileName.'"'; 3452 } 3453 } 3454 } 3455 } 3456 } 3457 return $out; 3458 } 3459 3460 /** 3461 * Reads $confFilePath (a module $conf-file) and returns information on the existence of TYPO3_MOD_PATH definition and MCONF_name 3462 * 3463 * @param string Absolute path to a "conf.php" file of a module which we are analysing. 3464 * @return array Information found. 3465 * @see writeTYPO3_MOD_PATH() 3466 */ 3467 function modConfFileAnalysis($confFilePath) { 3468 $lines = explode(chr(10),t3lib_div::getUrl($confFilePath)); 3469 $confFileInfo = array(); 3470 $confFileInfo['lines'] = $lines; 3471 3472 foreach($lines as $k => $l) { 3473 $line = trim($l); 3474 3475 unset($reg); 3476 if (preg_match('/^define[[:space:]]*\([[:space:]]*["\']TYPO3_MOD_PATH["\'][[:space:]]*,[[:space:]]*["\']([[:alnum:]_\/\.]+)["\'][[:space:]]*\)[[:space:]]*;/',$line,$reg)) { 3477 $confFileInfo['TYPO3_MOD_PATH'] = array($k,$reg); 3478 } 3479 3480 unset($reg); 3481 if (preg_match('/^\$MCONF\[["\']?name["\']?\][[:space:]]*=[[:space:]]*["\']([[:alnum:]_]+)["\'];/',$line,$reg)) { 3482 $confFileInfo['MCONF_name'] = array($k,$reg); 3483 } 3484 } 3485 return $confFileInfo; 3486 } 3487 3488 /** 3489 * Creates a MD5-hash array over the current files in the extension 3490 * 3491 * @param string Extension key 3492 * @param array Extension information array 3493 * @return array MD5-keys 3494 */ 3495 function serverExtensionMD5Array($extKey,$conf) { 3496 3497 // Creates upload-array - including filelist. 3498 $mUA = $this->makeUploadArray($extKey,$conf); 3499 3500 $md5Array = array(); 3501 if (is_array($mUA['FILES'])) { 3502 3503 // Traverse files. 3504 foreach($mUA['FILES'] as $fN => $d) { 3505 if ($fN!='ext_emconf.php') { 3506 $md5Array[$fN] = substr($d['content_md5'],0,4); 3507 } 3508 } 3509 } else debug($mUA); 3510 return $md5Array; 3511 } 3512 3513 /** 3514 * Compares two arrays with MD5-hash values for analysis of which files has changed. 3515 * 3516 * @param array Current values 3517 * @param array Past values 3518 * @return array Affected files 3519 */ 3520 function findMD5ArrayDiff($current,$past) { 3521 if (!is_array($current)) $current = array(); 3522 if (!is_array($past)) $past = array(); 3523 $filesInCommon = array_intersect($current,$past); 3524 $diff1 = array_keys(array_diff($past,$filesInCommon)); 3525 $diff2 = array_keys(array_diff($current,$filesInCommon)); 3526 $affectedFiles = array_unique(array_merge($diff1,$diff2)); 3527 return $affectedFiles; 3528 } 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 /*********************************** 3540 * 3541 * File system operations 3542 * 3543 **********************************/ 3544 3545 /** 3546 * Creates directories in $extDirPath 3547 * 3548 * @param array Array of directories to create relative to extDirPath, eg. "blabla", "blabla/blabla" etc... 3549 * @param string Absolute path to directory. 3550 * @return mixed Returns false on success or an error string 3551 */ 3552 function createDirsInPath($dirs,$extDirPath) { 3553 if (is_array($dirs)) { 3554 foreach($dirs as $dir) { 3555 $error = t3lib_div::mkdir_deep($extDirPath,$dir); 3556 if ($error) return $error; 3557 } 3558 } 3559 3560 return false; 3561 } 3562 3563 /** 3564 * Removes the extension directory (including content) 3565 * 3566 * @param string Extension directory to remove (with trailing slash) 3567 * @param boolean If set, will leave the extension directory 3568 * @return boolean False on success, otherwise error string. 3569 */ 3570 function removeExtDirectory($removePath,$removeContentOnly=0) { 3571 $errors = array(); 3572 if (@is_dir($removePath) && substr($removePath,-1)=='/' && ( 3573 t3lib_div::isFirstPartOfStr($removePath,PATH_site.$this->typePaths['G']) || 3574 t3lib_div::isFirstPartOfStr($removePath,PATH_site.$this->typePaths['L']) || 3575 (t3lib_div::isFirstPartOfStr($removePath,PATH_site.$this->typePaths['S']) && $this->systemInstall) || 3576 t3lib_div::isFirstPartOfStr($removePath,PATH_site.'fileadmin/_temp_/')) // Playing-around directory... 3577 ) { 3578 3579 // All files in extension directory: 3580 $fileArr = t3lib_div::getAllFilesAndFoldersInPath(array(),$removePath,'',1); 3581 if (is_array($fileArr)) { 3582 3583 // Remove files in dirs: 3584 foreach($fileArr as $removeFile) { 3585 if (!@is_dir($removeFile)) { 3586 if (@is_file($removeFile) && t3lib_div::isFirstPartOfStr($removeFile,$removePath) && strcmp($removeFile,$removePath)) { // ... we are very paranoid, so we check what cannot go wrong: that the file is in fact within the prefix path! 3587 @unlink($removeFile); 3588 clearstatcache(); 3589 if (@is_file($removeFile)) { 3590 $errors[] = 'Error: "'.$removeFile.'" could not be deleted!'; 3591 } 3592 } else $errors[] = 'Error: "'.$removeFile.'" was either not a file, or it was equal to the removed directory or simply outside the removed directory "'.$removePath.'"!'; 3593 } 3594 } 3595 3596 // Remove directories: 3597 $remDirs = $this->extractDirsFromFileList(t3lib_div::removePrefixPathFromList($fileArr,$removePath)); 3598 $remDirs = array_reverse($remDirs); // Must delete outer directories first... 3599 foreach($remDirs as $removeRelDir) { 3600 $removeDir = $removePath.$removeRelDir; 3601 if (@is_dir($removeDir)) { 3602 rmdir($removeDir); 3603 clearstatcache(); 3604 if (@is_dir($removeDir)) { 3605 $errors[] = 'Error: "'.$removeDir.'" could not be removed (are there files left?)'; 3606 } 3607 } else $errors[] = 'Error: "'.$removeDir.'" was not a directory!'; 3608 } 3609 3610 // If extension dir should also be removed: 3611 if (!$removeContentOnly) { 3612 rmdir($removePath); 3613 clearstatcache(); 3614 if (@is_dir($removePath)) { 3615 $errors[] = 'Error: Extension directory "'.$removePath.'" could not be removed (are there files or folders left?)'; 3616 } 3617 } 3618 } else $errors[] = 'Error: '.$fileArr; 3619 } else $errors[] = 'Error: Unallowed path to remove: '.$removePath; 3620 3621 // Return errors if any: 3622 return implode(chr(10),$errors); 3623 } 3624 3625 /** 3626 * Removes the current extension of $type and creates the base folder for the new one (which is going to be imported) 3627 * 3628 * @param array Data for imported extension 3629 * @param string Extension installation scope (L,G,S) 3630 * @param boolean If set, nothing will be deleted (neither directory nor files) 3631 * @return mixed Returns array on success (with extension directory), otherwise an error string. 3632 */ 3633 function clearAndMakeExtensionDir($importedData,$type,$dontDelete=0) { 3634 if (!$importedData['extKey']) return 'FATAL ERROR: Extension key was not set for some VERY strange reason. Nothing done...'; 3635 3636 // Setting install path (L, G, S or fileadmin/_temp_/) 3637 $path = ''; 3638 switch((string)$type) { 3639 case 'G': 3640 case 'L': 3641 $path = PATH_site.$this->typePaths[$type]; 3642 $suffix = ''; 3643 3644 // Creates the typo3conf/ext/ directory if it does NOT already exist: 3645 if ((string)$type=='L' && !@is_dir($path)) { 3646 t3lib_div::mkdir($path); 3647 } 3648 break; 3649 default: 3650 if ($this->systemInstall && (string)$type=='S') { 3651 $path = PATH_site.$this->typePaths[$type]; 3652 $suffix = ''; 3653 } else { 3654 $path = PATH_site.'fileadmin/_temp_/'; 3655 $suffix = '_'.date('dmy-His'); 3656 } 3657 break; 3658 } 3659 3660 // If the install path is OK... 3661 if ($path && @is_dir($path)) { 3662 3663 // Set extension directory: 3664 $extDirPath = $path.$importedData['extKey'].$suffix.'/'; 3665 3666 // Install dir was found, remove it then: 3667 if (@is_dir($extDirPath)) { 3668 if($dontDelete) return array($extDirPath); 3669 $res = $this->removeExtDirectory($extDirPath); 3670 if ($res) { 3671 return 'ERROR: Could not remove extension directory "'.$extDirPath.'". Reasons:<br /><br />'.nl2br($res); 3672 } 3673 } 3674 3675 // We go create... 3676 t3lib_div::mkdir($extDirPath); 3677 if (!is_dir($extDirPath)) return 'ERROR: Could not create extension directory "'.$extDirPath.'"'; 3678 return array($extDirPath); 3679 } else return 'ERROR: The extension install path "'.$path.'" was not a directory.'; 3680 } 3681 3682 /** 3683 * Unlink (delete) cache files 3684 * 3685 * @return integer Number of deleted files. 3686 */ 3687 function removeCacheFiles() { 3688 return t3lib_extMgm::removeCacheFiles(); 3689 } 3690 3691 /** 3692 * Extracts the directories in the $files array 3693 * 3694 * @param array Array of files / directories 3695 * @return array Array of directories from the input array. 3696 */ 3697 function extractDirsFromFileList($files) { 3698 $dirs = array(); 3699 3700 if (is_array($files)) { 3701 // Traverse files / directories array: 3702 foreach($files as $file) { 3703 if (substr($file,-1)=='/') { 3704 $dirs[$file] = $file; 3705 } else { 3706 $pI = pathinfo($file); 3707 if (strcmp($pI['dirname'],'') && strcmp($pI['dirname'],'.')) { 3708 $dirs[$pI['dirname'].'/'] = $pI['dirname'].'/'; 3709 } 3710 } 3711 } 3712 } 3713 return $dirs; 3714 } 3715 3716 /** 3717 * Returns the absolute path where the extension $extKey is installed (based on 'type' (SGL)) 3718 * 3719 * @param string Extension key 3720 * @param string Install scope type: L, G, S 3721 * @return string Returns the absolute path to the install scope given by input $type variable. It is checked if the path is a directory. Slash is appended. 3722 */ 3723 function getExtPath($extKey,$type) { 3724 $typeP = $this->typePaths[$type]; 3725 if ($typeP) { 3726 $path = PATH_site.$typeP.$extKey.'/'; 3727 return @is_dir($path) ? $path : ''; 3728 } else { 3729 return ''; 3730 } 3731 } 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 /******************************* 3743 * 3744 * Writing to "conf.php" and "localconf.php" files 3745 * 3746 ******************************/ 3747 3748 /** 3749 * Write new TYPO3_MOD_PATH to "conf.php" file. 3750 * 3751 * @param string Absolute path to a "conf.php" file of the backend module which we want to write back to. 3752 * @param string Install scope type: L, G, S 3753 * @param string Relative path for the module folder in extenson 3754 * @return string Returns message about the status. 3755 * @see modConfFileAnalysis() 3756 */ 3757 function writeTYPO3_MOD_PATH($confFilePath,$type,$mP) { 3758 $lines = explode(chr(10),t3lib_div::getUrl($confFilePath)); 3759 $confFileInfo = array(); 3760 $confFileInfo['lines'] = $lines; 3761 3762 $flag_M = 0; 3763 $flag_B = 0; 3764 3765 foreach($lines as $k => $l) { 3766 $line = trim($l); 3767 3768 unset($reg); 3769 if (preg_match('/^define[[:space:]]*\([[:space:]]*["\']TYPO3_MOD_PATH["\'][[:space:]]*,[[:space:]]*["\']([[:alnum:]_\/\.]+)["\'][[:space:]]*\)[[:space:]]*;/',$line,$reg)) { 3770 $lines[$k] = str_replace($reg[0], 'define(\'TYPO3_MOD_PATH\', \''.$this->typeRelPaths[$type].$mP.'\');', $lines[$k]); 3771 $flag_M = $k+1; 3772 } 3773 3774 unset($reg); 3775 if (preg_match('/^\$BACK_PATH[[:space:]]*=[[:space:]]*["\']([[:alnum:]_\/\.]+)["\'][[:space:]]*;/',$line,$reg)) { 3776 $lines[$k] = str_replace($reg[0], '$BACK_PATH=\''.$this->typeBackPaths[$type].'\';', $lines[$k]); 3777 $flag_B = $k+1; 3778 } 3779 } 3780 3781 if ($flag_B && $flag_M) { 3782 t3lib_div::writeFile($confFilePath,implode(chr(10),$lines)); 3783 return 'TYPO3_MOD_PATH and $BACK_PATH was updated in "'.substr($confFilePath,strlen(PATH_site)).'"'; 3784 } else return 'Error: Either TYPO3_MOD_PATH or $BACK_PATH was not found in the "'.$confFilePath.'" file. You must manually configure that!'; 3785 } 3786 3787 /** 3788 * Writes the extension list to "localconf.php" file 3789 * Removes the temp_CACHED* files before return. 3790 * 3791 * @param string List of extensions 3792 * @return void 3793 */ 3794 function writeNewExtensionList($newExtList) { 3795 global $TYPO3_CONF_VARS; 3796 3797 // Instance of install tool 3798 $instObj = new t3lib_install; 3799 $instObj->allowUpdateLocalConf =1; 3800 $instObj->updateIdentity = 'TYPO3 Extension Manager'; 3801 3802 // Get lines from localconf file 3803 $lines = $instObj->writeToLocalconf_control(); 3804 $instObj->setValueInLocalconfFile($lines, '$TYPO3_CONF_VARS[\'EXT\'][\'extList\']', $newExtList); 3805 $instObj->writeToLocalconf_control($lines); 3806 3807 $TYPO3_CONF_VARS['EXT']['extList'] = $newExtList; 3808 $this->removeCacheFiles(); 3809 } 3810 3811 /** 3812 * Writes the TSstyleconf values to "localconf.php" 3813 * Removes the temp_CACHED* files before return. 3814 * 3815 * @param string Extension key 3816 * @param array Configuration array to write back 3817 * @return void 3818 */ 3819 function writeTsStyleConfig($extKey,$arr) { 3820 3821 // Instance of install tool 3822 $instObj = new t3lib_install; 3823 $instObj->allowUpdateLocalConf =1; 3824 $instObj->updateIdentity = 'TYPO3 Extension Manager'; 3825 3826 // Get lines from localconf file 3827 $lines = $instObj->writeToLocalconf_control(); 3828 $instObj->setValueInLocalconfFile($lines, '$TYPO3_CONF_VARS[\'EXT\'][\'extConf\'][\''.$extKey.'\']', serialize($arr)); // This will be saved only if there are no linebreaks in it ! 3829 $instObj->writeToLocalconf_control($lines); 3830 3831 $this->removeCacheFiles(); 3832 } 3833 3834 /** 3835 * Forces update of local EM_CONF. This will renew the information of changed files. 3836 * 3837 * @param string Extension key 3838 * @param array Extension information array 3839 * @return string Status message 3840 */ 3841 function updateLocalEM_CONF($extKey,$extInfo) { 3842 $extInfo['EM_CONF']['_md5_values_when_last_written'] = serialize($this->serverExtensionMD5Array($extKey,$extInfo)); 3843 $emConfFileContent = $this->construct_ext_emconf_file($extKey,$extInfo['EM_CONF']); 3844 3845 $absPath = $this->getExtPath($extKey,$extInfo['type']); 3846 $emConfFileName = $absPath.'ext_emconf.php'; 3847 if($emConfFileContent) { 3848 3849 if(@is_file($emConfFileName)) { 3850 if(t3lib_div::writeFile($emConfFileName,$emConfFileContent) === true) { 3851 return '"'.substr($emConfFileName,strlen($absPath)).'" was updated with a cleaned up EM_CONF array.'; 3852 } else { 3853 return '<strong>Error: "'.$emConfFileName.'" was not writable!</strong>'; 3854 } 3855 } else return('<strong>Error: No file "'.$emConfFileName.'" found. DON\'T PANIC!</strong>'); 3856 } else { 3857 return 'No content to write to "'.substr($emConfFileName,strlen($absPath)).'"!'; 3858 } 3859 } 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 /******************************************* 3871 * 3872 * Compiling upload information, emconf-file etc. 3873 * 3874 *******************************************/ 3875 3876 /** 3877 * Compiles the ext_emconf.php file 3878 * 3879 * @param string Extension key 3880 * @param array EM_CONF array 3881 * @return string PHP file content, ready to write to ext_emconf.php file 3882 */ 3883 function construct_ext_emconf_file($extKey,$EM_CONF) { 3884 3885 // clean version number: 3886 $vDat = $this->renderVersion($EM_CONF['version']); 3887 $EM_CONF['version']=$vDat['version']; 3888 3889 $code = '<?php 3890 3891 ######################################################################## 3892 # Extension Manager/Repository config file for ext: "'.$extKey.'" 3893 # 3894 # Auto generated '.date('d-m-Y H:i').' 3895 # 3896 # Manual updates: 3897 # Only the data in the array - anything else is removed by next write. 3898 # "version" and "dependencies" must not be touched! 3899 ######################################################################## 3900 3901 $EM_CONF[$_EXTKEY] = '.$this->arrayToCode($EM_CONF, 0).'; 3902 3903 ?>'; 3904 return str_replace(chr(13), '', $code); 3905 } 3906 3907 /** 3908 * Enter description here... 3909 * 3910 * @param unknown_type $array 3911 * @param unknown_type $lines 3912 * @param unknown_type $level 3913 * @return unknown 3914 */ 3915 function arrayToCode($array, $level=0) { 3916 $lines = 'array('.chr(10); 3917 $level++; 3918 foreach($array as $k => $v) { 3919 if(strlen($k) && is_array($v)) { 3920 $lines .= str_repeat(chr(9),$level)."'".$k."' => ".$this->arrayToCode($v, $level); 3921 } elseif(strlen($k)) { 3922 $lines .= str_repeat(chr(9),$level)."'".$k."' => ".(t3lib_div::testInt($v) ? intval($v) : "'".t3lib_div::slashJS(trim($v),1)."'").','.chr(10); 3923 } 3924 } 3925 3926 $lines .= str_repeat(chr(9),$level-1).')'.($level-1==0 ? '':','.chr(10)); 3927 return $lines; 3928 } 3929 3930 /** 3931 * Make upload array out of extension 3932 * 3933 * @param string Extension key 3934 * @param array Extension information array 3935 * @return mixed Returns array with extension upload array on success, otherwise an error string. 3936 */ 3937 function makeUploadArray($extKey,$conf) { 3938 $extPath = $this->getExtPath($extKey,$conf['type']); 3939 3940 if ($extPath) { 3941 3942 // Get files for extension: 3943 $fileArr = array(); 3944 $fileArr = t3lib_div::getAllFilesAndFoldersInPath($fileArr,$extPath,'',0,99,$this->excludeForPackaging); 3945 3946 // Calculate the total size of those files: 3947 $totalSize = 0; 3948 foreach($fileArr as $file) { 3949 $totalSize+=filesize($file); 3950 } 3951 3952 // If the total size is less than the upper limit, proceed: 3953 if ($totalSize < $this->maxUploadSize) { 3954 3955 // Initialize output array: 3956 $uploadArray = array(); 3957 $uploadArray['extKey'] = $extKey; 3958 $uploadArray['EM_CONF'] = $conf['EM_CONF']; 3959 $uploadArray['misc']['codelines'] = 0; 3960 $uploadArray['misc']['codebytes'] = 0; 3961 3962 $uploadArray['techInfo'] = $this->makeDetailedExtensionAnalysis($extKey,$conf,1); 3963 3964 // Read all files: 3965 foreach($fileArr as $file) { 3966 $relFileName = substr($file,strlen($extPath)); 3967 $fI = pathinfo($relFileName); 3968 if ($relFileName!='ext_emconf.php') { // This file should be dynamically written... 3969 $uploadArray['FILES'][$relFileName] = array( 3970 'name' => $relFileName, 3971 'size' => filesize($file), 3972 'mtime' => filemtime($file), 3973 'is_executable' => (TYPO3_OS=='WIN' ? 0 : is_executable($file)), 3974 'content' => t3lib_div::getUrl($file) 3975 ); 3976 if (t3lib_div::inList('php,inc',strtolower($fI['extension']))) { 3977 $uploadArray['FILES'][$relFileName]['codelines']=count(explode(chr(10),$uploadArray['FILES'][$relFileName]['content'])); 3978 $uploadArray['misc']['codelines']+=$uploadArray['FILES'][$relFileName]['codelines']; 3979 $uploadArray['misc']['codebytes']+=$uploadArray['FILES'][$relFileName]['size']; 3980 3981 // locallang*.php files: 3982 if (substr($fI['basename'],0,9)=='locallang' && strstr($uploadArray['FILES'][$relFileName]['content'],'$LOCAL_LANG')) { 3983 $uploadArray['FILES'][$relFileName]['LOCAL_LANG']=$this->getSerializedLocalLang($file,$uploadArray['FILES'][$relFileName]['content']); 3984 } 3985 } 3986 $uploadArray['FILES'][$relFileName]['content_md5'] = md5($uploadArray['FILES'][$relFileName]['content']); 3987 } 3988 } 3989 3990 // Return upload-array: 3991 return $uploadArray; 3992 } else return 'Error: Total size of uncompressed upload ('.$totalSize.') exceeds '.t3lib_div::formatSize($this->maxUploadSize); 3993 } else { 3994 return 'Error: Extension path for extension "'.$extKey.'" not found'; 3995 } 3996 } 3997 3998 /** 3999 * Include a locallang file and return the $LOCAL_LANG array serialized. 4000 * 4001 * @param string Absolute path to locallang file to include. 4002 * @param string Old content of a locallang file (keeping the header content) 4003 * @return array Array with header/content as key 0/1 4004 * @see makeUploadArray() 4005 */ 4006 function getSerializedLocalLang($file,$content) { 4007 $returnParts = explode('$LOCAL_LANG',$content,2); 4008 4009 include($file); 4010 if (is_array($LOCAL_LANG)) { 4011 $returnParts[1] = serialize($LOCAL_LANG); 4012 return $returnParts; 4013 } else { 4014 return array(); 4015 } 4016 } 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 /******************************** 4028 * 4029 * Managing dependencies, conflicts, priorities, load order of extension keys 4030 * 4031 *******************************/ 4032 4033 /** 4034 * Adds extension to extension list and returns new list. If -1 is returned, an error happend. 4035 * Checks dependencies etc. 4036 * 4037 * @param string Extension key 4038 * @param array Extension information array - information about installed extensions 4039 * @return string New list of installed extensions or -1 if error 4040 * @see showExtDetails() 4041 */ 4042 function addExtToList($extKey,$instExtInfo) { 4043 global $TYPO3_LOADED_EXT; 4044 4045 // ext_emconf.php information: 4046 $conf = $instExtInfo[$extKey]['EM_CONF']; 4047 4048 // Get list of installed extensions and add this one. 4049 $listArr = array_keys($TYPO3_LOADED_EXT); 4050 if ($conf['priority']=='top') { 4051 array_unshift($listArr,$extKey); 4052 } else { 4053 $listArr[]=$extKey; 4054 } 4055 4056 // Manage other circumstances: 4057 $listArr = $this->managesPriorities($listArr,$instExtInfo); 4058 $listArr = $this->removeRequiredExtFromListArr($listArr); 4059 4060 // Implode unique list of extensions to load and return: 4061 $list = implode(',',array_unique($listArr)); 4062 return $list; 4063 } 4064 4065 /** 4066 * Enter description here... 4067 * 4068 * @param string $extKey 4069 * @param array $conf 4070 * @param array $instExtInfo 4071 * @return array 4072 */ 4073 function checkDependencies($extKey, $conf, $instExtInfo) { 4074 $content = ''; 4075 $depError = false; 4076 $msg = array(); 4077 $depsolver = t3lib_div::_POST('depsolver'); 4078 4079 if (isset($conf['constraints']['depends']) && is_array($conf['constraints']['depends'])) { 4080 foreach($conf['constraints']['depends'] as $depK => $depV) { 4081 if($depsolver['ignore'][$depK]) { 4082 $msg[] = '<br />Dependency on '.$depK.' ignored as requested. 4083 <input type="hidden" value="1" name="depsolver[ignore]['.$depK.']" />'; 4084 continue; 4085 } 4086 if($depK == 'php') { 4087 if(!$depV) continue; 4088 $versionRange = $this->splitVersionRange($depV); 4089 $phpv = strstr(PHP_VERSION,'-') ? substr(PHP_VERSION,0,strpos(PHP_VERSION,'-')) : PHP_VERSION; // Linux distributors like to add suffixes, like in 5.1.2-1. Those must be ignored! 4090 if ($versionRange[0]!='0.0.0' && version_compare($phpv,$versionRange[0],'<')) { 4091 $msg[] = '<br />The running PHP version ('.$phpv.') is lower than required ('.$versionRange[0].')'; 4092 $msg[] = ' <input type="checkbox" value="1" name="depsolver[ignore]['.$depK.']" id="checkIgnore_'.$depK.'" /> <label for="checkIgnore_'.$depK.'">Ignore this version requirement</label>'; 4093 $depError = true; 4094 continue; 4095 } elseif ($versionRange[1]!='0.0.0' && version_compare($phpv,$versionRange[1],'>')) { 4096 $msg[] = '<br />The running PHP version ('.$phpv.') is higher than allowed ('.$versionRange[1].')'; 4097 $msg[] = ' <input type="checkbox" value="1" name="depsolver[ignore]['.$depK.']" id="checkIgnore_'.$depK.'" /> <label for="checkIgnore_'.$depK.'">Ignore this version requirement</label>'; 4098 $depError = true; 4099 continue; 4100 } 4101 4102 } elseif ($depK == 'typo3') { 4103 if (!$depV) continue; 4104 4105 $versionRange = $this->splitVersionRange($depV); 4106 if ($versionRange[0]!='0.0.0' && version_compare(TYPO3_version,$versionRange[0],'<')) { 4107 $msg[] = '<br />The running TYPO3 version ('.TYPO3_version.') is lower than required ('.$versionRange[0].')'; 4108 $msg[] = ' <input type="checkbox" value="1" name="depsolver[ignore]['.$depK.']" id="checkIgnore_'.$depK.'" /> <label for="checkIgnore_'.$depK.'">Ignore this version requirement</label>'; 4109 $depError = true; 4110 continue; 4111 } elseif ($versionRange[1]!='0.0.0' && version_compare(TYPO3_version,$versionRange[1],'>')) { 4112 $msg[] = '<br />The running TYPO3 version ('.TYPO3_version.') is higher than allowed ('.$versionRange[1].')'; 4113 $msg[] = ' <input type="checkbox" value="1" name="depsolver[ignore]['.$depK.']" id="checkIgnore_'.$depK.'" /> <label for="checkIgnore_'.$depK.'">Ignore this version requirement</label>'; 4114 $depError = true; 4115 continue; 4116 } 4117 } elseif (strlen($depK) && !t3lib_extMgm::isLoaded($depK)) { // strlen check for braindead empty dependencies coming from extensions... 4118 if(!isset($instExtInfo[$depK])) { 4119 $msg[] = '<br />Extension "'.$depK.'" was not available in the system. Please import it from the TYPO3 Extension Repository.'; 4120 $msg[] = ' <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 href="index.php?CMD[importExt]='.$depK.'&CMD[loc]=L&CMD[standAlone]=1" target="_blank">Import now (opens a new window)</a>'; 4121 $msg[] = ' <input type="checkbox" value="1" name="depsolver[ignore]['.$depK.']" id="checkIgnore_'.$depK.'" /> <label for="checkIgnore_'.$depK.'">Ignore this extension requirement</label>'; 4122 } else { 4123 $msg[] = '<br />Extension "'.$depK.'" ('.$instExtInfo[$depK]['EM_CONF']['title'].') was not installed. Please install it first.'; 4124 $msg[] = ' '.$this->installButton().' <a href="'.htmlspecialchars('index.php?CMD[showExt]='.$depK.'&CMD[load]=1&CMD[clrCmd]=1&CMD[standAlone]=1&SET[singleDetails]=info').'" target="_blank">Install now (opens a new window)</a>'; 4125 $msg[] = ' <input type="checkbox" value="1" name="depsolver[ignore]['.$depK.']" id="checkIgnore_'.$depK.'" /> <label for="checkIgnore_'.$depK.'">Ignore this extension requirement</label>'; 4126 } 4127 $depError = true; 4128 } else { 4129 $versionRange = $this->splitVersionRange($depV); 4130 if ($versionRange[0]!='0.0.0' && version_compare($instExtInfo[$depK]['EM_CONF']['version'],$versionRange[0],'<')) { 4131 $msg[] = '<br />The running version of extension "'.$depK.'" ('.$instExtInfo[$depK]['EM_CONF']['version'].') is lower than required ('.$versionRange[0].')'; 4132 $msg[] = ' <input type="checkbox" value="1" name="depsolver[ignore]['.$depK.']" id="checkIgnore_'.$depK.'" /> <label for="checkIgnore_'.$depK.'">Ignore this version requirement</label>'; 4133 $depError = true; 4134 continue; 4135 } elseif ($versionRange[1]!='0.0.0' && version_compare($instExtInfo[$depK]['EM_CONF']['version'],$versionRange[1],'>')) { 4136 $msg[] = '<br />The running version of extension "'.$depK.'" ('.$instExtInfo[$depK]['EM_CONF']['version'].') is higher than allowed ('.$versionRange[1].')'; 4137 $msg[] = ' <input type="checkbox" value="1" name="depsolver[ignore]['.$depK.']" id="checkIgnore_'.$depK.'" /> <label for="checkIgnore_'.$depK.'">Ignore this version requirement</label>'; 4138 $depError = true; 4139 continue; 4140 } 4141 } 4142 } 4143 } 4144 if($depError) { 4145 $content.= $this->doc->section('Dependency Error',implode('<br />',$msg),0,1,2); 4146 } 4147 4148 // Check conflicts with other extensions: 4149 $conflictError = false; 4150 $msg = array(); 4151 4152 if (isset($conf['constraints']['conflicts']) && is_array($conf['constraints']['conflicts'])) { 4153 foreach((array)$conf['constraints']['conflicts'] as $conflictK => $conflictV) { 4154 if($depsolver['ignore'][$conflictK]) { 4155 $msg[] = '<br />Conflict with '.$conflictK.' ignored as requested. 4156 <input type="hidden" value="1" name="depsolver[ignore]['.$conflictK.']" />'; 4157 continue; 4158 } 4159 if (t3lib_extMgm::isLoaded($conflictK)) { 4160 $msg[] = 'The extensions "'.$extKey.'" and "'.$conflictK.'" ('.$instExtInfo[$conflictK]['EM_CONF']['title'].') will conflict with each other. Please remove "'.$conflictK.'" if you want to install "'.$extKey.'".'; 4161 $msg[] = ' '.$this->removeButton().' <a href="'.htmlspecialchars('index.php?CMD[showExt]='.$conflictK.'&CMD[remove]=1&CMD[clrCmd]=1&CMD[standAlone]=1&SET[singleDetails]=info').'" target="_blank">Remove now (opens a new window)</a>'; 4162 $msg[] = ' <input type="checkbox" value="1" name="depsolver[ignore]['.$conflictK.']" id="checkIgnore_'.$conflictK.'" /> <label for="checkIgnore_'.$conflictK.'">Ignore this conflict error</label>'; 4163 $conflictError = true; 4164 } 4165 } 4166 } 4167 if($conflictError) { 4168 $content.= $this->doc->section('Conflict Error',implode('<br />',$msg),0,1,2); 4169 } 4170 4171 // Check suggests on other extensions: 4172 if (isset($conf['constraints']['suggests']) && is_array($conf['constraints']['suggests'])) { 4173 $suggestion = false; 4174 $msg = array(); 4175 foreach($conf['constraints']['suggests'] as $suggestK => $suggestV) { 4176 if($depsolver['ignore'][$suggestK]) { 4177 $msg[] = '<br />Suggestion of '.$suggestK.' acknowledged. 4178 <input type="hidden" value="1" name="depsolver[ignore]['.$suggestK.']" />'; 4179 continue; 4180 } 4181 if (!t3lib_extMgm::isLoaded($suggestK)) { 4182 if (!isset($instExtInfo[$suggestK])) { 4183 $msg[] = 'Extension "'.$suggestK.'" was not available in the system. You may want to import it from the TYPO3 Extension Repository.'; 4184 $msg[] = ' <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 href="index.php?CMD[importExt]='.$depK.'&CMD[loc]=L&CMD[standAlone]=1" target="_blank">Import now (opens a new window)</a>'; 4185 $msg[] = ' <input type="checkbox" value="1" name="depsolver[ignore]['.$suggestK.']" id="checkIgnore_'.$suggestK.'" /> <label for="checkIgnore_'.$suggestK.'">Ignore this suggestion</label>'; 4186 } else { 4187 $msg[] = 'Extension "'.$suggestK.'" ('.$instExtInfo[$suggestK]['EM_CONF']['title'].') was not installed. You may want to install it.'; 4188 $msg[] = ' '.$this->installButton().' <a href="'.htmlspecialchars('index.php?CMD[showExt]='.$suggestK.'&CMD[load]=1&CMD[clrCmd]=1&CMD[standAlone]=1&SET[singleDetails]=info').'" target="_blank">Install now (opens a new window)</a>'; 4189 $msg[] = ' <input type="checkbox" value="1" name="depsolver[ignore]['.$suggestK.']" id="checkIgnore_'.$suggestK.'" /> <label for="checkIgnore_'.$suggestK.'">Ignore this suggestion</label>'; 4190 } 4191 $suggestion = true; 4192 } 4193 } 4194 if($suggestion) { 4195 $content .= $this->doc->section('Extensions suggested by extension "'.$extKey.'"',implode('<br />',$msg),0,1,1); 4196 } 4197 } 4198 4199 if($depError || $conflictError || $suggestion) { 4200 foreach($this->CMD as $k => $v) { 4201 $content .= '<input type="hidden" name="CMD['.$k.']" value="'.$v.'" />'; 4202 } 4203 $content .= '<br /><br /><input type="submit" value="Try again" />'; 4204 4205 return array('returnCode' => false, 'html' => $content); 4206 } 4207 4208 return array('returnCode' => true); 4209 } 4210 4211 /** 4212 * Remove extension key from the list of currently installed extensions and return list. If -1 is returned, an error happend. 4213 * Checks dependencies etc. 4214 * 4215 * @param string Extension key 4216 * @param array Extension information array - information about installed extensions 4217 * @return string New list of installed extensions or -1 if error 4218 * @see showExtDetails() 4219 */ 4220 function removeExtFromList($extKey,$instExtInfo) { 4221 global $TYPO3_LOADED_EXT; 4222 4223 // Initialize: 4224 $depList = array(); 4225 $listArr = array_keys($TYPO3_LOADED_EXT); 4226 4227 // Traverse all installed extensions to check if any of them have this extension as dependency since if that is the case it will not work out! 4228 foreach($listArr as $k => $ext) { 4229 if ($instExtInfo[$ext]['EM_CONF']['dependencies']) { 4230 $dep = t3lib_div::trimExplode(',',$instExtInfo[$ext]['EM_CONF']['dependencies'],1); 4231 if (in_array($extKey,$dep)) { 4232 $depList[] = $ext; 4233 } 4234 } 4235 if (!strcmp($ext,$extKey)) unset($listArr[$k]); 4236 } 4237 4238 // Returns either error or the new list 4239 if (count($depList)) { 4240 $msg = 'The extension(s) "'.implode(', ',$depList).'" depends on the extension you are trying to remove. The operation was not completed.'; 4241 $this->content.=$this->doc->section('Dependency Error',$msg,0,1,2); 4242 return -1; 4243 } else { 4244 $listArr = $this->removeRequiredExtFromListArr($listArr); 4245 $list = implode(',',array_unique($listArr)); 4246 return $list; 4247 } 4248 } 4249 4250 /** 4251 * This removes any required extensions from the $listArr - they should NOT be added to the common extension list, because they are found already in "requiredExt" list 4252 * 4253 * @param array Array of extension keys as values 4254 * @return array Modified array 4255 * @see removeExtFromList(), addExtToList() 4256 */ 4257 function removeRequiredExtFromListArr($listArr) { 4258 foreach($listArr as $k => $ext) { 4259 if (in_array($ext,$this->requiredExt) || !strcmp($ext,'_CACHEFILE')) unset($listArr[$k]); 4260 } 4261 return $listArr; 4262 } 4263 4264 /** 4265 * Traverse the array of installed extensions keys and arranges extensions in the priority order they should be in 4266 * 4267 * @param array Array of extension keys as values 4268 * @param array Extension information array 4269 * @return array Modified array of extention keys as values 4270 * @see addExtToList() 4271 */ 4272 function managesPriorities($listArr,$instExtInfo) { 4273 4274 // Initialize: 4275 $levels = array( 4276 'top' => array(), 4277 'middle' => array(), 4278 'bottom' => array(), 4279 ); 4280 4281 // Traverse list of extensions: 4282 foreach($listArr as $ext) { 4283 $prio = trim($instExtInfo[$ext]['EM_CONF']['priority']); 4284 switch((string)$prio) { 4285 case 'top': 4286 case 'bottom': 4287 $levels[$prio][] = $ext; 4288 break; 4289 default: 4290 $levels['middle'][] = $ext; 4291 break; 4292 } 4293 } 4294 return array_merge( 4295 $levels['top'], 4296 $levels['middle'], 4297 $levels['bottom'] 4298 ); 4299 } 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 /******************************* 4311 * 4312 * System Update functions (based on extension requirements) 4313 * 4314 ******************************/ 4315 4316 /** 4317 * Check if clear-cache should be performed, otherwise show form (for installation of extension) 4318 * Shown only if the extension has the clearCacheOnLoad flag set. 4319 * 4320 * @param string Extension key 4321 * @param array Extension information array 4322 * @return string HTML output (if form is shown) 4323 */ 4324 function checkClearCache($extInfo) { 4325 if ($extInfo['EM_CONF']['clearCacheOnLoad']) { 4326 if (t3lib_div::_POST('_clear_all_cache')) { // Action: Clearing the cache 4327 $tce = t3lib_div::makeInstance('t3lib_TCEmain'); 4328 $tce->stripslashes_values = 0; 4329 $tce->start(Array(),Array()); 4330 $tce->clear_cacheCmd('all'); 4331 } else { // Show checkbox for clearing cache: 4332 $content.= ' 4333 <br /> 4334 <h3>Clear cache</h3> 4335 <p>This extension requests the cache to be cleared when it is installed/removed.<br /> 4336 <label for="check_clear_all_cache">Clear all cache:</label> <input type="checkbox" name="_clear_all_cache" id="check_clear_all_cache" checked="checked" value="1" /><br /> 4337 </p> 4338 '; 4339 } 4340 } 4341 return $content; 4342 } 4343 4344 /** 4345 * Check if upload folder / "createDir" directories should be created. 4346 * 4347 * @param string Extension key 4348 * @param array Extension information array 4349 * @return string HTML content. 4350 */ 4351 function checkUploadFolder($extKey,$extInfo) { 4352 4353 // Checking for upload folder: 4354 $uploadFolder = PATH_site.$this->ulFolder($extKey); 4355 if ($extInfo['EM_CONF']['uploadfolder'] && !@is_dir($uploadFolder)) { 4356 if (t3lib_div::_POST('_uploadfolder')) { // CREATE dir: 4357 t3lib_div::mkdir($uploadFolder); 4358 $indexContent = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> 4359 <HTML> 4360 <HEAD> 4361 <TITLE></TITLE> 4362 <META http-equiv=Refresh Content="0; Url=../../"> 4363 </HEAD> 4364 </HTML>'; 4365 t3lib_div::writeFile($uploadFolder.'index.html',$indexContent); 4366 } else { // Show checkbox / HTML for creation: 4367 $content.=' 4368 <br /><h3>Create upload folder</h3> 4369 <p>The extension requires the upload folder "'.$this->ulFolder($extKey).'" to exist.<br /> 4370 <label for="check_uploadfolder">Create directory "'.$this->ulFolder($extKey).'":</label> <input type="checkbox" name="_uploadfolder" id="check_uploadfolder" checked="checked" value="1" /><br /> 4371 </p> 4372 '; 4373 } 4374 } 4375 4376 // Additional directories that should be created: 4377 if ($extInfo['EM_CONF']['createDirs']) { 4378 $createDirs = array_unique(t3lib_div::trimExplode(',',$extInfo['EM_CONF']['createDirs'],1)); 4379 4380 foreach($createDirs as $crDir) { 4381 if (!@is_dir(PATH_site.$crDir)) { 4382 if (t3lib_div::_POST('_createDir_'.md5($crDir))) { // CREATE dir: 4383 4384 // Initialize: 4385 $crDirStart = ''; 4386 $dirs_in_path = explode('/',preg_replace('/\/$/','',$crDir)); 4387 4388 // Traverse each part of the dir path and create it one-by-one: 4389 foreach($dirs_in_path as $dirP) { 4390 if (strcmp($dirP,'')) { 4391 $crDirStart.= $dirP.'/'; 4392 if (!@is_dir(PATH_site.$crDirStart)) { 4393 t3lib_div::mkdir(PATH_site.$crDirStart); 4394 $finalDir = PATH_site.$crDirStart; 4395 } 4396 } else { 4397 die('ERROR: The path "'.PATH_site.$crDir.'" could not be created.'); 4398 } 4399 } 4400 if ($finalDir) { 4401 $indexContent = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> 4402 <HTML> 4403 <HEAD> 4404 <TITLE></TITLE> 4405 <META http-equiv=Refresh Content="0; Url=/"> 4406 </HEAD> 4407 </HTML>'; 4408 t3lib_div::writeFile($finalDir.'index.html',$indexContent); 4409 } 4410 } else { // Show checkbox / HTML for creation: 4411 $md5CrDir = md5($crDir); 4412 $content.=' 4413 <br /> 4414 <h3>Create folder</h3> 4415 <p>The extension requires the folder "'.$crDir.'" to exist.<br /> 4416 <label for="check_createDir_'.$md5CrDir.'">Create directory "'.$crDir.'":</label> <input type="checkbox" name="_createDir_'.$md5CrDir.'" id="check_createDir_'.$md5CrDir.'" checked="checked" value="1" /><br /> 4417 </p> 4418 '; 4419 } 4420 } 4421 } 4422 } 4423 4424 return $content; 4425 } 4426 4427 /** 4428 * Validates the database according to extension requirements 4429 * Prints form for changes if any. If none, returns blank. If an update is ordered, empty is returned as well. 4430 * DBAL compliant (based on Install Tool code) 4431 * 4432 * @param string Extension key 4433 * @param array Extension information array 4434 * @param boolean If true, returns array with info. 4435 * @return mixed If $infoOnly, returns array with information. Otherwise performs update. 4436 */ 4437 function checkDBupdates($extKey,$extInfo,$infoOnly=0) { 4438 4439 // Initializing Install Tool object: 4440 $instObj = new t3lib_install; 4441 $instObj->INSTALL = t3lib_div::_GP('TYPO3_INSTALL'); 4442 $dbStatus = array(); 4443 4444 // Updating tables and fields? 4445 if (is_array($extInfo['files']) && in_array('ext_tables.sql',$extInfo['files'])) { 4446 $fileContent = t3lib_div::getUrl($this->getExtPath($extKey,$extInfo['type']).'ext_tables.sql'); 4447 4448 $FDfile = $instObj->getFieldDefinitions_sqlContent($fileContent); 4449 if (count($FDfile)) { 4450 $FDdb = $instObj->getFieldDefinitions_database(TYPO3_db); 4451 $diff = $instObj->getDatabaseExtra($FDfile, $FDdb); 4452 $update_statements = $instObj->getUpdateSuggestions($diff); 4453 4454 $dbStatus['structure']['tables_fields'] = $FDfile; 4455 $dbStatus['structure']['diff'] = $diff; 4456 4457 // Updating database... 4458 if (!$infoOnly && is_array($instObj->INSTALL['database_update'])) { 4459 $instObj->performUpdateQueries($update_statements['add'],$instObj->INSTALL['database_update']); 4460 $instObj->performUpdateQueries($update_statements['change'],$instObj->INSTALL['database_update']); 4461 $instObj->performUpdateQueries($update_statements['create_table'],$instObj->INSTALL['database_update']); 4462 } else { 4463 $content.=$instObj->generateUpdateDatabaseForm_checkboxes($update_statements['add'],'Add fields'); 4464 $content.=$instObj->generateUpdateDatabaseForm_checkboxes($update_statements['change'],'Changing fields',1,0,$update_statements['change_currentValue']); 4465 $content.=$instObj->generateUpdateDatabaseForm_checkboxes($update_statements['create_table'],'Add tables'); 4466 } 4467 } 4468 } 4469 4470 // Importing static tables? 4471 if (is_array($extInfo['files']) && in_array('ext_tables_static+adt.sql',$extInfo['files'])) { 4472 $fileContent = t3lib_div::getUrl($this->getExtPath($extKey,$extInfo['type']).'ext_tables_static+adt.sql'); 4473 4474 $statements = $instObj->getStatementArray($fileContent,1); 4475 list($statements_table, $insertCount) = $instObj->getCreateTables($statements,1); 4476 4477 // Execute import of static table content: 4478 if (!$infoOnly && is_array($instObj->INSTALL['database_import'])) { 4479 4480 // Traverse the tables 4481 foreach($instObj->INSTALL['database_import'] as $table => $md5str) { 4482 if ($md5str == md5($statements_table[$table])) { 4483 $GLOBALS['TYPO3_DB']->admin_query('DROP TABLE IF EXISTS '.$table); 4484 $GLOBALS['TYPO3_DB']->admin_query($statements_table[$table]); 4485 4486 if ($insertCount[$table]) { 4487 $statements_insert = $instObj->getTableInsertStatements($statements, $table); 4488 4489 foreach($statements_insert as $v) { 4490 $GLOBALS['TYPO3_DB']->admin_query($v); 4491 } 4492 } 4493 } 4494 } 4495 } else { 4496 $whichTables = $instObj->getListOfTables(); 4497 if (count($statements_table)) { 4498 $out = ''; 4499 foreach($statements_table as $table => $definition) { 4500 $exist = isset($whichTables[$table]); 4501 4502 $dbStatus['static'][$table]['exists'] = $exist; 4503 $dbStatus['static'][$table]['count'] = $insertCount[$table]; 4504 4505 $out.= '<tr> 4506 <td><input type="checkbox" name="TYPO3_INSTALL[database_import]['.$table.']" checked="checked" value="'.md5($definition).'" /></td> 4507 <td><strong>'.$table.'</strong></td> 4508 <td><img src="clear.gif" width="10" height="1" alt="" /></td> 4509 <td nowrap="nowrap">'.($insertCount[$table]?'Rows: '.$insertCount[$table]:'').'</td> 4510 <td><img src="clear.gif" width="10" height="1" alt="" /></td> 4511 <td nowrap="nowrap">'.($exist?'<img src="'.$GLOBALS['BACK_PATH'].'gfx/icon_warning.gif" width="18" height="16" align="top" alt="" />Table exists!':'').'</td> 4512 </tr>'; 4513 } 4514 $content.= ' 4515 <br /> 4516 <h3>Import static data</h3> 4517 <table border="0" cellpadding="0" cellspacing="0">'.$out.'</table>'; 4518 } 4519 } 4520 } 4521 4522 // Return array of information if $infoOnly, otherwise content. 4523 return $infoOnly ? $dbStatus : $content; 4524 } 4525 4526 /** 4527 * Updates the database according to extension requirements 4528 * DBAL compliant (based on Install Tool code) 4529 * 4530 * @param string Extension key 4531 * @param array Extension information array 4532 * @return void 4533 */ 4534 function forceDBupdates($extKey, $extInfo) { 4535 $instObj = new t3lib_install; 4536 4537 // Updating tables and fields? 4538 if (is_array($extInfo['files']) && in_array('ext_tables.sql',$extInfo['files'])) { 4539 $fileContent = t3lib_div::getUrl($this->getExtPath($extKey,$extInfo['type']).'ext_tables.sql'); 4540 4541 $FDfile = $instObj->getFieldDefinitions_sqlContent($fileContent); 4542 if (count($FDfile)) { 4543 $FDdb = $instObj->getFieldDefinitions_database(TYPO3_db); 4544 $diff = $instObj->getDatabaseExtra($FDfile, $FDdb); 4545 $update_statements = $instObj->getUpdateSuggestions($diff); 4546 4547 foreach((array)$update_statements['add'] as $string) { 4548 $GLOBALS['TYPO3_DB']->admin_query($string); 4549 } 4550 foreach((array)$update_statements['change'] as $string) { 4551 $GLOBALS['TYPO3_DB']->admin_query($string); 4552 } 4553 foreach((array)$update_statements['create_table'] as $string) { 4554 $GLOBALS['TYPO3_DB']->admin_query($string); 4555 } 4556 } 4557 } 4558 4559 // Importing static tables? 4560 if (is_array($extInfo['files']) && in_array('ext_tables_static+adt.sql',$extInfo['files'])) { 4561 $fileContent = t3lib_div::getUrl($this->getExtPath($extKey,$extInfo['type']).'ext_tables_static+adt.sql'); 4562 4563 $statements = $instObj->getStatementArray($fileContent,1); 4564 list($statements_table, $insertCount) = $instObj->getCreateTables($statements,1); 4565 4566 // Traverse the tables 4567 foreach($statements_table as $table => $query) { 4568 $GLOBALS['TYPO3_DB']->admin_query('DROP TABLE IF EXISTS '.$table); 4569 $GLOBALS['TYPO3_DB']->admin_query($query); 4570 4571 if ($insertCount[$table]) { 4572 $statements_insert = $instObj->getTableInsertStatements($statements, $table); 4573 4574 foreach($statements_insert as $v) { 4575 $GLOBALS['TYPO3_DB']->admin_query($v); 4576 } 4577 } 4578 } 4579 } 4580 } 4581 4582 /** 4583 * Produces the config form for an extension (if any template file, ext_conf_template.txt is found) 4584 * 4585 * @param string Extension key 4586 * @param array Extension information array 4587 * @param boolean If true, the form HTML content is returned, otherwise the content is set in $this->content. 4588 * @param string Submit-to URL (supposedly) 4589 * @param string Additional form fields to include. 4590 * @return string Depending on $output. Can return the whole form. 4591 */ 4592 function tsStyleConfigForm($extKey,$extInfo,$output=0,$script='',$addFields='') { 4593 global $TYPO3_CONF_VARS; 4594 4595 // Initialize: 4596 $absPath = $this->getExtPath($extKey,$extInfo['type']); 4597 $relPath = $this->typeRelPaths[$extInfo['type']].$extKey.'/'; 4598 4599 // Look for template file for form: 4600 if (@is_file($absPath.'ext_conf_template.txt')) { 4601 4602 // Load tsStyleConfig class and parse configuration template: 4603 $tsStyleConfig = t3lib_div::makeInstance('t3lib_tsStyleConfig'); 4604 $tsStyleConfig->doNotSortCategoriesBeforeMakingForm = TRUE; 4605 $theConstants = $tsStyleConfig->ext_initTSstyleConfig( 4606 t3lib_div::getUrl($absPath.'ext_conf_template.txt'), 4607 $relPath, 4608 $absPath, 4609 $GLOBALS['BACK_PATH'] 4610 ); 4611 4612 // Load the list of resources. 4613 $tsStyleConfig->ext_loadResources($absPath.'res/'); 4614 4615 // Load current value: 4616 $arr = unserialize($TYPO3_CONF_VARS['EXT']['extConf'][$extKey]); 4617 $arr = is_array($arr) ? $arr : array(); 4618 4619 // Call processing function for constants config and data before write and form rendering: 4620 if (is_array($TYPO3_CONF_VARS['SC_OPTIONS']['typo3/mod/tools/em/index.php']['tsStyleConfigForm'])) { 4621 $_params = array('fields' => &$theConstants, 'data' => &$arr, 'extKey' => $extKey); 4622 foreach($TYPO3_CONF_VARS['SC_OPTIONS']['typo3/mod/tools/em/index.php']['tsStyleConfigForm'] as $_funcRef) { 4623 t3lib_div::callUserFunction($_funcRef,$_params,$this); 4624 } 4625 unset($_params); 4626 } 4627 4628 // If saving operation is done: 4629 if (t3lib_div::_POST('submit')) { 4630 $tsStyleConfig->ext_procesInput(t3lib_div::_POST(),array(),$theConstants,array()); 4631 $arr = $tsStyleConfig->ext_mergeIncomingWithExisting($arr); 4632 $this->writeTsStyleConfig($extKey,$arr); 4633 } 4634 4635 // Setting value array 4636 $tsStyleConfig->ext_setValueArray($theConstants,$arr); 4637 4638 // Getting session data: 4639 $MOD_MENU = array(); 4640 $MOD_MENU['constant_editor_cat'] = $tsStyleConfig->ext_getCategoriesForModMenu(); 4641 $MOD_SETTINGS = t3lib_BEfunc::getModuleData($MOD_MENU, t3lib_div::_GP('SET'), 'xMod_test'); 4642 4643 // Resetting the menu (stop) 4644 if (count($MOD_MENU)>1) { 4645 $menu = 'Category: '.t3lib_BEfunc::getFuncMenu(0,'SET[constant_editor_cat]',$MOD_SETTINGS['constant_editor_cat'],$MOD_MENU['constant_editor_cat'],'','&CMD[showExt]='.$extKey); 4646 $this->content.=$this->doc->section('','<span class="nobr">'.$menu.'</span>'); 4647 $this->content.=$this->doc->spacer(10); 4648 } 4649 4650 // Category and constant editor config: 4651 $form = ' 4652 <table border="0" cellpadding="0" cellspacing="0" width="600"> 4653 <tr> 4654 <td>'.$tsStyleConfig->ext_getForm($MOD_SETTINGS['constant_editor_cat'],$theConstants,$script,$addFields).'</td> 4655 </tr> 4656 </table>'; 4657 if ($output) { 4658 return $form; 4659 } else { 4660 $this->content.=$this->doc->section('','</form>'.$form.'<form>'); 4661 } 4662 } 4663 } 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 /******************************* 4675 * 4676 * Dumping database (MySQL compliant) 4677 * 4678 ******************************/ 4679 4680 /** 4681 * Makes a dump of the tables/fields definitions for an extension 4682 * 4683 * @param array Array with table => field/key definition arrays in 4684 * @return string SQL for the table definitions 4685 * @see dumpStaticTables() 4686 */ 4687 function dumpTableAndFieldStructure($arr) { 4688 $tables = array(); 4689 4690 if (count($arr)) { 4691 4692 // Get file header comment: 4693 $tables[] = $this->dumpHeader(); 4694 4695 // Traverse tables, write each table/field definition: 4696 foreach($arr as $table => $fieldKeyInfo) { 4697 $tables[] = $this->dumpTableHeader($table,$fieldKeyInfo); 4698 } 4699 } 4700 4701 // Return result: 4702 return implode(chr(10).chr(10).chr(10),$tables); 4703 } 4704 4705 /** 4706 * Dump content for static tables 4707 * 4708 * @param string Comma list of tables from which to dump content 4709 * @return string Returns the content 4710 * @see dumpTableAndFieldStructure() 4711 */ 4712 function dumpStaticTables($tableList) { 4713 $instObj = new t3lib_install; 4714 $dbFields = $instObj->getFieldDefinitions_database(TYPO3_db); 4715 4716 $out = ''; 4717 $parts = t3lib_div::trimExplode(',',$tableList,1); 4718 4719 // Traverse the table list and dump each: 4720 foreach($parts as $table) { 4721 if (is_array($dbFields[$table]['fields'])) { 4722 $dHeader = $this->dumpHeader(); 4723 $header = $this->dumpTableHeader($table,$dbFields[$table],1); 4724 $insertStatements = $this->dumpTableContent($table,$dbFields[$table]['fields']); 4725 4726 $out.= $dHeader.chr(10).chr(10).chr(10). 4727 $header.chr(10).chr(10).chr(10). 4728 $insertStatements.chr(10).chr(10).chr(10); 4729 } else { 4730 die('Fatal error: Table for dump not found in database...'); 4731 } 4732 } 4733 return $out; 4734 } 4735 4736 /** 4737 * Header comments of the SQL dump file 4738 * 4739 * @return string Table header 4740 */ 4741 function dumpHeader() { 4742 return trim(' 4743 # TYPO3 Extension Manager dump 1.1 4744 # 4745 # Host: '.TYPO3_db_host.' Database: '.TYPO3_db.' 4746 #-------------------------------------------------------- 4747 '); 4748 } 4749 4750 /** 4751 * Dump CREATE TABLE definition 4752 * 4753 * @param string Table name 4754 * @param array Field and key information (as provided from Install Tool class!) 4755 * @param boolean If true, add "DROP TABLE IF EXISTS" 4756 * @return string Table definition SQL 4757 */ 4758 function dumpTableHeader($table,$fieldKeyInfo,$dropTableIfExists=0) { 4759 $lines = array(); 4760 $dump = ''; 4761 4762 // Create field definitions 4763 if (is_array($fieldKeyInfo['fields'])) { 4764 foreach($fieldKeyInfo['fields'] as $fieldN => $data) { 4765 $lines[]=' '.$fieldN.' '.$data; 4766 } 4767 } 4768 4769 // Create index key definitions 4770 if (is_array($fieldKeyInfo['keys'])) { 4771 foreach($fieldKeyInfo['keys'] as $fieldN => $data) { 4772 $lines[]=' '.$data; 4773 } 4774 } 4775 4776 // Compile final output: 4777 if (count($lines)) { 4778 $dump = trim(' 4779 # 4780 # Table structure for table "'.$table.'" 4781 # 4782 '.($dropTableIfExists ? 'DROP TABLE IF EXISTS '.$table.'; 4783 ' : '').'CREATE TABLE '.$table.' ( 4784 '.implode(','.chr(10),$lines).' 4785 );' 4786 ); 4787 } 4788 4789 return $dump; 4790 } 4791 4792 /** 4793 * Dump table content 4794 * Is DBAL compliant, but the dump format is written as MySQL standard. If the INSERT statements should be imported in a DBMS using other quoting than MySQL they must first be translated. t3lib_sqlengine can parse these queries correctly and translate them somehow. 4795 * 4796 * @param string Table name 4797 * @param array Field structure 4798 * @return string SQL Content of dump (INSERT statements) 4799 */ 4800 function dumpTableContent($table,$fieldStructure) { 4801 4802 // Substitution of certain characters (borrowed from phpMySQL): 4803 $search = array('\\', '\'', "\x00", "\x0a", "\x0d", "\x1a"); 4804 $replace = array('\\\\', '\\\'', '\0', '\n', '\r', '\Z'); 4805 4806 $lines = array(); 4807 4808 // Select all rows from the table: 4809 $result = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', $table, ''); 4810 4811 // Traverse the selected rows and dump each row as a line in the file: 4812 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result)) { 4813 $values = array(); 4814 reset($fieldStructure); 4815 while(list($field) = each($fieldStructure)) { 4816 $values[] = isset($row[$field]) ? "'".str_replace($search, $replace, $row[$field])."'" : 'NULL'; 4817 } 4818 $lines[] = 'INSERT INTO '.$table.' VALUES ('.implode(', ',$values).');'; 4819 } 4820 4821 // Free DB result: 4822 $GLOBALS['TYPO3_DB']->sql_free_result($result); 4823 4824 // Implode lines and return: 4825 return implode(chr(10),$lines); 4826 } 4827 4828 /** 4829 * Gets the table and field structure from database. 4830 * Which fields and which tables are determined from the ext_tables.sql file 4831 * 4832 * @param string Array with table.field values 4833 * @return array Array of tables and fields splitted. 4834 */ 4835 function getTableAndFieldStructure($parts) { 4836 // Instance of install tool 4837 $instObj = new t3lib_install; 4838 $dbFields = $instObj->getFieldDefinitions_database(TYPO3_db); 4839 4840 4841 $outTables = array(); 4842 foreach($parts as $table) { 4843 $tP = explode('.',$table); 4844 if ($tP[0] && isset($dbFields[$tP[0]])) { 4845 if ($tP[1]) { 4846 $kfP = explode('KEY:',$tP[1],2); 4847 if (count($kfP)==2 && !$kfP[0]) { // key: 4848 if (isset($dbFields[$tP[0]]['keys'][$kfP[1]])) $outTables[$tP[0]]['keys'][$kfP[1]] = $dbFields[$tP[0]]['keys'][$kfP[1]]; 4849 } else { 4850 if (isset($dbFields[$tP[0]]['fields'][$tP[1]])) $outTables[$tP[0]]['fields'][$tP[1]] = $dbFields[$tP[0]]['fields'][$tP[1]]; 4851 } 4852 } else { 4853 $outTables[$tP[0]] = $dbFields[$tP[0]]; 4854 } 4855 } 4856 } 4857 4858 return $outTables; 4859 } 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 /******************************* 4871 * 4872 * TER Communication functions 4873 * 4874 ******************************/ 4875 4876 4877 4878 /** 4879 * Processes return-data from online repository. 4880 * Currently only the returned emconf array is written to extension. 4881 * 4882 * @param array Command array returned from TER 4883 * @return string Message 4884 */ 4885 function uploadExtensionToTER($em) { 4886 $msg = ''; 4887 $response = $this->terConnection->uploadToTER($em); 4888 4889 if(!is_array($response)) return $response; 4890 4891 if($response['resultCode']==TX_TER_RESULT_EXTENSIONSUCCESSFULLYUPLOADED) { 4892 $em['extInfo']['EM_CONF']['version'] = $response['version']; 4893 $response['resultMessages'][] = 'The extension is now version: '.$response['version']; 4894 $response['resultMessages'][] = $this->updateLocalEM_CONF($em['extKey'],$em['extInfo']); 4895 } 4896 4897 $msg = '<ul><li>'.implode('</li><li>',$response['resultMessages']).'</li></ul>'; 4898 return $msg; 4899 } 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 /************************************ 4911 * 4912 * Various helper functions 4913 * 4914 ************************************/ 4915 4916 /** 4917 * Returns subtitles for the extension listings 4918 * 4919 * @param string List order type 4920 * @param string Key value 4921 * @return string output. 4922 */ 4923 function listOrderTitle($listOrder,$key) { 4924 switch($listOrder) { 4925 case 'cat': 4926 return isset($this->categories[$key])?$this->categories[$key]:'<em>['.$key.']</em>'; 4927 break; 4928 case 'author_company': 4929 return $key; 4930 break; 4931 case 'state': 4932 return $this->states[$key]; 4933 break; 4934 case 'type': 4935 return $this->typeDescr[$key]; 4936 break; 4937 } 4938 } 4939 4940 /** 4941 * Returns version information 4942 * 4943 * @param string Version code, x.x.x 4944 * @param string part: "", "int", "main", "sub", "dev" 4945 * @return string 4946 * @see renderVersion() 4947 */ 4948 function makeVersion($v,$mode) { 4949 $vDat = $this->renderVersion($v); 4950 return $vDat['version_'.$mode]; 4951 } 4952 4953 /** 4954 * Parses the version number x.x.x and returns an array with the various parts. 4955 * 4956 * @param string Version code, x.x.x 4957 * @param string Increase version part: "main", "sub", "dev" 4958 * @return string 4959 */ 4960 function renderVersion($v,$raise='') { 4961 $parts = t3lib_div::intExplode('.',$v.'..'); 4962 $parts[0] = t3lib_div::intInRange($parts[0],0,999); 4963 $parts[1] = t3lib_div::intInRange($parts[1],0,999); 4964 $parts[2] = t3lib_div::intInRange($parts[2],0,999); 4965 4966 switch((string)$raise) { 4967 case 'main': 4968 $parts[0]++; 4969 $parts[1]=0; 4970 $parts[2]=0; 4971 break; 4972 case 'sub': 4973 $parts[1]++; 4974 $parts[2]=0; 4975 break; 4976 case 'dev': 4977 $parts[2]++; 4978 break; 4979 } 4980 4981 $res = array(); 4982 $res['version'] = $parts[0].'.'.$parts[1].'.'.$parts[2]; 4983 $res['version_int'] = intval($parts[0]*1000000+$parts[1]*1000+$parts[2]); 4984 $res['version_main'] = $parts[0]; 4985 $res['version_sub'] = $parts[1]; 4986 $res['version_dev'] = $parts[2]; 4987 4988 return $res; 4989 } 4990 4991 /** 4992 * Returns upload folder for extension 4993 * 4994 * @param string Extension key 4995 * @return string Upload folder for extension 4996 */ 4997 function ulFolder($extKey) { 4998 return 'uploads/tx_'.str_replace('_','',$extKey).'/'; 4999 } 5000 5001 /** 5002 * Returns true if global OR local installation of extensions is allowed/possible. 5003 * 5004 * @return boolean Returns true if global OR local installation of extensions is allowed/possible. 5005 */ 5006 function importAtAll() { 5007 return ($GLOBALS['TYPO3_CONF_VARS']['EXT']['allowGlobalInstall'] || $GLOBALS['TYPO3_CONF_VARS']['EXT']['allowLocalInstall']); 5008 } 5009 5010 /** 5011 * Reports back if installation in a certain scope is possible. 5012 * 5013 * @param string Scope: G, L, S 5014 * @param string Extension lock-type (eg. "L" or "G") 5015 * @return boolean True if installation is allowed. 5016 */ 5017 function importAsType($type,$lockType='') { 5018 switch($type) { 5019 case 'G': 5020 return $GLOBALS['TYPO3_CONF_VARS']['EXT']['allowGlobalInstall'] && (!$lockType || !strcmp($lockType,$type)); 5021 break; 5022 case 'L': 5023 return $GLOBALS['TYPO3_CONF_VARS']['EXT']['allowLocalInstall'] && (!$lockType || !strcmp($lockType,$type)); 5024 break; 5025 case 'S': 5026 return $this->systemInstall; 5027 break; 5028 default: 5029 return false; 5030 } 5031 } 5032 5033 /** 5034 * Returns true if extensions in scope, $type, can be deleted (or installed for that sake) 5035 * 5036 * @param string Scope: "G" or "L" 5037 * @return boolean True if possible. 5038 */ 5039 function deleteAsType($type) { 5040 switch($type) { 5041 case 'G': 5042 return $GLOBALS['TYPO3_CONF_VARS']['EXT']['allowGlobalInstall']; 5043 break; 5044 case 'L': 5045 return $GLOBALS['TYPO3_CONF_VARS']['EXT']['allowLocalInstall']; 5046 break; 5047 default: 5048 return false; 5049 } 5050 } 5051 5052 /** 5053 * Evaluates differences in version numbers with three parts, x.x.x. Returns true if $v1 is greater than $v2 5054 * 5055 * @param string Version number 1 5056 * @param string Version number 2 5057 * @param integer Tolerance factor. For instance, set to 1000 to ignore difference in dev-version (third part) 5058 * @return boolean True if version 1 is greater than version 2 5059 */ 5060 function versionDifference($v1,$v2,$div=1) { 5061 return floor($this->makeVersion($v1,'int')/$div) > floor($this->makeVersion($v2,'int')/$div); 5062 } 5063 5064 /** 5065 * Returns true if the $str is found as the first part of a string in $array 5066 * 5067 * @param string String to test with. 5068 * @param array Input array 5069 * @param boolean If set, the test is case insensitive 5070 * @return boolean True if found. 5071 */ 5072 function first_in_array($str,$array,$caseInsensitive=FALSE) { 5073 if ($caseInsensitive) $str = strtolower($str); 5074 if (is_array($array)) { 5075 foreach($array as $cl) { 5076 if ($caseInsensitive) $cl = strtolower($cl); 5077 if (t3lib_div::isFirstPartOfStr($cl,$str)) return true; 5078 } 5079 } 5080 return false; 5081 } 5082 5083 /** 5084 * Returns the $EM_CONF array from an extensions ext_emconf.php file 5085 * 5086 * @param string Absolute path to EMCONF file. 5087 * @param string Extension key. 5088 * @return array EMconf array values. 5089 */ 5090 function includeEMCONF($path,$_EXTKEY) { 5091 @include($path); 5092 if(is_array($EM_CONF[$_EXTKEY])) { 5093 return $this->fixEMCONF($EM_CONF[$_EXTKEY]); 5094 } 5095 return false; 5096 } 5097 5098 /** 5099 * Searches for ->lookUpStr in extension and returns true if found (or if no search string is set) 5100 * 5101 * @param string Extension key 5102 * @param array Extension content 5103 * @return boolean If true, display extension in list 5104 */ 5105 function searchExtension($extKey,$row) { 5106 if ($this->lookUpStr) { 5107 return ( 5108 stristr($extKey,$this->lookUpStr) || 5109 stristr($row['EM_CONF']['title'],$this->lookUpStr) || 5110 stristr($row['EM_CONF']['description'],$this->lookUpStr) || 5111 stristr($row['EM_CONF']['author'],$this->lookUpStr) || 5112 stristr($row['EM_CONF']['author_company'],$this->lookUpStr) 5113 ); 5114 } else return true; 5115 } 5116 } 5117 5118 // Include extension? 5119 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['typo3/mod/tools/em/index.php']) { 5120 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['typo3/mod/tools/em/index.php']); 5121 } 5122 5123 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
| Généré le : Sun Nov 25 17:13:16 2007 | par Balluche grâce à PHPXref 0.7 |
|