Cleanup: Updated copyright comments
[Packages/TYPO3.CMS.git] / typo3 / sysext / lowlevel / clmods / class.double_files.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 * Cleaner module: Double Files
29 * User function called from tx_lowlevel_cleaner_core configured in ext_localconf.php
30 *
31 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
32 */
33 /**
34 * [CLASS/FUNCTION INDEX of SCRIPT]
35 *
36 *
37 *
38 * 58: class tx_lowlevel_double_files extends tx_lowlevel_cleaner_core
39 * 67: function tx_lowlevel_double_files()
40 * 99: function main()
41 * 182: function main_autoFix($resultArray)
42 *
43 * TOTAL FUNCTIONS: 3
44 * (This index is automatically created/updated by the extension "extdeveval")
45 *
46 */
47 /**
48 * Looking for double files
49 *
50 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
51 * @package TYPO3
52 * @subpackage tx_lowlevel
53 */
54 class tx_lowlevel_double_files extends tx_lowlevel_cleaner_core {
55
56 var $checkRefIndex = TRUE;
57
58 /**
59 * Constructor
60 *
61 * @return void
62 */
63 function tx_lowlevel_double_files() {
64 parent::tx_lowlevel_cleaner_core();
65
66 // Setting up help:
67 $this->cli_help['name'] = 'double_files -- Looking for files from TYPO3 managed records which are referenced more than one time (only one time allowed)';
68 $this->cli_help['description'] = trim('
69 Assumptions:
70 - a perfect integrity of the reference index table (always update the reference index table before using this tool!)
71 - files found in deleted records are included (otherwise you would see a false list of lost files)
72
73 Files attached to records in TYPO3 using a "group" type configuration in TCA or FlexForm DataStructure are managed exclusively by the system and there must always exist a 1-1 reference between the file and the reference in the record.
74 This tool will expose when such files are referenced from multiple locations which is considered an integrity error.
75 If a multi-reference is found it was typically created because the record was copied or modified outside of TCEmain which will otherwise maintain the relations correctly.
76 Multi-references should be resolved to 1-1 references as soon as possible. The danger of keeping multi-references is that if the file is removed from one of the refering records it will actually be deleted in the file system, leaving missing files for the remaining referers!
77
78 Automatic Repair of Errors:
79 - The multi-referenced file is copied under a new name and references updated.
80
81 Manual repair suggestions:
82 - None that can not be handled by the automatic repair.
83 ');
84
85 $this->cli_help['examples'] = '/.../cli_dispatch.phpsh lowlevel_cleaner double_files -s -r
86 This will check the system for double files relations.';
87 }
88
89 /**
90 * Find managed files which are referred to more than one time
91 * Fix methods: API in t3lib_refindex that allows to change the value of a reference (we could copy the file) or remove reference
92 *
93 * @return array
94 */
95 function main() {
96 global $TYPO3_DB;
97
98 // Initialize result array:
99 $resultArray = array(
100 'message' => $this->cli_help['name'].LF.LF.$this->cli_help['description'],
101 'headers' => array(
102 'multipleReferencesList_count' => array('Number of multi-reference files','(See below)',0),
103 'singleReferencesList_count' => array('Number of files correctly referenced','The amount of correct 1-1 references',0),
104 'multipleReferencesList' => array('Entries with files having multiple references','These are serious problems that should be resolved ASAP to prevent data loss! '.$this->label_infoString,3),
105 'dirname_registry' => array('Registry of directories in which files are found.','Registry includes which table/field pairs store files in them plus how many files their store.',0),
106 'missingFiles' => array('Tracking missing files','(Extra feature, not related to tracking of double references. Further, the list may include more files than found in the missing_files()-test because this list includes missing files from deleted records.)',0),
107 'warnings' => array('Warnings picked up','',2)
108 ),
109 'multipleReferencesList_count' => array('count' => 0),
110 'singleReferencesList_count' => array('count' => 0),
111 'multipleReferencesList' => array(),
112 'dirname_registry' => array(),
113 'missingFiles' => array(),
114 'warnings' => array()
115 );
116
117 // Select all files in the reference table not found by a soft reference parser (thus TCA configured)
118 $recs = $TYPO3_DB->exec_SELECTgetRows(
119 '*',
120 'sys_refindex',
121 'ref_table='.$TYPO3_DB->fullQuoteStr('_FILE', 'sys_refindex').
122 ' AND softref_key='.$TYPO3_DB->fullQuoteStr('', 'sys_refindex'),
123 '',
124 'sorting DESC'
125 );
126
127 // Traverse the files and put into a large table:
128 $tempCount = array();
129 if (is_array($recs)) {
130 foreach($recs as $rec) {
131
132 // Compile info string for location of reference:
133 $infoString = $this->infoStr($rec);
134
135 // Registering occurencies in directories:
136 $resultArray['dirname_registry'][dirname($rec['ref_string'])][$rec['tablename'].':'.$rec['field']]++;
137
138 // Handle missing file:
139 if (!@is_file(PATH_site.$rec['ref_string'])) {
140 $resultArray['missingFiles'][$rec['ref_string']][$rec['hash']] = $infoString;
141 ksort($resultArray['missingFiles'][$rec['ref_string']]); // Sort by array key
142 }
143
144 // Add entry if file has multiple references pointing to it:
145 if (isset($tempCount[$rec['ref_string']])) {
146 if (!is_array($resultArray['multipleReferencesList'][$rec['ref_string']])) {
147 $resultArray['multipleReferencesList'][$rec['ref_string']] = array();
148 $resultArray['multipleReferencesList'][$rec['ref_string']][$tempCount[$rec['ref_string']][1]] = $tempCount[$rec['ref_string']][0];
149 }
150 $resultArray['multipleReferencesList'][$rec['ref_string']][$rec['hash']] = $infoString;
151 ksort($resultArray['multipleReferencesList'][$rec['ref_string']]);
152 } else {
153 $tempCount[$rec['ref_string']] = array($infoString,$rec['hash']);
154 }
155 }
156 }
157
158 ksort($resultArray['missingFiles']);
159 ksort($resultArray['multipleReferencesList']);
160
161 // Add count for multi-references:
162 $resultArray['multipleReferencesList_count']['count'] = count($resultArray['multipleReferencesList']);
163 $resultArray['singleReferencesList_count']['count'] = count($tempCount) - $resultArray['multipleReferencesList_count']['count'];
164
165 // Sort dirname registry and add warnings for directories outside uploads/
166 ksort($resultArray['dirname_registry']);
167 foreach($resultArray['dirname_registry'] as $dir => $temp) {
168 ksort($resultArray['dirname_registry'][$dir]);
169 if (!t3lib_div::isFirstPartOfStr($dir,'uploads/')) {
170 $resultArray['warnings'][t3lib_div::shortmd5($dir)] = 'Directory "'.$dir.'" was outside uploads/ which is unusual practice in TYPO3 although not forbidden. Directory used by the following table:field pairs: '.implode(',',array_keys($temp));
171 }
172 }
173
174 return $resultArray;
175 }
176
177 /**
178 * Mandatory autofix function
179 * Will run auto-fix on the result array. Echos status during processing.
180 *
181 * @param array Result array from main() function
182 * @return void
183 */
184 function main_autoFix($resultArray) {
185 foreach($resultArray['multipleReferencesList'] as $key => $value) {
186 $absFileName = t3lib_div::getFileAbsFileName($key);
187 if ($absFileName && @is_file($absFileName)) {
188 echo 'Processing file: '.$key.LF;
189 $c=0;
190 foreach($value as $hash => $recReference) {
191 if ($c==0) {
192 echo ' Keeping '.$key.' for record "'.$recReference.'"'.LF;
193 } else {
194 // Create unique name for file:
195 $fileFunc = t3lib_div::makeInstance('t3lib_basicFileFunctions');
196 $newName = $fileFunc->getUniqueName(basename($key), dirname($absFileName));
197 echo ' Copying '.$key.' to '.substr($newName,strlen(PATH_site)).' for record "'.$recReference.'": ';
198
199 if ($bypass = $this->cli_noExecutionCheck($recReference)) {
200 echo $bypass;
201 } else {
202 t3lib_div::upload_copy_move($absFileName,$newName);
203 clearstatcache();
204
205 if (@is_file($newName)) {
206 $sysRefObj = t3lib_div::makeInstance('t3lib_refindex');
207 $error = $sysRefObj->setReferenceValue($hash,basename($newName));
208 if ($error) {
209 echo ' ERROR: t3lib_refindex::setReferenceValue(): '.$error.LF;
210 exit;
211 } else echo "DONE";
212 } else {
213 echo ' ERROR: File "'.$newName.'" was not created!';
214 }
215 }
216 echo LF;
217 }
218 $c++;
219 }
220 } else {
221 echo ' ERROR: File "'.$absFileName.'" was not found!';
222 }
223 }
224 }
225 }
226
227 ?>