TYPO3 API  SVNRelease
class.double_files.php
Go to the documentation of this file.
00001 <?php
00002 /***************************************************************
00003 *  Copyright notice
00004 *
00005 *  (c) 1999-2011 Kasper Skårhøj (kasperYYYY@typo3.com)
00006 *  All rights reserved
00007 *
00008 *  This script is part of the TYPO3 project. The TYPO3 project is
00009 *  free software; you can redistribute it and/or modify
00010 *  it under the terms of the GNU General Public License as published by
00011 *  the Free Software Foundation; either version 2 of the License, or
00012 *  (at your option) any later version.
00013 *
00014 *  The GNU General Public License can be found at
00015 *  http://www.gnu.org/copyleft/gpl.html.
00016 *  A copy is found in the textfile GPL.txt and important notices to the license
00017 *  from the author is found in LICENSE.txt distributed with these scripts.
00018 *
00019 *
00020 *  This script is distributed in the hope that it will be useful,
00021 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00022 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023 *  GNU General Public License for more details.
00024 *
00025 *  This copyright notice MUST APPEAR in all copies of the script!
00026 ***************************************************************/
00027 /**
00028  * Cleaner module: Double Files
00029  * User function called from tx_lowlevel_cleaner_core configured in ext_localconf.php
00030  *
00031  * @author  Kasper Skårhøj <kasperYYYY@typo3.com>
00032  */
00033 /**
00034  * [CLASS/FUNCTION INDEX of SCRIPT]
00035  *
00036  *
00037  *
00038  *   58: class tx_lowlevel_double_files extends tx_lowlevel_cleaner_core
00039  *   67:     function tx_lowlevel_double_files()
00040  *   99:     function main()
00041  *  182:     function main_autoFix($resultArray)
00042  *
00043  * TOTAL FUNCTIONS: 3
00044  * (This index is automatically created/updated by the extension "extdeveval")
00045  *
00046  */
00047 /**
00048  * Looking for double files
00049  *
00050  * @author  Kasper Skårhøj <kasperYYYY@typo3.com>
00051  * @package TYPO3
00052  * @subpackage tx_lowlevel
00053  */
00054 class tx_lowlevel_double_files extends tx_lowlevel_cleaner_core {
00055 
00056     var $checkRefIndex = TRUE;
00057 
00058     /**
00059      * Constructor
00060      *
00061      * @return  void
00062      */
00063     function tx_lowlevel_double_files() {
00064         parent::tx_lowlevel_cleaner_core();
00065 
00066             // Setting up help:
00067         $this->cli_help['name'] = 'double_files -- Looking for files from TYPO3 managed records which are referenced more than one time (only one time allowed)';
00068         $this->cli_help['description'] = trim('
00069 Assumptions:
00070 - a perfect integrity of the reference index table (always update the reference index table before using this tool!)
00071 - files found in deleted records are included (otherwise you would see a false list of lost files)
00072 
00073 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.
00074 This tool will expose when such files are referenced from multiple locations which is considered an integrity error.
00075 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.
00076 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!
00077 
00078 Automatic Repair of Errors:
00079 - The multi-referenced file is copied under a new name and references updated.
00080 
00081 Manual repair suggestions:
00082 - None that can not be handled by the automatic repair.
00083 ');
00084 
00085         $this->cli_help['examples'] = '/.../cli_dispatch.phpsh lowlevel_cleaner double_files -s -r
00086 This will check the system for double files relations.';
00087     }
00088 
00089     /**
00090      * Find managed files which are referred to more than one time
00091      * Fix methods: API in t3lib_refindex that allows to change the value of a reference (we could copy the file) or remove reference
00092      *
00093      * @return  array
00094      */
00095     function main() {
00096         global $TYPO3_DB;
00097 
00098             // Initialize result array:
00099         $resultArray = array(
00100             'message' => $this->cli_help['name'].LF.LF.$this->cli_help['description'],
00101             'headers' => array(
00102                 'multipleReferencesList_count' => array('Number of multi-reference files','(See below)',0),
00103                 'singleReferencesList_count' => array('Number of files correctly referenced','The amount of correct 1-1 references',0),
00104                 '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),
00105                 '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),
00106                 '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),
00107                 'warnings' => array('Warnings picked up','',2)
00108             ),
00109             'multipleReferencesList_count' => array('count' => 0),
00110             'singleReferencesList_count' => array('count' => 0),
00111             'multipleReferencesList' => array(),
00112             'dirname_registry' => array(),
00113             'missingFiles' => array(),
00114             'warnings' => array()
00115         );
00116 
00117             // Select all files in the reference table not found by a soft reference parser (thus TCA configured)
00118         $recs = $TYPO3_DB->exec_SELECTgetRows(
00119             '*',
00120             'sys_refindex',
00121             'ref_table='.$TYPO3_DB->fullQuoteStr('_FILE', 'sys_refindex').
00122                 ' AND softref_key='.$TYPO3_DB->fullQuoteStr('', 'sys_refindex'),
00123             '',
00124             'sorting DESC'
00125         );
00126 
00127             // Traverse the files and put into a large table:
00128         $tempCount = array();
00129         if (is_array($recs)) {
00130             foreach($recs as $rec)  {
00131 
00132                     // Compile info string for location of reference:
00133                 $infoString = $this->infoStr($rec);
00134 
00135                     // Registering occurencies in directories:
00136                 $resultArray['dirname_registry'][dirname($rec['ref_string'])][$rec['tablename'].':'.$rec['field']]++;
00137 
00138                     // Handle missing file:
00139                 if (!@is_file(PATH_site.$rec['ref_string']))    {
00140                     $resultArray['missingFiles'][$rec['ref_string']][$rec['hash']] = $infoString;
00141                     ksort($resultArray['missingFiles'][$rec['ref_string']]);    // Sort by array key
00142                 }
00143 
00144                     // Add entry if file has multiple references pointing to it:
00145                 if (isset($tempCount[$rec['ref_string']]))  {
00146                     if (!is_array($resultArray['multipleReferencesList'][$rec['ref_string']]))  {
00147                         $resultArray['multipleReferencesList'][$rec['ref_string']] = array();
00148                         $resultArray['multipleReferencesList'][$rec['ref_string']][$tempCount[$rec['ref_string']][1]] = $tempCount[$rec['ref_string']][0];
00149                     }
00150                     $resultArray['multipleReferencesList'][$rec['ref_string']][$rec['hash']] = $infoString;
00151                     ksort($resultArray['multipleReferencesList'][$rec['ref_string']]);
00152                 } else {
00153                     $tempCount[$rec['ref_string']] = array($infoString,$rec['hash']);
00154                 }
00155             }
00156         }
00157 
00158         ksort($resultArray['missingFiles']);
00159         ksort($resultArray['multipleReferencesList']);
00160 
00161             // Add count for multi-references:
00162         $resultArray['multipleReferencesList_count']['count'] = count($resultArray['multipleReferencesList']);
00163         $resultArray['singleReferencesList_count']['count'] = count($tempCount) - $resultArray['multipleReferencesList_count']['count'];
00164 
00165             // Sort dirname registry and add warnings for directories outside uploads/
00166         ksort($resultArray['dirname_registry']);
00167         foreach($resultArray['dirname_registry'] as $dir => $temp)  {
00168             ksort($resultArray['dirname_registry'][$dir]);
00169             if (!t3lib_div::isFirstPartOfStr($dir,'uploads/'))  {
00170                 $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));
00171             }
00172         }
00173 
00174         return $resultArray;
00175     }
00176 
00177     /**
00178      * Mandatory autofix function
00179      * Will run auto-fix on the result array. Echos status during processing.
00180      *
00181      * @param   array       Result array from main() function
00182      * @return  void
00183      */
00184     function main_autoFix($resultArray) {
00185         foreach($resultArray['multipleReferencesList'] as $key => $value)   {
00186             $absFileName = t3lib_div::getFileAbsFileName($key);
00187             if ($absFileName && @is_file($absFileName)) {
00188                 echo 'Processing file: '.$key.LF;
00189                 $c=0;
00190                 foreach($value as $hash => $recReference)   {
00191                     if ($c==0)  {
00192                         echo '  Keeping '.$key.' for record "'.$recReference.'"'.LF;
00193                     } else {
00194                             // Create unique name for file:
00195                         $fileFunc = t3lib_div::makeInstance('t3lib_basicFileFunctions');
00196                         $newName = $fileFunc->getUniqueName(basename($key), dirname($absFileName));
00197                         echo '  Copying '.$key.' to '.substr($newName,strlen(PATH_site)).' for record "'.$recReference.'": ';
00198 
00199                         if ($bypass = $this->cli_noExecutionCheck($recReference))   {
00200                             echo $bypass;
00201                         } else {
00202                             t3lib_div::upload_copy_move($absFileName,$newName);
00203                             clearstatcache();
00204 
00205                             if (@is_file($newName)) {
00206                                 $sysRefObj = t3lib_div::makeInstance('t3lib_refindex');
00207                                 $error = $sysRefObj->setReferenceValue($hash,basename($newName));
00208                                 if ($error) {
00209                                     echo '  ERROR:  t3lib_refindex::setReferenceValue(): '.$error.LF;
00210                                     exit;
00211                                 } else echo "DONE";
00212                             } else {
00213                                 echo '  ERROR: File "'.$newName.'" was not created!';
00214                             }
00215                         }
00216                         echo LF;
00217                     }
00218                     $c++;
00219                 }
00220             } else {
00221                 echo '  ERROR: File "'.$absFileName.'" was not found!';
00222             }
00223         }
00224     }
00225 }
00226 
00227 ?>