TYPO3 API  SVNRelease
class.rte_images.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: RTE magicc images
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  *   56: class tx_lowlevel_rte_images extends tx_lowlevel_cleaner_core
00039  *   65:     function tx_lowlevel_rte_images()
00040  *   99:     function main()
00041  *  181:     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 RTE images integrity
00049  *
00050  * @author  Kasper Skårhøj <kasperYYYY@typo3.com>
00051  * @package TYPO3
00052  * @subpackage tx_lowlevel
00053  */
00054 class tx_lowlevel_rte_images extends tx_lowlevel_cleaner_core {
00055 
00056     var $checkRefIndex = TRUE;
00057 
00058     /**
00059      * Constructor
00060      *
00061      * @return  void
00062      */
00063     function tx_lowlevel_rte_images()   {
00064         parent::tx_lowlevel_cleaner_core();
00065 
00066             // Setting up help:
00067         $this->cli_help['name'] = 'rte_images -- Looking up all occurencies of RTEmagic images in the database and check existence of parent and copy files on the file system plus report possibly lost files of this type.';
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 - that all RTEmagic image files in the database are registered with the soft reference parser "images"
00072 - images found in deleted records are included (means that you might find lost RTEmagic images after flushing deleted records)
00073 
00074 The assumptions are not requirements by the TYPO3 API but reflects the de facto implementation of most TYPO3 installations.
00075 However, many custom fields using an RTE will probably not have the "images" soft reference parser registered and so the index will be incomplete and not listing all RTEmagic image files.
00076 The consequence of this limitation is that you should be careful if you wish to delete lost RTEmagic images - they could be referenced from a field not parsed by the "images" soft reference parser!
00077 
00078 Automatic Repair of Errors:
00079 - Will search for double-usages of RTEmagic images and make copies as required.
00080 - Lost files can be deleted automatically by setting the value "lostFiles" as an optional parameter to --AUTOFIX, but otherwise delete them manually if you do not recognize them as used somewhere the system does not know about.
00081 
00082 Manual repair suggestions:
00083 - Missing files: Re-insert missing files or edit record where the reference is found.
00084 ');
00085 
00086         $this->cli_help['examples'] = '/.../cli_dispatch.phpsh lowlevel_cleaner rte_images -s -r
00087 Reports problems with RTE images';
00088     }
00089 
00090     /**
00091      * Analyse situation with RTE magic images. (still to define what the most useful output is).
00092      * Fix methods: API in t3lib_refindex that allows to change the value of a reference (we could copy the files) or remove reference
00093      *
00094      * @return  array
00095      */
00096     function main() {
00097             global $TYPO3_DB;
00098 
00099             // Initialize result array:
00100         $resultArray = array(
00101             'message' => $this->cli_help['name'].LF.LF.$this->cli_help['description'],
00102             'headers' => array(
00103                 'completeFileList' => array('Complete list of used RTEmagic files','Both parent and copy are listed here including usage count (which should in theory all be "1"). This list does not exclude files that might be missing.',1),
00104                 'RTEmagicFilePairs' => array('Statistical info about RTEmagic files','(copy used as index)',0),
00105                 'doubleFiles' => array('Duplicate RTEmagic image files','These files are RTEmagic images found used in multiple records! RTEmagic images should be used by only one record at a time. A large amount of such images probably stems from previous versions of TYPO3 (before 4.2) which did not support making copies automatically of RTEmagic images in case of new copies / versions.',3),
00106                 'missingFiles' => array('Missing RTEmagic image files','These files are not found in the file system! Should be corrected!',3),
00107                 'lostFiles' => array('Lost RTEmagic files from uploads/','These files you might be able to delete but only if _all_ RTEmagic images are found by the soft reference parser. If you are using the RTE in third-party extensions it is likely that the soft reference parser is not applied correctly to their RTE and thus these "lost" files actually represent valid RTEmagic images, just not registered. Lost files can be auto-fixed but only if you specifically set "lostFiles" as parameter to the --AUTOFIX option.',2),
00108             ),
00109             'RTEmagicFilePairs' => array(),
00110             'doubleFiles' => array(),
00111             'completeFileList' => array(),
00112             'missingFiles' => array(),
00113             'lostFiles' => array(),
00114         );
00115 
00116             // Select all RTEmagic files in the reference table (only from soft references of course)
00117         $recs = $TYPO3_DB->exec_SELECTgetRows(
00118             '*',
00119             'sys_refindex',
00120             'ref_table='.$TYPO3_DB->fullQuoteStr('_FILE', 'sys_refindex').
00121                 ' AND ref_string LIKE '.$TYPO3_DB->fullQuoteStr('%/RTEmagic%', 'sys_refindex').
00122                 ' AND softref_key='.$TYPO3_DB->fullQuoteStr('images', 'sys_refindex'),
00123             '',
00124             'sorting DESC'
00125         );
00126 
00127             // Traverse the files and put into a large table:
00128         if (is_array($recs)) {
00129             foreach($recs as $rec)  {
00130                 $filename = basename($rec['ref_string']);
00131                 if (t3lib_div::isFirstPartOfStr($filename,'RTEmagicC_'))    {
00132                     $original = 'RTEmagicP_'.preg_replace('/\.[[:alnum:]]+$/','',substr($filename,10));
00133                     $infoString = $this->infoStr($rec);
00134 
00135                         // Build index:
00136                     $resultArray['RTEmagicFilePairs'][$rec['ref_string']]['exists'] = @is_file(PATH_site.$rec['ref_string']);
00137                     $resultArray['RTEmagicFilePairs'][$rec['ref_string']]['original'] = substr($rec['ref_string'],0,-strlen($filename)).$original;
00138                     $resultArray['RTEmagicFilePairs'][$rec['ref_string']]['original_exists'] = @is_file(PATH_site.$resultArray['RTEmagicFilePairs'][$rec['ref_string']]['original']);
00139                     $resultArray['RTEmagicFilePairs'][$rec['ref_string']]['count']++;
00140                     $resultArray['RTEmagicFilePairs'][$rec['ref_string']]['usedIn'][$rec['hash']] = $infoString;
00141 
00142                     $resultArray['completeFileList'][$resultArray['RTEmagicFilePairs'][$rec['ref_string']]['original']]++;
00143                     $resultArray['completeFileList'][$rec['ref_string']]++;
00144 
00145                         // Missing files:
00146                     if (!$resultArray['RTEmagicFilePairs'][$rec['ref_string']]['exists'])   {
00147                         $resultArray['missingFiles'][$rec['ref_string']] = $resultArray['RTEmagicFilePairs'][$rec['ref_string']]['usedIn'];
00148                     }
00149                     if (!$resultArray['RTEmagicFilePairs'][$rec['ref_string']]['original_exists'])  {
00150                         $resultArray['missingFiles'][$resultArray['RTEmagicFilePairs'][$rec['ref_string']]['original']] = $resultArray['RTEmagicFilePairs'][$rec['ref_string']]['usedIn'];
00151                     }
00152                 }
00153             }
00154 
00155                 // Searching for duplicates:
00156             foreach($resultArray['RTEmagicFilePairs'] as $fileName => $fileInfo) {
00157                 if ($fileInfo['count']>1 && $fileInfo['exists'] && $fileInfo['original_exists'])    {
00158                     $resultArray['doubleFiles'][$fileName] = $fileInfo['usedIn'];
00159                 }
00160             }
00161         }
00162 
00163             // Now, ask for RTEmagic files inside uploads/ folder:
00164         $cleanerModules = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['lowlevel']['cleanerModules'];
00165         $cleanerMode = t3lib_div::getUserObj($cleanerModules['lost_files'][0]);
00166         $resLostFiles = $cleanerMode->main(array(),FALSE,TRUE);
00167         if (is_array($resLostFiles['RTEmagicFiles']))   {
00168             foreach($resLostFiles['RTEmagicFiles'] as $fileName) {
00169                 if (!isset($resultArray['completeFileList'][$fileName]))    {
00170                     $resultArray['lostFiles'][$fileName] = $fileName;
00171                 }
00172             }
00173         }
00174 
00175 
00176         ksort($resultArray['RTEmagicFilePairs']);
00177         ksort($resultArray['completeFileList']);
00178         ksort($resultArray['missingFiles']);
00179         ksort($resultArray['doubleFiles']);
00180         ksort($resultArray['lostFiles']);
00181     #   print_r($resultArray);
00182 
00183         return $resultArray;
00184     }
00185 
00186     /**
00187      * Mandatory autofix function
00188      * Will run auto-fix on the result array. Echos status during processing.
00189      *
00190      * @param   array       Result array from main() function
00191      * @return  void
00192      */
00193     function main_autoFix($resultArray) {
00194 
00195         $limitTo = $this->cli_args['--AUTOFIX'][0];
00196 
00197         if (is_array($resultArray['doubleFiles']))  {
00198             if (!$limitTo || $limitTo==='doubleFiles')  {
00199 
00200                 echo 'FIXING double-usages of RTE files in uploads/: '.LF;
00201                 foreach($resultArray['RTEmagicFilePairs'] as $fileName => $fileInfo) {
00202 
00203                         // Only fix something if there is a usage count of more than 1 plus if both original and copy exists:
00204                     if ($fileInfo['count']>1 && $fileInfo['exists'] && $fileInfo['original_exists'])    {
00205 
00206                             // Traverse all records using the file:
00207                         $c=0;
00208                         foreach($fileInfo['usedIn'] as $hash => $recordID)  {
00209                             if ($c==0)  {
00210                                 echo '  Keeping file '.$fileName.' for record '.$recordID.LF;
00211                             } else {
00212                                     // CODE below is adapted from "class.tx_impexp.php" where there is support for duplication of RTE images:
00213                                 echo '  Copying file '.basename($fileName).' for record '.$recordID.' ';
00214 
00215                                     // Initialize; Get directory prefix for file and set the original name:
00216                                 $dirPrefix = dirname($fileName).'/';
00217                                 $rteOrigName = basename($fileInfo['original']);
00218 
00219                                     // If filename looks like an RTE file, and the directory is in "uploads/", then process as a RTE file!
00220                                 if ($rteOrigName && t3lib_div::isFirstPartOfStr($dirPrefix,'uploads/') && @is_dir(PATH_site.$dirPrefix))    {   // RTE:
00221 
00222                                         // From the "original" RTE filename, produce a new "original" destination filename which is unused.
00223                                     $fileProcObj = $this->getFileProcObj();
00224                                     $origDestName = $fileProcObj->getUniqueName($rteOrigName, PATH_site.$dirPrefix);
00225 
00226                                         // Create copy file name:
00227                                     $pI = pathinfo($fileName);
00228                                     $copyDestName = dirname($origDestName).'/RTEmagicC_'.substr(basename($origDestName),10).'.'.$pI['extension'];
00229                                     if (!@is_file($copyDestName) && !@is_file($origDestName)
00230                                         && $origDestName===t3lib_div::getFileAbsFileName($origDestName) && $copyDestName===t3lib_div::getFileAbsFileName($copyDestName))    {
00231 
00232                                         echo ' to '.basename($copyDestName);
00233 
00234                                         if ($bypass = $this->cli_noExecutionCheck($fileName))   {
00235                                             echo $bypass;
00236                                         } else {
00237                                                 // Making copies:
00238                                             t3lib_div::upload_copy_move(PATH_site.$fileInfo['original'],$origDestName);
00239                                             t3lib_div::upload_copy_move(PATH_site.$fileName,$copyDestName);
00240                                             clearstatcache();
00241 
00242                                             if (@is_file($copyDestName))    {
00243                                                 $sysRefObj = t3lib_div::makeInstance('t3lib_refindex');
00244                                                 $error = $sysRefObj->setReferenceValue($hash,substr($copyDestName,strlen(PATH_site)));
00245                                                 if ($error) {
00246                                                     echo '  - ERROR:    t3lib_refindex::setReferenceValue(): '.$error.LF;
00247                                                     exit;
00248                                                 } else echo " - DONE";
00249                                             } else {
00250                                                 echo '  - ERROR: File "'.$copyDestName.'" was not created!';
00251                                             }
00252                                         }
00253                                     } else echo '   - ERROR: Could not construct new unique names for file!';
00254                                 } else echo '   - ERROR: Maybe directory of file was not within "uploads/"?';
00255                                 echo LF;
00256                             }
00257                             $c++;
00258                         }
00259                     }
00260                 }
00261             } else echo 'Bypassing fixing of double-usages since --AUTOFIX was not "doubleFiles"'.LF;
00262         }
00263 
00264 
00265         if (is_array($resultArray['lostFiles']))    {
00266             if ($limitTo==='lostFiles') {
00267                 echo 'Removing lost RTEmagic files from folders inside uploads/: '.LF;
00268 
00269                 foreach($resultArray['lostFiles'] as $key => $value)    {
00270                     $absFileName = t3lib_div::getFileAbsFileName($value);
00271                     echo 'Deleting file: "'.$absFileName.'": ';
00272                     if ($bypass = $this->cli_noExecutionCheck($absFileName))    {
00273                         echo $bypass;
00274                     } else {
00275                         if ($absFileName && @is_file($absFileName)) {
00276                             unlink($absFileName);
00277                             echo 'DONE';
00278                         } else {
00279                             echo '  ERROR: File "'.$absFileName.'" was not found!';
00280                         }
00281                     }
00282                     echo LF;
00283                 }
00284             }
00285         } else echo 'Bypassing fixing of double-usages since --AUTOFIX was not "lostFiles"'.LF;
00286     }
00287 
00288     /**
00289      * Returns file processing object, initialized only once.
00290      *
00291      * @return  object      File processor object
00292      */
00293     function getFileProcObj() {
00294         if (!is_object($this->fileProcObj)) {
00295             $this->fileProcObj = t3lib_div::makeInstance('t3lib_extFileFunctions');
00296             $this->fileProcObj->init($GLOBALS['FILEMOUNTS'], $GLOBALS['TYPO3_CONF_VARS']['BE']['fileExtensions']);
00297             $this->fileProcObj->init_actionPerms($GLOBALS['BE_USER']->getFileoperationPermissions());
00298         }
00299         return $this->fileProcObj;
00300     }
00301 }
00302 
00303 ?>