Documentation TYPO3 par Ameos |
00001 <?php 00002 /*************************************************************** 00003 * Copyright notice 00004 * 00005 * (c) 1999-2005 Kasper Skaarhoj (kasperYYYY@typo3.com) 00006 * All rights reserved 00007 * 00008 * This script is part of the TYPO3 project. The TYPO3 project is 00009 * free software; you can redistribute it and/or modify 00010 * it under the terms of the GNU General Public License as published by 00011 * the Free Software Foundation; either version 2 of the License, or 00012 * (at your option) any later version. 00013 * 00014 * The GNU General Public License can be found at 00015 * http://www.gnu.org/copyleft/gpl.html. 00016 * A copy is found in the textfile GPL.txt and important notices to the license 00017 * from the author is found in LICENSE.txt distributed with these scripts. 00018 * 00019 * 00020 * This script is distributed in the hope that it will be useful, 00021 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00023 * GNU General Public License for more details. 00024 * 00025 * This copyright notice MUST APPEAR in all copies of the script! 00026 ***************************************************************/ 00059 require_once(PATH_t3lib.'class.t3lib_admin.php'); 00060 require_once(PATH_t3lib.'class.t3lib_cli.php'); 00061 00062 00063 00071 class tx_lowlevel_cleaner_core extends t3lib_cli { 00072 00073 var $genTree_traverseDeleted = TRUE; 00074 var $genTree_traverseVersions = TRUE; 00075 00076 00077 00078 var $label_infoString = 'The list of records is organized as [table]:[uid]:[field]:[flexpointer]:[softref_key]'; 00079 var $pagetreePlugins = array(); 00080 var $cleanerModules = array(); 00081 00082 00088 function tx_lowlevel_cleaner_core() { 00089 00090 // Running parent class constructor 00091 parent::t3lib_cli(); 00092 00093 $this->cleanerModules = (array)$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['lowlevel']['cleanerModules']; 00094 00095 // Adding options to help archive: 00096 $this->cli_options[] = array('-r', 'Execute this tool, otherwise help is shown'); 00097 $this->cli_options[] = array('-v level', 'Verbosity level 0-3', "The value of level can be:\n 0 = all output\n 1 = info and greater (default)\n 2 = warnings and greater\n 3 = errors"); 00098 $this->cli_options[] = array('--refindex mode', 'Mode for reference index handling for operations that require a clean reference index ("update"/"ignore")', 'Options are "check" (default), "update" and "ignore". By default, the reference index is checked before running analysis that require a clean index. If the check fails, the analysis is not run. You can choose to bypass this completely (using value "ignore") or ask to have the index updated right away before the analysis (using value "update")'); 00099 $this->cli_options[] = array('--AUTOFIX', 'Repairs errors that can be automatically fixed.', 'Only add this option after having run the test without it so you know what will happen when you add this option!'); 00100 $this->cli_options[] = array('--dryrun', 'With --AUTOFIX it will only simulate a repair process','You may like to use this to see what the --AUTOFIX option will be doing. It will output the whole process like if a fix really occurred but nothing is in fact happening'); 00101 $this->cli_options[] = array('--YES', 'Implicit YES to all questions','Use this with EXTREME care. The option "-i" is not affected by this option.'); 00102 $this->cli_options[] = array('-i', 'Interactive','Will ask you before running the AUTOFIX on each element.'); 00103 $this->cli_options[] = array('--filterRegex expr', 'Define an expression for preg_match() that must match the element ID in order to auto repair it','The element ID is the string in quotation marks when the text \'Cleaning ... in "ELEMENT ID"\'. "expr" is the expression for preg_match(). To match for example "Nature3.JPG" and "Holiday3.JPG" you can use "/.*3.JPG/". To match for example "Image.jpg" and "Image.JPG" you can use "/.*.jpg/i". Try a --dryrun first to see what the matches are!'); 00104 $this->cli_options[] = array('--showhowto', 'Displays HOWTO file for cleaner script.'); 00105 00106 // Setting help texts: 00107 $this->cli_help['name'] = 'lowlevel_cleaner -- Analysis and clean-up tools for TYPO3 installations'; 00108 $this->cli_help['synopsis'] = 'toolkey ###OPTIONS###'; 00109 $this->cli_help['description'] = "Dispatches to various analysis and clean-up tools which can plug into the API of this script. Typically you can run tests that will take longer than the usual max execution time of PHP. Such tasks could be checking for orphan records in the page tree or flushing all published versions in the system. For the complete list of options, please explore each of the 'toolkey' keywords below:\n\n ".implode("\n ",array_keys($this->cleanerModules)); 00110 $this->cli_help['examples'] = "/.../cli_dispatch.phpsh lowlevel_cleaner missing_files -s -r\nThis will show you missing files in the TYPO3 system and only report back if errors were found."; 00111 $this->cli_help['author'] = "Kasper Skaarhoej, (c) 2006"; 00112 } 00113 00114 00115 00116 00117 00118 00119 00120 00121 00122 /************************** 00123 * 00124 * CLI functionality 00125 * 00126 *************************/ 00127 00134 function cli_main($argv) { 00135 00136 // Force user to admin state and set workspace to "Live": 00137 $GLOBALS['BE_USER']->user['admin'] = 1; 00138 $GLOBALS['BE_USER']->setWorkspace(0); 00139 00140 // Print Howto: 00141 if ($this->cli_isArg('--showhowto')) { 00142 $howto = t3lib_div::getUrl(t3lib_extMgm::extPath('lowlevel').'HOWTO_clean_up_TYPO3_installations.txt'); 00143 echo wordwrap($howto,120).chr(10); 00144 exit; 00145 } 00146 00147 // Print help 00148 $analysisType = (string)$this->cli_args['_DEFAULT'][1]; 00149 if (!$analysisType) { 00150 $this->cli_validateArgs(); 00151 $this->cli_help(); 00152 exit; 00153 } 00154 00155 // Analysis type: 00156 switch((string)$analysisType) { 00157 default: 00158 if (is_array($this->cleanerModules[$analysisType])) { 00159 $cleanerMode = &t3lib_div::getUserObj($this->cleanerModules[$analysisType][0]); 00160 $cleanerMode->cli_validateArgs(); 00161 00162 if ($this->cli_isArg('-r')) { // Run it... 00163 if (!$cleanerMode->checkRefIndex || $this->cli_referenceIndexCheck()) { 00164 $res = $cleanerMode->main(); 00165 $this->cli_printInfo($analysisType, $res); 00166 00167 // Autofix... 00168 if ($this->cli_isArg('--AUTOFIX')) { 00169 if ($this->cli_isArg('--YES') || $this->cli_keyboardInput_yes("\n\nNOW Running --AUTOFIX on result. OK?".($this->cli_isArg('--dryrun')?' (--dryrun simulation)':''))) { 00170 $cleanerMode->main_autofix($res); 00171 } else { 00172 $this->cli_echo("ABORTING AutoFix...\n",1); 00173 } 00174 } 00175 } 00176 } else { // Help only... 00177 $cleanerMode->cli_help(); 00178 exit; 00179 } 00180 } else { 00181 $this->cli_echo("ERROR: Analysis Type '".$analysisType."' is unknown.\n",1); 00182 exit; 00183 } 00184 break; 00185 } 00186 } 00187 00193 function cli_referenceIndexCheck() { 00194 00195 // Reference index option: 00196 $refIndexMode = isset($this->cli_args['--refindex']) ? $this->cli_args['--refindex'][0] : 'check'; 00197 if (!t3lib_div::inList('update,ignore,check', $refIndexMode)) { 00198 $this->cli_echo("ERROR: Wrong value for --refindex argument.\n",1); 00199 exit; 00200 } 00201 00202 switch($refIndexMode) { 00203 case 'check': 00204 case 'update': 00205 $refIndexObj = t3lib_div::makeInstance('t3lib_refindex'); 00206 list($headerContent,$bodyContent,$errorCount) = $refIndexObj->updateIndex($refIndexMode=='check',$this->cli_echo()); 00207 00208 if ($errorCount && $refIndexMode=='check') { 00209 $ok = FALSE; 00210 $this->cli_echo("ERROR: Reference Index Check failed! (run with '--refindex update' to fix)\n",1); 00211 } else { 00212 $ok = TRUE; 00213 } 00214 break; 00215 case 'ignore': 00216 $this->cli_echo("Reference Index Check: Bypassing reference index check...\n"); 00217 $ok = TRUE; 00218 break; 00219 } 00220 00221 return $ok; 00222 } 00223 00228 function cli_noExecutionCheck($matchString) { 00229 00230 // Check for filter: 00231 if ($this->cli_isArg('--filterRegex') && $regex = $this->cli_argValue('--filterRegex',0)) { 00232 if (!preg_match($regex,$matchString)) return 'BYPASS: Filter Regex "'.$regex.'" did not match string "'.$matchString.'"'; 00233 } 00234 // Check for interactive mode 00235 if ($this->cli_isArg('-i')) { 00236 if (!$this->cli_keyboardInput_yes(' EXECUTE?')) { 00237 return 'BYPASS...'; 00238 } 00239 } 00240 // Check for 00241 if ($this->cli_isArg('--dryrun')) return 'BYPASS: --dryrun set'; 00242 } 00243 00251 function cli_printInfo($header,$res) { 00252 00253 $detailLevel = t3lib_div::intInRange($this->cli_isArg('-v') ? $this->cli_argValue('-v') : 1,0,3); 00254 $silent = !$this->cli_echo(); 00255 00256 $severity = array( 00257 0 => 'MESSAGE', 00258 1 => 'INFO', 00259 2 => 'WARNING', 00260 3 => 'ERROR', 00261 ); 00262 00263 // Header output: 00264 if ($detailLevel <= 1) { 00265 $this->cli_echo( 00266 "*********************************************\n". 00267 $header."\n". 00268 "*********************************************\n"); 00269 $this->cli_echo(wordwrap(trim($res['message'])).chr(10).chr(10)); 00270 } 00271 00272 // Traverse headers for output: 00273 if (is_array($res['headers'])) { 00274 foreach($res['headers'] as $key => $value) { 00275 00276 if ($detailLevel <= intval($value[2])) { 00277 if (is_array($res[$key]) && (count($res[$key]) || !$silent)) { 00278 00279 // Header and explanaion: 00280 $this->cli_echo('---------------------------------------------'.chr(10),1); 00281 $this->cli_echo('['.$header.']'.chr(10),1); 00282 $this->cli_echo($value[0].' ['.$severity[$value[2]].']'.chr(10),1); 00283 $this->cli_echo('---------------------------------------------'.chr(10),1); 00284 if (trim($value[1])) { 00285 $this->cli_echo('Explanation: '.wordwrap(trim($value[1])).chr(10).chr(10),1); 00286 } 00287 } 00288 00289 // Content: 00290 if (is_array($res[$key])) { 00291 if (count($res[$key])) { 00292 if ($this->cli_echo('',1)) { print_r($res[$key]); } 00293 } else { 00294 $this->cli_echo('(None)'.chr(10).chr(10)); 00295 } 00296 } else { 00297 $this->cli_echo($res[$key].chr(10).chr(10)); 00298 } 00299 } 00300 } 00301 } 00302 } 00303 00304 00305 00306 00307 00308 00309 00310 00311 00312 00313 00314 00315 /************************** 00316 * 00317 * Page tree traversal 00318 * 00319 *************************/ 00320 00331 function genTree($rootID,$depth=1000,$echoLevel=0,$callBack='') { 00332 00333 // Initialize: 00334 $this->workspaceIndex = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid,title','sys_workspace','1=1'.t3lib_BEfunc::deleteClause('sys_workspace'),'','','','uid'); 00335 $this->workspaceIndex[-1] = TRUE; 00336 $this->workspaceIndex[0] = TRUE; 00337 00338 $this->recStats = array( 00339 'all' => array(), // All records connected in tree including versions (the reverse are orphans). All Info and Warning categories below are included here (and therefore safe if you delete the reverse of the list) 00340 'deleted' => array(), // Subset of "alL" that are deleted-flagged [Info] 00341 'versions' => array(), // Subset of "all" which are offline versions (pid=-1). [Info] 00342 'versions_published' => array(), // Subset of "versions" that is a count of 1 or more (has been published) [Info] 00343 'versions_liveWS' => array(), // Subset of "versions" that exists in live workspace [Info] 00344 'versions_lost_workspace' => array(), // Subset of "versions" that doesn't belong to an existing workspace [Warning: Fix by move to live workspace] 00345 'versions_inside_versioned_page' => array(), // Subset of "versions" This is versions of elements found inside an already versioned branch / page. In real life this can work out, but is confusing and the backend should prevent this from happening to people. [Warning: Fix by deleting those versions (or publishing them)] 00346 'illegal_record_under_versioned_page' => array(), // If a page is "element" or "page" version and records are found attached to it, they might be illegally attached, so this will tell you. [Error: Fix by deleting orphans since they are not registered in "all" category] 00347 'misplaced_at_rootlevel' => array(), // Subset of "all": Those that should not be at root level but are. [Warning: Fix by moving record into page tree] 00348 'misplaced_inside_tree' => array(), // Subset of "all": Those that are inside page tree but should be at root level [Warning: Fix by setting PID to zero] 00349 ); 00350 00351 // Start traversal: 00352 $this->genTree_traverse($rootID,$depth,$echoLevel,$callBack); 00353 00354 if ($echoLevel>0) echo chr(10).chr(10); 00355 } 00356 00370 function genTree_traverse($rootID,$depth,$echoLevel=0,$callBack='',$versionSwapmode='',$rootIsVersion=0,$accumulatedPath='') { 00371 00372 // Register page: 00373 $this->recStats['all']['pages'][$rootID] = $rootID; 00374 $pageRecord = t3lib_BEfunc::getRecordRaw('pages','uid='.intval($rootID),'deleted,title,t3ver_count,t3ver_wsid'); 00375 $accumulatedPath.='/'.$pageRecord['title']; 00376 00377 // Register if page is deleted: 00378 if ($pageRecord['deleted']) { 00379 $this->recStats['deleted']['pages'][$rootID] = $rootID; 00380 } 00381 // If rootIsVersion is set it means that the input rootID is that of a version of a page. See below where the recursive call is made. 00382 if ($rootIsVersion) { 00383 $this->recStats['versions']['pages'][$rootID] = $rootID; 00384 if ($pageRecord['t3ver_count']>=1 && $pageRecord['t3ver_wsid']==0) { // If it has been published and is in archive now... 00385 $this->recStats['versions_published']['pages'][$rootID] = $rootID; 00386 } 00387 if ($pageRecord['t3ver_wsid']==0) { // If it has been published and is in archive now... 00388 $this->recStats['versions_liveWS']['pages'][$rootID] = $rootID; 00389 } 00390 if (!isset($this->workspaceIndex[$pageRecord['t3ver_wsid']])) { // If it doesn't belong to a workspace... 00391 $this->recStats['versions_lost_workspace']['pages'][$rootID] = $rootID; 00392 } 00393 if ($rootIsVersion==2) { // In case the rootID is a version inside a versioned page 00394 $this->recStats['versions_inside_versioned_page']['pages'][$rootID] = $rootID; 00395 } 00396 } 00397 00398 if ($echoLevel>0) 00399 echo chr(10).$accumulatedPath.' ['.$rootID.']'. 00400 ($pageRecord['deleted'] ? ' (DELETED)':''). 00401 ($this->recStats['versions_published']['pages'][$rootID] ? ' (PUBLISHED)':'') 00402 ; 00403 if ($echoLevel>1 && $this->recStats['versions_lost_workspace']['pages'][$rootID]) 00404 echo chr(10).' ERROR! This version belongs to non-existing workspace ('.$pageRecord['t3ver_wsid'].')!'; 00405 if ($echoLevel>1 && $this->recStats['versions_inside_versioned_page']['pages'][$rootID]) 00406 echo chr(10).' WARNING! This version is inside an already versioned page or branch!'; 00407 00408 // Call back: 00409 if ($callBack) { 00410 $this->$callBack('pages',$rootID,$echoLevel,$versionSwapmode,$rootIsVersion); 00411 } 00412 00413 // Traverse tables of records that belongs to page: 00414 foreach($GLOBALS['TCA'] as $tableName => $cfg) { 00415 if ($tableName!='pages') { 00416 00417 // Select all records belonging to page: 00418 $resSub = $GLOBALS['TYPO3_DB']->exec_SELECTquery( 00419 'uid'.($GLOBALS['TCA'][$tableName]['ctrl']['delete']?','.$GLOBALS['TCA'][$tableName]['ctrl']['delete']:''), 00420 $tableName, 00421 'pid='.intval($rootID). 00422 ($this->genTree_traverseDeleted ? '' : t3lib_BEfunc::deleteClause($tableName)) 00423 ); 00424 00425 $count = $GLOBALS['TYPO3_DB']->sql_num_rows($resSub); 00426 if ($count) { 00427 if ($echoLevel==2) echo chr(10).' \-'.$tableName.' ('.$count.')'; 00428 } 00429 00430 while ($rowSub = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($resSub)) { 00431 if ($echoLevel==3) echo chr(10).' \-'.$tableName.':'.$rowSub['uid']; 00432 00433 // If the rootID represents an "element" or "page" version type, we must check if the record from this table is allowed to belong to this: 00434 if ($versionSwapmode=='SWAPMODE:-1' || ($versionSwapmode=='SWAPMODE:0' && !$GLOBALS['TCA'][$tableName]['ctrl']['versioning_followPages'])) { 00435 // This is illegal records under a versioned page - therefore not registered in $this->recStats['all'] so they should be orphaned: 00436 $this->recStats['illegal_record_under_versioned_page'][$tableName][$rowSub['uid']] = $rowSub['uid']; 00437 if ($echoLevel>1) echo chr(10).' ERROR! Illegal record ('.$tableName.':'.$rowSub['uid'].') under versioned page!'; 00438 } else { 00439 $this->recStats['all'][$tableName][$rowSub['uid']] = $rowSub['uid']; 00440 00441 // Register deleted: 00442 if ($GLOBALS['TCA'][$tableName]['ctrl']['delete'] && $rowSub[$GLOBALS['TCA'][$tableName]['ctrl']['delete']]) { 00443 $this->recStats['deleted'][$tableName][$rowSub['uid']] = $rowSub['uid']; 00444 if ($echoLevel==3) echo ' (DELETED)'; 00445 } 00446 00447 // Check location of records regarding tree root: 00448 if (!$GLOBALS['TCA'][$tableName]['ctrl']['rootLevel'] && $rootID==0) { 00449 $this->recStats['misplaced_at_rootlevel'][$tableName][$rowSub['uid']] = $rowSub['uid']; 00450 if ($echoLevel>1) echo chr(10).' ERROR! Misplaced record ('.$tableName.':'.$rowSub['uid'].') on rootlevel!'; 00451 } 00452 if ($GLOBALS['TCA'][$tableName]['ctrl']['rootLevel']==1 && $rootID>0) { 00453 $this->recStats['misplaced_inside_tree'][$tableName][$rowSub['uid']] = $rowSub['uid']; 00454 if ($echoLevel>1) echo chr(10).' ERROR! Misplaced record ('.$tableName.':'.$rowSub['uid'].') inside page tree!'; 00455 } 00456 00457 // Traverse plugins: 00458 if ($callBack) { 00459 $this->$callBack($tableName,$rowSub['uid'],$echoLevel,$versionSwapmode,$rootIsVersion); 00460 } 00461 00462 // Add any versions of those records: 00463 if ($this->genTree_traverseVersions) { 00464 $versions = t3lib_BEfunc::selectVersionsOfRecord($tableName, $rowSub['uid'], 'uid,t3ver_wsid,t3ver_count'.($GLOBALS['TCA'][$tableName]['ctrl']['delete']?','.$GLOBALS['TCA'][$tableName]['ctrl']['delete']:''), 0, TRUE); 00465 if (is_array($versions)) { 00466 foreach($versions as $verRec) { 00467 if (!$verRec['_CURRENT_VERSION']) { 00468 if ($echoLevel==3) echo chr(10).' \-[#OFFLINE VERSION: WS#'.$verRec['t3ver_wsid'].'/Cnt:'.$verRec['t3ver_count'].'] '.$tableName.':'.$verRec['uid'].')'; 00469 $this->recStats['all'][$tableName][$verRec['uid']] = $verRec['uid']; 00470 00471 // Register deleted: 00472 if ($GLOBALS['TCA'][$tableName]['ctrl']['delete'] && $verRec[$GLOBALS['TCA'][$tableName]['ctrl']['delete']]) { 00473 $this->recStats['deleted'][$tableName][$verRec['uid']] = $verRec['uid']; 00474 if ($echoLevel==3) echo ' (DELETED)'; 00475 } 00476 00477 // Register version: 00478 $this->recStats['versions'][$tableName][$verRec['uid']] = $verRec['uid']; 00479 if ($verRec['t3ver_count']>=1 && $verRec['t3ver_wsid']==0) { // Only register published versions in LIVE workspace (published versions in draft workspaces are allowed) 00480 $this->recStats['versions_published'][$tableName][$verRec['uid']] = $verRec['uid']; 00481 if ($echoLevel==3) echo ' (PUBLISHED)'; 00482 } 00483 if ($verRec['t3ver_wsid']==0) { 00484 $this->recStats['versions_liveWS'][$tableName][$verRec['uid']] = $verRec['uid']; 00485 } 00486 if (!isset($this->workspaceIndex[$verRec['t3ver_wsid']])) { 00487 $this->recStats['versions_lost_workspace'][$tableName][$verRec['uid']] = $verRec['uid']; 00488 if ($echoLevel>1) echo chr(10).' ERROR! Version ('.$tableName.':'.$verRec['uid'].') belongs to non-existing workspace ('.$verRec['t3ver_wsid'].')!'; 00489 } 00490 if ($versionSwapmode) { // In case we are inside a versioned branch, there should not exists versions inside that "branch". 00491 $this->recStats['versions_inside_versioned_page'][$tableName][$verRec['uid']] = $verRec['uid']; 00492 if ($echoLevel>1) echo chr(10).' ERROR! This version ('.$tableName.':'.$verRec['uid'].') is inside an already versioned page or branch!'; 00493 } 00494 00495 // Traverse plugins: 00496 if ($callBack) { 00497 $this->$callBack($tableName,$verRec['uid'],$echoLevel,$versionSwapmode,$rootIsVersion); 00498 } 00499 } 00500 } 00501 } 00502 unset($versions); 00503 } 00504 } 00505 } 00506 } 00507 } 00508 unset($resSub); 00509 unset($rowSub); 00510 00511 // Find subpages to root ID and traverse (only when rootID is not a version or is a branch-version): 00512 if (!$versionSwapmode || $versionSwapmode=='SWAPMODE:1') { 00513 if ($depth>0) { 00514 $depth--; 00515 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery( 00516 'uid', 00517 'pages', 00518 'pid='.intval($rootID). 00519 ($this->genTree_traverseDeleted ? '' : t3lib_BEfunc::deleteClause('pages')), 00520 '', 00521 'sorting' 00522 ); 00523 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) { 00524 $this->genTree_traverse($row['uid'],$depth,$echoLevel,$callBack,$versionSwapmode,0,$accumulatedPath); 00525 } 00526 } 00527 00528 // Add any versions of pages 00529 if ($rootID>0 && $this->genTree_traverseVersions) { 00530 $versions = t3lib_BEfunc::selectVersionsOfRecord('pages', $rootID, 'uid,t3ver_oid,t3ver_wsid,t3ver_count,t3ver_swapmode', 0, TRUE); 00531 if (is_array($versions)) { 00532 foreach($versions as $verRec) { 00533 if (!$verRec['_CURRENT_VERSION']) { 00534 $this->genTree_traverse($verRec['uid'],$depth,$echoLevel,$callBack,'SWAPMODE:'.t3lib_div::intInRange($verRec['t3ver_swapmode'],-1,1),$versionSwapmode?2:1,$accumulatedPath.' [#OFFLINE VERSION: WS#'.$verRec['t3ver_wsid'].'/Cnt:'.$verRec['t3ver_count'].']'); 00535 } 00536 } 00537 } 00538 } 00539 } 00540 } 00541 00542 00543 00544 00545 00546 00547 00548 00549 /************************** 00550 * 00551 * Helper functions 00552 * 00553 *************************/ 00554 00561 function infoStr($rec) { 00562 return $rec['tablename'].':'.$rec['recuid'].':'.$rec['field'].':'.$rec['flexpointer'].':'.$rec['softref_key'].($rec['deleted'] ? ' (DELETED)':''); 00563 } 00564 } 00565 00566 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/lowlevel/class.tx_lowlevel_cleaner.php']) { 00567 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/lowlevel/class.tx_lowlevel_cleaner.php']); 00568 } 00569 ?>