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