|
TYPO3 API
SVNRelease
|
00001 <?php 00002 /*************************************************************** 00003 * Copyright notice 00004 * 00005 * (c) 1999-2011 Kasper Skårhøj (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 ***************************************************************/ 00027 /** 00028 * Core functions for cleaning and analysing 00029 * 00030 * $Id: class.tx_lowlevel_cleaner_core.php 10478 2011-02-17 11:08:43Z ohader $ 00031 * 00032 * @author Kasper Skårhøj <kasperYYYY@typo3.com> 00033 */ 00034 /** 00035 * [CLASS/FUNCTION INDEX of SCRIPT] 00036 * 00037 * 00038 * 00039 * 71: class tx_lowlevel_cleaner_core extends t3lib_cli 00040 * 88: function tx_lowlevel_cleaner_core() 00041 * 00042 * SECTION: CLI functionality 00043 * 134: function cli_main($argv) 00044 * 193: function cli_referenceIndexCheck() 00045 * 228: function cli_noExecutionCheck($matchString) 00046 * 251: function cli_printInfo($header,$res) 00047 * 00048 * SECTION: Page tree traversal 00049 * 331: function genTree($rootID,$depth=1000,$echoLevel=0,$callBack='') 00050 * 369: function genTree_traverse($rootID,$depth,$echoLevel=0,$callBack='',$versionSwapmode='',$rootIsVersion=0,$accumulatedPath='') 00051 * 00052 * SECTION: Helper functions 00053 * 554: function infoStr($rec) 00054 * 00055 * TOTAL FUNCTIONS: 8 00056 * (This index is automatically created/updated by the extension "extdeveval") 00057 * 00058 */ 00059 00060 00061 /** 00062 * Core functions for cleaning and analysing 00063 * 00064 * @author Kasper Skårhøj <kasperYYYY@typo3.com> 00065 * @package TYPO3 00066 * @subpackage tx_lowlevel 00067 */ 00068 class tx_lowlevel_cleaner_core extends t3lib_cli { 00069 00070 var $genTree_traverseDeleted = TRUE; 00071 var $genTree_traverseVersions = TRUE; 00072 00073 00074 00075 var $label_infoString = 'The list of records is organized as [table]:[uid]:[field]:[flexpointer]:[softref_key]'; 00076 var $pagetreePlugins = array(); 00077 var $cleanerModules = array(); 00078 00079 var $performanceStatistics = array(); 00080 00081 protected $workspaceIndex = array(); 00082 00083 00084 /** 00085 * Constructor 00086 * 00087 * @return void 00088 */ 00089 function tx_lowlevel_cleaner_core() { 00090 00091 // Running parent class constructor 00092 parent::t3lib_cli(); 00093 00094 $this->cleanerModules = (array)$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['lowlevel']['cleanerModules']; 00095 00096 // Adding options to help archive: 00097 $this->cli_options[] = array('-r', 'Execute this tool, otherwise help is shown'); 00098 $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"); 00099 $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")'); 00100 $this->cli_options[] = array('--AUTOFIX [testName]', '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! The optional parameter "[testName]" works for some tool keys to limit the fixing to a particular test.'); 00101 $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'); 00102 $this->cli_options[] = array('--YES', 'Implicit YES to all questions','Use this with EXTREME care. The option "-i" is not affected by this option.'); 00103 $this->cli_options[] = array('-i', 'Interactive','Will ask you before running the AUTOFIX on each element.'); 00104 $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!'); 00105 $this->cli_options[] = array('--showhowto', 'Displays HOWTO file for cleaner script.'); 00106 00107 // Setting help texts: 00108 $this->cli_help['name'] = 'lowlevel_cleaner -- Analysis and clean-up tools for TYPO3 installations'; 00109 $this->cli_help['synopsis'] = 'toolkey ###OPTIONS###'; 00110 $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)); 00111 $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."; 00112 $this->cli_help['author'] = "Kasper Skaarhoej, (c) 2006"; 00113 } 00114 00115 00116 00117 00118 00119 00120 00121 00122 00123 /************************** 00124 * 00125 * CLI functionality 00126 * 00127 *************************/ 00128 00129 /** 00130 * CLI engine 00131 * 00132 * @param array Command line arguments 00133 * @return string 00134 */ 00135 function cli_main($argv) { 00136 00137 // Force user to admin state and set workspace to "Live": 00138 $GLOBALS['BE_USER']->user['admin'] = 1; 00139 $GLOBALS['BE_USER']->setWorkspace(0); 00140 00141 // Print Howto: 00142 if ($this->cli_isArg('--showhowto')) { 00143 $howto = t3lib_div::getUrl(t3lib_extMgm::extPath('lowlevel').'HOWTO_clean_up_TYPO3_installations.txt'); 00144 echo wordwrap($howto,120).LF; 00145 exit; 00146 } 00147 00148 // Print help 00149 $analysisType = (string)$this->cli_args['_DEFAULT'][1]; 00150 if (!$analysisType) { 00151 $this->cli_validateArgs(); 00152 $this->cli_help(); 00153 exit; 00154 } 00155 00156 // Analysis type: 00157 switch((string)$analysisType) { 00158 default: 00159 if (is_array($this->cleanerModules[$analysisType])) { 00160 $cleanerMode = t3lib_div::getUserObj($this->cleanerModules[$analysisType][0]); 00161 $cleanerMode->cli_validateArgs(); 00162 00163 if ($this->cli_isArg('-r')) { // Run it... 00164 if (!$cleanerMode->checkRefIndex || $this->cli_referenceIndexCheck()) { 00165 $res = $cleanerMode->main(); 00166 $this->cli_printInfo($analysisType, $res); 00167 00168 // Autofix... 00169 if ($this->cli_isArg('--AUTOFIX')) { 00170 if ($this->cli_isArg('--YES') || $this->cli_keyboardInput_yes("\n\nNOW Running --AUTOFIX on result. OK?".($this->cli_isArg('--dryrun')?' (--dryrun simulation)':''))) { 00171 $cleanerMode->main_autofix($res); 00172 } else { 00173 $this->cli_echo("ABORTING AutoFix...\n",1); 00174 } 00175 } 00176 } 00177 } else { // Help only... 00178 $cleanerMode->cli_help(); 00179 exit; 00180 } 00181 } else { 00182 $this->cli_echo("ERROR: Analysis Type '".$analysisType."' is unknown.\n",1); 00183 exit; 00184 } 00185 break; 00186 } 00187 } 00188 00189 /** 00190 * Checks reference index 00191 * 00192 * @return boolean TRUE if reference index was OK (either OK, updated or ignored) 00193 */ 00194 function cli_referenceIndexCheck() { 00195 00196 // Reference index option: 00197 $refIndexMode = isset($this->cli_args['--refindex']) ? $this->cli_args['--refindex'][0] : 'check'; 00198 if (!t3lib_div::inList('update,ignore,check', $refIndexMode)) { 00199 $this->cli_echo("ERROR: Wrong value for --refindex argument.\n",1); 00200 exit; 00201 } 00202 00203 switch($refIndexMode) { 00204 case 'check': 00205 case 'update': 00206 $refIndexObj = t3lib_div::makeInstance('t3lib_refindex'); 00207 list($headerContent,$bodyContent,$errorCount) = $refIndexObj->updateIndex($refIndexMode=='check',$this->cli_echo()); 00208 00209 if ($errorCount && $refIndexMode=='check') { 00210 $ok = FALSE; 00211 $this->cli_echo("ERROR: Reference Index Check failed! (run with '--refindex update' to fix)\n",1); 00212 } else { 00213 $ok = TRUE; 00214 } 00215 break; 00216 case 'ignore': 00217 $this->cli_echo("Reference Index Check: Bypassing reference index check...\n"); 00218 $ok = TRUE; 00219 break; 00220 } 00221 00222 return $ok; 00223 } 00224 00225 /** 00226 * @param [type] $matchString: ... 00227 * @return string If string, it's the reason for not executing. Returning FALSE means it should execute. 00228 */ 00229 function cli_noExecutionCheck($matchString) { 00230 00231 // Check for filter: 00232 if ($this->cli_isArg('--filterRegex') && $regex = $this->cli_argValue('--filterRegex',0)) { 00233 if (!preg_match($regex,$matchString)) return 'BYPASS: Filter Regex "'.$regex.'" did not match string "'.$matchString.'"'; 00234 } 00235 // Check for interactive mode 00236 if ($this->cli_isArg('-i')) { 00237 if (!$this->cli_keyboardInput_yes(' EXECUTE?')) { 00238 return 'BYPASS...'; 00239 } 00240 } 00241 // Check for 00242 if ($this->cli_isArg('--dryrun')) return 'BYPASS: --dryrun set'; 00243 } 00244 00245 /** 00246 * Formats a result array from a test so it fits output in the shell 00247 * 00248 * @param string name of the test (eg. function name) 00249 * @param array Result array from an analyze function 00250 * @return void Outputs with echo - capture content with output buffer if needed. 00251 */ 00252 function cli_printInfo($header,$res) { 00253 00254 $detailLevel = t3lib_div::intInRange($this->cli_isArg('-v') ? $this->cli_argValue('-v') : 1,0,3); 00255 $silent = !$this->cli_echo(); 00256 00257 $severity = array( 00258 0 => 'MESSAGE', 00259 1 => 'INFO', 00260 2 => 'WARNING', 00261 3 => 'ERROR', 00262 ); 00263 00264 // Header output: 00265 if ($detailLevel <= 1) { 00266 $this->cli_echo( 00267 "*********************************************\n". 00268 $header.LF. 00269 "*********************************************\n"); 00270 $this->cli_echo(wordwrap(trim($res['message'])).LF.LF); 00271 } 00272 00273 // Traverse headers for output: 00274 if (is_array($res['headers'])) { 00275 foreach($res['headers'] as $key => $value) { 00276 00277 if ($detailLevel <= intval($value[2])) { 00278 if (is_array($res[$key]) && (count($res[$key]) || !$silent)) { 00279 00280 // Header and explanaion: 00281 $this->cli_echo('---------------------------------------------'.LF,1); 00282 $this->cli_echo('['.$header.']'.LF,1); 00283 $this->cli_echo($value[0].' ['.$severity[$value[2]].']'.LF,1); 00284 $this->cli_echo('---------------------------------------------'.LF,1); 00285 if (trim($value[1])) { 00286 $this->cli_echo('Explanation: '.wordwrap(trim($value[1])).LF.LF,1); 00287 } 00288 } 00289 00290 // Content: 00291 if (is_array($res[$key])) { 00292 if (count($res[$key])) { 00293 if ($this->cli_echo('',1)) { print_r($res[$key]); } 00294 } else { 00295 $this->cli_echo('(None)'.LF.LF); 00296 } 00297 } else { 00298 $this->cli_echo($res[$key].LF.LF); 00299 } 00300 } 00301 } 00302 } 00303 } 00304 00305 00306 00307 00308 00309 00310 00311 00312 00313 00314 00315 00316 /************************** 00317 * 00318 * Page tree traversal 00319 * 00320 *************************/ 00321 00322 /** 00323 * Traverses the FULL/part of page tree, mainly to register ALL validly connected records (to find orphans) but also to register deleted records, versions etc. 00324 * Output (in $this->recStats) can be useful for multiple purposes. 00325 * 00326 * @param integer Root page id from where to start traversal. Use "0" (zero) to have full page tree (necessary when spotting orphans, otherwise you can run it on parts only) 00327 * @param integer Depth to traverse. zero is do not traverse at all. 1 = 1 sublevel, 1000= 1000 sublevels (all...) 00328 * @param boolean If >0, will echo information about the traversal process. 00329 * @param string Call back function (from this class or subclass) 00330 * @return void 00331 */ 00332 function genTree($rootID,$depth=1000,$echoLevel=0,$callBack='') { 00333 00334 $pt = t3lib_div::milliseconds();$this->performanceStatistics['genTree()']=''; 00335 00336 // Initialize: 00337 if (t3lib_extMgm::isLoaded('workspaces')) { 00338 $this->workspaceIndex = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid,title','sys_workspace','1=1'.t3lib_BEfunc::deleteClause('sys_workspace'),'','','','uid'); 00339 } 00340 $this->workspaceIndex[-1] = TRUE; 00341 $this->workspaceIndex[0] = TRUE; 00342 00343 $this->recStats = array( 00344 '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) 00345 'deleted' => array(), // Subset of "alL" that are deleted-flagged [Info] 00346 'versions' => array(), // Subset of "all" which are offline versions (pid=-1). [Info] 00347 'versions_published' => array(), // Subset of "versions" that is a count of 1 or more (has been published) [Info] 00348 'versions_liveWS' => array(), // Subset of "versions" that exists in live workspace [Info] 00349 'versions_lost_workspace' => array(), // Subset of "versions" that doesn't belong to an existing workspace [Warning: Fix by move to live workspace] 00350 '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)] 00351 '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] 00352 '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] 00353 '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] 00354 ); 00355 00356 // Start traversal: 00357 $pt2 = t3lib_div::milliseconds();$this->performanceStatistics['genTree_traverse()']=''; $this->performanceStatistics['genTree_traverse():TraverseTables']=''; 00358 $this->genTree_traverse($rootID,$depth,$echoLevel,$callBack); 00359 $this->performanceStatistics['genTree_traverse()'] = t3lib_div::milliseconds()-$pt2; 00360 00361 // Sort recStats (for diff'able displays) 00362 foreach($this->recStats as $kk => $vv) { 00363 foreach($this->recStats[$kk] as $tables => $recArrays) { 00364 ksort($this->recStats[$kk][$tables]); 00365 } 00366 ksort($this->recStats[$kk]); 00367 } 00368 00369 if ($echoLevel>0) echo LF.LF; 00370 00371 00372 // Processing performance statistics: 00373 $this->performanceStatistics['genTree()'] = t3lib_div::milliseconds()-$pt; 00374 00375 // Count records: 00376 foreach($GLOBALS['TCA'] as $tableName => $cfg) { 00377 // Select all records belonging to page: 00378 $resSub = $GLOBALS['TYPO3_DB']->exec_SELECTquery( 00379 'count(*)', 00380 $tableName, 00381 '' 00382 ); 00383 $countRow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($resSub); 00384 $this->performanceStatistics['MySQL_count'][$tableName]=$countRow['count(*)']; 00385 $this->performanceStatistics['CSV'].=LF.$tableName.','. 00386 $this->performanceStatistics['genTree_traverse():TraverseTables:']['MySQL'][$tableName].','. 00387 $this->performanceStatistics['genTree_traverse():TraverseTables:']['Proc'][$tableName].','. 00388 $this->performanceStatistics['MySQL_count'][$tableName]; 00389 } 00390 00391 $this->performanceStatistics['recStats_size']['(ALL)']=strlen(serialize($this->recStats)); 00392 foreach($this->recStats as $key => $arrcontent) { 00393 $this->performanceStatistics['recStats_size'][$key]=strlen(serialize($arrcontent)); 00394 } 00395 } 00396 00397 /** 00398 * Recursive traversal of page tree: 00399 * 00400 * @param integer Page root id (must be online, valid page record - or zero for page tree root) 00401 * @param integer Depth 00402 * @param integer Echo Level 00403 * @param string Call back function (from this class or subclass) 00404 * @param string DON'T set from outside, internal. (indicates we are inside a version of a page) 00405 * @param integer DON'T set from outside, internal. (1: Indicates that rootID is a version of a page, 2: ...that it is even a version of a version (which triggers a warning!) 00406 * @param string Internal string that accumulates the path 00407 * @return void 00408 * @access private 00409 */ 00410 function genTree_traverse($rootID,$depth,$echoLevel=0,$callBack='',$versionSwapmode='',$rootIsVersion=0,$accumulatedPath='') { 00411 00412 // Register page: 00413 $this->recStats['all']['pages'][$rootID] = $rootID; 00414 $pageRecord = t3lib_BEfunc::getRecordRaw('pages','uid='.intval($rootID),'deleted,title,t3ver_count,t3ver_wsid'); 00415 $accumulatedPath.='/'.$pageRecord['title']; 00416 00417 // Register if page is deleted: 00418 if ($pageRecord['deleted']) { 00419 $this->recStats['deleted']['pages'][$rootID] = $rootID; 00420 } 00421 // 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. 00422 if ($rootIsVersion) { 00423 $this->recStats['versions']['pages'][$rootID] = $rootID; 00424 if ($pageRecord['t3ver_count']>=1 && $pageRecord['t3ver_wsid']==0) { // If it has been published and is in archive now... 00425 $this->recStats['versions_published']['pages'][$rootID] = $rootID; 00426 } 00427 if ($pageRecord['t3ver_wsid']==0) { // If it has been published and is in archive now... 00428 $this->recStats['versions_liveWS']['pages'][$rootID] = $rootID; 00429 } 00430 if (!isset($this->workspaceIndex[$pageRecord['t3ver_wsid']])) { // If it doesn't belong to a workspace... 00431 $this->recStats['versions_lost_workspace']['pages'][$rootID] = $rootID; 00432 } 00433 if ($rootIsVersion==2) { // In case the rootID is a version inside a versioned page 00434 $this->recStats['versions_inside_versioned_page']['pages'][$rootID] = $rootID; 00435 } 00436 } 00437 00438 if ($echoLevel>0) 00439 echo LF.$accumulatedPath.' ['.$rootID.']'. 00440 ($pageRecord['deleted'] ? ' (DELETED)':''). 00441 ($this->recStats['versions_published']['pages'][$rootID] ? ' (PUBLISHED)':'') 00442 ; 00443 if ($echoLevel>1 && $this->recStats['versions_lost_workspace']['pages'][$rootID]) 00444 echo LF.' ERROR! This version belongs to non-existing workspace ('.$pageRecord['t3ver_wsid'].')!'; 00445 if ($echoLevel>1 && $this->recStats['versions_inside_versioned_page']['pages'][$rootID]) 00446 echo LF.' WARNING! This version is inside an already versioned page or branch!'; 00447 00448 // Call back: 00449 if ($callBack) { 00450 $this->$callBack('pages',$rootID,$echoLevel,$versionSwapmode,$rootIsVersion); 00451 } 00452 00453 $pt3 = t3lib_div::milliseconds(); 00454 00455 // Traverse tables of records that belongs to page: 00456 foreach($GLOBALS['TCA'] as $tableName => $cfg) { 00457 if ($tableName!='pages') { 00458 00459 // Select all records belonging to page: 00460 $pt4=t3lib_div::milliseconds(); 00461 $resSub = $GLOBALS['TYPO3_DB']->exec_SELECTquery( 00462 'uid'.($GLOBALS['TCA'][$tableName]['ctrl']['delete']?','.$GLOBALS['TCA'][$tableName]['ctrl']['delete']:''), 00463 $tableName, 00464 'pid='.intval($rootID). 00465 ($this->genTree_traverseDeleted ? '' : t3lib_BEfunc::deleteClause($tableName)) 00466 ); 00467 $this->performanceStatistics['genTree_traverse():TraverseTables:']['MySQL']['(ALL)']+= t3lib_div::milliseconds()-$pt4; 00468 $this->performanceStatistics['genTree_traverse():TraverseTables:']['MySQL'][$tableName]+= t3lib_div::milliseconds()-$pt4; 00469 00470 $pt5=t3lib_div::milliseconds(); 00471 $count = $GLOBALS['TYPO3_DB']->sql_num_rows($resSub); 00472 if ($count) { 00473 if ($echoLevel==2) echo LF.' \-'.$tableName.' ('.$count.')'; 00474 } 00475 00476 while ($rowSub = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($resSub)) { 00477 if ($echoLevel==3) echo LF.' \-'.$tableName.':'.$rowSub['uid']; 00478 00479 // 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: 00480 if ($versionSwapmode=='SWAPMODE:-1' || ($versionSwapmode=='SWAPMODE:0' && !$GLOBALS['TCA'][$tableName]['ctrl']['versioning_followPages'])) { 00481 // This is illegal records under a versioned page - therefore not registered in $this->recStats['all'] so they should be orphaned: 00482 $this->recStats['illegal_record_under_versioned_page'][$tableName][$rowSub['uid']] = $rowSub['uid']; 00483 if ($echoLevel>1) echo LF.' ERROR! Illegal record ('.$tableName.':'.$rowSub['uid'].') under versioned page!'; 00484 } else { 00485 $this->recStats['all'][$tableName][$rowSub['uid']] = $rowSub['uid']; 00486 00487 // Register deleted: 00488 if ($GLOBALS['TCA'][$tableName]['ctrl']['delete'] && $rowSub[$GLOBALS['TCA'][$tableName]['ctrl']['delete']]) { 00489 $this->recStats['deleted'][$tableName][$rowSub['uid']] = $rowSub['uid']; 00490 if ($echoLevel==3) echo ' (DELETED)'; 00491 } 00492 00493 // Check location of records regarding tree root: 00494 if (!$GLOBALS['TCA'][$tableName]['ctrl']['rootLevel'] && $rootID==0) { 00495 $this->recStats['misplaced_at_rootlevel'][$tableName][$rowSub['uid']] = $rowSub['uid']; 00496 if ($echoLevel>1) echo LF.' ERROR! Misplaced record ('.$tableName.':'.$rowSub['uid'].') on rootlevel!'; 00497 } 00498 if ($GLOBALS['TCA'][$tableName]['ctrl']['rootLevel']==1 && $rootID>0) { 00499 $this->recStats['misplaced_inside_tree'][$tableName][$rowSub['uid']] = $rowSub['uid']; 00500 if ($echoLevel>1) echo LF.' ERROR! Misplaced record ('.$tableName.':'.$rowSub['uid'].') inside page tree!'; 00501 } 00502 00503 // Traverse plugins: 00504 if ($callBack) { 00505 $this->$callBack($tableName,$rowSub['uid'],$echoLevel,$versionSwapmode,$rootIsVersion); 00506 } 00507 00508 // Add any versions of those records: 00509 if ($this->genTree_traverseVersions) { 00510 $versions = t3lib_BEfunc::selectVersionsOfRecord($tableName, $rowSub['uid'], 'uid,t3ver_wsid,t3ver_count'.($GLOBALS['TCA'][$tableName]['ctrl']['delete']?','.$GLOBALS['TCA'][$tableName]['ctrl']['delete']:''), 0, TRUE); 00511 if (is_array($versions)) { 00512 foreach($versions as $verRec) { 00513 if (!$verRec['_CURRENT_VERSION']) { 00514 if ($echoLevel==3) echo LF.' \-[#OFFLINE VERSION: WS#'.$verRec['t3ver_wsid'].'/Cnt:'.$verRec['t3ver_count'].'] '.$tableName.':'.$verRec['uid'].')'; 00515 $this->recStats['all'][$tableName][$verRec['uid']] = $verRec['uid']; 00516 00517 // Register deleted: 00518 if ($GLOBALS['TCA'][$tableName]['ctrl']['delete'] && $verRec[$GLOBALS['TCA'][$tableName]['ctrl']['delete']]) { 00519 $this->recStats['deleted'][$tableName][$verRec['uid']] = $verRec['uid']; 00520 if ($echoLevel==3) echo ' (DELETED)'; 00521 } 00522 00523 // Register version: 00524 $this->recStats['versions'][$tableName][$verRec['uid']] = $verRec['uid']; 00525 if ($verRec['t3ver_count']>=1 && $verRec['t3ver_wsid']==0) { // Only register published versions in LIVE workspace (published versions in draft workspaces are allowed) 00526 $this->recStats['versions_published'][$tableName][$verRec['uid']] = $verRec['uid']; 00527 if ($echoLevel==3) echo ' (PUBLISHED)'; 00528 } 00529 if ($verRec['t3ver_wsid']==0) { 00530 $this->recStats['versions_liveWS'][$tableName][$verRec['uid']] = $verRec['uid']; 00531 } 00532 if (!isset($this->workspaceIndex[$verRec['t3ver_wsid']])) { 00533 $this->recStats['versions_lost_workspace'][$tableName][$verRec['uid']] = $verRec['uid']; 00534 if ($echoLevel>1) echo LF.' ERROR! Version ('.$tableName.':'.$verRec['uid'].') belongs to non-existing workspace ('.$verRec['t3ver_wsid'].')!'; 00535 } 00536 if ($versionSwapmode) { // In case we are inside a versioned branch, there should not exists versions inside that "branch". 00537 $this->recStats['versions_inside_versioned_page'][$tableName][$verRec['uid']] = $verRec['uid']; 00538 if ($echoLevel>1) echo LF.' ERROR! This version ('.$tableName.':'.$verRec['uid'].') is inside an already versioned page or branch!'; 00539 } 00540 00541 // Traverse plugins: 00542 if ($callBack) { 00543 $this->$callBack($tableName,$verRec['uid'],$echoLevel,$versionSwapmode,$rootIsVersion); 00544 } 00545 } 00546 } 00547 } 00548 unset($versions); 00549 } 00550 } 00551 } 00552 00553 $this->performanceStatistics['genTree_traverse():TraverseTables:']['Proc']['(ALL)']+= t3lib_div::milliseconds()-$pt5; 00554 $this->performanceStatistics['genTree_traverse():TraverseTables:']['Proc'][$tableName]+= t3lib_div::milliseconds()-$pt5; 00555 00556 } 00557 } 00558 unset($resSub); 00559 unset($rowSub); 00560 $this->performanceStatistics['genTree_traverse():TraverseTables']+= t3lib_div::milliseconds()-$pt3; 00561 00562 // Find subpages to root ID and traverse (only when rootID is not a version or is a branch-version): 00563 if (!$versionSwapmode || $versionSwapmode=='SWAPMODE:1') { 00564 if ($depth>0) { 00565 $depth--; 00566 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery( 00567 'uid', 00568 'pages', 00569 'pid='.intval($rootID). 00570 ($this->genTree_traverseDeleted ? '' : t3lib_BEfunc::deleteClause('pages')), 00571 '', 00572 'sorting' 00573 ); 00574 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) { 00575 $this->genTree_traverse($row['uid'],$depth,$echoLevel,$callBack,$versionSwapmode,0,$accumulatedPath); 00576 } 00577 } 00578 00579 // Add any versions of pages 00580 if ($rootID>0 && $this->genTree_traverseVersions) { 00581 $versions = t3lib_BEfunc::selectVersionsOfRecord('pages', $rootID, 'uid,t3ver_oid,t3ver_wsid,t3ver_count,t3ver_swapmode', 0, TRUE); 00582 if (is_array($versions)) { 00583 foreach($versions as $verRec) { 00584 if (!$verRec['_CURRENT_VERSION']) { 00585 $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'].']'); 00586 } 00587 } 00588 } 00589 } 00590 } 00591 } 00592 00593 00594 00595 00596 00597 00598 00599 00600 /************************** 00601 * 00602 * Helper functions 00603 * 00604 *************************/ 00605 00606 /** 00607 * Compile info-string 00608 * 00609 * @param array Input record from sys_refindex 00610 * @return string String identifying the main record of the reference 00611 */ 00612 function infoStr($rec) { 00613 return $rec['tablename'].':'.$rec['recuid'].':'.$rec['field'].':'.$rec['flexpointer'].':'.$rec['softref_key'].($rec['deleted'] ? ' (DELETED)':''); 00614 } 00615 } 00616 00617 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/lowlevel/class.tx_lowlevel_cleaner.php'])) { 00618 include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/lowlevel/class.tx_lowlevel_cleaner.php']); 00619 } 00620 00621 ?>
1.8.0