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