Revert "[RELEASE] Release of TYPO3 4.6.0alpha1"
[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('uid' => $row['uid'], 'pid' => $row['pid'], 'title' => strip_tags($row[$GLOBALS['TCA'][$table]['ctrl']['label']]));
347 $lostIdList[] = $row['uid'];
348 }
349 if ($table == 'pages') {
350 $this->lostPagesList = implode(',', $lostIdList);
351 }
352 }
353 }
354 }
355
356 /**
357 * 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.
358 *
359 * @param string Database tablename
360 * @param integer The uid of the record which will have the PID value set to 0 (zero)
361 * @return boolean TRUE if done.
362 */
363 function fixLostRecord($table, $uid) {
364 if ($table && $GLOBALS['TCA'][$table] && $uid && is_array($this->lRecords[$table][$uid]) && $GLOBALS['BE_USER']->user['admin']) {
365
366 $updateFields = array();
367 $updateFields['pid'] = 0;
368 if ($GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['disabled']) { // If possible a lost record restored is hidden as default
369 $updateFields[$GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['disabled']] = 1;
370 }
371
372 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid=' . intval($uid), $updateFields);
373
374 return TRUE;
375 } else {
376 return FALSE;
377 }
378 }
379
380 /**
381 * Counts records from $GLOBALS['TCA']-tables that ARE attached to an existing page.
382 *
383 * @param string list of pid's (page-record uid's). This list is probably made by genTree()
384 * @return array an array with the number of records from all $GLOBALS['TCA']-tables that are attached to a PID in the pid-list.
385 */
386 function countRecords($pid_list) {
387 $list = array();
388 $list_n = array();
389 if ($pid_list) {
390 foreach ($GLOBALS['TCA'] as $table => $tableConf) {
391 t3lib_div::loadTCA($table);
392
393 $pid_list_tmp = $pid_list;
394 if (!isset($GLOBALS['TCA'][$table]['ctrl']['versioningWS']) || !$GLOBALS['TCA'][$table]['ctrl']['versioningWS']) {
395 // Remove preceding "-1," for non-versioned tables
396 $pid_list_tmp = preg_replace('/^\-1,/', '', $pid_list_tmp);
397 }
398
399 $count = $GLOBALS['TYPO3_DB']->exec_SELECTcountRows('uid', $table, 'pid IN (' . $pid_list_tmp . ')');
400 if ($count) {
401 $list[$table] = $count;
402 }
403
404 $count = $GLOBALS['TYPO3_DB']->exec_SELECTcountRows('uid', $table, 'pid IN (' . $pid_list_tmp . ')' . t3lib_BEfunc::deleteClause($table));
405 if ($count) {
406 $list_n[$table] = $count;
407 }
408 }
409 }
410 return array('all' => $list, 'non_deleted' => $list_n);
411 }
412
413 /**
414 * Finding relations in database based on type 'group' (files or database-uid's in a list)
415 *
416 * @param string $mode = file, $mode = db, $mode = '' (all...)
417 * @return array An array with all fields listed that somehow are references to other records (foreign-keys) or files
418 */
419 function getGroupFields($mode) {
420 $result = array();
421 foreach ($GLOBALS['TCA'] as $table => $tableConf) {
422 t3lib_div::loadTCA($table);
423 $cols = $GLOBALS['TCA'][$table]['columns'];
424 foreach ($cols as $field => $config) {
425 if ($config['config']['type'] == 'group') {
426 if (
427 ((!$mode || $mode == 'file') && $config['config']['internal_type'] == 'file') ||
428 ((!$mode || $mode == 'db') && $config['config']['internal_type'] == 'db')
429 ) {
430 $result[$table][] = $field;
431 }
432 }
433 if ((!$mode || $mode == 'db') && $config['config']['type'] == 'select' && $config['config']['foreign_table']) {
434 $result[$table][] = $field;
435 }
436 }
437 if ($result[$table]) {
438 $result[$table] = implode(',', $result[$table]);
439 }
440 }
441 return $result;
442 }
443
444 /**
445 * Finds all fields that hold filenames from uploadfolder
446 *
447 * @param string Path to uploadfolder
448 * @return array An array with all fields listed that have references to files in the $uploadfolder
449 */
450 function getFileFields($uploadfolder) {
451 $result = array();
452 foreach ($GLOBALS['TCA'] as $table => $tableConf) {
453 t3lib_div::loadTCA($table);
454 $cols = $GLOBALS['TCA'][$table]['columns'];
455 foreach ($cols as $field => $config) {
456 if ($config['config']['type'] == 'group' && $config['config']['internal_type'] == 'file' && $config['config']['uploadfolder'] == $uploadfolder) {
457 $result[] = array($table, $field);
458 }
459 }
460 }
461 return $result;
462 }
463
464 /**
465 * Returns an array with arrays of table/field pairs which are allowed to hold references to the input table name - according to $GLOBALS['TCA']
466 *
467 * @param string Table name
468 * @return array
469 */
470 function getDBFields($theSearchTable) {
471 $result = array();
472 reset($GLOBALS['TCA']);
473 foreach ($GLOBALS['TCA'] as $table => $tableConf) {
474 t3lib_div::loadTCA($table);
475 $cols = $GLOBALS['TCA'][$table]['columns'];
476 foreach ($cols as $field => $config) {
477 if ($config['config']['type'] == 'group' && $config['config']['internal_type'] == 'db') {
478 if (trim($config['config']['allowed']) == '*' || strstr($config['config']['allowed'], $theSearchTable)) {
479 $result[] = array($table, $field);
480 }
481 } elseif ($config['config']['type'] == 'select' && $config['config']['foreign_table'] == $theSearchTable) {
482 $result[] = array($table, $field);
483 }
484 }
485 }
486 return $result;
487 }
488
489 /**
490 * This selects non-empty-records from the tables/fields in the fkey_array generated by getGroupFields()
491 *
492 * @param array Array with tables/fields generated by getGroupFields()
493 * @return void
494 * @see getGroupFields()
495 */
496 function selectNonEmptyRecordsWithFkeys($fkey_arrays) {
497 if (is_array($fkey_arrays)) {
498 foreach ($fkey_arrays as $table => $field_list) {
499 if ($GLOBALS['TCA'][$table] && trim($field_list)) {
500 t3lib_div::loadTCA($table);
501 $fieldArr = explode(',', $field_list);
502
503 if (t3lib_extMgm::isLoaded('dbal')) {
504 $fields = $GLOBALS['TYPO3_DB']->admin_get_fields($table);
505 $field = array_shift($fieldArr);
506 $cl_fl = ($GLOBALS['TYPO3_DB']->MetaType($fields[$field]['type'], $table) == 'I'
507 || $GLOBALS['TYPO3_DB']->MetaType($fields[$field]['type'], $table) == 'N'
508 || $GLOBALS['TYPO3_DB']->MetaType($fields[$field]['type'], $table) == 'R')
509 ? $field . '!=0'
510 : $field . '!=\'\'';
511 foreach ($fieldArr as $field) {
512 $cl_fl .= ($GLOBALS['TYPO3_DB']->MetaType($fields[$field]['type'], $table) == 'I'
513 || $GLOBALS['TYPO3_DB']->MetaType($fields[$field]['type'], $table) == 'N'
514 || $GLOBALS['TYPO3_DB']->MetaType($fields[$field]['type'], $table) == 'R')
515 ? ' OR ' . $field . '!=0'
516 : ' OR ' . $field . '!=\'\'';
517 }
518 unset($fields);
519 }
520 else {
521 $cl_fl = implode('!=\'\' OR ', $fieldArr) . '!=\'\'';
522 }
523
524 $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid,' . $field_list, $table, $cl_fl);
525 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres)) {
526 foreach ($fieldArr as $field) {
527 if (trim($row[$field])) {
528 $fieldConf = $GLOBALS['TCA'][$table]['columns'][$field]['config'];
529 if ($fieldConf['type'] == 'group') {
530 if ($fieldConf['internal_type'] == 'file') {
531 // files...
532 if ($fieldConf['MM']) {
533 $tempArr = array();
534 /** @var $dbAnalysis t3lib_loadDBGroup */
535 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
536 $dbAnalysis->start('', 'files', $fieldConf['MM'], $row['uid']);
537 foreach ($dbAnalysis->itemArray as $somekey => $someval) {
538 if ($someval['id']) {
539 $tempArr[] = $someval['id'];
540 }
541 }
542 } else {
543 $tempArr = explode(',', trim($row[$field]));
544 }
545 foreach ($tempArr as $file) {
546 $file = trim($file);
547 if ($file) {
548 $this->checkFileRefs[$fieldConf['uploadfolder']][$file] += 1;
549 }
550 }
551 }
552 if ($fieldConf['internal_type'] == 'db') {
553 /** @var $dbAnalysis t3lib_loadDBGroup */
554 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
555 $dbAnalysis->start($row[$field], $fieldConf['allowed'], $fieldConf['MM'], $row['uid'], $table, $fieldConf);
556 foreach ($dbAnalysis->itemArray as $tempArr) {
557 $this->checkGroupDBRefs[$tempArr['table']][$tempArr['id']] += 1;
558 }
559 }
560 }
561 if ($fieldConf['type'] == 'select' && $fieldConf['foreign_table']) {
562 /** @var $dbAnalysis t3lib_loadDBGroup */
563 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
564 $dbAnalysis->start($row[$field], $fieldConf['foreign_table'], $fieldConf['MM'], $row['uid'], $table, $fieldConf);
565 foreach ($dbAnalysis->itemArray as $tempArr) {
566 if ($tempArr['id'] > 0) {
567 $this->checkGroupDBRefs[$fieldConf['foreign_table']][$tempArr['id']] += 1;
568 }
569 }
570 }
571 }
572 }
573 }
574 $GLOBALS['TYPO3_DB']->sql_free_result($mres);
575 }
576 }
577 }
578 }
579
580 /**
581 * Depends on selectNonEmpty.... to be executed first!!
582 *
583 * @return array Report over files; keys are "moreReferences", "noReferences", "noFile", "error"
584 */
585 function testFileRefs() {
586 $output = array();
587 // handle direct references with upload folder setting (workaround)
588 $newCheckFileRefs = array();
589 foreach ($this->checkFileRefs as $folder => $files) {
590 // only direct references without a folder setting
591 if ($folder !== '') {
592 $newCheckFileRefs[$folder] = $files;
593 continue;
594 }
595
596 foreach ($files as $file => $references) {
597
598 // direct file references have often many references (removes occurences in the moreReferences section of the result array)
599 if ($references > 1) {
600 $references = 1;
601 }
602
603 // the directory must be empty (prevents checking of the root directory)
604 $directory = dirname($file);
605 if ($directory !== '') {
606 $newCheckFileRefs[$directory][basename($file)] = $references;
607 }
608 }
609 }
610 $this->checkFileRefs = $newCheckFileRefs;
611
612 foreach ($this->checkFileRefs as $folder => $fileArr) {
613 $path = PATH_site . $folder;
614 if (@is_dir($path)) {
615 $d = dir($path);
616 while ($entry = $d->read()) {
617 if (@is_file($path . '/' . $entry)) {
618 if (isset($fileArr[$entry])) {
619 if ($fileArr[$entry] > 1) {
620 $temp = $this->whereIsFileReferenced($folder, $entry);
621 $tempList = '';
622 foreach ($temp as $inf) {
623 $tempList .= '[' . $inf['table'] . '][' . $inf['uid'] . '][' . $inf['field'] . '] (pid:' . $inf['pid'] . ') - ';
624 }
625 $output['moreReferences'][] = array($path, $entry, $fileArr[$entry], $tempList);
626 }
627 unset($fileArr[$entry]);
628 } else {
629 // contains workaround for direct references
630 if (!strstr($entry, 'index.htm') && !preg_match('/^' . preg_quote($GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'], '/') . '/', $folder)) {
631 $output['noReferences'][] = array($path, $entry);
632 }
633 }
634 }
635 }
636 $d->close();
637 $tempCounter = 0;
638 foreach ($fileArr as $file => $value) {
639 // workaround for direct file references
640 if (preg_match('/^' . preg_quote($GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'], '/') . '/', $folder)) {
641 $file = $folder . '/' . $file;
642 $folder = '';
643 $path = substr(PATH_site, 0, -1);
644 }
645 $temp = $this->whereIsFileReferenced($folder, $file);
646 $tempList = '';
647 foreach ($temp as $inf) {
648 $tempList .= '[' . $inf['table'] . '][' . $inf['uid'] . '][' . $inf['field'] . '] (pid:' . $inf['pid'] . ') - ';
649 }
650 $tempCounter++;
651 $output['noFile'][substr($path, -3) . '_' . substr($file, 0, 3) . '_' . $tempCounter] = array($path, $file, $tempList);
652 }
653 } else {
654 $output['error'][] = array($path);
655 }
656 }
657 return $output;
658 }
659
660 /**
661 * Depends on selectNonEmpty.... to be executed first!!
662 *
663 * @param array Table with key/value pairs being table names and arrays with uid numbers
664 * @return string HTML Error message
665 */
666 function testDBRefs($theArray) {
667 $result = '';
668 foreach ($theArray as $table => $dbArr) {
669 if ($GLOBALS['TCA'][$table]) {
670 $idlist = array_keys($dbArr);
671
672 $theList = implode(',', $idlist);
673 if ($theList) {
674 $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', $table, 'uid IN (' . $theList . ')' . t3lib_BEfunc::deleteClause($table));
675 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres)) {
676 if (isset($dbArr[$row['uid']])) {
677 unset ($dbArr[$row['uid']]);
678 } else {
679 $result .= 'Strange Error. ...<br />';
680 }
681 }
682 foreach ($dbArr as $theId => $theC) {
683 $result .= 'There are ' . $theC . ' records pointing to this missing or deleted record; [' . $table . '][' . $theId . ']<br />';
684 }
685 }
686 } else {
687 $result .= 'Codeerror. Table is not a table...<br />';
688 }
689 }
690 return $result;
691 }
692
693 /**
694 * Finding all references to record based on table/uid
695 *
696 * @param string Table name
697 * @param integer Uid of database record
698 * @return array Array with other arrays containing information about where references was found
699 */
700 function whereIsRecordReferenced($searchTable, $id) {
701 $fileFields = $this->getDBFields($searchTable); // Gets tables / Fields that reference to files...
702 $theRecordList = array();
703 foreach ($fileFields as $info) {
704 $table = $info[0];
705 $field = $info[1];
706 t3lib_div::loadTCA($table);
707 $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
708 'uid,pid,' . $GLOBALS['TCA'][$table]['ctrl']['label'] . ',' . $field,
709 $table,
710 $field . ' LIKE \'%' . $GLOBALS['TYPO3_DB']->quoteStr($id, $table) . '%\''
711 );
712 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres)) {
713 // Now this is the field, where the reference COULD come from. But we're not garanteed, so we must carefully examine the data.
714 $fieldConf = $GLOBALS['TCA'][$table]['columns'][$field]['config'];
715 $allowedTables = ($fieldConf['type'] == 'group') ? $fieldConf['allowed'] : $fieldConf['foreign_table'];
716 /** @var $dbAnalysis t3lib_loadDBGroup */
717 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
718 $dbAnalysis->start($row[$field], $allowedTables, $fieldConf['MM'], $row['uid'], $table, $fieldConf);
719 foreach ($dbAnalysis->itemArray as $tempArr) {
720 if ($tempArr['table'] == $searchTable && $tempArr['id'] == $id) {
721 $theRecordList[] = array('table' => $table, 'uid' => $row['uid'], 'field' => $field, 'pid' => $row['pid']);
722 }
723 }
724 }
725 $GLOBALS['TYPO3_DB']->sql_free_result($mres);
726 }
727 return $theRecordList;
728 }
729
730 /**
731 * Finding all references to file based on uploadfolder / filename
732 *
733 * @param string Upload folder where file is found
734 * @param string Filename to search for
735 * @return array Array with other arrays containing information about where references was found
736 */
737 function whereIsFileReferenced($uploadfolder, $filename) {
738 $fileFields = $this->getFileFields($uploadfolder); // Gets tables / Fields that reference to files...
739 $theRecordList = array();
740 foreach ($fileFields as $info) {
741 $table = $info[0];
742 $field = $info[1];
743 $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
744 'uid,pid,' . $GLOBALS['TCA'][$table]['ctrl']['label'] . ',' . $field,
745 $table,
746 $field . ' LIKE \'%' . $GLOBALS['TYPO3_DB']->quoteStr($filename, $table) . '%\''
747 );
748 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres)) {
749 // Now this is the field, where the reference COULD come from. But we're not guaranteed, so we must carefully examine the data.
750 $tempArr = explode(',', trim($row[$field]));
751 foreach ($tempArr as $file) {
752 $file = trim($file);
753 if ($file == $filename) {
754 $theRecordList[] = array('table' => $table, 'uid' => $row['uid'], 'field' => $field, 'pid' => $row['pid']);
755 }
756 }
757 }
758 }
759 return $theRecordList;
760 }
761 }
762
763
764 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_admin.php'])) {
765 include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_admin.php']);
766 }
767 ?>