[TASK] Add missing sql_free_result in t3lib classes
[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 /**
38 * This class holds functions used by the TYPO3 backend to check the integrity of the database (The DBint module, 'lowlevel' extension)
39 *
40 * Depends on: Depends on loaddbgroup from t3lib/
41 *
42 * @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!
43 * @see SC_mod_tools_dbint_index::func_relations(), SC_mod_tools_dbint_index::func_records()
44 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
45 * @package TYPO3
46 * @subpackage t3lib
47 */
48 class t3lib_admin {
49 /** @var boolean If set, genTree() includes deleted pages. This is default.*/
50 var $genTree_includeDeleted = TRUE;
51
52 /** @var boolean If set, genTree() includes versionized pages/records. This is default.*/
53 var $genTree_includeVersions = TRUE;
54
55 /** @var boolean If set, genTree() includes records from pages. */
56 var $genTree_includeRecords = FALSE;
57
58 /** @var string Extra where-clauses for the tree-selection */
59 var $perms_clause = '';
60
61 /** @var int If set, genTree() generates HTML, that visualizes the tree. */
62 var $genTree_makeHTML = 0;
63
64 // Internal
65 /** @var array Will hold id/rec pairs from genTree() */
66 var $page_idArray = array();
67
68 /** @var array */
69 var $rec_idArray = array();
70
71 /** @var string Will hold the HTML-code visualising the tree. genTree() */
72 var $genTree_HTML = '';
73
74 /** @var string */
75 var $backPath = '';
76
77 // Internal
78 /** @var array */
79 var $checkFileRefs = array();
80
81 /** @var array From the select-fields */
82 var $checkSelectDBRefs = array();
83
84 /** @var array From the group-fields */
85 var $checkGroupDBRefs = array();
86
87 /** @var array Statistics */
88 var $recStats = array(
89 'allValid' => array(),
90 'published_versions' => array(),
91 'deleted' => array(),
92 );
93
94 /** @var array */
95 var $lRecords = array();
96
97 /** @var string */
98 var $lostPagesList = '';
99
100
101 /**
102 * Generates a list of Page-uid's that corresponds to the tables in the tree.
103 * This list should ideally include all records in the pages-table.
104 *
105 * @param integer $theID a pid (page-record id) from which to start making the tree
106 * @param string $depthData HTML-code (image-tags) used when this function calls itself recursively.
107 * @param boolean $versions 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
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->recStats['deleted']++;
172 }
173 if ($row['hidden']) {
174 $this->recStats['hidden']++;
175 }
176 $this->recStats['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 $GLOBALS['TYPO3_DB']->sql_free_result($res);
200 }
201
202 /**
203 * @param integer $theID a pid (page-record id) from which to start making the tree
204 * @param string $depthData HTML-code used when this function calls itself recursively.
205 * @param string $table Table to get the records from
206 * @param boolean $versions Internal variable, don't set from outside!
207 * @return void
208 */
209 function genTree_records($theID, $depthData, $table = '', $versions = FALSE) {
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
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 // Select all versions of this record:
268 if ($this->genTree_includeVersions && $GLOBALS['TCA'][$table]['ctrl']['versioningWS']) {
269 $genHTML = $depthData . '<img' . t3lib_iconWorks::skinImg($this->backPath, 'gfx/ol/' . $LN . '.gif', 'width="18" height="16"') . ' align="top" alt="" />';
270
271 $this->genTree_records($newID, $genHTML, $table, TRUE);
272 }
273 }
274
275 $GLOBALS['TYPO3_DB']->sql_free_result($res);
276 }
277
278 /**
279 * Generates tree and returns statistics
280 *
281 * @param integer $root
282 * @return array Record statistics
283 * @deprecated and unused since 6.0, will be removed two versions later
284 */
285 function genTreeStatus($root = 0) {
286 t3lib_div::logDeprecatedFunction();
287 $this->genTree_includeDeleted = TRUE; // if set, genTree() includes deleted pages. This is default.
288 $this->genTree_includeVersions = TRUE; // if set, genTree() includes verisonized pages/records. This is default.
289 $this->genTree_includeRecords = TRUE; // if set, genTree() includes records from pages.
290 $this->perms_clause = ''; // extra where-clauses for the tree-selection
291 $this->genTree_makeHTML = 0; // if set, genTree() generates HTML, that visualizes the tree.
292
293 $this->genTree($root, '');
294
295 return $this->recStats;
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 $pid_list 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 $this->lostPagesList = '';
306 if ($pid_list) {
307 foreach ($GLOBALS['TCA'] as $table => $tableConf) {
308 t3lib_div::loadTCA($table);
309
310 $pid_list_tmp = $pid_list;
311 if (!isset($GLOBALS['TCA'][$table]['ctrl']['versioningWS']) || !$GLOBALS['TCA'][$table]['ctrl']['versioningWS']) {
312 // Remove preceding "-1," for non-versioned tables
313 $pid_list_tmp = preg_replace('/^\-1,/', '', $pid_list_tmp);
314 }
315
316 $garbage = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
317 'uid,pid,' . $GLOBALS['TCA'][$table]['ctrl']['label'],
318 $table,
319 'pid NOT IN (' . $pid_list_tmp . ')'
320 );
321 $lostIdList = array();
322 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($garbage)) {
323 $this->lRecords[$table][$row['uid']] = array(
324 'uid' => $row['uid'],
325 'pid' => $row['pid'],
326 'title' => strip_tags(t3lib_BEfunc::getRecordTitle($table, $row)),
327 );
328 $lostIdList[] = $row['uid'];
329 }
330
331 $GLOBALS['TYPO3_DB']->sql_free_result($garbage);
332
333 if ($table == 'pages') {
334 $this->lostPagesList = implode(',', $lostIdList);
335 }
336 }
337 }
338 }
339
340 /**
341 * Fixes lost record from $table with uid $uid by setting the PID to zero.
342 * If there is a disabled column for the record that will be set as well.
343 *
344 * @param string $table Database tablename
345 * @param integer $uid The uid of the record which will have the PID value set to 0 (zero)
346 * @return boolean TRUE if done.
347 */
348 function fixLostRecord($table, $uid) {
349 if ($table && $GLOBALS['TCA'][$table] && $uid && is_array($this->lRecords[$table][$uid]) && $GLOBALS['BE_USER']->user['admin']) {
350
351 $updateFields = array();
352 $updateFields['pid'] = 0;
353 // If possible a lost record restored is hidden as default
354 if ($GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['disabled']) {
355 $updateFields[$GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['disabled']] = 1;
356 }
357
358 $GLOBALS['TYPO3_DB']->exec_UPDATEquery($table, 'uid=' . intval($uid), $updateFields);
359
360 return TRUE;
361 } else {
362 return FALSE;
363 }
364 }
365
366 /**
367 * Counts records from $GLOBALS['TCA']-tables that ARE attached to an existing page.
368 *
369 * @param string $pid_list list of pid's (page-record uid's). This list is probably made by genTree()
370 * @return array an array with the number of records from all $GLOBALS['TCA']-tables that are attached to a PID in the pid-list.
371 */
372 function countRecords($pid_list) {
373 $list = array();
374 $list_n = array();
375 if ($pid_list) {
376 foreach ($GLOBALS['TCA'] as $table => $tableConf) {
377 t3lib_div::loadTCA($table);
378
379 $pid_list_tmp = $pid_list;
380 if (!isset($GLOBALS['TCA'][$table]['ctrl']['versioningWS']) || !$GLOBALS['TCA'][$table]['ctrl']['versioningWS']) {
381 // Remove preceding "-1," for non-versioned tables
382 $pid_list_tmp = preg_replace('/^\-1,/', '', $pid_list_tmp);
383 }
384
385 $count = $GLOBALS['TYPO3_DB']->exec_SELECTcountRows('uid', $table, 'pid IN (' . $pid_list_tmp . ')');
386 if ($count) {
387 $list[$table] = $count;
388 }
389
390 $count = $GLOBALS['TYPO3_DB']->exec_SELECTcountRows('uid', $table, 'pid IN (' . $pid_list_tmp . ')' . t3lib_BEfunc::deleteClause($table));
391 if ($count) {
392 $list_n[$table] = $count;
393 }
394 }
395 }
396 return array('all' => $list, 'non_deleted' => $list_n);
397 }
398
399 /**
400 * Finding relations in database based on type 'group' (files or database-uid's in a list)
401 *
402 * @param string $mode $mode = file, $mode = db, $mode = '' (all...)
403 * @return array An array with all fields listed that somehow are references to other records (foreign-keys) or files
404 */
405 function getGroupFields($mode) {
406 $result = array();
407 foreach ($GLOBALS['TCA'] as $table => $tableConf) {
408 t3lib_div::loadTCA($table);
409 $cols = $GLOBALS['TCA'][$table]['columns'];
410 foreach ($cols as $field => $config) {
411 if ($config['config']['type'] == 'group') {
412 if (
413 ((!$mode || $mode == 'file') && $config['config']['internal_type'] == 'file') ||
414 ((!$mode || $mode == 'db') && $config['config']['internal_type'] == 'db')
415 ) {
416 $result[$table][] = $field;
417 }
418 }
419 if ((!$mode || $mode == 'db') && $config['config']['type'] == 'select' && $config['config']['foreign_table']) {
420 $result[$table][] = $field;
421 }
422 }
423 if ($result[$table]) {
424 $result[$table] = implode(',', $result[$table]);
425 }
426 }
427 return $result;
428 }
429
430 /**
431 * Finds all fields that hold filenames from uploadfolder
432 *
433 * @param string $uploadfolder Path to uploadfolder
434 * @return array An array with all fields listed that have references to files in the $uploadfolder
435 */
436 function getFileFields($uploadfolder) {
437 $result = array();
438 foreach ($GLOBALS['TCA'] as $table => $tableConf) {
439 t3lib_div::loadTCA($table);
440 $cols = $GLOBALS['TCA'][$table]['columns'];
441 foreach ($cols as $field => $config) {
442 if ($config['config']['type'] == 'group' && $config['config']['internal_type'] == 'file' && $config['config']['uploadfolder'] == $uploadfolder) {
443 $result[] = array($table, $field);
444 }
445 }
446 }
447 return $result;
448 }
449
450 /**
451 * Returns an array with arrays of table/field pairs which are allowed to hold references to the input table name - according to $GLOBALS['TCA']
452 *
453 * @param string $theSearchTable Table name
454 * @return array
455 */
456 function getDBFields($theSearchTable) {
457 $result = array();
458 foreach ($GLOBALS['TCA'] as $table => $tableConf) {
459 t3lib_div::loadTCA($table);
460 $cols = $GLOBALS['TCA'][$table]['columns'];
461 foreach ($cols as $field => $config) {
462 if ($config['config']['type'] == 'group' && $config['config']['internal_type'] == 'db') {
463 if (trim($config['config']['allowed']) == '*' || strstr($config['config']['allowed'], $theSearchTable)) {
464 $result[] = array($table, $field);
465 }
466 } elseif ($config['config']['type'] == 'select' && $config['config']['foreign_table'] == $theSearchTable) {
467 $result[] = array($table, $field);
468 }
469 }
470 }
471 return $result;
472 }
473
474 /**
475 * This selects non-empty-records from the tables/fields in the fkey_array generated by getGroupFields()
476 *
477 * @param array $fkey_arrays Array with tables/fields generated by getGroupFields()
478 * @return void
479 * @see getGroupFields()
480 */
481 function selectNonEmptyRecordsWithFkeys($fkey_arrays) {
482 if (is_array($fkey_arrays)) {
483 foreach ($fkey_arrays as $table => $field_list) {
484 if ($GLOBALS['TCA'][$table] && trim($field_list)) {
485 t3lib_div::loadTCA($table);
486 $fieldArr = explode(',', $field_list);
487
488 if (t3lib_extMgm::isLoaded('dbal')) {
489 $fields = $GLOBALS['TYPO3_DB']->admin_get_fields($table);
490 $field = array_shift($fieldArr);
491 $cl_fl = ($GLOBALS['TYPO3_DB']->MetaType($fields[$field]['type'], $table) == 'I'
492 || $GLOBALS['TYPO3_DB']->MetaType($fields[$field]['type'], $table) == 'N'
493 || $GLOBALS['TYPO3_DB']->MetaType($fields[$field]['type'], $table) == 'R')
494 ? $field . '<>0'
495 : $field . '<>\'\'';
496 foreach ($fieldArr as $field) {
497 $cl_fl .= ($GLOBALS['TYPO3_DB']->MetaType($fields[$field]['type'], $table) == 'I'
498 || $GLOBALS['TYPO3_DB']->MetaType($fields[$field]['type'], $table) == 'N'
499 || $GLOBALS['TYPO3_DB']->MetaType($fields[$field]['type'], $table) == 'R')
500 ? ' OR ' . $field . '<>0'
501 : ' OR ' . $field . '<>\'\'';
502 }
503 unset($fields);
504 }
505 else {
506 $cl_fl = implode('<>\'\' OR ', $fieldArr) . '<>\'\'';
507 }
508
509 $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid,' . $field_list, $table, $cl_fl);
510 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres)) {
511 foreach ($fieldArr as $field) {
512 if (trim($row[$field])) {
513 $fieldConf = $GLOBALS['TCA'][$table]['columns'][$field]['config'];
514 if ($fieldConf['type'] == 'group') {
515 if ($fieldConf['internal_type'] == 'file') {
516 // Files...
517 if ($fieldConf['MM']) {
518 $tempArr = array();
519 /** @var $dbAnalysis t3lib_loadDBGroup */
520 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
521 $dbAnalysis->start('', 'files', $fieldConf['MM'], $row['uid']);
522 foreach ($dbAnalysis->itemArray as $somekey => $someval) {
523 if ($someval['id']) {
524 $tempArr[] = $someval['id'];
525 }
526 }
527 } else {
528 $tempArr = explode(',', trim($row[$field]));
529 }
530 foreach ($tempArr as $file) {
531 $file = trim($file);
532 if ($file) {
533 $this->checkFileRefs[$fieldConf['uploadfolder']][$file] += 1;
534 }
535 }
536 }
537 if ($fieldConf['internal_type'] == 'db') {
538 /** @var $dbAnalysis t3lib_loadDBGroup */
539 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
540 $dbAnalysis->start($row[$field], $fieldConf['allowed'], $fieldConf['MM'], $row['uid'], $table, $fieldConf);
541 foreach ($dbAnalysis->itemArray as $tempArr) {
542 $this->checkGroupDBRefs[$tempArr['table']][$tempArr['id']] += 1;
543 }
544 }
545 }
546 if ($fieldConf['type'] == 'select' && $fieldConf['foreign_table']) {
547 /** @var $dbAnalysis t3lib_loadDBGroup */
548 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
549 $dbAnalysis->start($row[$field], $fieldConf['foreign_table'], $fieldConf['MM'], $row['uid'], $table, $fieldConf);
550 foreach ($dbAnalysis->itemArray as $tempArr) {
551 if ($tempArr['id'] > 0) {
552 $this->checkGroupDBRefs[$fieldConf['foreign_table']][$tempArr['id']] += 1;
553 }
554 }
555 }
556 }
557 }
558 }
559 $GLOBALS['TYPO3_DB']->sql_free_result($mres);
560 }
561 }
562 }
563 }
564
565 /**
566 * Depends on selectNonEmpty.... to be executed first!!
567 *
568 * @return array Report over files; keys are "moreReferences", "noReferences", "noFile", "error"
569 */
570 function testFileRefs() {
571 $output = array();
572 // Handle direct references with upload folder setting (workaround)
573 $newCheckFileRefs = array();
574 foreach ($this->checkFileRefs as $folder => $files) {
575 // Only direct references without a folder setting
576 if ($folder !== '') {
577 $newCheckFileRefs[$folder] = $files;
578 continue;
579 }
580
581 foreach ($files as $file => $references) {
582
583 // Direct file references have often many references (removes occurences in the moreReferences section of the result array)
584 if ($references > 1) {
585 $references = 1;
586 }
587
588 // The directory must be empty (prevents checking of the root directory)
589 $directory = dirname($file);
590 if ($directory !== '') {
591 $newCheckFileRefs[$directory][basename($file)] = $references;
592 }
593 }
594 }
595 $this->checkFileRefs = $newCheckFileRefs;
596
597 foreach ($this->checkFileRefs as $folder => $fileArr) {
598 $path = PATH_site . $folder;
599 if (@is_dir($path)) {
600 $d = dir($path);
601 while ($entry = $d->read()) {
602 if (@is_file($path . '/' . $entry)) {
603 if (isset($fileArr[$entry])) {
604 if ($fileArr[$entry] > 1) {
605 $temp = $this->whereIsFileReferenced($folder, $entry);
606 $tempList = '';
607 foreach ($temp as $inf) {
608 $tempList .= '[' . $inf['table'] . '][' . $inf['uid'] . '][' . $inf['field'] . '] (pid:' . $inf['pid'] . ') - ';
609 }
610 $output['moreReferences'][] = array($path, $entry, $fileArr[$entry], $tempList);
611 }
612 unset($fileArr[$entry]);
613 } else {
614 // Contains workaround for direct references
615 if (!strstr($entry, 'index.htm') && !preg_match('/^' . preg_quote($GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'], '/') . '/', $folder)) {
616 $output['noReferences'][] = array($path, $entry);
617 }
618 }
619 }
620 }
621 $d->close();
622 $tempCounter = 0;
623 foreach ($fileArr as $file => $value) {
624 // Workaround for direct file references
625 if (preg_match('/^' . preg_quote($GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'], '/') . '/', $folder)) {
626 $file = $folder . '/' . $file;
627 $folder = '';
628 $path = substr(PATH_site, 0, -1);
629 }
630 $temp = $this->whereIsFileReferenced($folder, $file);
631 $tempList = '';
632 foreach ($temp as $inf) {
633 $tempList .= '[' . $inf['table'] . '][' . $inf['uid'] . '][' . $inf['field'] . '] (pid:' . $inf['pid'] . ') - ';
634 }
635 $tempCounter++;
636 $output['noFile'][substr($path, -3) . '_' . substr($file, 0, 3) . '_' . $tempCounter] = array($path, $file, $tempList);
637 }
638 } else {
639 $output['error'][] = array($path);
640 }
641 }
642 return $output;
643 }
644
645 /**
646 * Depends on selectNonEmpty.... to be executed first!!
647 *
648 * @param array $theArray Table with key/value pairs being table names and arrays with uid numbers
649 * @return string HTML Error message
650 */
651 function testDBRefs($theArray) {
652 $result = '';
653 foreach ($theArray as $table => $dbArr) {
654 if ($GLOBALS['TCA'][$table]) {
655 $idlist = array_keys($dbArr);
656
657 $theList = implode(',', $idlist);
658 if ($theList) {
659 $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', $table, 'uid IN (' . $theList . ')' . t3lib_BEfunc::deleteClause($table));
660 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres)) {
661 if (isset($dbArr[$row['uid']])) {
662 unset ($dbArr[$row['uid']]);
663 } else {
664 $result .= 'Strange Error. ...<br />';
665 }
666 }
667
668 $GLOBALS['TYPO3_DB']->sql_free_result($mres);
669
670 foreach ($dbArr as $theId => $theC) {
671 $result .= 'There are ' . $theC . ' records pointing to this missing or deleted record; [' . $table . '][' . $theId . ']<br />';
672 }
673 }
674 } else {
675 $result .= 'Codeerror. Table is not a table...<br />';
676 }
677 }
678 return $result;
679 }
680
681 /**
682 * Finding all references to record based on table/uid
683 *
684 * @param string $searchTable Table name
685 * @param integer $id Uid of database record
686 * @return array Array with other arrays containing information about where references was found
687 */
688 function whereIsRecordReferenced($searchTable, $id) {
689 // Gets tables / Fields that reference to files
690 $fileFields = $this->getDBFields($searchTable);
691 $theRecordList = array();
692 foreach ($fileFields as $info) {
693 $table = $info[0];
694 $field = $info[1];
695 t3lib_div::loadTCA($table);
696 $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
697 'uid,pid,' . $GLOBALS['TCA'][$table]['ctrl']['label'] . ',' . $field,
698 $table,
699 $field . ' LIKE \'%' . $GLOBALS['TYPO3_DB']->quoteStr($id, $table) . '%\''
700 );
701 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres)) {
702 // Now this is the field, where the reference COULD come from. But we're not garanteed, so we must carefully examine the data.
703 $fieldConf = $GLOBALS['TCA'][$table]['columns'][$field]['config'];
704 $allowedTables = ($fieldConf['type'] == 'group') ? $fieldConf['allowed'] : $fieldConf['foreign_table'];
705 /** @var $dbAnalysis t3lib_loadDBGroup */
706 $dbAnalysis = t3lib_div::makeInstance('t3lib_loadDBGroup');
707 $dbAnalysis->start($row[$field], $allowedTables, $fieldConf['MM'], $row['uid'], $table, $fieldConf);
708 foreach ($dbAnalysis->itemArray as $tempArr) {
709 if ($tempArr['table'] == $searchTable && $tempArr['id'] == $id) {
710 $theRecordList[] = array('table' => $table, 'uid' => $row['uid'], 'field' => $field, 'pid' => $row['pid']);
711 }
712 }
713 }
714 $GLOBALS['TYPO3_DB']->sql_free_result($mres);
715 }
716 return $theRecordList;
717 }
718
719 /**
720 * Finding all references to file based on uploadfolder / filename
721 *
722 * @param string $uploadfolder Upload folder where file is found
723 * @param string $filename Filename to search for
724 * @return array Array with other arrays containing information about where references was found
725 */
726 function whereIsFileReferenced($uploadfolder, $filename) {
727 // Gets tables / Fields that reference to files
728 $fileFields = $this->getFileFields($uploadfolder);
729 $theRecordList = array();
730 foreach ($fileFields as $info) {
731 $table = $info[0];
732 $field = $info[1];
733 $mres = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
734 'uid,pid,' . $GLOBALS['TCA'][$table]['ctrl']['label'] . ',' . $field,
735 $table,
736 $field . ' LIKE \'%' . $GLOBALS['TYPO3_DB']->quoteStr($filename, $table) . '%\''
737 );
738 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($mres)) {
739 // Now this is the field, where the reference COULD come from.
740 // But we're not guaranteed, so we must carefully examine the data.
741 $tempArr = explode(',', trim($row[$field]));
742 foreach ($tempArr as $file) {
743 $file = trim($file);
744 if ($file == $filename) {
745 $theRecordList[] = array('table' => $table, 'uid' => $row['uid'], 'field' => $field, 'pid' => $row['pid']);
746 }
747 }
748 }
749
750 $GLOBALS['TYPO3_DB']->sql_free_result($mres);
751 }
752 return $theRecordList;
753 }
754 }
755
756 ?>