‪TYPO3CMS  9.5
DatabaseIntegrityCheck.php
Go to the documentation of this file.
1 <?php
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
17 use Doctrine\DBAL\Types\Types;
27 
37 {
41  public ‪$genTree_includeDeleted = true;
42 
46  public ‪$genTree_includeVersions = true;
47 
51  public ‪$genTree_includeRecords = false;
52 
56  public ‪$page_idArray = [];
57 
61  protected ‪$page_translatedPageIDArray = [];
62 
66  public ‪$rec_idArray = [];
67 
71  public ‪$checkFileRefs = [];
72 
76  public ‪$checkSelectDBRefs = [];
77 
81  public ‪$checkGroupDBRefs = [];
82 
86  public ‪$recStats = [
87  'allValid' => [],
88  'published_versions' => [],
89  'deleted' => []
90  ];
91 
95  public ‪$lRecords = [];
96 
100  public ‪$lostPagesList = '';
101 
105  public function ‪__construct()
106  {
107  trigger_error('TYPO3\CMS\Core\Integrity\DatabaseIntegrityCheck will be removed in TYPO3 v10.0, use TYPO3\CMS\Lowlevel\Integrity\DatabaseIntegrityCheck instead.', E_USER_DEPRECATED);
108  }
109 
113  public function ‪getPageTranslatedPageIDArray(): array
114  {
116  }
117 
126  public function ‪genTree($theID, $depthData = '', $versions = false)
127  {
128  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
129  $queryBuilder->getRestrictions()->removeAll();
130  if (!$this->genTree_includeDeleted) {
131  $queryBuilder->getRestrictions()->add(GeneralUtility::makeInstance(DeletedRestriction::class));
132  }
133  $queryBuilder->select('uid', 'title', 'doktype', 'deleted', 'hidden', 'sys_language_uid')
134  ->from('pages')
135  ->orderBy('sorting');
136  if ($versions) {
137  $queryBuilder->addSelect('t3ver_wsid', 't3ver_id', 't3ver_count');
138  $queryBuilder->where(
139  $queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter(-1, \PDO::PARAM_INT)),
140  $queryBuilder->expr()->eq('t3ver_oid', $queryBuilder->createNamedParameter($theID, \PDO::PARAM_INT))
141  );
142  } else {
143  $queryBuilder->where(
144  $queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($theID, \PDO::PARAM_INT))
145  );
146  }
147  $result = $queryBuilder->execute();
148  // Traverse the records selected
149  while ($row = $result->fetch()) {
150  $newID = $row['uid'];
151  // Register various data for this item:
152  if ($row['sys_language_uid'] === 0) {
153  $this->page_idArray[$newID] = $row;
154  } else {
155  $this->page_translatedPageIDArray[$newID] = $row;
156  }
157  $this->recStats['all_valid']['pages'][$newID] = $newID;
158  if ($row['deleted']) {
159  $this->recStats['deleted']['pages'][$newID] = $newID;
160  }
161  if ($versions && $row['t3ver_count'] >= 1) {
162  $this->recStats['published_versions']['pages'][$newID] = $newID;
163  }
164  if ($row['deleted']) {
165  $this->recStats['deleted']++;
166  }
167  if ($row['hidden']) {
168  $this->recStats['hidden']++;
169  }
170  $this->recStats['doktype'][$row['doktype']]++;
171  // If all records should be shown, do so:
172  if ($this->genTree_includeRecords) {
173  foreach (‪$GLOBALS['TCA'] as $tableName => $cfg) {
174  if ($tableName !== 'pages') {
175  $this->‪genTree_records($newID, '', $tableName);
176  }
177  }
178  }
179  // Add sub pages:
180  $this->‪genTree($newID);
181  // If versions are included in the tree, add those now:
182  if ($this->genTree_includeVersions) {
183  $this->‪genTree($newID, '', true);
184  }
185  }
186  }
187 
194  public function ‪genTree_records($theID, $_ = '', $table = '', $versions = false)
195  {
196  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
197  $queryBuilder->getRestrictions()->removeAll();
198  if (!$this->genTree_includeDeleted) {
199  $queryBuilder->getRestrictions()->add(GeneralUtility::makeInstance(DeletedRestriction::class));
200  }
201  $queryBuilder
202  ->select(...explode(',', ‪BackendUtility::getCommonSelectFields($table)))
203  ->from($table);
204 
205  // Select all records from table pointing to this page
206  if ($versions) {
207  $queryBuilder->where(
208  $queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter(-1, \PDO::PARAM_INT)),
209  $queryBuilder->expr()->eq('t3ver_oid', $queryBuilder->createNamedParameter($theID, \PDO::PARAM_INT))
210  );
211  } else {
212  $queryBuilder->where(
213  $queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($theID, \PDO::PARAM_INT))
214  );
215  }
216  $queryResult = $queryBuilder->execute();
217  // Traverse selected
218  while ($row = $queryResult->fetch()) {
219  $newID = $row['uid'];
220  // Register various data for this item:
221  $this->rec_idArray[$table][$newID] = $row;
222  $this->recStats['all_valid'][$table][$newID] = $newID;
223  if ($row['deleted']) {
224  $this->recStats['deleted'][$table][$newID] = $newID;
225  }
226  if ($versions && $row['t3ver_count'] >= 1 && $row['t3ver_wsid'] == 0) {
227  $this->recStats['published_versions'][$table][$newID] = $newID;
228  }
229  // Select all versions of this record:
230  if ($this->genTree_includeVersions && ‪$GLOBALS['TCA'][$table]['ctrl']['versioningWS']) {
231  $this->‪genTree_records($newID, '', $table, true);
232  }
233  }
234  }
235 
241  public function ‪lostRecords($pid_list)
242  {
243  $this->lostPagesList = '';
244  $pageIds = GeneralUtility::intExplode(',', $pid_list);
245  if (is_array($pageIds)) {
246  foreach (‪$GLOBALS['TCA'] as $table => $tableConf) {
247  $pageIdsForTable = $pageIds;
248  // Remove preceding "-1," for non-versioned tables
250  $pageIdsForTable = array_combine($pageIdsForTable, $pageIdsForTable);
251  unset($pageIdsForTable[-1]);
252  }
253  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
254  $queryBuilder->getRestrictions()->removeAll();
255  $selectFields = ['uid', 'pid'];
256  if (!empty(‪$GLOBALS['TCA'][$table]['ctrl']['label'])) {
257  $selectFields[] = ‪$GLOBALS['TCA'][$table]['ctrl']['label'];
258  }
259  $queryResult = $queryBuilder->select(...$selectFields)
260  ->from($table)
261  ->where(
262  $queryBuilder->expr()->notIn(
263  'pid',
264  $queryBuilder->createNamedParameter($pageIdsForTable, Connection::PARAM_INT_ARRAY)
265  )
266  )
267  ->execute();
268  $lostIdList = [];
269  while ($row = $queryResult->fetch()) {
270  $this->lRecords[$table][$row['uid']] = [
271  'uid' => $row['uid'],
272  'pid' => $row['pid'],
273  'title' => strip_tags(‪BackendUtility::getRecordTitle($table, $row))
274  ];
275  $lostIdList[] = $row['uid'];
276  }
277  if ($table === 'pages') {
278  $this->lostPagesList = implode(',', $lostIdList);
279  }
280  }
281  }
282  }
283 
292  public function ‪fixLostRecord($table, $uid)
293  {
294  if ($table && ‪$GLOBALS['TCA'][$table] && $uid && is_array($this->lRecords[$table][$uid]) && ‪$GLOBALS['BE_USER']->isAdmin()) {
295  $updateFields = [
296  'pid' => 0
297  ];
298  // If possible a lost record restored is hidden as default
299  if (‪$GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['disabled']) {
300  $updateFields[‪$GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['disabled']] = 1;
301  }
302  GeneralUtility::makeInstance(ConnectionPool::class)
303  ->getConnectionForTable($table)
304  ->update($table, $updateFields, ['uid' => (int)$uid]);
305  return true;
306  }
307  return false;
308  }
309 
316  public function ‪countRecords($pid_list)
317  {
318  $list = [];
319  $list_n = [];
320  $pageIds = GeneralUtility::intExplode(',', $pid_list);
321  if (!empty($pageIds)) {
322  foreach (‪$GLOBALS['TCA'] as $table => $tableConf) {
323  $pageIdsForTable = $pageIds;
324  // Remove preceding "-1," for non-versioned tables
326  $pageIdsForTable = array_combine($pageIdsForTable, $pageIdsForTable);
327  unset($pageIdsForTable[-1]);
328  }
329  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
330  $queryBuilder->getRestrictions()->removeAll();
331  $count = $queryBuilder->count('uid')
332  ->from($table)
333  ->where(
334  $queryBuilder->expr()->in(
335  'pid',
336  $queryBuilder->createNamedParameter($pageIds, Connection::PARAM_INT_ARRAY)
337  )
338  )
339  ->execute()
340  ->fetchColumn(0);
341  if ($count) {
342  $list[$table] = $count;
343  }
344 
345  // same query excluding all deleted records
346  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
347  $queryBuilder->getRestrictions()
348  ->removeAll()
349  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
350  $count = $queryBuilder->count('uid')
351  ->from($table)
352  ->where(
353  $queryBuilder->expr()->in(
354  'pid',
355  $queryBuilder->createNamedParameter($pageIdsForTable, Connection::PARAM_INT_ARRAY)
356  )
357  )
358  ->execute()
359  ->fetchColumn(0);
360  if ($count) {
361  $list_n[$table] = $count;
362  }
363  }
364  }
365  return ['all' => $list, 'non_deleted' => $list_n];
366  }
367 
374  public function ‪getGroupFields($mode)
375  {
376  $result = [];
377  foreach (‪$GLOBALS['TCA'] as $table => $tableConf) {
378  $cols = ‪$GLOBALS['TCA'][$table]['columns'];
379  foreach ($cols as $field => $config) {
380  if ($config['config']['type'] === 'group') {
381  if ((!$mode || $mode === 'file') && $config['config']['internal_type'] === 'file' || (!$mode || $mode === 'db') && $config['config']['internal_type'] === 'db') {
382  // @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0. Deprecation logged by TcaMigration class. Remove the type=file specific code.
383  $result[$table][] = $field;
384  }
385  }
386  if ((!$mode || $mode === 'db') && $config['config']['type'] === 'select' && $config['config']['foreign_table']) {
387  $result[$table][] = $field;
388  }
389  }
390  if ($result[$table]) {
391  $result[$table] = implode(',', $result[$table]);
392  }
393  }
394  return $result;
395  }
396 
404  public function ‪getFileFields($uploadfolder)
405  {
406  $result = [];
407  foreach (‪$GLOBALS['TCA'] as $table => $tableConf) {
408  $cols = ‪$GLOBALS['TCA'][$table]['columns'];
409  foreach ($cols as $field => $config) {
410  if ($config['config']['type'] === 'group' && $config['config']['internal_type'] === 'file' && $config['config']['uploadfolder'] == $uploadfolder) {
411  $result[] = [$table, $field];
412  }
413  }
414  }
415  return $result;
416  }
417 
424  public function ‪getDBFields($theSearchTable)
425  {
426  $result = [];
427  foreach (‪$GLOBALS['TCA'] as $table => $tableConf) {
428  $cols = ‪$GLOBALS['TCA'][$table]['columns'];
429  foreach ($cols as $field => $config) {
430  if ($config['config']['type'] === 'group' && $config['config']['internal_type'] === 'db') {
431  if (trim($config['config']['allowed']) === '*' || strstr($config['config']['allowed'], $theSearchTable)) {
432  $result[] = [$table, $field];
433  }
434  } elseif ($config['config']['type'] === 'select' && $config['config']['foreign_table'] == $theSearchTable) {
435  $result[] = [$table, $field];
436  }
437  }
438  }
439  return $result;
440  }
441 
448  public function ‪selectNonEmptyRecordsWithFkeys($fkey_arrays)
449  {
450  if (is_array($fkey_arrays)) {
451  $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
452  foreach ($fkey_arrays as $table => $field_list) {
453  if (‪$GLOBALS['TCA'][$table] && trim($field_list)) {
454  $connection = $connectionPool->getConnectionForTable($table);
455  $schemaManager = $connection->getSchemaManager();
456  $tableColumns = $schemaManager->listTableColumns($table);
457 
458  $queryBuilder = $connectionPool->getQueryBuilderForTable($table);
459  $queryBuilder->getRestrictions()->removeAll();
460 
461  ‪$fields = GeneralUtility::trimExplode(',', $field_list, true);
462 
463  $queryBuilder->select('uid')
464  ->from($table);
465  $whereClause = [];
466 
467  foreach (‪$fields as $fieldName) {
468  // The array index of $tableColumns is the lowercased column name!
469  // It is quoted for keywords
470  $column = $tableColumns[strtolower($fieldName)]
471  ?? $tableColumns[$connection->quoteIdentifier(strtolower($fieldName))];
472  if (!$column) {
473  // Throw meaningful exception if field does not exist in DB - 'none' is not filtered here since the
474  // method is only called with type=group fields
475  throw new \RuntimeException(
476  'Field ' . $fieldName . ' for table ' . $table . ' has been defined in TCA, but does not exist in DB',
477  1536248936
478  );
479  }
480  $fieldType = $column->getType()->getName();
481  if (in_array(
482  $fieldType,
483  [Types::BIGINT, Types::INTEGER, Types::SMALLINT, Types::DECIMAL, Types::FLOAT],
484  true
485  )) {
486  $whereClause[] = $queryBuilder->expr()->andX(
487  $queryBuilder->expr()->isNotNull($fieldName),
488  $queryBuilder->expr()->neq(
489  $fieldName,
490  $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
491  )
492  );
493  } elseif (in_array($fieldType, [Types::STRING, Types::TEXT], true)) {
494  $whereClause[] = $queryBuilder->expr()->andX(
495  $queryBuilder->expr()->isNotNull($fieldName),
496  $queryBuilder->expr()->neq(
497  $fieldName,
498  $queryBuilder->createNamedParameter('', \PDO::PARAM_STR)
499  )
500  );
501  } elseif ($fieldType === Types::BLOB) {
502  $whereClause[] = $queryBuilder->expr()->andX(
503  $queryBuilder->expr()->isNotNull($fieldName),
504  $queryBuilder->expr()
505  ->comparison(
506  $queryBuilder->expr()->length($fieldName),
508  $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
509  )
510  );
511  }
512  }
513  $queryResult = $queryBuilder->orWhere(...$whereClause)->execute();
514 
515  while ($row = $queryResult->fetch()) {
516  foreach (‪$fields as $field) {
517  if (trim($row[$field])) {
518  $fieldConf = ‪$GLOBALS['TCA'][$table]['columns'][$field]['config'];
519  if ($fieldConf['type'] === 'group') {
520  if ($fieldConf['internal_type'] === 'file') {
521  // @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0. Deprecation logged by TcaMigration class.
522  // Files...
523  if ($fieldConf['MM']) {
524  $tempArr = [];
525  $dbAnalysis = GeneralUtility::makeInstance(RelationHandler::class);
526  $dbAnalysis->start('', 'files', $fieldConf['MM'], $row['uid']);
527  foreach ($dbAnalysis->itemArray as $somekey => $someval) {
528  if ($someval['id']) {
529  $tempArr[] = $someval['id'];
530  }
531  }
532  } else {
533  $tempArr = explode(',', trim($row[$field]));
534  }
535  foreach ($tempArr as $file) {
536  $file = trim($file);
537  if ($file) {
538  $this->checkFileRefs[$fieldConf['uploadfolder']][$file] += 1;
539  }
540  }
541  }
542  if ($fieldConf['internal_type'] === 'db') {
543  $dbAnalysis = GeneralUtility::makeInstance(RelationHandler::class);
544  $dbAnalysis->start(
545  $row[$field],
546  $fieldConf['allowed'],
547  $fieldConf['MM'],
548  $row['uid'],
549  $table,
550  $fieldConf
551  );
552  foreach ($dbAnalysis->itemArray as $tempArr) {
553  $this->checkGroupDBRefs[$tempArr['table']][$tempArr['id']] += 1;
554  }
555  }
556  }
557  if ($fieldConf['type'] === 'select' && $fieldConf['foreign_table']) {
558  $dbAnalysis = GeneralUtility::makeInstance(RelationHandler::class);
559  $dbAnalysis->start(
560  $row[$field],
561  $fieldConf['foreign_table'],
562  $fieldConf['MM'],
563  $row['uid'],
564  $table,
565  $fieldConf
566  );
567  foreach ($dbAnalysis->itemArray as $tempArr) {
568  if ($tempArr['id'] > 0) {
569  $this->checkGroupDBRefs[$fieldConf['foreign_table']][$tempArr['id']] += 1;
570  }
571  }
572  }
573  }
574  }
575  }
576  }
577  }
578  }
579  }
580 
586  public function ‪testFileRefs()
587  {
588  ‪$output = [];
589  // Handle direct references with upload folder setting (workaround)
590  $newCheckFileRefs = [];
591  foreach ($this->checkFileRefs as $folder => $files) {
592  // Only direct references without a folder setting
593  if ($folder !== '') {
594  $newCheckFileRefs[$folder] = $files;
595  continue;
596  }
597  foreach ($files as $file => $references) {
598  // Direct file references have often many references (removes occurrences in the moreReferences section of the result array)
599  if ($references > 1) {
600  $references = 1;
601  }
602  // The directory must be empty (prevents checking of the root directory)
603  $directory = ‪PathUtility::dirname($file);
604  if ($directory !== '') {
605  $newCheckFileRefs[$directory][‪PathUtility::basename($file)] = $references;
606  }
607  }
608  }
609  $this->checkFileRefs = $newCheckFileRefs;
610  foreach ($this->checkFileRefs as $folder => $fileArr) {
611  $path = ‪Environment::getPublicPath() . '/' . $folder;
612  if (@is_dir($path) && @is_readable($path)) {
613  $d = dir($path);
614  while ($entry = $d->read()) {
615  if (@is_file($path . '/' . $entry)) {
616  if (isset($fileArr[$entry])) {
617  if ($fileArr[$entry] > 1) {
618  $temp = $this->‪whereIsFileReferenced($folder, $entry);
619  $tempList = '';
620  foreach ($temp as $inf) {
621  $tempList .= '[' . $inf['table'] . '][' . $inf['uid'] . '][' . $inf['field'] . '] (pid:' . $inf['pid'] . ') - ';
622  }
623  ‪$output['moreReferences'][] = [$path, $entry, $fileArr[$entry], $tempList];
624  }
625  unset($fileArr[$entry]);
626  } else {
627  // Contains workaround for direct references
628  if (!strstr($entry, 'index.htm') && !preg_match('/^' . preg_quote(‪$GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'], '/') . '/', $folder)) {
629  ‪$output['noReferences'][] = [$path, $entry];
630  }
631  }
632  }
633  }
634  $d->close();
635  $tempCounter = 0;
636  foreach ($fileArr as $file => $value) {
637  // Workaround for direct file references
638  if (preg_match('/^' . preg_quote(‪$GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'], '/') . '/', $folder)) {
639  $file = $folder . '/' . $file;
640  $folder = '';
642  }
643  $temp = $this->‪whereIsFileReferenced($folder, $file);
644  $tempList = '';
645  foreach ($temp as $inf) {
646  $tempList .= '[' . $inf['table'] . '][' . $inf['uid'] . '][' . $inf['field'] . '] (pid:' . $inf['pid'] . ') - ';
647  }
648  $tempCounter++;
649  ‪$output['noFile'][substr($path, -3) . '_' . substr($file, 0, 3) . '_' . $tempCounter] = [$path, $file, $tempList];
650  }
651  } else {
652  ‪$output['error'][] = [$path];
653  }
654  }
655  return ‪$output;
656  }
657 
664  public function ‪testDBRefs($theArray)
665  {
666  $result = '';
667  foreach ($theArray as $table => $dbArr) {
668  if (‪$GLOBALS['TCA'][$table]) {
669  $ids = array_keys($dbArr);
670  if (!empty($ids)) {
671  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
672  ->getQueryBuilderForTable($table);
673  $queryBuilder->getRestrictions()
674  ->removeAll()
675  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
676  $queryResult = $queryBuilder
677  ->select('uid')
678  ->from($table)
679  ->where(
680  $queryBuilder->expr()->in(
681  'uid',
682  $queryBuilder->createNamedParameter($ids, Connection::PARAM_INT_ARRAY)
683  )
684  )
685  ->execute();
686  while ($row = $queryResult->fetch()) {
687  if (isset($dbArr[$row['uid']])) {
688  unset($dbArr[$row['uid']]);
689  } else {
690  $result .= 'Strange Error. ...<br />';
691  }
692  }
693  foreach ($dbArr as $theId => $theC) {
694  $result .= 'There are ' . $theC . ' records pointing to this missing or deleted record; [' . $table . '][' . $theId . ']<br />';
695  }
696  }
697  } else {
698  $result .= 'Codeerror. Table is not a table...<br />';
699  }
700  }
701  return $result;
702  }
703 
711  public function ‪whereIsRecordReferenced($searchTable, $id)
712  {
713  // Gets tables / Fields that reference to files
714  $fileFields = $this->‪getDBFields($searchTable);
715  $theRecordList = [];
716  foreach ($fileFields as $info) {
717  list($table, $field) = $info;
718  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
719  $queryBuilder->getRestrictions()->removeAll();
720  $queryResult = $queryBuilder
721  ->select('uid', 'pid', ‪$GLOBALS['TCA'][$table]['ctrl']['label'], $field)
722  ->from($table)
723  ->where(
724  $queryBuilder->expr()->like(
725  $field,
726  $queryBuilder->createNamedParameter('%' . $queryBuilder->escapeLikeWildcards($id) . '%')
727  )
728  )
729  ->execute();
730 
731  while ($row = $queryResult->fetch()) {
732  // Now this is the field, where the reference COULD come from.
733  // But we're not guaranteed, so we must carefully examine the data.
734  $fieldConf = ‪$GLOBALS['TCA'][$table]['columns'][$field]['config'];
735  $allowedTables = $fieldConf['type'] === 'group' ? $fieldConf['allowed'] : $fieldConf['foreign_table'];
736  $dbAnalysis = GeneralUtility::makeInstance(RelationHandler::class);
737  $dbAnalysis->start($row[$field], $allowedTables, $fieldConf['MM'], $row['uid'], $table, $fieldConf);
738  foreach ($dbAnalysis->itemArray as $tempArr) {
739  if ($tempArr['table'] == $searchTable && $tempArr['id'] == $id) {
740  $theRecordList[] = [
741  'table' => $table,
742  'uid' => $row['uid'],
743  'field' => $field,
744  'pid' => $row['pid']
745  ];
746  }
747  }
748  }
749  }
750  return $theRecordList;
751  }
752 
760  public function ‪whereIsFileReferenced($uploadFolder, $filename)
761  {
762  // Gets tables / Fields that reference to files
763  $fileFields = $this->‪getFileFields($uploadFolder);
764  $theRecordList = [];
765  foreach ($fileFields as $info) {
766  list($table, $field) = $info;
767  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
768  $queryBuilder->getRestrictions()->removeAll();
769  $queryResult = $queryBuilder
770  ->select('uid', 'pid', ‪$GLOBALS['TCA'][$table]['ctrl']['label'], $field)
771  ->from($table)
772  ->where(
773  $queryBuilder->expr()->like(
774  $field,
775  $queryBuilder->createNamedParameter('%' . $queryBuilder->escapeLikeWildcards($filename) . '%')
776  )
777  )
778  ->execute();
779  while ($row = $queryResult->fetch()) {
780  // Now this is the field, where the reference COULD come from.
781  // But we're not guaranteed, so we must carefully examine the data.
782  $tempArr = explode(',', trim($row[$field]));
783  foreach ($tempArr as $file) {
784  $file = trim($file);
785  if ($file == $filename) {
786  $theRecordList[] = [
787  'table' => $table,
788  'uid' => $row['uid'],
789  'field' => $field,
790  'pid' => $row['pid']
791  ];
792  }
793  }
794  }
795  }
796  return $theRecordList;
797  }
798 }
‪TYPO3\CMS\Core\Integrity\DatabaseIntegrityCheck\$checkGroupDBRefs
‪array $checkGroupDBRefs
Definition: DatabaseIntegrityCheck.php:75
‪TYPO3\CMS\Core\Integrity\DatabaseIntegrityCheck\$checkFileRefs
‪array $checkFileRefs
Definition: DatabaseIntegrityCheck.php:67
‪TYPO3\CMS\Core\Integrity\DatabaseIntegrityCheck\getGroupFields
‪array getGroupFields($mode)
Definition: DatabaseIntegrityCheck.php:365
‪TYPO3\CMS\Core\Utility\PathUtility
Definition: PathUtility.php:23
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder
Definition: ExpressionBuilder.php:33
‪TYPO3\CMS\Core\Core\Environment\getPublicPath
‪static string getPublicPath()
Definition: Environment.php:153
‪TYPO3\CMS\Core\Utility\PathUtility\dirname
‪static string dirname($path)
Definition: PathUtility.php:185
‪TYPO3\CMS\Core\Integrity\DatabaseIntegrityCheck\$rec_idArray
‪array $rec_idArray
Definition: DatabaseIntegrityCheck.php:63
‪TYPO3\CMS\Core\Database\RelationHandler
Definition: RelationHandler.php:32
‪TYPO3\CMS\Backend\Utility\BackendUtility\getCommonSelectFields
‪static string getCommonSelectFields($table, $prefix='', $fields=[])
Definition: BackendUtility.php:2397
‪TYPO3\CMS\Core\Integrity\DatabaseIntegrityCheck\$page_idArray
‪$page_idArray
Definition: DatabaseIntegrityCheck.php:54
‪TYPO3\CMS\Core\Integrity\DatabaseIntegrityCheck\$genTree_includeVersions
‪$genTree_includeVersions
Definition: DatabaseIntegrityCheck.php:45
‪$fields
‪$fields
Definition: pages.php:4
‪TYPO3\CMS\Core\Integrity\DatabaseIntegrityCheck\__construct
‪__construct()
Definition: DatabaseIntegrityCheck.php:96
‪TYPO3\CMS\Core\Utility\PathUtility\basename
‪static string basename($path)
Definition: PathUtility.php:164
‪TYPO3\CMS\Backend\Utility\BackendUtility\isTableWorkspaceEnabled
‪static bool isTableWorkspaceEnabled($table)
Definition: BackendUtility.php:4493
‪TYPO3\CMS\Core\Integrity\DatabaseIntegrityCheck\$checkSelectDBRefs
‪array $checkSelectDBRefs
Definition: DatabaseIntegrityCheck.php:71
‪TYPO3\CMS\Core\Integrity\DatabaseIntegrityCheck\$recStats
‪array $recStats
Definition: DatabaseIntegrityCheck.php:79
‪TYPO3\CMS\Core\Integrity\DatabaseIntegrityCheck\lostRecords
‪lostRecords($pid_list)
Definition: DatabaseIntegrityCheck.php:232
‪TYPO3\CMS\Core\Integrity\DatabaseIntegrityCheck\$lostPagesList
‪string $lostPagesList
Definition: DatabaseIntegrityCheck.php:91
‪TYPO3\CMS\Core\Integrity\DatabaseIntegrityCheck\testFileRefs
‪array testFileRefs()
Definition: DatabaseIntegrityCheck.php:577
‪TYPO3\CMS\Core\Integrity\DatabaseIntegrityCheck\getPageTranslatedPageIDArray
‪array getPageTranslatedPageIDArray()
Definition: DatabaseIntegrityCheck.php:104
‪TYPO3\CMS\Core\Integrity\DatabaseIntegrityCheck\$genTree_includeRecords
‪bool $genTree_includeRecords
Definition: DatabaseIntegrityCheck.php:49
‪TYPO3\CMS\Core\Integrity\DatabaseIntegrityCheck\testDBRefs
‪string testDBRefs($theArray)
Definition: DatabaseIntegrityCheck.php:655
‪TYPO3\CMS\Core\Integrity\DatabaseIntegrityCheck
Definition: DatabaseIntegrityCheck.php:37
‪TYPO3\CMS\Core\Integrity\DatabaseIntegrityCheck\genTree
‪genTree($theID, $depthData='', $versions=false)
Definition: DatabaseIntegrityCheck.php:117
‪TYPO3\CMS\Core\Integrity
Definition: DatabaseIntegrityCheck.php:2
‪TYPO3\CMS\Core\Integrity\DatabaseIntegrityCheck\selectNonEmptyRecordsWithFkeys
‪selectNonEmptyRecordsWithFkeys($fkey_arrays)
Definition: DatabaseIntegrityCheck.php:439
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\GT
‪const GT
Definition: ExpressionBuilder.php:38
‪TYPO3\CMS\Backend\Utility\BackendUtility\getRecordTitle
‪static string getRecordTitle($table, $row, $prep=false, $forceResult=true)
Definition: BackendUtility.php:1811
‪TYPO3\CMS\Backend\Utility\BackendUtility
Definition: BackendUtility.php:72
‪$output
‪$output
Definition: annotationChecker.php:113
‪TYPO3\CMS\Core\Integrity\DatabaseIntegrityCheck\genTree_records
‪genTree_records($theID, $_='', $table='', $versions=false)
Definition: DatabaseIntegrityCheck.php:185
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:31
‪TYPO3\CMS\Core\Integrity\DatabaseIntegrityCheck\fixLostRecord
‪bool fixLostRecord($table, $uid)
Definition: DatabaseIntegrityCheck.php:283
‪TYPO3\CMS\Core\Integrity\DatabaseIntegrityCheck\getFileFields
‪array getFileFields($uploadfolder)
Definition: DatabaseIntegrityCheck.php:395
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction
Definition: DeletedRestriction.php:26
‪TYPO3\CMS\Core\Core\Environment
Definition: Environment.php:39
‪TYPO3\CMS\Core\Integrity\DatabaseIntegrityCheck\$page_translatedPageIDArray
‪$page_translatedPageIDArray
Definition: DatabaseIntegrityCheck.php:59
‪TYPO3\CMS\Core\Integrity\DatabaseIntegrityCheck\whereIsRecordReferenced
‪array whereIsRecordReferenced($searchTable, $id)
Definition: DatabaseIntegrityCheck.php:702
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:44
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:45
‪TYPO3\CMS\Core\Integrity\DatabaseIntegrityCheck\$genTree_includeDeleted
‪bool $genTree_includeDeleted
Definition: DatabaseIntegrityCheck.php:40
‪TYPO3\CMS\Core\Integrity\DatabaseIntegrityCheck\countRecords
‪array countRecords($pid_list)
Definition: DatabaseIntegrityCheck.php:307
‪TYPO3\CMS\Core\Integrity\DatabaseIntegrityCheck\$lRecords
‪array $lRecords
Definition: DatabaseIntegrityCheck.php:87
‪TYPO3\CMS\Core\Integrity\DatabaseIntegrityCheck\whereIsFileReferenced
‪array whereIsFileReferenced($uploadFolder, $filename)
Definition: DatabaseIntegrityCheck.php:751
‪TYPO3\CMS\Core\Integrity\DatabaseIntegrityCheck\getDBFields
‪array getDBFields($theSearchTable)
Definition: DatabaseIntegrityCheck.php:415