[BUGFIX] Show correct record title
[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 reset($GLOBALS['TCA']);
477 foreach ($GLOBALS['TCA'] as $table => $tableConf) {
478 t3lib_div::loadTCA($table);
479 $cols = $GLOBALS['TCA'][$table]['columns'];
480 foreach ($cols as $field => $config) {
481 if ($config['config']['type'] == 'group' && $config['config']['internal_type'] == 'db') {
482 if (trim($config['config']['allowed']) == '*' || strstr($config['config']['allowed'], $theSearchTable)) {
483 $result[] = array($table, $field);
484 }
485 } elseif ($config['config']['type'] == 'select' && $config['config']['foreign_table'] == $theSearchTable) {
486 $result[] = array($table, $field);
487 }
488 }
489 }
490 return $result;
491 }
492
493 /**
494 * This selects non-empty-records from the tables/fields in the fkey_array generated by getGroupFields()
495 *
496 * @param array Array with tables/fields generated by getGroupFields()
497 * @return void
498 * @see getGroupFields()
499 */
500 function selectNonEmptyRecordsWithFkeys($fkey_arrays) {
501 if (is_array($fkey_arrays)) {
502 foreach ($fkey_arrays as $table => $field_list) {
503 if ($GLOBALS['TCA'][$table] && trim($field_list)) {
504 t3lib_div::loadTCA($table);
505 $fieldArr = explode(',', $field_list);
506
507 if (t3lib_extMgm::isLoaded('dbal')) {
508 $fields = $GLOBALS['TYPO3_DB']->admin_get_fields($table);
509 $field = array_shift($fieldArr);
510 $cl_fl = ($GLOBALS['TYPO3_DB']->MetaType($fields[$field]['type'], $table) == 'I'
511 || $GLOBALS['TYPO3_DB']->MetaType($fields[$field]['type'], $table) == 'N'
512 || $GLOBALS['TYPO3_DB']->MetaType($fields[$field]['type'], $table) == 'R')
513 ? $field . '!=0'
514 : $field . '!=\'\'';
515 foreach ($fieldArr as $field) {
516 $cl_fl .= ($GLOBALS['TYPO3_DB']->MetaType($fields[$field]['type'], $table) == 'I'
517 || $GLOBALS['TYPO3_DB']->MetaType($fields[$field]['type'], $table) == 'N'
518 || $GLOBALS['TYPO3_DB']->MetaType($fields[$field]['type'], $table) == 'R')
519 ? ' OR ' . $field . '!=0'
520 : ' OR ' . $field . '!=\'\'';
521 }
522 unset($fields);
523 }
524 else {
525 $cl_fl = implode('!=\'\' OR ', $fieldArr) . '!=\'\'';
526 }
527
528 $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid,' . $field_list, $table, $cl_fl);
529 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres)) {
530 foreach ($fieldArr as $field) {
531 if (trim($row[$field])) {
532 $fieldConf = $GLOBALS['TCA'][$table]['columns'][$field]['config'];
533 if ($fieldConf['type'] == 'group') {
534 if ($fieldConf['internal_type'] == 'file') {
535 // files...
536 if ($fieldConf['MM']) {
537 $tempArr = array();
538 /** @var $dbAnalysis t3lib_loadDBGroup */
539 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
540 $dbAnalysis->start('', 'files', $fieldConf['MM'], $row['uid']);
541 foreach ($dbAnalysis->itemArray as $somekey => $someval) {
542 if ($someval['id']) {
543 $tempArr[] = $someval['id'];
544 }
545 }
546 } else {
547 $tempArr = explode(',', trim($row[$field]));
548 }
549 foreach ($tempArr as $file) {
550 $file = trim($file);
551 if ($file) {
552 $this->checkFileRefs[$fieldConf['uploadfolder']][$file] += 1;
553 }
554 }
555 }
556 if ($fieldConf['internal_type'] == 'db') {
557 /** @var $dbAnalysis t3lib_loadDBGroup */
558 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
559 $dbAnalysis->start($row[$field], $fieldConf['allowed'], $fieldConf['MM'], $row['uid'], $table, $fieldConf);
560 foreach ($dbAnalysis->itemArray as $tempArr) {
561 $this->checkGroupDBRefs[$tempArr['table']][$tempArr['id']] += 1;
562 }
563 }
564 }
565 if ($fieldConf['type'] == 'select' && $fieldConf['foreign_table']) {
566 /** @var $dbAnalysis t3lib_loadDBGroup */
567 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
568 $dbAnalysis->start($row[$field], $fieldConf['foreign_table'], $fieldConf['MM'], $row['uid'], $table, $fieldConf);
569 foreach ($dbAnalysis->itemArray as $tempArr) {
570 if ($tempArr['id'] > 0) {
571 $this->checkGroupDBRefs[$fieldConf['foreign_table']][$tempArr['id']] += 1;
572 }
573 }
574 }
575 }
576 }
577 }
578 $GLOBALS['TYPO3_DB']->sql_free_result($mres);
579 }
580 }
581 }
582 }
583
584 /**
585 * Depends on selectNonEmpty.... to be executed first!!
586 *
587 * @return array Report over files; keys are "moreReferences", "noReferences", "noFile", "error"
588 */
589 function testFileRefs() {
590 $output = array();
591 // handle direct references with upload folder setting (workaround)
592 $newCheckFileRefs = array();
593 foreach ($this->checkFileRefs as $folder => $files) {
594 // only direct references without a folder setting
595 if ($folder !== '') {
596 $newCheckFileRefs[$folder] = $files;
597 continue;
598 }
599
600 foreach ($files as $file => $references) {
601
602 // direct file references have often many references (removes occurences in the moreReferences section of the result array)
603 if ($references > 1) {
604 $references = 1;
605 }
606
607 // the directory must be empty (prevents checking of the root directory)
608 $directory = dirname($file);
609 if ($directory !== '') {
610 $newCheckFileRefs[$directory][basename($file)] = $references;
611 }
612 }
613 }
614 $this->checkFileRefs = $newCheckFileRefs;
615
616 foreach ($this->checkFileRefs as $folder => $fileArr) {
617 $path = PATH_site . $folder;
618 if (@is_dir($path)) {
619 $d = dir($path);
620 while ($entry = $d->read()) {
621 if (@is_file($path . '/' . $entry)) {
622 if (isset($fileArr[$entry])) {
623 if ($fileArr[$entry] > 1) {
624 $temp = $this->whereIsFileReferenced($folder, $entry);
625 $tempList = '';
626 foreach ($temp as $inf) {
627 $tempList .= '[' . $inf['table'] . '][' . $inf['uid'] . '][' . $inf['field'] . '] (pid:' . $inf['pid'] . ') - ';
628 }
629 $output['moreReferences'][] = array($path, $entry, $fileArr[$entry], $tempList);
630 }
631 unset($fileArr[$entry]);
632 } else {
633 // contains workaround for direct references
634 if (!strstr($entry, 'index.htm') && !preg_match('/^' . preg_quote($GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'], '/') . '/', $folder)) {
635 $output['noReferences'][] = array($path, $entry);
636 }
637 }
638 }
639 }
640 $d->close();
641 $tempCounter = 0;
642 foreach ($fileArr as $file => $value) {
643 // workaround for direct file references
644 if (preg_match('/^' . preg_quote($GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'], '/') . '/', $folder)) {
645 $file = $folder . '/' . $file;
646 $folder = '';
647 $path = substr(PATH_site, 0, -1);
648 }
649 $temp = $this->whereIsFileReferenced($folder, $file);
650 $tempList = '';
651 foreach ($temp as $inf) {
652 $tempList .= '[' . $inf['table'] . '][' . $inf['uid'] . '][' . $inf['field'] . '] (pid:' . $inf['pid'] . ') - ';
653 }
654 $tempCounter++;
655 $output['noFile'][substr($path, -3) . '_' . substr($file, 0, 3) . '_' . $tempCounter] = array($path, $file, $tempList);
656 }
657 } else {
658 $output['error'][] = array($path);
659 }
660 }
661 return $output;
662 }
663
664 /**
665 * Depends on selectNonEmpty.... to be executed first!!
666 *
667 * @param array Table with key/value pairs being table names and arrays with uid numbers
668 * @return string HTML Error message
669 */
670 function testDBRefs($theArray) {
671 $result = '';
672 foreach ($theArray as $table => $dbArr) {
673 if ($GLOBALS['TCA'][$table]) {
674 $idlist = array_keys($dbArr);
675
676 $theList = implode(',', $idlist);
677 if ($theList) {
678 $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', $table, 'uid IN (' . $theList . ')' . t3lib_BEfunc::deleteClause($table));
679 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres)) {
680 if (isset($dbArr[$row['uid']])) {
681 unset ($dbArr[$row['uid']]);
682 } else {
683 $result .= 'Strange Error. ...<br />';
684 }
685 }
686 foreach ($dbArr as $theId => $theC) {
687 $result .= 'There are ' . $theC . ' records pointing to this missing or deleted record; [' . $table . '][' . $theId . ']<br />';
688 }
689 }
690 } else {
691 $result .= 'Codeerror. Table is not a table...<br />';
692 }
693 }
694 return $result;
695 }
696
697 /**
698 * Finding all references to record based on table/uid
699 *
700 * @param string Table name
701 * @param integer Uid of database record
702 * @return array Array with other arrays containing information about where references was found
703 */
704 function whereIsRecordReferenced($searchTable, $id) {
705 $fileFields = $this->getDBFields($searchTable); // Gets tables / Fields that reference to files...
706 $theRecordList = array();
707 foreach ($fileFields as $info) {
708 $table = $info[0];
709 $field = $info[1];
710 t3lib_div::loadTCA($table);
711 $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
712 'uid,pid,' . $GLOBALS['TCA'][$table]['ctrl']['label'] . ',' . $field,
713 $table,
714 $field . ' LIKE \'%' . $GLOBALS['TYPO3_DB']->quoteStr($id, $table) . '%\''
715 );
716 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres)) {
717 // Now this is the field, where the reference COULD come from. But we're not garanteed, so we must carefully examine the data.
718 $fieldConf = $GLOBALS['TCA'][$table]['columns'][$field]['config'];
719 $allowedTables = ($fieldConf['type'] == 'group') ? $fieldConf['allowed'] : $fieldConf['foreign_table'];
720 /** @var $dbAnalysis t3lib_loadDBGroup */
721 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
722 $dbAnalysis->start($row[$field], $allowedTables, $fieldConf['MM'], $row['uid'], $table, $fieldConf);
723 foreach ($dbAnalysis->itemArray as $tempArr) {
724 if ($tempArr['table'] == $searchTable && $tempArr['id'] == $id) {
725 $theRecordList[] = array('table' => $table, 'uid' => $row['uid'], 'field' => $field, 'pid' => $row['pid']);
726 }
727 }
728 }
729 $GLOBALS['TYPO3_DB']->sql_free_result($mres);
730 }
731 return $theRecordList;
732 }
733
734 /**
735 * Finding all references to file based on uploadfolder / filename
736 *
737 * @param string Upload folder where file is found
738 * @param string Filename to search for
739 * @return array Array with other arrays containing information about where references was found
740 */
741 function whereIsFileReferenced($uploadfolder, $filename) {
742 $fileFields = $this->getFileFields($uploadfolder); // Gets tables / Fields that reference to files...
743 $theRecordList = array();
744 foreach ($fileFields as $info) {
745 $table = $info[0];
746 $field = $info[1];
747 $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
748 'uid,pid,' . $GLOBALS['TCA'][$table]['ctrl']['label'] . ',' . $field,
749 $table,
750 $field . ' LIKE \'%' . $GLOBALS['TYPO3_DB']->quoteStr($filename, $table) . '%\''
751 );
752 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres)) {
753 // Now this is the field, where the reference COULD come from. But we're not guaranteed, so we must carefully examine the data.
754 $tempArr = explode(',', trim($row[$field]));
755 foreach ($tempArr as $file) {
756 $file = trim($file);
757 if ($file == $filename) {
758 $theRecordList[] = array('table' => $table, 'uid' => $row['uid'], 'field' => $field, 'pid' => $row['pid']);
759 }
760 }
761 }
762 }
763 return $theRecordList;
764 }
765 }
766
767
768 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_admin.php'])) {
769 include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_admin.php']);
770 }
771 ?>