[BUGFIX] Missing initialization of variables
[Packages/TYPO3.CMS.git] / t3lib / class.t3lib_admin.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 1999-2011 Kasper Skårhøj (kasperYYYY@typo3.com)
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
18 *
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27 /**
28 * Contains a class for evaluation of database integrity according to $TCA
29 * Most of these functions are considered obsolete!
30 *
31 * $Id$
32 * Revised for TYPO3 3.6 July/2003 by Kasper Skårhøj
33 * XHTML compliant
34 *
35 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
36 */
37 /**
38 * [CLASS/FUNCTION INDEX of SCRIPT]
39 *
40 *
41 *
42 * 93: class t3lib_admin
43 * 128: function genTree($theID, $depthData, $versions=FALSE)
44 * 217: function genTree_records($theID, $depthData, $table='', $versions=FALSE)
45 * 292: function genTreeStatus()
46 * 315: function lostRecords($pid_list)
47 * 346: function fixLostRecord($table,$uid)
48 * 367: function countRecords($pid_list)
49 * 395: function getGroupFields($mode)
50 * 429: function getFileFields($uploadfolder)
51 * 452: function getDBFields($theSearchTable)
52 * 480: function selectNonEmptyRecordsWithFkeys($fkey_arrays)
53 * 569: function testFileRefs ()
54 * 620: function testDBRefs($theArray)
55 * 658: function whereIsRecordReferenced($searchTable,$id)
56 * 695: function whereIsFileReferenced($uploadfolder,$filename)
57 *
58 * TOTAL FUNCTIONS: 14
59 * (This index is automatically created/updated by the extension "extdeveval")
60 *
61 */
62
63
64 /**
65 * This class holds functions used by the TYPO3 backend to check the integrity of the database (The DBint module, 'lowlevel' extension)
66 *
67 * Depends on: Depends on loaddbgroup from t3lib/
68 *
69 * @todo Need to really extend this class when the tcemain library has been updated and the whole API is better defined. There are some known bugs in this library. Further it would be nice with a facility to not only analyze but also clean up!
70 * @see SC_mod_tools_dbint_index::func_relations(), SC_mod_tools_dbint_index::func_records()
71 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
72 * @package TYPO3
73 * @subpackage t3lib
74 */
75 class t3lib_admin {
76 /** @var bool If set, genTree() includes deleted pages. This is default.*/
77 var $genTree_includeDeleted = TRUE;
78
79 /** @var bool If set, genTree() includes versionized pages/records. This is default.*/
80 var $genTree_includeVersions = TRUE;
81
82 /** @var bool If set, genTree() includes records from pages. */
83 var $genTree_includeRecords = FALSE;
84
85 /** @var string Extra where-clauses for the tree-selection */
86 var $perms_clause = '';
87
88 /** @var int If set, genTree() generates HTML, that visualizes the tree. */
89 var $genTree_makeHTML = 0;
90
91 // internal
92 /** @var array Will hold id/rec pairs from genTree() */
93 var $page_idArray = array();
94
95 /** @var array */
96 var $rec_idArray = array();
97
98 /** @var string Will hold the HTML-code visualising the tree. genTree() */
99 var $genTree_HTML = '';
100
101 /** @var string */
102 var $backPath = '';
103
104 // internal
105 /** @var array */
106 var $checkFileRefs = array();
107
108 /** @var array From the select-fields */
109 var $checkSelectDBRefs = array();
110
111 /** @var array From the group-fields */
112 var $checkGroupDBRefs = array();
113
114 /** @var array Statistics */
115 var $recStats = array(
116 'allValid' => array(),
117 'published_versions' => array(),
118 'deleted' => array(),
119 );
120
121 /** @var array */
122 var $lRecords = array();
123
124 /** @var string */
125 var $lostPagesList = '';
126
127
128 /**
129 * Generates a list of Page-uid's that corresponds to the tables in the tree. This list should ideally include all records in the pages-table.
130 *
131 * @param integer a pid (page-record id) from which to start making the tree
132 * @param string HTML-code (image-tags) used when this function calls itself recursively.
133 * @param boolean Internal variable, don't set from outside!
134 * @return void
135 */
136 function genTree($theID, $depthData, $versions = FALSE) {
137
138 if ($versions) {
139 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
140 'uid,title,doktype,deleted,t3ver_wsid,t3ver_id,t3ver_count,t3ver_swapmode' . (t3lib_extMgm::isLoaded('cms') ? ',hidden' : ''),
141 'pages',
142 'pid=-1 AND t3ver_oid=' . intval($theID) . ' ' . ((!$this->genTree_includeDeleted) ? 'AND deleted=0' : '') . $this->perms_clause,
143 '',
144 'sorting'
145 );
146 } else {
147 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
148 'uid,title,doktype,deleted' . (t3lib_extMgm::isLoaded('cms') ? ',hidden' : ''),
149 'pages',
150 'pid=' . intval($theID) . ' ' . ((!$this->genTree_includeDeleted) ? 'AND deleted=0' : '') . $this->perms_clause,
151 '',
152 'sorting'
153 );
154 }
155
156 // Traverse the records selected:
157 $a = 0;
158 $c = $GLOBALS['TYPO3_DB']->sql_num_rows($res);
159 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
160
161 // Prepare the additional label used in the HTML output in case of versions:
162 if ($versions) {
163 $versionLabel = '[v1.' . $row['t3ver_id'] . '; WS#' . $row['t3ver_wsid'] . ']';
164 } else {
165 $versionLabel = '';
166 }
167
168 $a++;
169 $newID = $row['uid'];
170
171 // Build HTML output:
172 if ($this->genTree_makeHTML) {
173 $this->genTree_HTML .= LF . '<div><span class="nobr">';
174 $PM = 'join';
175 $LN = ($a == $c) ? 'blank' : 'line';
176 $BTM = ($a == $c) ? 'bottom' : '';
177 $this->genTree_HTML .= $depthData .
178 '<img' . t3lib_iconWorks::skinImg($this->backPath, 'gfx/ol/' . $PM . $BTM . '.gif', 'width="18" height="16"') . ' align="top" alt="" />' .
179 $versionLabel .
180 t3lib_iconWorks::getSpriteIconForRecord('pages', $row) .
181 htmlspecialchars($row['uid'] . ': ' . t3lib_div::fixed_lgd_cs(strip_tags($row['title']), 50)) . '</span></div>';
182 }
183
184 // Register various data for this item:
185 $this->page_idArray[$newID] = $row;
186
187 $this->recStats['all_valid']['pages'][$newID] = $newID;
188 # if ($versions) $this->recStats['versions']['pages'][$newID] = $newID;
189 if ($row['deleted']) {
190 $this->recStats['deleted']['pages'][$newID] = $newID;
191 }
192 if ($versions && $row['t3ver_count'] >= 1) {
193 $this->recStats['published_versions']['pages'][$newID] = $newID;
194 }
195
196 if ($row['deleted']) {
197 $this->recStats['deleted']++;
198 }
199 if ($row['hidden']) {
200 $this->recStats['hidden']++;
201 }
202 $this->recStats['doktype'][$row['doktype']]++;
203
204 // Create the HTML code prefix for recursive call:
205 $genHTML = $depthData . '<img' . t3lib_iconWorks::skinImg($this->backPath, 'gfx/ol/' . $LN . '.gif', 'width="18" height="16"') . ' align="top" alt="" />' . $versionLabel;
206
207 // If all records should be shown, do so:
208 if ($this->genTree_includeRecords) {
209 foreach ($GLOBALS['TCA'] as $tableName => $cfg) {
210 if ($tableName != 'pages') {
211 $this->genTree_records($newID, $this->genTree_HTML ? $genHTML : '', $tableName);
212 }
213 }
214 }
215
216 // Add sub pages:
217 $this->genTree($newID, $this->genTree_HTML ? $genHTML : '');
218
219 // If versions are included in the tree, add those now:
220 if ($this->genTree_includeVersions) {
221 $this->genTree($newID, $this->genTree_HTML ? $genHTML : '', TRUE);
222 }
223 }
224 }
225
226 /**
227 * @param integer a pid (page-record id) from which to start making the tree
228 * @param string HTML-code used when this function calls itself recursively.
229 * @param string Table to get the records from
230 * @param bool Internal variable, don't set from outside!
231 * @return void
232 */
233 function genTree_records($theID, $depthData, $table = '', $versions = FALSE) {
234 global $TCA;
235
236 if ($versions) {
237 // Select all records from table pointing to this page:
238 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
239 t3lib_BEfunc::getCommonSelectFields($table),
240 $table,
241 'pid=-1 AND t3ver_oid=' . intval($theID) .
242 (!$this->genTree_includeDeleted ? t3lib_BEfunc::deleteClause($table) : '')
243 );
244 } else {
245 // Select all records from table pointing to this page:
246 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
247 t3lib_BEfunc::getCommonSelectFields($table),
248 $table,
249 'pid=' . intval($theID) .
250 (!$this->genTree_includeDeleted ? t3lib_BEfunc::deleteClause($table) : '')
251 );
252 }
253
254 // Traverse selected:
255 $a = 0;
256 $c = $GLOBALS['TYPO3_DB']->sql_num_rows($res);
257 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
258
259 // Prepare the additional label used in the HTML output in case of versions:
260 if ($versions) {
261 $versionLabel = '[v1.' . $row['t3ver_id'] . '; WS#' . $row['t3ver_wsid'] . ']';
262 } else {
263 $versionLabel = '';
264 }
265
266 $a++;
267 $newID = $row['uid'];
268
269 // Build HTML output:
270 if ($this->genTree_makeHTML) {
271 $this->genTree_HTML .= LF . '<div><span class="nobr">';
272 $PM = 'join';
273 $LN = ($a == $c) ? 'blank' : 'line';
274 $BTM = ($a == $c) ? 'bottom' : '';
275 $this->genTree_HTML .= $depthData .
276 '<img' . t3lib_iconWorks::skinImg($this->backPath, 'gfx/ol/' . $PM . $BTM . '.gif', 'width="18" height="16"') . ' align="top" alt="" />' .
277 $versionLabel .
278 t3lib_iconWorks::getSpriteIconForRecord($table, $row, array('title' => $table)) . htmlspecialchars($row['uid'] . ': ' . t3lib_BEfunc::getRecordTitle($table, $row)) . '</span></div>';
279 }
280
281 // Register various data for this item:
282 $this->rec_idArray[$table][$newID] = $row;
283
284 $this->recStats['all_valid'][$table][$newID] = $newID;
285 # $this->recStats[$versions?'versions':'live'][$table][$newID] = $newID;
286 if ($row['deleted']) {
287 $this->recStats['deleted'][$table][$newID] = $newID;
288 }
289 if ($versions && $row['t3ver_count'] >= 1 && $row['t3ver_wsid'] == 0) {
290 $this->recStats['published_versions'][$table][$newID] = $newID;
291 }
292
293 # if ($row['deleted']) {$this->recStat['deleted']++;}
294 # if ($row['hidden']) {$this->recStat['hidden']++;}
295
296
297 // Select all versions of this record:
298 if ($this->genTree_includeVersions && $TCA[$table]['ctrl']['versioningWS']) {
299 $genHTML = $depthData . '<img' . t3lib_iconWorks::skinImg($this->backPath, 'gfx/ol/' . $LN . '.gif', 'width="18" height="16"') . ' align="top" alt="" />';
300
301 $this->genTree_records($newID, $genHTML, $table, TRUE);
302 }
303 }
304 }
305
306 /**
307 * Generates tree and returns statistics
308 *
309 * @return array Record statistics
310 */
311 function genTreeStatus($root = 0) {
312 $this->genTree_includeDeleted = TRUE; // if set, genTree() includes deleted pages. This is default.
313 $this->genTree_includeVersions = TRUE; // if set, genTree() includes verisonized pages/records. This is default.
314 $this->genTree_includeRecords = TRUE; // if set, genTree() includes records from pages.
315 $this->perms_clause = ''; // extra where-clauses for the tree-selection
316 $this->genTree_makeHTML = 0; // if set, genTree() generates HTML, that visualizes the tree.
317
318 $this->genTree($root, '');
319
320 return $this->recStats;
321 }
322
323
324 /**
325 * Fills $this->lRecords with the records from all tc-tables that are not attached to a PID in the pid-list.
326 *
327 * @param string list of pid's (page-record uid's). This list is probably made by genTree()
328 * @return void
329 */
330 function lostRecords($pid_list) {
331 global $TCA;
332 $this->lostPagesList = '';
333 if ($pid_list) {
334 foreach ($TCA as $table => $tableConf) {
335 t3lib_div::loadTCA($table);
336
337 $pid_list_tmp = $pid_list;
338 if (!isset($TCA[$table]['ctrl']['versioningWS']) || !$TCA[$table]['ctrl']['versioningWS']) {
339 // Remove preceding "-1," for non-versioned tables
340 $pid_list_tmp = preg_replace('/^\-1,/', '', $pid_list_tmp);
341 }
342
343 $garbage = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
344 'uid,pid,' . $TCA[$table]['ctrl']['label'],
345 $table,
346 'pid NOT IN (' . $pid_list_tmp . ')'
347 );
348 $lostIdList = array();
349 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($garbage)) {
350 $this->lRecords[$table][$row['uid']] = array('uid' => $row['uid'], 'pid' => $row['pid'], 'title' => strip_tags($row[$TCA[$table]['ctrl']['label']]));
351 $lostIdList[] = $row['uid'];
352 }
353 if ($table == 'pages') {
354 $this->lostPagesList = implode(',', $lostIdList);
355 }
356 }
357 }
358 }
359
360 /**
361 * Fixes lost record from $table with uid $uid by setting the PID to zero. If there is a disabled column for the record that will be set as well.
362 *
363 * @param string Database tablename
364 * @param integer The uid of the record which will have the PID value set to 0 (zero)
365 * @return boolean True if done.
366 */
367 function fixLostRecord($table, $uid) {
368 if ($table && $GLOBALS['TCA'][$table] && $uid && is_array($this->lRecords[$table][$uid]) && $GLOBALS['BE_USER']->user['admin']) {
369
370 $updateFields = array();
371 $updateFields['pid'] = 0;
372 if ($GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['disabled']) { // If possible a lost record restored is hidden as default
373 $updateFields[$GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['disabled']] = 1;
374 }
375
376 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid=' . intval($uid), $updateFields);
377
378 return TRUE;
379 } else {
380 return FALSE;
381 }
382 }
383
384 /**
385 * Counts records from $TCA-tables that ARE attached to an existing page.
386 *
387 * @param string list of pid's (page-record uid's). This list is probably made by genTree()
388 * @return array an array with the number of records from all $TCA-tables that are attached to a PID in the pid-list.
389 */
390 function countRecords($pid_list) {
391 global $TCA;
392 $list = array();
393 $list_n = array();
394 if ($pid_list) {
395 foreach ($TCA as $table => $tableConf) {
396 t3lib_div::loadTCA($table);
397
398 $pid_list_tmp = $pid_list;
399 if (!isset($TCA[$table]['ctrl']['versioningWS']) || !$TCA[$table]['ctrl']['versioningWS']) {
400 // Remove preceding "-1," for non-versioned tables
401 $pid_list_tmp = preg_replace('/^\-1,/', '', $pid_list_tmp);
402 }
403
404 $count = $GLOBALS['TYPO3_DB']->exec_SELECTcountRows('uid', $table, 'pid IN (' . $pid_list_tmp . ')');
405 if ($count) {
406 $list[$table] = $count;
407 }
408
409 $count = $GLOBALS['TYPO3_DB']->exec_SELECTcountRows('uid', $table, 'pid IN (' . $pid_list_tmp . ')' . t3lib_BEfunc::deleteClause($table));
410 if ($count) {
411 $list_n[$table] = $count;
412 }
413 }
414 }
415 return array('all' => $list, 'non_deleted' => $list_n);
416 }
417
418 /**
419 * Finding relations in database based on type 'group' (files or database-uid's in a list)
420 *
421 * @param string $mode = file, $mode = db, $mode = '' (all...)
422 * @return array An array with all fields listed that somehow are references to other records (foreign-keys) or files
423 */
424 function getGroupFields($mode) {
425 global $TCA;
426 $result = array();
427 foreach ($TCA as $table => $tableConf) {
428 t3lib_div::loadTCA($table);
429 $cols = $TCA[$table]['columns'];
430 foreach ($cols as $field => $config) {
431 if ($config['config']['type'] == 'group') {
432 if (
433 ((!$mode || $mode == 'file') && $config['config']['internal_type'] == 'file') ||
434 ((!$mode || $mode == 'db') && $config['config']['internal_type'] == 'db')
435 ) {
436 $result[$table][] = $field;
437 }
438 }
439 if ((!$mode || $mode == 'db') && $config['config']['type'] == 'select' && $config['config']['foreign_table']) {
440 $result[$table][] = $field;
441 }
442 }
443 if ($result[$table]) {
444 $result[$table] = implode(',', $result[$table]);
445 }
446 }
447 return $result;
448 }
449
450 /**
451 * Finds all fields that hold filenames from uploadfolder
452 *
453 * @param string Path to uploadfolder
454 * @return array An array with all fields listed that have references to files in the $uploadfolder
455 */
456 function getFileFields($uploadfolder) {
457 global $TCA;
458 $result = array();
459 foreach ($TCA as $table => $tableConf) {
460 t3lib_div::loadTCA($table);
461 $cols = $TCA[$table]['columns'];
462 foreach ($cols as $field => $config) {
463 if ($config['config']['type'] == 'group' && $config['config']['internal_type'] == 'file' && $config['config']['uploadfolder'] == $uploadfolder) {
464 $result[] = array($table, $field);
465 }
466 }
467 }
468 return $result;
469 }
470
471 /**
472 * Returns an array with arrays of table/field pairs which are allowed to hold references to the input table name - according to $TCA
473 *
474 * @param string Table name
475 * @return array
476 */
477 function getDBFields($theSearchTable) {
478 global $TCA;
479 $result = array();
480 reset($TCA);
481 foreach ($TCA as $table => $tableConf) {
482 t3lib_div::loadTCA($table);
483 $cols = $TCA[$table]['columns'];
484 foreach ($cols as $field => $config) {
485 if ($config['config']['type'] == 'group' && $config['config']['internal_type'] == 'db') {
486 if (trim($config['config']['allowed']) == '*' || strstr($config['config']['allowed'], $theSearchTable)) {
487 $result[] = array($table, $field);
488 }
489 } elseif ($config['config']['type'] == 'select' && $config['config']['foreign_table'] == $theSearchTable) {
490 $result[] = array($table, $field);
491 }
492 }
493 }
494 return $result;
495 }
496
497 /**
498 * This selects non-empty-records from the tables/fields in the fkey_array generated by getGroupFields()
499 *
500 * @param array Array with tables/fields generated by getGroupFields()
501 * @return void
502 * @see getGroupFields()
503 */
504 function selectNonEmptyRecordsWithFkeys($fkey_arrays) {
505 global $TCA;
506 if (is_array($fkey_arrays)) {
507 foreach ($fkey_arrays as $table => $field_list) {
508 if ($TCA[$table] && trim($field_list)) {
509 t3lib_div::loadTCA($table);
510 $fieldArr = explode(',', $field_list);
511
512 if (t3lib_extMgm::isLoaded('dbal')) {
513 $fields = $GLOBALS['TYPO3_DB']->admin_get_fields($table);
514 $field = array_shift($fieldArr);
515 $cl_fl = ($GLOBALS['TYPO3_DB']->MetaType($fields[$field]['type'], $table) == 'I'
516 || $GLOBALS['TYPO3_DB']->MetaType($fields[$field]['type'], $table) == 'N'
517 || $GLOBALS['TYPO3_DB']->MetaType($fields[$field]['type'], $table) == 'R')
518 ? $field . '!=0'
519 : $field . '!=\'\'';
520 foreach ($fieldArr as $field) {
521 $cl_fl .= ($GLOBALS['TYPO3_DB']->MetaType($fields[$field]['type'], $table) == 'I'
522 || $GLOBALS['TYPO3_DB']->MetaType($fields[$field]['type'], $table) == 'N'
523 || $GLOBALS['TYPO3_DB']->MetaType($fields[$field]['type'], $table) == 'R')
524 ? ' OR ' . $field . '!=0'
525 : ' OR ' . $field . '!=\'\'';
526 }
527 unset($fields);
528 }
529 else {
530 $cl_fl = implode('!=\'\' OR ', $fieldArr) . '!=\'\'';
531 }
532
533 $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid,' . $field_list, $table, $cl_fl);
534 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres)) {
535 foreach ($fieldArr as $field) {
536 if (trim($row[$field])) {
537 $fieldConf = $TCA[$table]['columns'][$field]['config'];
538 if ($fieldConf['type'] == 'group') {
539 if ($fieldConf['internal_type'] == 'file') {
540 // files...
541 if ($fieldConf['MM']) {
542 $tempArr = array();
543 /** @var $dbAnalysis t3lib_loadDBGroup */
544 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
545 $dbAnalysis->start('', 'files', $fieldConf['MM'], $row['uid']);
546 foreach ($dbAnalysis->itemArray as $somekey => $someval) {
547 if ($someval['id']) {
548 $tempArr[] = $someval['id'];
549 }
550 }
551 } else {
552 $tempArr = explode(',', trim($row[$field]));
553 }
554 foreach ($tempArr as $file) {
555 $file = trim($file);
556 if ($file) {
557 $this->checkFileRefs[$fieldConf['uploadfolder']][$file] += 1;
558 }
559 }
560 }
561 if ($fieldConf['internal_type'] == 'db') {
562 /** @var $dbAnalysis t3lib_loadDBGroup */
563 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
564 $dbAnalysis->start($row[$field], $fieldConf['allowed'], $fieldConf['MM'], $row['uid'], $table, $fieldConf);
565 foreach ($dbAnalysis->itemArray as $tempArr) {
566 $this->checkGroupDBRefs[$tempArr['table']][$tempArr['id']] += 1;
567 }
568 }
569 }
570 if ($fieldConf['type'] == 'select' && $fieldConf['foreign_table']) {
571 /** @var $dbAnalysis t3lib_loadDBGroup */
572 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
573 $dbAnalysis->start($row[$field], $fieldConf['foreign_table'], $fieldConf['MM'], $row['uid'], $table, $fieldConf);
574 foreach ($dbAnalysis->itemArray as $tempArr) {
575 if ($tempArr['id'] > 0) {
576 $this->checkGroupDBRefs[$fieldConf['foreign_table']][$tempArr['id']] += 1;
577 }
578 }
579 }
580 }
581 }
582 }
583 $GLOBALS['TYPO3_DB']->sql_free_result($mres);
584 }
585 }
586 }
587 }
588
589 /**
590 * Depends on selectNonEmpty.... to be executed first!!
591 *
592 * @return array Report over files; keys are "moreReferences", "noReferences", "noFile", "error"
593 */
594 function testFileRefs() {
595 $output = array();
596 // handle direct references with upload folder setting (workaround)
597 $newCheckFileRefs = array();
598 foreach ($this->checkFileRefs as $folder => $files) {
599 // only direct references without a folder setting
600 if ($folder !== '') {
601 $newCheckFileRefs[$folder] = $files;
602 continue;
603 }
604
605 foreach ($files as $file => $references) {
606
607 // direct file references have often many references (removes occurences in the moreReferences section of the result array)
608 if ($references > 1) {
609 $references = 1;
610 }
611
612 // the directory must be empty (prevents checking of the root directory)
613 $directory = dirname($file);
614 if ($directory !== '') {
615 $newCheckFileRefs[$directory][basename($file)] = $references;
616 }
617 }
618 }
619 $this->checkFileRefs = $newCheckFileRefs;
620
621 foreach ($this->checkFileRefs as $folder => $fileArr) {
622 $path = PATH_site . $folder;
623 if (@is_dir($path)) {
624 $d = dir($path);
625 while ($entry = $d->read()) {
626 if (@is_file($path . '/' . $entry)) {
627 if (isset($fileArr[$entry])) {
628 if ($fileArr[$entry] > 1) {
629 $temp = $this->whereIsFileReferenced($folder, $entry);
630 $tempList = '';
631 foreach ($temp as $inf) {
632 $tempList .= '[' . $inf['table'] . '][' . $inf['uid'] . '][' . $inf['field'] . '] (pid:' . $inf['pid'] . ') - ';
633 }
634 $output['moreReferences'][] = array($path, $entry, $fileArr[$entry], $tempList);
635 }
636 unset($fileArr[$entry]);
637 } else {
638 // contains workaround for direct references
639 if (!strstr($entry, 'index.htm') && !preg_match('/^' . preg_quote($GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'], '/') . '/', $folder)) {
640 $output['noReferences'][] = array($path, $entry);
641 }
642 }
643 }
644 }
645 $d->close();
646 $tempCounter = 0;
647 foreach ($fileArr as $file => $value) {
648 // workaround for direct file references
649 if (preg_match('/^' . preg_quote($GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'], '/') . '/', $folder)) {
650 $file = $folder . '/' . $file;
651 $folder = '';
652 $path = substr(PATH_site, 0, -1);
653 }
654 $temp = $this->whereIsFileReferenced($folder, $file);
655 $tempList = '';
656 foreach ($temp as $inf) {
657 $tempList .= '[' . $inf['table'] . '][' . $inf['uid'] . '][' . $inf['field'] . '] (pid:' . $inf['pid'] . ') - ';
658 }
659 $tempCounter++;
660 $output['noFile'][substr($path, -3) . '_' . substr($file, 0, 3) . '_' . $tempCounter] = array($path, $file, $tempList);
661 }
662 } else {
663 $output['error'][] = array($path);
664 }
665 }
666 return $output;
667 }
668
669 /**
670 * Depends on selectNonEmpty.... to be executed first!!
671 *
672 * @param array Table with key/value pairs being table names and arrays with uid numbers
673 * @return string HTML Error message
674 */
675 function testDBRefs($theArray) {
676 global $TCA;
677 $result = '';
678 foreach ($theArray as $table => $dbArr) {
679 if ($TCA[$table]) {
680 $idlist = array_keys($dbArr);
681
682 $theList = implode(',', $idlist);
683 if ($theList) {
684 $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', $table, 'uid IN (' . $theList . ')' . t3lib_BEfunc::deleteClause($table));
685 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres)) {
686 if (isset($dbArr[$row['uid']])) {
687 unset ($dbArr[$row['uid']]);
688 } else {
689 $result .= 'Strange Error. ...<br />';
690 }
691 }
692 foreach ($dbArr as $theId => $theC) {
693 $result .= 'There are ' . $theC . ' records pointing to this missing or deleted record; [' . $table . '][' . $theId . ']<br />';
694 }
695 }
696 } else {
697 $result .= 'Codeerror. Table is not a table...<br />';
698 }
699 }
700 return $result;
701 }
702
703 /**
704 * Finding all references to record based on table/uid
705 *
706 * @param string Table name
707 * @param integer Uid of database record
708 * @return array Array with other arrays containing information about where references was found
709 */
710 function whereIsRecordReferenced($searchTable, $id) {
711 global $TCA;
712 $fileFields = $this->getDBFields($searchTable); // Gets tables / Fields that reference to files...
713 $theRecordList = array();
714 foreach ($fileFields as $info) {
715 $table = $info[0];
716 $field = $info[1];
717 t3lib_div::loadTCA($table);
718 $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
719 'uid,pid,' . $TCA[$table]['ctrl']['label'] . ',' . $field,
720 $table,
721 $field . ' LIKE \'%' . $GLOBALS['TYPO3_DB']->quoteStr($id, $table) . '%\''
722 );
723 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres)) {
724 // Now this is the field, where the reference COULD come from. But we're not garanteed, so we must carefully examine the data.
725 $fieldConf = $TCA[$table]['columns'][$field]['config'];
726 $allowedTables = ($fieldConf['type'] == 'group') ? $fieldConf['allowed'] : $fieldConf['foreign_table'];
727 /** @var $dbAnalysis t3lib_loadDBGroup */
728 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
729 $dbAnalysis->start($row[$field], $allowedTables, $fieldConf['MM'], $row['uid'], $table, $fieldConf);
730 foreach ($dbAnalysis->itemArray as $tempArr) {
731 if ($tempArr['table'] == $searchTable && $tempArr['id'] == $id) {
732 $theRecordList[] = array('table' => $table, 'uid' => $row['uid'], 'field' => $field, 'pid' => $row['pid']);
733 }
734 }
735 }
736 $GLOBALS['TYPO3_DB']->sql_free_result($mres);
737 }
738 return $theRecordList;
739 }
740
741 /**
742 * Finding all references to file based on uploadfolder / filename
743 *
744 * @param string Upload folder where file is found
745 * @param string Filename to search for
746 * @return array Array with other arrays containing information about where references was found
747 */
748 function whereIsFileReferenced($uploadfolder, $filename) {
749 global $TCA;
750 $fileFields = $this->getFileFields($uploadfolder); // Gets tables / Fields that reference to files...
751 $theRecordList = array();
752 foreach ($fileFields as $info) {
753 $table = $info[0];
754 $field = $info[1];
755 $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
756 'uid,pid,' . $TCA[$table]['ctrl']['label'] . ',' . $field,
757 $table,
758 $field . ' LIKE \'%' . $GLOBALS['TYPO3_DB']->quoteStr($filename, $table) . '%\''
759 );
760 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres)) {
761 // Now this is the field, where the reference COULD come from. But we're not guaranteed, so we must carefully examine the data.
762 $tempArr = explode(',', trim($row[$field]));
763 foreach ($tempArr as $file) {
764 $file = trim($file);
765 if ($file == $filename) {
766 $theRecordList[] = array('table' => $table, 'uid' => $row['uid'], 'field' => $field, 'pid' => $row['pid']);
767 }
768 }
769 }
770 }
771 return $theRecordList;
772 }
773 }
774
775
776 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_admin.php'])) {
777 include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_admin.php']);
778 }
779 ?>