TYPO3 API  SVNRelease
class.tx_impexp.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  * T3D file Import/Export library (TYPO3 Record Document)
00029  *
00030  * @author  Kasper Skårhøj <kasperYYYY@typo3.com>
00031  */
00032 /**
00033  * [CLASS/FUNCTION INDEX of SCRIPT]
00034  *
00035  *
00036  *
00037  *  198: class tx_impexp
00038  *
00039  *              SECTION: Initialize
00040  *  261:     function init($dontCompress=0,$mode='')
00041  *
00042  *              SECTION: Export / Init + Meta Data
00043  *  292:     function setHeaderBasics()
00044  *  316:     function setCharset($charset)
00045  *  331:     function setMetaData($title,$description,$notes,$packager_username,$packager_name,$packager_email)
00046  *  351:     function addThumbnail($imgFilepath)
00047  *
00048  *              SECTION: Export / Init Page tree
00049  *  389:     function setPageTree($idH)
00050  *  402:     function unsetExcludedSections($idH)
00051  *  424:     function flatInversePageTree($idH,$a=array())
00052  *  447:     function flatInversePageTree_pid($idH,$a=array(),$pid=-1)
00053  *
00054  *              SECTION: Export
00055  *  486:     function export_addRecord($table,$row,$relationLevel=0)
00056  *  544:     function export_addDBRelations($relationLevel=0)
00057  *  648:     function export_addDBRelations_registerRelation($fI, &$addR, $tokenID='')
00058  *  672:     function export_addFilesFromRelations()
00059  *  773:     function export_addFile($fI, $recordRef='', $fieldname='')
00060  *  898:     function flatDBrels($dbrels)
00061  *  924:     function flatSoftRefs($dbrels)
00062  *
00063  *              SECTION: File Output
00064  *  988:     function compileMemoryToFileContent($type='')
00065  * 1014:     function createXML()
00066  * 1106:     function doOutputCompress()
00067  * 1117:     function addFilePart($data, $compress=FALSE)
00068  *
00069  *              SECTION: Import
00070  * 1150:     function importData($pid)
00071  * 1191:     function writeRecords_pages($pid)
00072  * 1246:     function writeRecords_pages_order($pid)
00073  * 1284:     function writeRecords_records($pid)
00074  * 1334:     function writeRecords_records_order($mainPid)
00075  * 1383:     function addSingle($table,$uid,$pid)
00076  * 1457:     function addToMapId($substNEWwithIDs)
00077  * 1477:     function getNewTCE()
00078  * 1491:     function unlinkTempFiles()
00079  *
00080  *              SECTION: Import / Relations setting
00081  * 1529:     function setRelations()
00082  * 1584:     function setRelations_db($itemArray)
00083  * 1611:     function import_addFileNameToBeCopied($fI)
00084  * 1634:     function setFlexFormRelations()
00085  * 1718:     function remapListedDBRecords_flexFormCallBack($pParams, $dsConf, $dataValue, $dataValue_ext1, $dataValue_ext2, $path)
00086  *
00087  *              SECTION: Import / Soft References
00088  * 1760:     function processSoftReferences()
00089  * 1851:     function processSoftReferences_flexFormCallBack($pParams, $dsConf, $dataValue, $dataValue_ext1, $dataValue_ext2, $path)
00090  * 1890:     function processSoftReferences_substTokens($tokenizedContent, $softRefCfgs, $table, $uid)
00091  * 1954:     function processSoftReferences_saveFile($relFileName, $cfg, $table, $uid)
00092  * 2015:     function processSoftReferences_saveFile_createRelFile($origDirPrefix, $fileName, $fileID, $table, $uid)
00093  * 2104:     function writeFileVerify($fileName, $fileID, $bypassMountCheck=FALSE)
00094  * 2131:     function checkOrCreateDir($dirPrefix)
00095  * 2164:     function verifyFolderAccess($dirPrefix, $noAlternative=FALSE)
00096  *
00097  *              SECTION: File Input
00098  * 2214:     function loadFile($filename,$all=0)
00099  * 2257:     function getNextFilePart($fd,$unserialize=0,$name='')
00100  * 2284:     function loadContent($filecontent)
00101  * 2302:     function getNextContentPart($filecontent,&$pointer,$unserialize=0,$name='')
00102  * 2327:     function loadInit()
00103  * 2343:     function fixCharsets()
00104  *
00105  *              SECTION: Visual rendering of import/export memory, $this->dat
00106  * 2398:     function displayContentOverview()
00107  * 2506:     function traversePageTree($pT,&$lines,$preCode='')
00108  * 2541:     function traversePageRecords($pT,&$lines)
00109  * 2568:     function traverseAllRecords($pT,&$lines)
00110  * 2590:     function singleRecordLines($table,$uid,&$lines,$preCode,$checkImportInPidRecord=0)
00111  * 2748:     function addRelations($rels,&$lines,$preCode,$recurCheck=array(),$htmlColorClass='')
00112  * 2813:     function addFiles($rels,&$lines,$preCode,$htmlColorClass='',$tokenID='')
00113  * 2931:     function checkDokType($checkTable,$doktype)
00114  * 2947:     function renderControls($r)
00115  * 2975:     function softrefSelector($cfg)
00116  *
00117  *              SECTION: Helper functions of kinds
00118  * 3051:     function isTableStatic($table)
00119  * 3065:     function inclRelation($table)
00120  * 3080:     function isExcluded($table,$uid)
00121  * 3092:     function includeSoftref($tokenID)
00122  * 3102:     function checkPID($pid)
00123  * 3119:     function dontIgnorePid($table, $uid)
00124  * 3132:     function doesRecordExist($table,$uid,$fields='')
00125  * 3142:     function getRecordPath($pid)
00126  * 3159:     function renderSelectBox($prefix,$value,$optValues)
00127  * 3183:     function compareRecords($databaseRecord, $importRecord, $table, $inverseDiff=FALSE)
00128  * 3250:     function getRTEoriginalFilename($string)
00129  * 3267:     function &getFileProcObj()
00130  *
00131  *              SECTION: Error handling
00132  * 3299:     function error($msg)
00133  * 3308:     function printErrorLog()
00134  *
00135  * TOTAL FUNCTIONS: 72
00136  * (This index is automatically created/updated by the extension "extdeveval")
00137  *
00138  */
00139 /**
00140  * EXAMPLE for using the impexp-class for exporting stuff:
00141  *
00142  *      // Create and initialize:
00143  *  $this->export = t3lib_div::makeInstance('tx_impexp');
00144  *  $this->export->init();
00145  *      // Set which tables relations we will allow:
00146  *  $this->export->relOnlyTables[]="tt_news";   // exclusively includes. See comment in the class
00147  *
00148  *      // Adding records:
00149  *  $this->export->export_addRecord("pages",$this->pageinfo);
00150  *  $this->export->export_addRecord("pages",t3lib_BEfunc::getRecord("pages",38));
00151  *  $this->export->export_addRecord("pages",t3lib_BEfunc::getRecord("pages",39));
00152  *  $this->export->export_addRecord("tt_content",t3lib_BEfunc::getRecord("tt_content",12));
00153  *  $this->export->export_addRecord("tt_content",t3lib_BEfunc::getRecord("tt_content",74));
00154  *  $this->export->export_addRecord("sys_template",t3lib_BEfunc::getRecord("sys_template",20));
00155  *
00156  *      // Adding all the relations (recursively in 5 levels so relations has THEIR relations registered as well)
00157  *  for($a=0;$a<5;$a++) {
00158  *      $addR = $this->export->export_addDBRelations($a);
00159  *      if (!count($addR)) break;
00160  *  }
00161  *
00162  *      // Finally load all the files.
00163  *  $this->export->export_addFilesFromRelations();  // MUST be after the DBrelations are set so that file from ALL added records are included!
00164  *
00165  *      // Now the internal DAT array is ready to export:
00166  *  #debug($this->export->dat);
00167  *
00168  *      // Write export
00169  *  $out = $this->export->compileMemoryToFileContent();
00170  *  #t3lib_div::writeFile(PATH_site."fileadmin/relations.t3d",$out);
00171  *  #debug(strlen($out));
00172  */
00173 
00174 @ini_set('max_execution_time',600);
00175 @ini_set('memory_limit','256m');
00176 
00177 
00178 
00179 
00180 
00181 
00182 
00183 /**
00184  * T3D file Import/Export library (TYPO3 Record Document)
00185  *
00186  * @author  Kasper Skårhøj <kasperYYYY@typo3.com>
00187  * @package TYPO3
00188  * @subpackage tx_impexp
00189  */
00190 class tx_impexp {
00191 
00192         // Configuration, general
00193     var $showStaticRelations = FALSE;       // If set, static relations (not exported) will be shown in overview as well
00194     var $fileadminFolderName = 'fileadmin'; // Name of the "fileadmin" folder where files for export/import should be located
00195 
00196     var $mode = '';                         // Whether "import" or "export" mode of object. Set through init() function
00197     var $update = FALSE;                    // Updates all records that has same UID instead of creating new!
00198     var $doesImport = FALSE;                // Is set by importData() when an import has been done.
00199 
00200         // Configuration, import
00201     var $display_import_pid_record = '';        // If set to a page-record, then the preview display of the content will expect this page-record to be the target for the import and accordingly display validation information. This triggers the visual view of the import/export memory to validate if import is possible
00202     var $suggestedInsertUids = array();     // Used to register the forged UID values for imported records that we want to create with the same UIDs as in the import file. Admin-only feature.
00203     var $import_mode = array();             // Setting import modes during update state: as_new, exclude, force_uid
00204     var $global_ignore_pid = FALSE;         // If set, PID correct is ignored globally
00205     var $force_all_UIDS = FALSE;            // If set, all UID values are forced! (update or import)
00206     var $showDiff = FALSE;                  // If set, a diff-view column is added to the overview.
00207     var $allowPHPScripts = FALSE;           // If set, and if the user is admin, allow the writing of PHP scripts to fileadmin/ area.
00208     var $enableLogging = FALSE;             // Disable logging when importing
00209     var $softrefInputValues = array();      // Array of values to substitute in editable softreferences.
00210     var $fileIDMap = array();               // Mapping between the fileID from import memory and the final filenames they are written to.
00211 
00212         // Configuration, export
00213     var $maxFileSize = 1000000;     // 1MB max file size
00214     var $maxRecordSize = 1000000;   // 1MB max record size
00215     var $maxExportSize = 10000000;  // 10MB max export size
00216     var $relOnlyTables = array();   // add table names here which are THE ONLY ones which will be included into export if found as relations. '_ALL' will allow all tables.
00217     var $relStaticTables = array(); // add tables names here which should not be exported with the file. (Where relations should be mapped to same UIDs in target system).
00218     var $excludeMap = array();      // Exclude map. Keys are table:uid  pairs and if set, records are not added to the export.
00219     var $softrefCfg = array();      // Soft Reference Token ID modes.
00220     var $extensionDependencies = array();       // Listing extension dependencies.
00221     var $dontCompress = 0;          // Set  by user: If set, compression in t3d files is disabled
00222     var $includeExtFileResources = 0;   // Boolean, if set, HTML file resources are included.
00223     var $extFileResourceExtensions = 'html,htm,css';    // Files with external media (HTML/css style references inside)
00224 
00225         // Internal, dynamic:
00226     var $import_mapId = array();        // After records are written this array is filled with [table][original_uid] = [new_uid]
00227     var $import_newId = array();        // Keys are [tablename]:[new NEWxxx ids (or when updating it is uids)] while values are arrays with table/uid of the original record it is based on. By the array keys the new ids can be looked up inside tcemain
00228     var $import_newId_pids = array();   // Page id map for page tree (import)
00229     var $import_data = array();         // Internal data accumulation for writing records during import
00230     var $errorLog = array();            // Error log.
00231     var $cache_getRecordPath = array(); // Cache for record paths
00232     var $checkPID_cache = array();      // Cache of checkPID values.
00233 
00234     var $compress = 0;                  // Set internally if the gzcompress function exists
00235     var $dat = array();                 // Internal import/export memory
00236 
00237     /**
00238      * File processing object
00239      *
00240      * @var t3lib_extFileFunctions
00241      */
00242     var $fileProcObj = '';
00243 
00244 
00245 
00246     /**************************
00247      *
00248      * Initialize
00249      *
00250      *************************/
00251 
00252     /**
00253      * Init the object, both import and export
00254      *
00255      * @param   boolean     If set, compression in t3d files is disabled
00256      * @param   string      Mode of usage, either "import" or "export"
00257      * @return  void
00258      */
00259     function init($dontCompress=0,$mode='') {
00260         $this->compress = function_exists('gzcompress');
00261         $this->dontCompress = $dontCompress;
00262 
00263         $this->mode = $mode;
00264     }
00265 
00266 
00267 
00268 
00269 
00270 
00271 
00272 
00273 
00274 
00275 
00276 
00277 
00278 
00279     /**************************
00280      *
00281      * Export / Init + Meta Data
00282      *
00283      *************************/
00284 
00285     /**
00286      * Set header basics
00287      *
00288      * @return  void
00289      */
00290     function setHeaderBasics()  {
00291 
00292             // Initializing:
00293         if (is_array($this->softrefCfg))    {
00294             foreach($this->softrefCfg as $key => $value)    {
00295                 if (!strlen($value['mode']))    unset($this->softrefCfg[$key]);
00296             }
00297         }
00298 
00299             // Setting in header memory:
00300         $this->dat['header']['XMLversion'] = '1.0';     // Version of file format
00301         $this->dat['header']['meta'] = array();         // Initialize meta data array (to put it in top of file)
00302         $this->dat['header']['relStaticTables'] = $this->relStaticTables;   // Add list of tables to consider static
00303         $this->dat['header']['excludeMap'] = $this->excludeMap;             // The list of excluded records
00304         $this->dat['header']['softrefCfg'] = $this->softrefCfg;         // Soft Reference mode for elements
00305         $this->dat['header']['extensionDependencies'] = $this->extensionDependencies;       // List of extensions the import depends on.
00306     }
00307 
00308     /**
00309      * Set charset
00310      *
00311      * @param   string      Charset for the content in the export. During import the character set will be converted if the target system uses another charset.
00312      * @return  void
00313      */
00314     function setCharset($charset)   {
00315         $this->dat['header']['charset'] = $charset;
00316     }
00317 
00318     /**
00319      * Sets meta data
00320      *
00321      * @param   string      Title of the export
00322      * @param   string      Description of the export
00323      * @param   string      Notes about the contents
00324      * @param   string      Backend Username of the packager (the guy making the export)
00325      * @param   string      Real name of the packager
00326      * @param   string      Email of the packager
00327      * @return  void
00328      */
00329     function setMetaData($title,$description,$notes,$packager_username,$packager_name,$packager_email)  {
00330         $this->dat['header']['meta'] = array(
00331             'title' => $title,
00332             'description' => $description,
00333             'notes' => $notes,
00334             'packager_username' => $packager_username,
00335             'packager_name' => $packager_name,
00336             'packager_email' => $packager_email,
00337             'TYPO3_version' => TYPO3_version,
00338             'created' => strftime('%A %e. %B %Y', $GLOBALS['EXEC_TIME']),
00339         );
00340     }
00341 
00342     /**
00343      * Sets a thumbnail image to the exported file
00344      *
00345      * @param   string      Filename reference, gif, jpg, png. Absolute path.
00346      * @return  void
00347      */
00348     function addThumbnail($imgFilepath) {
00349         if (@is_file($imgFilepath)) {
00350             $imgInfo = @getimagesize($imgFilepath);
00351             if (is_array($imgInfo)) {
00352                 $fileContent = t3lib_div::getUrl($imgFilepath);
00353                 $this->dat['header']['thumbnail'] = array(
00354                     'imgInfo' => $imgInfo,
00355                     'content' => $fileContent,
00356                     'filesize' => strlen($fileContent),
00357                     'filemtime' => filemtime($imgFilepath),
00358                     'filename' => basename($imgFilepath)
00359                 );
00360             }
00361         }
00362     }
00363 
00364 
00365 
00366 
00367 
00368 
00369 
00370 
00371 
00372 
00373 
00374     /**************************
00375      *
00376      * Export / Init Page tree
00377      *
00378      *************************/
00379 
00380     /**
00381      * Sets the page-tree array in the export header and returns the array in a flattened version
00382      *
00383      * @param   array       Hierarchy of ids, the page tree: array([uid] => array("uid" => [uid], "subrow" => array(.....)), [uid] => ....)
00384      * @return  array       The hierarchical page tree converted to a one-dimensional list of pages
00385      */
00386     function setPageTree($idH)  {
00387         $this->dat['header']['pagetree'] = $this->unsetExcludedSections($idH);
00388         return $this->flatInversePageTree($this->dat['header']['pagetree']);
00389     }
00390 
00391     /**
00392      * Removes entries in the page tree which are found in ->excludeMap[]
00393      *
00394      * @param   array       Page uid hierarchy
00395      * @return  array       Modified input array
00396      * @access private
00397      * @see setPageTree()
00398      */
00399     function unsetExcludedSections($idH)    {
00400         if (is_array($idH)) {
00401             foreach ($idH as $k => $v) {
00402                 if ($this->excludeMap['pages:'.$idH[$k]['uid']])    {
00403                     unset($idH[$k]);
00404                 } elseif (is_array($idH[$k]['subrow'])) {
00405                     $idH[$k]['subrow'] = $this->unsetExcludedSections($idH[$k]['subrow']);
00406                 }
00407             }
00408         }
00409         return $idH;
00410     }
00411 
00412     /**
00413      * Recursively flattening the idH array (for setPageTree() function)
00414      *
00415      * @param   array       Page uid hierarchy
00416      * @param   array       Accumulation array of pages (internal, don't set from outside)
00417      * @return  array       Array with uid-uid pairs for all pages in the page tree.
00418      * @see flatInversePageTree_pid()
00419      */
00420     function flatInversePageTree($idH,$a=array())   {
00421         if (is_array($idH)) {
00422             $idH = array_reverse($idH);
00423             foreach ($idH as $k => $v) {
00424                 $a[$v['uid']] = $v['uid'];
00425                 if (is_array($v['subrow'])) {
00426                     $a = $this->flatInversePageTree($v['subrow'],$a);
00427                 }
00428             }
00429         }
00430         return $a;
00431     }
00432 
00433     /**
00434      * Recursively flattening the idH array (for setPageTree() function), setting PIDs as values
00435      *
00436      * @param   array       Page uid hierarchy
00437      * @param   array       Accumulation array of pages (internal, don't set from outside)
00438      * @param   integer     PID value (internal)
00439      * @return  array       Array with uid-pid pairs for all pages in the page tree.
00440      * @see flatInversePageTree()
00441      */
00442     function flatInversePageTree_pid($idH,$a=array(),$pid=-1)   {
00443         if (is_array($idH)) {
00444             $idH = array_reverse($idH);
00445             foreach ($idH as $k => $v) {
00446                 $a[$v['uid']] = $pid;
00447                 if (is_array($v['subrow'])) {
00448                     $a = $this->flatInversePageTree_pid($v['subrow'],$a,$v['uid']);
00449                 }
00450             }
00451         }
00452         return $a;
00453     }
00454 
00455 
00456 
00457 
00458 
00459 
00460 
00461 
00462 
00463 
00464 
00465     /**************************
00466      *
00467      * Export
00468      *
00469      *************************/
00470 
00471     /**
00472      * Adds the record $row from $table.
00473      * No checking for relations done here. Pure data.
00474      *
00475      * @param   string      Table name
00476      * @param   array       Record row.
00477      * @param   integer     (Internal) if the record is added as a relation, this is set to the "level" it was on.
00478      * @return  void
00479      */
00480     function export_addRecord($table,$row,$relationLevel=0) {
00481 
00482         t3lib_BEfunc::workspaceOL($table,$row);
00483 
00484         if (strcmp($table,'') && is_array($row) && $row['uid']>0 && !$this->excludeMap[$table.':'.$row['uid']]) {
00485             if ($this->checkPID($table==='pages' ? $row['uid'] : $row['pid']))  {
00486                 if (!isset($this->dat['records'][$table.':'.$row['uid']]))  {
00487 
00488                         // Prepare header info:
00489                     $headerInfo = array();
00490                     $headerInfo['uid'] = $row['uid'];
00491                     $headerInfo['pid'] = $row['pid'];
00492                     $headerInfo['title'] = t3lib_div::fixed_lgd_cs(t3lib_BEfunc::getRecordTitle($table,$row),40);
00493                     $headerInfo['size'] = strlen(serialize($row));
00494                     if ($relationLevel) {
00495                         $headerInfo['relationLevel'] = $relationLevel;
00496                     }
00497 
00498                         // If record content is not too large in size, set the header content and add the rest:
00499                     if ($headerInfo['size']<$this->maxRecordSize)   {
00500 
00501                             // Set the header summary:
00502                         $this->dat['header']['records'][$table][$row['uid']] = $headerInfo;
00503 
00504                             // Create entry in the PID lookup:
00505                         $this->dat['header']['pid_lookup'][$row['pid']][$table][$row['uid']]=1;
00506 
00507                             // Initialize reference index object:
00508                         $refIndexObj = t3lib_div::makeInstance('t3lib_refindex');
00509                         $refIndexObj->WSOL = TRUE;  // Yes to workspace overlays for exporting....
00510 
00511                             // Data:
00512                         $this->dat['records'][$table.':'.$row['uid']] = array();
00513                         $this->dat['records'][$table.':'.$row['uid']]['data'] = $row;
00514                         $this->dat['records'][$table.':'.$row['uid']]['rels'] = $refIndexObj->getRelations($table,$row);
00515                         $this->errorLog = array_merge($this->errorLog,$refIndexObj->errorLog);  // Merge error logs.
00516 
00517                             // Add information about the relations in the record in the header:
00518                         $this->dat['header']['records'][$table][$row['uid']]['rels'] = $this->flatDBrels($this->dat['records'][$table.':'.$row['uid']]['rels']);
00519 
00520                             // Add information about the softrefs to header:
00521                         $this->dat['header']['records'][$table][$row['uid']]['softrefs'] = $this->flatSoftRefs($this->dat['records'][$table.':'.$row['uid']]['rels']);
00522 
00523                     } else $this->error('Record '.$table.':'.$row['uid'].' was larger than maxRecordSize ('.t3lib_div::formatSize($this->maxRecordSize).')');
00524                 } else $this->error('Record '.$table.':'.$row['uid'].' already added.');
00525             } else $this->error('Record '.$table.':'.$row['uid'].' was outside your DB mounts!');
00526         }
00527     }
00528 
00529     /**
00530      * This analyses the existing added records, finds all database relations to records and adds these records to the export file.
00531      * This function can be called repeatedly until it returns an empty array. In principle it should not allow to infinite recursivity, but you better set a limit...
00532      * Call this BEFORE the ext_addFilesFromRelations (so files from added relations are also included of course)
00533      *
00534      * @param   integer     Recursion level
00535      * @return  array       overview of relations found and added: Keys [table]:[uid], values array with table and id
00536      * @see export_addFilesFromRelations()
00537      */
00538     function export_addDBRelations($relationLevel=0)    {
00539         global $TCA;
00540 
00541             // Initialize:
00542         $addR = array();
00543 
00544             // Traverse all "rels" registered for "records"
00545         if (is_array($this->dat['records']))    {
00546             foreach ($this->dat['records'] as $k => $value) {
00547                 if (is_array($this->dat['records'][$k]))    {
00548                     foreach ($this->dat['records'][$k]['rels'] as $fieldname => $vR) {
00549 #debug($vR);
00550                             // For all DB types of relations:
00551                         if ($vR['type']=='db')  {
00552                             foreach($vR['itemArray'] as $fI)    {
00553                                 $this->export_addDBRelations_registerRelation($fI, $addR);
00554                             }
00555                         }
00556 
00557                             // For all flex/db types of relations:
00558                         if ($vR['type']=='flex')    {
00559                                 // DB relations in flex form fields:
00560                             if (is_array($vR['flexFormRels']['db']))    {
00561                                 foreach($vR['flexFormRels']['db'] as $subList)  {
00562                                     foreach($subList as $fI)    {
00563                                         $this->export_addDBRelations_registerRelation($fI, $addR);
00564                                     }
00565                                 }
00566                             }
00567                                 // DB oriented soft references in flex form fields:
00568                             if (is_array($vR['flexFormRels']['softrefs']))  {
00569                                 foreach($vR['flexFormRels']['softrefs'] as $subList)    {
00570                                     foreach($subList['keys'] as $spKey => $elements)    {
00571                                         foreach($elements as $el)   {
00572                                             if ($el['subst']['type'] === 'db' && $this->includeSoftref($el['subst']['tokenID']))    {
00573                                                 list($tempTable, $tempUid) = explode(':', $el['subst']['recordRef']);
00574                                                 $fI = array(
00575                                                     'table' => $tempTable,
00576                                                     'id' => $tempUid
00577                                                 );
00578                                                 $this->export_addDBRelations_registerRelation($fI, $addR, $el['subst']['tokenID']);
00579                                             }
00580                                         }
00581                                     }
00582                                 }
00583                             }
00584                         }
00585 
00586                             // In any case, if there are soft refs:
00587                         if (is_array($vR['softrefs']['keys']))  {
00588                             foreach($vR['softrefs']['keys'] as $spKey => $elements) {
00589                                 foreach($elements as $el)   {
00590                                     if ($el['subst']['type'] === 'db' && $this->includeSoftref($el['subst']['tokenID']))    {
00591                                         list($tempTable, $tempUid) = explode(':', $el['subst']['recordRef']);
00592                                         $fI = array(
00593                                             'table' => $tempTable,
00594                                             'id' => $tempUid
00595                                         );
00596                                         $this->export_addDBRelations_registerRelation($fI, $addR, $el['subst']['tokenID']);
00597                                     }
00598                                 }
00599                             }
00600                         }
00601                     }
00602                 }
00603             }
00604         } else $this->error('There were no records available.');
00605 
00606             // Now, if there were new records to add, do so:
00607         if (count($addR))   {
00608             foreach($addR as $fI)   {
00609 
00610                     // Get and set record:
00611                 $row = t3lib_BEfunc::getRecord($fI['table'],$fI['id']);
00612                 if (is_array($row)) {
00613                     $this->export_addRecord($fI['table'],$row,$relationLevel+1);
00614                 }
00615 
00616                     // Set status message
00617                 if ($fI['id']>0)    {   // Relation pointers always larger than zero except certain "select" types with negative values pointing to uids - but that is not supported here.
00618                     $rId = $fI['table'].':'.$fI['id'];
00619                     if (!isset($this->dat['records'][$rId]))    {
00620                         $this->dat['records'][$rId] = 'NOT_FOUND';
00621                         $this->error('Relation record '.$rId.' was not found!');
00622                     }
00623                 }
00624             }
00625         }
00626 
00627             // Return overview of relations found and added
00628         return $addR;
00629     }
00630 
00631     /**
00632      * Helper function for export_addDBRelations()
00633      *
00634      * @param   array       Array with table/id keys to add
00635      * @param   array       Add array, passed by reference to be modified
00636      * @param   string      Softref Token ID, if applicable.
00637      * @return  void
00638      * @see export_addDBRelations()
00639      */
00640     function export_addDBRelations_registerRelation($fI, &$addR, $tokenID='')   {
00641         global $TCA;
00642 
00643         $rId = $fI['table'].':'.$fI['id'];
00644         if (isset($TCA[$fI['table']])
00645                 && !$this->isTableStatic($fI['table'])
00646                 && !$this->isExcluded($fI['table'],$fI['id'])
00647                 && (!$tokenID || $this->includeSoftref($tokenID))
00648                 && $this->inclRelation($fI['table'])
00649                 )   {
00650             if (!isset($this->dat['records'][$rId]))    {
00651                     // Set this record to be included since it is not already.
00652                 $addR[$rId] = $fI;
00653             }
00654         }
00655     }
00656 
00657     /**
00658      * This adds all files in relations.
00659      * Call this method AFTER adding all records including relations.
00660      *
00661      * @return  void
00662      * @see export_addDBRelations()
00663      */
00664     function export_addFilesFromRelations() {
00665 
00666             // Traverse all "rels" registered for "records"
00667         if (is_array($this->dat['records']))    {
00668             foreach ($this->dat['records'] as $k => $value) {
00669                 if (is_array($this->dat['records'][$k]['rels']))    {
00670                     foreach ($this->dat['records'][$k]['rels'] as $fieldname => $vR) {
00671 
00672                             // For all file type relations:
00673                         if ($vR['type']=='file')    {
00674                             foreach($vR['newValueFiles'] as $key => $fI)    {
00675                                 $this->export_addFile($fI, $k, $fieldname);
00676                                     // Remove the absolute reference to the file so it doesn't expose absolute paths from source server:
00677                                 unset($this->dat['records'][$k]['rels'][$fieldname]['newValueFiles'][$key]['ID_absFile']);
00678                             }
00679                         }
00680 
00681                             // For all flex type relations:
00682                         if ($vR['type']=='flex')    {
00683                             if (is_array($vR['flexFormRels']['file']))  {
00684                                 foreach($vR['flexFormRels']['file'] as $key => $subList)    {
00685                                     foreach($subList as $subKey => $fI) {
00686                                         $this->export_addFile($fI, $k, $fieldname);
00687                                             // Remove the absolute reference to the file so it doesn't expose absolute paths from source server:
00688                                         unset($this->dat['records'][$k]['rels'][$fieldname]['flexFormRels']['file'][$key][$subKey]['ID_absFile']);
00689                                     }
00690                                 }
00691                             }
00692 
00693                                 // DB oriented soft references in flex form fields:
00694                             if (is_array($vR['flexFormRels']['softrefs']))  {
00695                                 foreach($vR['flexFormRels']['softrefs'] as $key => $subList)    {
00696                                     foreach($subList['keys'] as $spKey => $elements)    {
00697                                         foreach($elements as $subKey => $el)    {
00698                                             if ($el['subst']['type'] === 'file' && $this->includeSoftref($el['subst']['tokenID']))  {
00699 
00700                                                     // Create abs path and ID for file:
00701                                                 $ID_absFile = t3lib_div::getFileAbsFileName(PATH_site.$el['subst']['relFileName']);
00702                                                 $ID = md5($ID_absFile);
00703 
00704                                                 if ($ID_absFile)    {
00705                                                     if (!$this->dat['files'][$ID])  {
00706                                                         $fI = array(
00707                                                             'filename' => basename($ID_absFile),
00708                                                             'ID_absFile' => $ID_absFile,
00709                                                             'ID' => $ID,
00710                                                             'relFileName' => $el['subst']['relFileName']
00711                                                         );
00712                                                         $this->export_addFile($fI, '_SOFTREF_');
00713                                                     }
00714                                                     $this->dat['records'][$k]['rels'][$fieldname]['flexFormRels']['softrefs'][$key]['keys'][$spKey][$subKey]['file_ID'] = $ID;
00715                                                 }
00716                                             }
00717                                         }
00718                                     }
00719                                 }
00720                             }
00721                         }
00722 
00723                             // In any case, if there are soft refs:
00724                         if (is_array($vR['softrefs']['keys']))  {
00725                             foreach($vR['softrefs']['keys'] as $spKey => $elements) {
00726                                 foreach($elements as $subKey => $el)    {
00727                                     if ($el['subst']['type'] === 'file' && $this->includeSoftref($el['subst']['tokenID']))  {
00728 
00729                                             // Create abs path and ID for file:
00730                                         $ID_absFile = t3lib_div::getFileAbsFileName(PATH_site.$el['subst']['relFileName']);
00731                                         $ID = md5($ID_absFile);
00732 
00733                                         if ($ID_absFile)    {
00734                                             if (!$this->dat['files'][$ID])  {
00735                                                 $fI = array(
00736                                                     'filename' => basename($ID_absFile),
00737                                                     'ID_absFile' => $ID_absFile,
00738                                                     'ID' => $ID,
00739                                                     'relFileName' => $el['subst']['relFileName']
00740                                                 );
00741                                                 $this->export_addFile($fI, '_SOFTREF_');
00742                                             }
00743                                             $this->dat['records'][$k]['rels'][$fieldname]['softrefs']['keys'][$spKey][$subKey]['file_ID'] = $ID;
00744                                         }
00745                                     }
00746                                 }
00747                             }
00748                         }
00749                     }
00750                 }
00751             }
00752         } else $this->error('There were no records available.');
00753     }
00754 
00755     /**
00756      * Adds a files content to the export memory
00757      *
00758      * @param   array       File information with three keys: "filename" = filename without path, "ID_absFile" = absolute filepath to the file (including the filename), "ID" = md5 hash of "ID_absFile". "relFileName" is optional for files attached to records, but mandatory for soft referenced files (since the relFileName determines where such a file should be stored!)
00759      * @param   string      If the file is related to a record, this is the id on the form [table]:[id]. Information purposes only.
00760      * @param   string      If the file is related to a record, this is the field name it was related to. Information purposes only.
00761      * @return  void
00762      */
00763     function export_addFile($fI, $recordRef='', $fieldname='')  {
00764         if (@is_file($fI['ID_absFile']))    {
00765             if (filesize($fI['ID_absFile']) < $this->maxFileSize)   {
00766                 $fileRec = array();
00767                 $fileRec['filesize'] = filesize($fI['ID_absFile']);
00768                 $fileRec['filename'] = basename($fI['ID_absFile']);
00769                 $fileRec['filemtime'] = filemtime($fI['ID_absFile']);
00770                     //for internal type file_reference
00771                 $fileRec['relFileRef'] = substr($fI['ID_absFile'], strlen(PATH_site));
00772                 if ($recordRef) {
00773                     $fileRec['record_ref'] = $recordRef.'/'.$fieldname;
00774                 }
00775                 if ($fI['relFileName']) {
00776                     $fileRec['relFileName'] = $fI['relFileName'];
00777                 }
00778 
00779                     // Setting this data in the header
00780                 $this->dat['header']['files'][$fI['ID']] = $fileRec;
00781 
00782                     // ... and for the recordlisting, why not let us know WHICH relations there was...
00783                 if ($recordRef && $recordRef!=='_SOFTREF_') {
00784                     $refParts = explode(':',$recordRef,2);
00785                     if (!is_array($this->dat['header']['records'][$refParts[0]][$refParts[1]]['filerefs'])) {
00786                         $this->dat['header']['records'][$refParts[0]][$refParts[1]]['filerefs'] = array();
00787                     }
00788                     $this->dat['header']['records'][$refParts[0]][$refParts[1]]['filerefs'][] = $fI['ID'];
00789                 }
00790 
00791                     // ... and finally add the heavy stuff:
00792                 $fileRec['content'] = t3lib_div::getUrl($fI['ID_absFile']);
00793                 $fileRec['content_md5'] = md5($fileRec['content']);
00794                 $this->dat['files'][$fI['ID']] = $fileRec;
00795 
00796 
00797                     // For soft references, do further processing:
00798                 if ($recordRef === '_SOFTREF_') {
00799 
00800                         // RTE files?
00801                     if ($RTEoriginal = $this->getRTEoriginalFilename(basename($fI['ID_absFile'])))  {
00802                         $RTEoriginal_absPath = dirname($fI['ID_absFile']).'/'.$RTEoriginal;
00803                         if (@is_file($RTEoriginal_absPath)) {
00804 
00805                             $RTEoriginal_ID = md5($RTEoriginal_absPath);
00806 
00807                             $fileRec = array();
00808                             $fileRec['filesize'] = filesize($RTEoriginal_absPath);
00809                             $fileRec['filename'] = basename($RTEoriginal_absPath);
00810                             $fileRec['filemtime'] = filemtime($RTEoriginal_absPath);
00811                             $fileRec['record_ref'] = '_RTE_COPY_ID:'.$fI['ID'];
00812                             $this->dat['header']['files'][$fI['ID']]['RTE_ORIG_ID'] = $RTEoriginal_ID;
00813 
00814                                 // Setting this data in the header
00815                             $this->dat['header']['files'][$RTEoriginal_ID] = $fileRec;
00816 
00817                                 // ... and finally add the heavy stuff:
00818                             $fileRec['content'] = t3lib_div::getUrl($RTEoriginal_absPath);
00819                             $fileRec['content_md5'] = md5($fileRec['content']);
00820                             $this->dat['files'][$RTEoriginal_ID] = $fileRec;
00821                         } else {
00822                             $this->error('RTE original file "'.substr($RTEoriginal_absPath,strlen(PATH_site)).'" was not found!');
00823                         }
00824                     }
00825 
00826                         // Files with external media?
00827                         // This is only done with files grabbed by a softreference parser since it is deemed improbable that hard-referenced files should undergo this treatment.
00828                     $html_fI = pathinfo(basename($fI['ID_absFile']));
00829                     if ($this->includeExtFileResources && t3lib_div::inList($this->extFileResourceExtensions,strtolower($html_fI['extension'])))    {
00830                         $uniquePrefix = '###' . md5($GLOBALS['EXEC_TIME']) . '###';
00831 
00832                         if (strtolower($html_fI['extension'])==='css')  {
00833                             $prefixedMedias = explode($uniquePrefix, preg_replace('/(url[[:space:]]*\([[:space:]]*["\']?)([^"\')]*)(["\']?[[:space:]]*\))/i', '\1'.$uniquePrefix.'\2'.$uniquePrefix.'\3', $fileRec['content']));
00834                         } else {    // html, htm:
00835                             $htmlParser = t3lib_div::makeInstance('t3lib_parsehtml');
00836                             $prefixedMedias = explode($uniquePrefix, $htmlParser->prefixResourcePath($uniquePrefix,$fileRec['content'],array(),$uniquePrefix));
00837                         }
00838 
00839                         $htmlResourceCaptured = FALSE;
00840                         foreach($prefixedMedias as $k => $v)    {
00841                             if ($k%2)   {
00842                                 $EXTres_absPath = t3lib_div::resolveBackPath(dirname($fI['ID_absFile']).'/'.$v);
00843                                 $EXTres_absPath = t3lib_div::getFileAbsFileName($EXTres_absPath);
00844                                 if ($EXTres_absPath && t3lib_div::isFirstPartOfStr($EXTres_absPath,PATH_site.$this->fileadminFolderName.'/') && @is_file($EXTres_absPath))  {
00845 
00846                                     $htmlResourceCaptured = TRUE;
00847                                     $EXTres_ID = md5($EXTres_absPath);
00848                                     $this->dat['header']['files'][$fI['ID']]['EXT_RES_ID'][] = $EXTres_ID;
00849                                     $prefixedMedias[$k] = '{EXT_RES_ID:'.$EXTres_ID.'}';
00850 
00851                                         // Add file to memory if it is not set already:
00852                                     if (!isset($this->dat['header']['files'][$EXTres_ID]))      {
00853                                         $fileRec = array();
00854                                         $fileRec['filesize'] = filesize($EXTres_absPath);
00855                                         $fileRec['filename'] = basename($EXTres_absPath);
00856                                         $fileRec['filemtime'] = filemtime($EXTres_absPath);
00857                                         $fileRec['record_ref'] = '_EXT_PARENT_:'.$fI['ID'];
00858 
00859                                         $fileRec['parentRelFileName'] = $v;     // Media relative to the HTML file.
00860 
00861                                             // Setting this data in the header
00862                                         $this->dat['header']['files'][$EXTres_ID] = $fileRec;
00863 
00864                                             // ... and finally add the heavy stuff:
00865                                         $fileRec['content'] = t3lib_div::getUrl($EXTres_absPath);
00866                                         $fileRec['content_md5'] = md5($fileRec['content']);
00867                                         $this->dat['files'][$EXTres_ID] = $fileRec;
00868                                     }
00869                                 }
00870                             }
00871                         }
00872 
00873                         if ($htmlResourceCaptured)  {
00874                             $this->dat['files'][$fI['ID']]['tokenizedContent'] = implode('', $prefixedMedias);
00875                         }
00876                     }
00877                 }
00878 
00879             } else  $this->error($fI['ID_absFile'].' was larger ('.t3lib_div::formatSize(filesize($fI['ID_absFile'])).') than the maxFileSize ('.t3lib_div::formatSize($this->maxFileSize).')! Skipping.');
00880         } else $this->error($fI['ID_absFile'].' was not a file! Skipping.');
00881     }
00882 
00883     /**
00884      * DB relations flattend to 1-dim array.
00885      * The list will be unique, no table/uid combination will appear twice.
00886      *
00887      * @param   array       2-dim Array of database relations organized by table key
00888      * @return  array       1-dim array where entries are table:uid and keys are array with table/id
00889      */
00890     function flatDBrels($dbrels)    {
00891         $list = array();
00892 
00893         foreach($dbrels as $dat)    {
00894             if ($dat['type']=='db') {
00895                 foreach($dat['itemArray'] as $i)    {
00896                     $list[$i['table'].':'.$i['id']] = $i;
00897                 }
00898             }
00899             if ($dat['type']=='flex' && is_array($dat['flexFormRels']['db']))   {
00900                 foreach($dat['flexFormRels']['db'] as $subList) {
00901                     foreach($subList as $i) {
00902                         $list[$i['table'].':'.$i['id']] = $i;
00903                     }
00904                 }
00905             }
00906         }
00907         return $list;
00908     }
00909 
00910     /**
00911      * Soft References flattend to 1-dim array.
00912      *
00913      * @param   array       2-dim Array of database relations organized by table key
00914      * @return  array       1-dim array where entries are arrays with properties of the soft link found and keys are a unique combination of field, spKey, structure path if applicable and token ID
00915      */
00916     function flatSoftRefs($dbrels)  {
00917         $list = array();
00918 #debug($dbrels);
00919         foreach($dbrels as $field => $dat)  {
00920             if (is_array($dat['softrefs']['keys'])) {
00921                 foreach($dat['softrefs']['keys'] as $spKey => $elements)    {
00922                     if (is_array($elements))    {
00923                         foreach($elements as $subKey => $el)    {
00924                             $lKey = $field.':'.$spKey.':'.$subKey;
00925                             $list[$lKey] = array_merge(array('field' => $field, 'spKey' => $spKey),$el);
00926 
00927                                 // Add file_ID key to header - slightly "risky" way of doing this because if the calculation changes for the same value in $this->records[...] this will not work anymore!
00928                             if ($el['subst'] && $el['subst']['relFileName'])    {
00929                                 $list[$lKey]['file_ID'] = md5(PATH_site.$el['subst']['relFileName']);
00930                             }
00931                         }
00932                     }
00933                 }
00934             }
00935             if ($dat['type']=='flex' && is_array($dat['flexFormRels']['softrefs'])) {
00936                 foreach($dat['flexFormRels']['softrefs'] as $structurePath => $subSoftrefs) {
00937                     if (is_array($subSoftrefs['keys'])) {
00938                         foreach($subSoftrefs['keys'] as $spKey => $elements)    {
00939                             foreach($elements as $subKey => $el)    {
00940                                 $lKey = $field.':'.$structurePath.':'.$spKey.':'.$subKey;
00941                                 $list[$lKey] = array_merge(array('field' => $field, 'spKey' => $spKey, 'structurePath' => $structurePath),$el);
00942 
00943                                     // Add file_ID key to header - slightly "risky" way of doing this because if the calculation changes for the same value in $this->records[...] this will not work anymore!
00944                                 if ($el['subst'] && $el['subst']['relFileName'])    {
00945                                     $list[$lKey]['file_ID'] = md5(PATH_site.$el['subst']['relFileName']);
00946                                 }
00947                             }
00948                         }
00949                     }
00950                 }
00951             }
00952         }
00953 
00954 #debug($list);
00955         return $list;
00956     }
00957 
00958 
00959 
00960 
00961 
00962 
00963 
00964 
00965 
00966 
00967 
00968     /**************************
00969      *
00970      * File Output
00971      *
00972      *************************/
00973 
00974     /**
00975      * This compiles and returns the data content for an exported file
00976      *
00977      * @param   string      Type of output; "xml" gives xml, otherwise serialized array, possibly compressed.
00978      * @return  string      The output file stream
00979      */
00980     function compileMemoryToFileContent($type='')   {
00981 
00982         if ($type=='xml')   {
00983             $out = $this->createXML();
00984         } else {
00985             $compress = $this->doOutputCompress();
00986             $out = '';
00987 
00988             // adding header:
00989             $out.= $this->addFilePart(serialize($this->dat['header']),$compress);
00990 
00991             // adding records:
00992             $out.= $this->addFilePart(serialize($this->dat['records']),$compress);
00993 
00994             // adding files:
00995             $out.= $this->addFilePart(serialize($this->dat['files']),$compress);
00996         }
00997 
00998         return $out;
00999     }
01000 
01001     /**
01002      * Creates XML string from input array
01003      *
01004      * @return  string      XML content
01005      */
01006     function createXML()    {
01007 
01008             // Options:
01009         $options = array(
01010             'alt_options' => array(
01011                 '/header' => array(
01012                     'disableTypeAttrib' => TRUE,
01013                     'clearStackPath' => TRUE,
01014                     'parentTagMap' => array(
01015                         'files' => 'file',
01016                         'records' => 'table',
01017                         'table' => 'rec',
01018                         'rec:rels' => 'relations',
01019                         'relations' => 'element',
01020                         'filerefs' => 'file',
01021                         'pid_lookup' => 'page_contents',
01022                         'header:relStaticTables' => 'static_tables',
01023                         'static_tables' => 'tablename',
01024                         'excludeMap' => 'item',
01025                         'softrefCfg' => 'softrefExportMode',
01026                         'extensionDependencies' => 'extkey',
01027                         'softrefs' => 'softref_element',
01028                     ),
01029                     'alt_options' => array(
01030                         '/pagetree' => array(
01031                             'disableTypeAttrib' => TRUE,
01032                             'useIndexTagForNum' => 'node',
01033                             'parentTagMap' => array(
01034                                 'node:subrow' => 'node'
01035                             )
01036                         ),
01037                         '/pid_lookup/page_contents' => array(
01038                             'disableTypeAttrib' => TRUE,
01039                             'parentTagMap' => array(
01040                                 'page_contents' => 'table'
01041                             ),
01042                             'grandParentTagMap' => array(
01043                                 'page_contents/table' => 'item'
01044                             )
01045                         )
01046                     )
01047                 ),
01048                 '/records' => array(
01049                     'disableTypeAttrib' => TRUE,
01050                     'parentTagMap' => array(
01051                         'records' => 'tablerow',
01052                         'tablerow:data' => 'fieldlist',
01053                         'tablerow:rels' => 'related',
01054                         'related' => 'field',
01055                         'field:itemArray' => 'relations',
01056                         'field:newValueFiles' => 'filerefs',
01057                         'field:flexFormRels' => 'flexform',
01058                         'relations' => 'element',
01059                         'filerefs' => 'file',
01060                         'flexform:db' => 'db_relations',
01061                         'flexform:file' => 'file_relations',
01062                         'flexform:softrefs' => 'softref_relations',
01063                         'softref_relations' => 'structurePath',
01064                         'db_relations' => 'path',
01065                         'file_relations' => 'path',
01066                         'path' => 'element',
01067                         'keys' => 'softref_key',
01068                         'softref_key' => 'softref_element',
01069                     ),
01070                     'alt_options' => array(
01071                         '/records/tablerow/fieldlist' => array(
01072                             'useIndexTagForAssoc' => 'field',
01073                         )
01074                     )
01075                 ),
01076                 '/files' => array(
01077                     'disableTypeAttrib' => TRUE,
01078                     'parentTagMap' => array(
01079                         'files' => 'file',
01080                     ),
01081                 ),
01082             )
01083         );
01084 
01085             // Creating XML file from $outputArray:
01086         $charset = $this->dat['header']['charset'] ? $this->dat['header']['charset'] : 'iso-8859-1';
01087         $XML = '<?xml version="1.0" encoding="'.$charset.'" standalone="yes" ?>'.LF;
01088         $XML.= t3lib_div::array2xml($this->dat,'',0,'T3RecordDocument',0,$options);
01089 
01090         return $XML;
01091     }
01092 
01093     /**
01094      * Returns true if the output should be compressed.
01095      *
01096      * @return  boolean     True if compression is possible AND requested.
01097      */
01098     function doOutputCompress() {
01099         return $this->compress && !$this->dontCompress;
01100     }
01101 
01102     /**
01103      * Returns a content part for a filename being build.
01104      *
01105      * @param   array       Data to store in part
01106      * @param   boolean     Compress file?
01107      * @return  string      Content stream.
01108      */
01109     function addFilePart($data, $compress=FALSE)    {
01110         if ($compress)  $data = gzcompress($data);
01111         return md5($data).':'.
01112                 ($compress?'1':'0').':'.
01113                 str_pad(strlen($data),10,'0',STR_PAD_LEFT).':'.
01114                 $data.':';
01115     }
01116 
01117 
01118 
01119 
01120 
01121 
01122 
01123 
01124 
01125 
01126 
01127 
01128 
01129 
01130     /***********************
01131      *
01132      * Import
01133      *
01134      ***********************/
01135 
01136     /**
01137      * Imports the internal data array to $pid.
01138      *
01139      * @param   integer     Page ID in which to import the content
01140      * @return  void        ...
01141      */
01142     function importData($pid)   {
01143 
01144             // Set this flag to indicate that an import is being/has been done.
01145         $this->doesImport = 1;
01146 
01147             // Initialize:
01148             // These vars MUST last for the whole section not being cleared. They are used by the method setRelations() which are called at the end of the import session.
01149         $this->import_mapId = array();
01150         $this->import_newId = array();
01151         $this->import_newId_pids = array();
01152 
01153             // Temporary files stack initialized:
01154         $this->unlinkFiles = array();
01155         $this->alternativeFileName = array();
01156         $this->alternativeFilePath = array();
01157 
01158             // Write records, first pages, then the rest
01159             // Fields with "hard" relations to database, files and flexform fields are kept empty during this run
01160         $this->writeRecords_pages($pid);
01161         $this->writeRecords_records($pid);
01162 
01163             // Finally all the file and DB record references must be fixed. This is done after all records have supposedly been written to database:
01164             // $this->import_mapId will indicate two things: 1) that a record WAS written to db and 2) that it has got a new id-number.
01165         $this->setRelations();
01166 
01167             // And when all DB relations are in place, we can fix file and DB relations in flexform fields (since data structures often depends on relations to a DS record):
01168         $this->setFlexFormRelations();
01169 
01170             // Unlink temporary files:
01171         $this->unlinkTempFiles();
01172 
01173             // Finally, traverse all records and process softreferences with substitution attributes.
01174         $this->processSoftReferences();
01175     }
01176 
01177     /**
01178      * Writing pagetree/pages to database:
01179      *
01180      * @param   integer     PID in which to import. If the operation is an update operation, the root of the page tree inside will be moved to this PID unless it is the same as the root page from the import
01181      * @return  void
01182      * @see writeRecords_records()
01183      */
01184     function writeRecords_pages($pid)   {
01185 
01186             // First, write page structure if any:
01187         if (is_array($this->dat['header']['records']['pages'])) {
01188 
01189                 // $pageRecords is a copy of the pages array in the imported file. Records here are unset one by one when the addSingle function is called.
01190             $pageRecords = $this->dat['header']['records']['pages'];
01191             $this->import_data = array();
01192 
01193                 // First add page tree if any
01194             if (is_array($this->dat['header']['pagetree'])) {
01195                 $pagesFromTree = $this->flatInversePageTree($this->dat['header']['pagetree']);
01196                 foreach($pagesFromTree as $uid) {
01197                     $thisRec = $this->dat['header']['records']['pages'][$uid];
01198                         // PID: Set the main $pid, unless a NEW-id is found
01199                     $setPid = isset($this->import_newId_pids[$thisRec['pid']])  ? $this->import_newId_pids[$thisRec['pid']] : $pid;
01200                     $this->addSingle('pages',$uid,$setPid);
01201                     unset($pageRecords[$uid]);
01202                 }
01203             }
01204 
01205                 // Then add all remaining pages not in tree on root level:
01206             if (count($pageRecords))    {
01207                 $remainingPageUids = array_keys($pageRecords);
01208                 foreach($remainingPageUids as $pUid)    {
01209                     $this->addSingle('pages',$pUid,$pid);
01210                 }
01211             }
01212 
01213                 // Now write to database:
01214             $tce = $this->getNewTCE();
01215             $this->callHook('before_writeRecordsPages', array(
01216                 'tce' => &$tce,
01217                 'data' => &$this->import_data,
01218             ));
01219             $tce->suggestedInsertUids = $this->suggestedInsertUids;
01220             $tce->start($this->import_data,Array());
01221             $tce->process_datamap();
01222             $this->callHook('after_writeRecordsPages', array(
01223                 'tce' => &$tce
01224             ));
01225 
01226                 // post-processing: Registering new ids (end all tcemain sessions with this)
01227             $this->addToMapId($tce->substNEWwithIDs);
01228 
01229                 // In case of an update, order pages from the page tree correctly:
01230             if ($this->update && is_array($this->dat['header']['pagetree']))    {
01231                 $this->writeRecords_pages_order($pid);
01232             }
01233         }
01234     }
01235 
01236     /**
01237      * Organize all updated pages in page tree so they are related like in the import file
01238      * Only used for updates and when $this->dat['header']['pagetree'] is an array.
01239      *
01240      * @param   integer     Page id in which to import
01241      * @return  void
01242      * @access private
01243      * @see writeRecords_pages(), writeRecords_records_order()
01244      */
01245     function writeRecords_pages_order($pid) {
01246         $cmd_data = array();
01247 
01248             // Get uid-pid relations and traverse them in order to map to possible new IDs
01249         $pidsFromTree = $this->flatInversePageTree_pid($this->dat['header']['pagetree']);
01250 
01251         foreach($pidsFromTree as $origPid => $newPid)   {
01252             if ($newPid>=0 && $this->dontIgnorePid('pages', $origPid))  {
01253                 if (substr($this->import_newId_pids[$origPid],0,3)==='NEW') {   // If the page had a new id (because it was created) use that instead!
01254 
01255                     if ($this->import_mapId['pages'][$origPid]) {
01256                         $mappedPid = $this->import_mapId['pages'][$origPid];
01257                         $cmd_data['pages'][$mappedPid]['move'] = $newPid;
01258                     }
01259                 } else {
01260                     $cmd_data['pages'][$origPid]['move'] = $newPid;
01261                 }
01262             }
01263         }
01264 
01265             // Execute the move commands if any:
01266         if (count($cmd_data))   {
01267             $tce = $this->getNewTCE();
01268             $this->callHook('before_writeRecordsPagesOrder', array(
01269                 'tce' => &$tce,
01270                 'data' => &$cmd_data,
01271             ));
01272             $tce->start(Array(),$cmd_data);
01273             $tce->process_cmdmap();
01274             $this->callHook('after_writeRecordsPagesOrder', array(
01275                 'tce' => &$tce,
01276             ));
01277         }
01278 
01279     }
01280 
01281     /**
01282      * Write all database records except pages (writtein in writeRecords_pages())
01283      *
01284      * @param   integer     Page id in which to import
01285      * @return  void
01286      * @see writeRecords_pages()
01287      */
01288     function writeRecords_records($pid) {
01289         global $TCA;
01290 
01291             // Write the rest of the records
01292         $this->import_data = array();
01293         if (is_array($this->dat['header']['records']))  {
01294             foreach ($this->dat['header']['records'] as $table => $recs) {
01295                 if ($table!='pages')    {
01296                     foreach ($recs as $uid => $thisRec) {
01297                             // PID: Set the main $pid, unless a NEW-id is found
01298                         $setPid = isset($this->import_mapId['pages'][$thisRec['pid']]) ? $this->import_mapId['pages'][$thisRec['pid']] : $pid;
01299                         if (is_array($TCA[$table]) && $TCA[$table]['ctrl']['rootLevel'])    {
01300                             $setPid = 0;
01301                         }
01302 
01303                             // Add record:
01304                         $this->addSingle($table,$uid,$setPid);
01305                     }
01306                 }
01307             }
01308         } else $this->error('Error: No records defined in internal data array.');
01309 
01310             // Now write to database:
01311         $tce = $this->getNewTCE();
01312         $this->callHook('before_writeRecordsRecords', array(
01313             'tce' => &$tce,
01314             'data' => &$this->import_data,
01315         ));
01316         $tce->suggestedInsertUids = $this->suggestedInsertUids;
01317         $tce->reverseOrder=1;   // Because all records are being submitted in their correct order with positive pid numbers - and so we should reverse submission order internally.
01318         $tce->start($this->import_data,Array());
01319         $tce->process_datamap();
01320         $this->callHook('after_writeRecordsRecords', array(
01321             'tce' => &$tce,
01322         ));
01323 
01324             // post-processing: Removing files and registering new ids (end all tcemain sessions with this)
01325         $this->addToMapId($tce->substNEWwithIDs);
01326 
01327             // In case of an update, order pages from the page tree correctly:
01328         if ($this->update)  {
01329             $this->writeRecords_records_order($pid);
01330         }
01331     }
01332 
01333     /**
01334      * Organize all updated record to their new positions.
01335      * Only used for updates
01336      *
01337      * @param   integer     Main PID into which we import.
01338      * @return  void
01339      * @access private
01340      * @see writeRecords_records(), writeRecords_pages_order()
01341      */
01342     function writeRecords_records_order($mainPid)   {
01343         $cmd_data = array();
01344 
01345         if (is_array($this->dat['header']['pagetree'])) {
01346             $pagesFromTree = $this->flatInversePageTree($this->dat['header']['pagetree']);
01347         } else $pagesFromTree = array();
01348 
01349         if (is_array($this->dat['header']['pid_lookup']))   {
01350             foreach($this->dat['header']['pid_lookup'] as $pid => $recList) {
01351                 $newPid = isset($this->import_mapId['pages'][$pid]) ? $this->import_mapId['pages'][$pid] : $mainPid;
01352 
01353                 if (t3lib_div::testInt($newPid))    {
01354                     foreach($recList as $tableName => $uidList) {
01355                         if (($tableName!='pages' || !$pagesFromTree[$pid]) && is_array($uidList))   {       // If $mainPid===$newPid then we are on root level and we can consider to move pages as well! (they will not be in the page tree!)
01356                             $uidList = array_reverse(array_keys($uidList));
01357                             foreach($uidList as $uid)   {
01358                                 if ($this->dontIgnorePid($tableName, $uid)) {
01359                                     $cmd_data[$tableName][$uid]['move'] = $newPid;
01360                                 } else {
01361                                     // nothing
01362                                 }
01363                             }
01364                         }
01365                     }
01366                 }
01367             }
01368         }
01369 
01370             // Execute the move commands if any:
01371         if (count($cmd_data))   {
01372             $tce = $this->getNewTCE();
01373             $this->callHook('before_writeRecordsRecordsOrder', array(
01374                 'tce' => &$tce,
01375                 'data' => &$cmd_data,
01376             ));
01377             $tce->start(Array(),$cmd_data);
01378             $tce->process_cmdmap();
01379             $this->callHook('after_writeRecordsRecordsOrder', array(
01380                 'tce' => &$tce,
01381             ));
01382         }
01383     }
01384 
01385     /**
01386      * Adds a single record to the $importData array. Also copies files to tempfolder.
01387      * However all File/DB-references and flexform field contents are set to blank for now! That is done with setRelations() later
01388      *
01389      * @param   string      Table name (from import memory)
01390      * @param   integer     Record UID (from import memory)
01391      * @param   integer     Page id
01392      * @return  void
01393      * @see writeRecords()
01394      */
01395     function addSingle($table,$uid,$pid)    {
01396         if ($this->import_mode[$table.':'.$uid]!=='exclude')    {
01397             $record = $this->dat['records'][$table.':'.$uid]['data'];
01398             if (is_array($record))  {
01399 
01400                 if ($this->update && $this->doesRecordExist($table,$uid) && $this->import_mode[$table.':'.$uid]!=='as_new') {
01401                     $ID = $uid;
01402                 } else {
01403 #debug($this->import_mode[$table.':'.$uid],$table.':'.$uid);
01404                     $ID = uniqid('NEW');
01405                 }
01406                 $this->import_newId[$table.':'.$ID] = array('table' => $table, 'uid' => $uid);
01407                 if ($table=='pages')    $this->import_newId_pids[$uid] = $ID;
01408 
01409                     // Set main record data:
01410                 $this->import_data[$table][$ID] = $record;
01411                 $this->import_data[$table][$ID]['tx_impexp_origuid'] = $this->import_data[$table][$ID]['uid'];
01412 
01413                     // Reset permission data:
01414                 if ($table==='pages')   {
01415                         // Have to reset the user/group IDs so pages are owned by importing user. Otherwise strange things may happen for non-admins!
01416                     unset($this->import_data[$table][$ID]['perms_userid']);
01417                     unset($this->import_data[$table][$ID]['perms_groupid']);
01418 
01419                         // user/group/everybody settings is kept - but these might still conflict with possibilities for writing the content!"
01420                     #unset($this->import_data[$table][$ID]['perms_user']);
01421                     #unset($this->import_data[$table][$ID]['perms_group']);
01422                     #unset($this->import_data[$table][$ID]['perms_everybody']);
01423                 }
01424 
01425                     // PID and UID:
01426                 unset($this->import_data[$table][$ID]['uid']);
01427                 if (t3lib_div::testInt($ID))    {   // Updates:
01428                     unset($this->import_data[$table][$ID]['pid']);
01429                 } else {    // Inserts:
01430                     $this->import_data[$table][$ID]['pid'] = $pid;
01431 
01432                     if ((($this->import_mode[$table.':'.$uid]==='force_uid' && $this->update) || $this->force_all_UIDS) && $GLOBALS['BE_USER']->isAdmin())  {
01433 #debug($this->import_mode[$table.':'.$uid],$table.':'.$uid);
01434                         $this->import_data[$table][$ID]['uid'] = $uid;
01435                         $this->suggestedInsertUids[$table.':'.$uid] = 'DELETE';
01436                     }
01437                 }
01438 
01439                     // Setting db/file blank:
01440                 foreach ($this->dat['records'][$table.':'.$uid]['rels'] as $field => $config) {
01441                     switch((string)$config['type']) {
01442                         case 'db':
01443                         case 'file':
01444                                 // Fixed later in ->setRelations() [because we need to know ALL newly created IDs before we can map relations!]
01445                                 // In the meantime we set NO values for relations:
01446                             $this->import_data[$table][$ID][$field] = '';
01447                         break;
01448                         case 'flex':
01449                                 // Fixed later in setFlexFormRelations()
01450                                 // In the meantime we set NO value for flexforms - this is mainly because file references inside will not be processed properly; In fact references will point to no file or existing files (in which case there will be double-references which is a big problem of course!)
01451                             $this->import_data[$table][$ID][$field] = '';
01452                         break;
01453                     }
01454                 }
01455             } elseif ($table.':'.$uid != 'pages:0') {   // On root level we don't want this error message.
01456                 $this->error('Error: no record was found in data array!',1);
01457             }
01458         }
01459     }
01460 
01461     /**
01462      * Registers the substNEWids in memory.
01463      *
01464      * @param   array       $substNEWwithIDs from tcemain to be merged into internal mapping variable in this object
01465      * @return  void
01466      * @see writeRecords()
01467      */
01468     function addToMapId($substNEWwithIDs)   {
01469         foreach ($this->import_data as $table => $recs) {
01470             foreach ($recs as $id => $value) {
01471                 $old_uid = $this->import_newId[$table.':'.$id]['uid'];
01472                 if (isset($substNEWwithIDs[$id]))   {
01473                     $this->import_mapId[$table][$old_uid] = $substNEWwithIDs[$id];
01474                 } elseif ($this->update) {
01475                     $this->import_mapId[$table][$old_uid] = $id;    // Map same ID to same ID....
01476                 } else $this->error('Possible error: '.$table.':'.$old_uid.' had no new id assigned to it. This indicates that the record was not added to database during import. Please check changelog!',1);
01477             }
01478         }
01479     }
01480 
01481     /**
01482      * Returns a new $TCE object
01483      *
01484      * @return  object      $TCE object
01485      */
01486     function getNewTCE()    {
01487         $tce = t3lib_div::makeInstance('t3lib_TCEmain');
01488         $tce->stripslashes_values = 0;
01489         $tce->dontProcessTransformations = 1;
01490         $tce->enableLogging = $this->enableLogging;
01491         $tce->alternativeFileName = $this->alternativeFileName;
01492         $tce->alternativeFilePath = $this->alternativeFilePath;
01493         return $tce;
01494     }
01495 
01496     /**
01497      * Cleaning up all the temporary files stored in typo3temp/ folder
01498      *
01499      * @return  void
01500      */
01501     function unlinkTempFiles()  {
01502         foreach($this->unlinkFiles as $fileName)    {
01503             if (t3lib_div::isFirstPartOfStr($fileName, PATH_site.'typo3temp/')) {
01504                 t3lib_div::unlink_tempfile($fileName);
01505                 clearstatcache();
01506                 if (is_file($fileName)) {
01507                     $this->error('Error: '.$fileName.' was NOT unlinked as it should have been!',1);
01508                 }
01509             } else $this->error('Error: '.$fileName.' was not in temp-path. Not removed!',1);
01510         }
01511         $this->unlinkFiles = array();
01512     }
01513 
01514 
01515 
01516 
01517 
01518 
01519 
01520 
01521 
01522 
01523 
01524 
01525 
01526     /***************************
01527      *
01528      * Import / Relations setting
01529      *
01530      ***************************/
01531 
01532     /**
01533      * At the end of the import process all file and DB relations should be set properly (that is relations to imported records are all re-created so imported records are correctly related again)
01534      * Relations in flexform fields are processed in setFlexFormRelations() after this function
01535      *
01536      * @return  void
01537      * @see setFlexFormRelations()
01538      */
01539     function setRelations() {
01540         global $TCA;
01541 
01542         $updateData = array();
01543 
01544             // import_newId contains a register of all records that was in the import memorys "records" key
01545         foreach ($this->import_newId as $nId => $dat) {
01546             $table = $dat['table'];
01547             $uid = $dat['uid']; // original UID - NOT the new one!
01548 
01549                 // If the record has been written and received a new id, then proceed:
01550             if (is_array($this->import_mapId[$table]) && isset($this->import_mapId[$table][$uid]))  {
01551                 $thisNewUid = t3lib_BEfunc::wsMapId($table,$this->import_mapId[$table][$uid]);
01552 
01553                 if (is_array($this->dat['records'][$table.':'.$uid]['rels']))   {
01554 
01555                         // Traverse relation fields of each record
01556                     foreach ($this->dat['records'][$table.':'.$uid]['rels'] as $field => $config) {
01557                         switch((string)$config['type']) {
01558                             case 'db':
01559                                 if (is_array($config['itemArray']) && count($config['itemArray']))  {
01560                                     $valArray = $this->setRelations_db($config['itemArray']);
01561                                     $updateData[$table][$thisNewUid][$field] = implode(',',$valArray);  // List of [table]_[uid]
01562                                 }
01563                             break;
01564                             case 'file':
01565                                 if (is_array($config['newValueFiles']) && count($config['newValueFiles']))  {
01566                                     $valArr = array();
01567                                     foreach($config['newValueFiles'] as $fI)    {
01568                                         $valArr[] = $this->import_addFileNameToBeCopied($fI);
01569                                     }
01570                                     $updateData[$table][$thisNewUid][$field] = implode(',',$valArr);    // List of absolute files
01571                                 }
01572                             break;
01573                         }
01574                     }
01575                 } else $this->error('Error: no record was found in data array!',1);
01576             } else $this->error('Error: this records is NOT created it seems! ('.$table.':'.$uid.')',1);
01577         }
01578         if (count($updateData)) {
01579             $tce = $this->getNewTCE();
01580             $this->callHook('before_setRelation', array(
01581                 'tce' => &$tce,
01582                 'data' => &$updateData,
01583             ));
01584             $tce->start($updateData,Array());
01585             $tce->process_datamap();
01586             $this->callHook('after_setRelations', array(
01587                 'tce' => &$tce,
01588             ));
01589         }
01590     }
01591 
01592     /**
01593      * Maps relations for database
01594      *
01595      * @param   array       Array of item sets (table/uid) from a dbAnalysis object
01596      * @return  array       Array with values [table]_[uid]. These values have the regular tcemain-input group/select type which means they will automatically be processed into a uid-list or MM relations.
01597      */
01598     function setRelations_db($itemArray)    {
01599         $valArray = array();
01600 
01601         foreach($itemArray as $relDat)  {
01602             if (is_array($this->import_mapId[$relDat['table']]) && isset($this->import_mapId[$relDat['table']][$relDat['id']])) {
01603 
01604                 #debug('FOUND: '.$relDat['table'].':'.$relDat['id']);
01605                 $valArray[] = $relDat['table'].'_'.$this->import_mapId[$relDat['table']][$relDat['id']];
01606             } elseif ($this->isTableStatic($relDat['table']) || $this->isExcluded($relDat['table'], $relDat['id']) || $relDat['id']<0) {    // Checking for less than zero because some select types could contain negative values, eg. fe_groups (-1, -2) and sys_language (-1 = ALL languages). This must be handled on both export and import.
01607 
01608                 #debug('STATIC: '.$relDat['table'].':'.$relDat['id']);
01609                 $valArray[] = $relDat['table'].'_'.$relDat['id'];
01610             } else {
01611 
01612                 $this->error('Lost relation: '.$relDat['table'].':'.$relDat['id'],1);
01613             }
01614         }
01615 
01616         return $valArray;
01617     }
01618 
01619     /**
01620      * Writes the file from import array to temp dir and returns the filename of it.
01621      *
01622      * @param   array       File information with three keys: "filename" = filename without path, "ID_absFile" = absolute filepath to the file (including the filename), "ID" = md5 hash of "ID_absFile"
01623      * @return  string      Absolute filename of the temporary filename of the file. In ->alternativeFileName the original name is set.
01624      */
01625     function import_addFileNameToBeCopied($fI)  {
01626         if (is_array($this->dat['files'][$fI['ID']]))   {
01627             $tmpFile = t3lib_div::tempnam('import_temp_');
01628             t3lib_div::writeFile($tmpFile,$this->dat['files'][$fI['ID']]['content']);
01629             clearstatcache();
01630             if (@is_file($tmpFile)) {
01631                 $this->unlinkFiles[] = $tmpFile;
01632                 if (filesize($tmpFile)==$this->dat['files'][$fI['ID']]['filesize']) {
01633                     $this->alternativeFileName[$tmpFile] = $fI['filename'];
01634                     $this->alternativeFilePath[$tmpFile] = $this->dat['files'][$fI['ID']]['relFileRef'];
01635 
01636                     return $tmpFile;
01637                 } else $this->error('Error: temporary file '.$tmpFile.' had a size ('.filesize($tmpFile).') different from the original ('.$this->dat['files'][$fI['ID']]['filesize'].')',1);
01638             } else $this->error('Error: temporary file '.$tmpFile.' was not written as it should have been!',1);
01639         } else $this->error('Error: No file found for ID '.$fI['ID'],1);
01640     }
01641 
01642     /**
01643      * After all DB relations has been set in the end of the import (see setRelations()) then it is time to correct all relations inside of FlexForm fields.
01644      * The reason for doing this after is that the setting of relations may affect (quite often!) which data structure is used for the flexforms field!
01645      *
01646      * @return  void
01647      * @see setRelations()
01648      */
01649     function setFlexFormRelations() {
01650         global $TCA;
01651 
01652         $updateData = array();
01653             // import_newId contains a register of all records that was in the import memorys "records" key
01654         foreach ($this->import_newId as $nId => $dat) {
01655             $table = $dat['table'];
01656             $uid = $dat['uid']; // original UID - NOT the new one!
01657 
01658                 // If the record has been written and received a new id, then proceed:
01659             if (is_array($this->import_mapId[$table]) && isset($this->import_mapId[$table][$uid]))  {
01660                 $thisNewUid = t3lib_BEfunc::wsMapId($table,$this->import_mapId[$table][$uid]);
01661                 if (is_array($this->dat['records'][$table.':'.$uid]['rels']))   {
01662                     t3lib_div::loadTCA($table);
01663 
01664                         // Traverse relation fields of each record
01665                     foreach ($this->dat['records'][$table.':'.$uid]['rels'] as $field => $config) {
01666                         switch((string)$config['type']) {
01667                             case 'flex':
01668                                     // Get XML content and set as default value (string, non-processed):
01669                                 $updateData[$table][$thisNewUid][$field] = $this->dat['records'][$table.':'.$uid]['data'][$field];
01670 
01671                                     // If there has been registered relations inside the flex form field, run processing on the content:
01672                                 if (count($config['flexFormRels']['db']) || count($config['flexFormRels']['file'])) {
01673                                     $origRecordRow = t3lib_BEfunc::getRecord($table,$thisNewUid,'*');   // This will fetch the new row for the element (which should be updated with any references to data structures etc.)
01674                                     $conf = $TCA[$table]['columns'][$field]['config'];
01675                                     if (is_array($origRecordRow) && is_array($conf) && $conf['type']==='flex')  {
01676                                             // Get current data structure and value array:
01677                                         $dataStructArray = t3lib_BEfunc::getFlexFormDS($conf, $origRecordRow, $table);
01678                                         $currentValueArray = t3lib_div::xml2array($updateData[$table][$thisNewUid][$field]);
01679                                             // Do recursive processing of the XML data:
01680                                         $iteratorObj = t3lib_div::makeInstance('t3lib_TCEmain');
01681                                         $iteratorObj->callBackObj = $this;
01682                                         $currentValueArray['data'] = $iteratorObj->checkValue_flex_procInData(
01683                                                     $currentValueArray['data'],
01684                                                     array(),    // Not used.
01685                                                     array(),    // Not used.
01686                                                     $dataStructArray,
01687                                                     array($table,$thisNewUid,$field,$config),   // Parameters.
01688                                                     'remapListedDBRecords_flexFormCallBack'
01689                                                 );
01690                                             // The return value is set as an array which means it will be processed by tcemain for file and DB references!
01691                                         if (is_array($currentValueArray['data']))   {
01692                                             $updateData[$table][$thisNewUid][$field] = $currentValueArray;
01693                                         }
01694                                     }
01695                                 }
01696                             break;
01697                         }
01698                     }
01699                 } else $this->error('Error: no record was found in data array!',1);
01700             } else $this->error('Error: this records is NOT created it seems! ('.$table.':'.$uid.')',1);
01701         }
01702         if (count($updateData)) {
01703             $tce = $this->getNewTCE();
01704             $this->callHook('before_setFlexFormRelations', array(
01705                 'tce' => &$tce,
01706                 'data' => &$updateData,
01707             ));
01708             $tce->start($updateData,Array());
01709             $tce->process_datamap();
01710             $this->callHook('after_setFlexFormRelations', array(
01711                 'tce' => &$tce,
01712             ));
01713         }
01714     }
01715 
01716     /**
01717      * Callback function for traversing the FlexForm structure in relation to remapping database relations
01718      *
01719      * @param   array       Set of parameters in numeric array: table, uid, field
01720      * @param   array       TCA config for field (from Data Structure of course)
01721      * @param   string      Field value (from FlexForm XML)
01722      * @param   string      Not used
01723      * @param   string      Not used
01724      * @param   string      Path of where the data structure of the element is found
01725      * @return  array       Array where the "value" key carries the value.
01726      * @see setFlexFormRelations()
01727      */
01728     function remapListedDBRecords_flexFormCallBack($pParams, $dsConf, $dataValue, $dataValue_ext1, $dataValue_ext2, $path)  {
01729 
01730             // Extract parameters:
01731         list($table,$uid,$field,$config) = $pParams;
01732 
01733             // In case the $path is used as index without a trailing slash we will remove that
01734         if (!is_array($config['flexFormRels']['db'][$path]) && is_array($config['flexFormRels']['db'][rtrim($path, '/')]))  {
01735             $path = rtrim($path, '/');
01736         }
01737         if (is_array($config['flexFormRels']['db'][$path])) {
01738             $valArray = $this->setRelations_db($config['flexFormRels']['db'][$path]);
01739             $dataValue = implode(',',$valArray);
01740         }
01741 
01742         if (is_array($config['flexFormRels']['file'][$path]))   {
01743             foreach($config['flexFormRels']['file'][$path] as $fI)  {
01744                 $valArr[] = $this->import_addFileNameToBeCopied($fI);
01745             }
01746             $dataValue = implode(',',$valArr);
01747         }
01748 
01749         return array('value' => $dataValue);
01750     }
01751 
01752 
01753 
01754 
01755 
01756 
01757 
01758 
01759 
01760 
01761 
01762     /**************************
01763      *
01764      * Import / Soft References
01765      *
01766      *************************/
01767 
01768     /**
01769      * Processing of soft references
01770      *
01771      * @return  void
01772      */
01773     function processSoftReferences()    {
01774         global $TCA;
01775 
01776             // Initialize:
01777         $inData = array();
01778 
01779             // Traverse records:
01780         if (is_array($this->dat['header']['records']))  {
01781             foreach($this->dat['header']['records'] as $table => $recs) {
01782                 foreach($recs as $uid => $thisRec)  {
01783 
01784                         // If there are soft references defined, traverse those:
01785                     if (isset($TCA[$table]) && is_array($thisRec['softrefs']))  {
01786                         t3lib_div::loadTCA($table);
01787 
01788                             // First traversal is to collect softref configuration and split them up based on fields. This could probably also have been done with the "records" key instead of the header.
01789                         $fieldsIndex = array();
01790                         foreach($thisRec['softrefs'] as $softrefDef)    {
01791 
01792                                 // If a substitution token is set:
01793                             if ($softrefDef['field'] && is_array($softrefDef['subst']) && $softrefDef['subst']['tokenID'])  {
01794                                 $fieldsIndex[$softrefDef['field']][$softrefDef['subst']['tokenID']] = $softrefDef;
01795                             }
01796                         }
01797 
01798                             // The new id:
01799                         $thisNewUid = t3lib_BEfunc::wsMapId($table,$this->import_mapId[$table][$uid]);
01800 
01801                             // Now, if there are any fields that require substitution to be done, lets go for that:
01802                         foreach($fieldsIndex as $field => $softRefCfgs) {
01803                             if (is_array($TCA[$table]['columns'][$field]))  {
01804                                 $conf = $TCA[$table]['columns'][$field]['config'];
01805                                 if ($conf['type']==='flex') {
01806 
01807                                     $origRecordRow = t3lib_BEfunc::getRecord($table,$thisNewUid,'*');   // This will fetch the new row for the element (which should be updated with any references to data structures etc.)
01808                                     if (is_array($origRecordRow))   {
01809 
01810                                             // Get current data structure and value array:
01811                                         $dataStructArray = t3lib_BEfunc::getFlexFormDS($conf, $origRecordRow, $table);
01812                                         $currentValueArray = t3lib_div::xml2array($origRecordRow[$field]);
01813 
01814                                             // Do recursive processing of the XML data:
01815                                         $iteratorObj = t3lib_div::makeInstance('t3lib_TCEmain');
01816                                         $iteratorObj->callBackObj = $this;
01817                                         $currentValueArray['data'] = $iteratorObj->checkValue_flex_procInData(
01818                                                     $currentValueArray['data'],
01819                                                     array(),    // Not used.
01820                                                     array(),    // Not used.
01821                                                     $dataStructArray,
01822                                                     array($table,$uid,$field,$softRefCfgs), // Parameters (using old UID on purpose!)
01823                                                     'processSoftReferences_flexFormCallBack'
01824                                                 );
01825 
01826                                             // The return value is set as an array which means it will be processed by tcemain for file and DB references!
01827                                         if (is_array($currentValueArray['data']))   {
01828                                             $inData[$table][$thisNewUid][$field] = $currentValueArray;
01829                                         }
01830                                     }
01831                                 } else {
01832                                         // Get tokenizedContent string and proceed only if that is not blank:
01833                                     $tokenizedContent = $this->dat['records'][$table.':'.$uid]['rels'][$field]['softrefs']['tokenizedContent'];
01834                                     if (strlen($tokenizedContent) && is_array($softRefCfgs))    {
01835                                         $inData[$table][$thisNewUid][$field] = $this->processSoftReferences_substTokens($tokenizedContent, $softRefCfgs, $table, $uid);
01836                                     }
01837                                 }
01838                             }
01839                         }
01840                     }
01841                 }
01842             }
01843         }
01844 
01845             // Now write to database:
01846         $tce = $this->getNewTCE();
01847         $this->callHook('before_processSoftReferences', array(
01848                 'tce' => &$tce,
01849                 'data' => &$inData,
01850             ));
01851         $tce->enableLogging = TRUE;
01852         $tce->start($inData, Array());
01853         $tce->process_datamap();
01854         $this->callHook('after_processSoftReferences', array(
01855             'tce' => &$tce,
01856         ));
01857     }
01858 
01859     /**
01860      * Callback function for traversing the FlexForm structure in relation to remapping softreference relations
01861      *
01862      * @param   array       Set of parameters in numeric array: table, uid, field
01863      * @param   array       TCA config for field (from Data Structure of course)
01864      * @param   string      Field value (from FlexForm XML)
01865      * @param   string      Not used
01866      * @param   string      Not used
01867      * @param   string      Path of where the data structure where the element is found
01868      * @return  array       Array where the "value" key carries the value.
01869      * @see setFlexFormRelations()
01870      */
01871     function processSoftReferences_flexFormCallBack($pParams, $dsConf, $dataValue, $dataValue_ext1, $dataValue_ext2, $path) {
01872 
01873             // Extract parameters:
01874         list($table,$origUid,$field,$softRefCfgs)   = $pParams;
01875 
01876         if (is_array($softRefCfgs)) {
01877 
01878                 // First, find all soft reference configurations for this structure path (they are listed flat in the header):
01879             $thisSoftRefCfgList = array();
01880             foreach($softRefCfgs as $sK => $sV) {
01881                 if ($sV['structurePath']===$path)   {
01882                     $thisSoftRefCfgList[$sK] = $sV;
01883                 }
01884             }
01885 
01886                 // If any was found, do processing:
01887             if (count($thisSoftRefCfgList)) {
01888 
01889                     // Get tokenizedContent string and proceed only if that is not blank:
01890                 $tokenizedContent = $this->dat['records'][$table.':'.$origUid]['rels'][$field]['flexFormRels']['softrefs'][$path]['tokenizedContent'];
01891                 if (strlen($tokenizedContent))  {
01892                     $dataValue = $this->processSoftReferences_substTokens($tokenizedContent, $thisSoftRefCfgList, $table, $origUid);
01893                 }
01894             }
01895         }
01896 
01897             // Return
01898         return array('value' => $dataValue);
01899     }
01900 
01901     /**
01902      * Substition of softreference tokens
01903      *
01904      * @param   string      Content of field with soft reference tokens in.
01905      * @param   array       Soft reference configurations
01906      * @param   string      Table for which the processing occurs
01907      * @param   string      UID of record from table
01908      * @return  string      The input content with tokens substituted according to entries in softRefCfgs
01909      */
01910     function processSoftReferences_substTokens($tokenizedContent, $softRefCfgs, $table, $uid)   {
01911 
01912             // traverse each softref type for this field:
01913         foreach($softRefCfgs as $cfg)   {
01914 
01915                 // Get token ID:
01916             $tokenID = $cfg['subst']['tokenID'];
01917 
01918                 // Default is current token value:
01919             $insertValue = $cfg['subst']['tokenValue'];
01920 
01921                 // Based on mode:
01922             switch((string)$this->softrefCfg[$tokenID]['mode']) {
01923                 case 'exclude':
01924                     // Exclude is a simple passthrough of the value
01925                 break;
01926                 case 'editable':
01927                         // Editable always picks up the value from this input array:
01928                     $insertValue = $this->softrefInputValues[$tokenID];
01929                 break;
01930                 default:
01931                         // Mapping IDs/creating files: Based on type, look up new value:
01932                     switch((string)$cfg['subst']['type'])   {
01933                         case 'db':
01934                             default:
01935                                     // Trying to map database element if found in the mapID array:
01936                                 list($tempTable,$tempUid) = explode(':',$cfg['subst']['recordRef']);
01937                                 if (isset($this->import_mapId[$tempTable][$tempUid]))   {
01938                                     $insertValue = t3lib_BEfunc::wsMapId($tempTable,$this->import_mapId[$tempTable][$tempUid]);
01939 
01940                                         // Look if reference is to a page and the original token value was NOT an integer - then we assume is was an alias and try to look up the new one!
01941                                     if ($tempTable==='pages' && !t3lib_div::testInt($cfg['subst']['tokenValue']))   {
01942                                         $recWithUniqueValue = t3lib_BEfunc::getRecord($tempTable,$insertValue, 'alias');
01943                                         if ($recWithUniqueValue['alias'])   {
01944                                             $insertValue = $recWithUniqueValue['alias'];
01945                                         }
01946                                     }
01947                                 }
01948                             break;
01949                         break;
01950                         case 'file':
01951                                 // Create / Overwrite file:
01952                             $insertValue = $this->processSoftReferences_saveFile($cfg['subst']['relFileName'], $cfg, $table, $uid);
01953                         break;
01954                     }
01955                 break;
01956             }
01957 
01958                 // Finally, swap the soft reference token in tokenized content with the insert value:
01959             $tokenizedContent = str_replace('{softref:'.$tokenID.'}', $insertValue, $tokenizedContent);
01960         }
01961 
01962         return $tokenizedContent;
01963     }
01964 
01965     /**
01966      * Process a soft reference file
01967      *
01968      * @param   string      Old Relative filename
01969      * @param   array       soft reference configuration array
01970      * @param   string      Table for which the processing occurs
01971      * @param   string      UID of record from table
01972      * @return  string      New relative filename (value to insert instead of the softref token)
01973      */
01974     function processSoftReferences_saveFile($relFileName, $cfg, $table, $uid)   {
01975 
01976         if ($fileHeaderInfo = $this->dat['header']['files'][$cfg['file_ID']])   {
01977                 // Initialize; Get directory prefix for file and find possible RTE filename
01978             $dirPrefix = dirname($relFileName).'/';
01979             $rteOrigName = $this->getRTEoriginalFilename(basename($relFileName));
01980 
01981                 // If filename looks like an RTE file, and the directory is in "uploads/", then process as a RTE file!
01982             if ($rteOrigName && t3lib_div::isFirstPartOfStr($dirPrefix,'uploads/')) {   // RTE:
01983 
01984                     // First, find unique RTE file name:
01985                 if (@is_dir(PATH_site.$dirPrefix))  {
01986 
01987                         // From the "original" RTE filename, produce a new "original" destination filename which is unused. Even if updated, the image should be unique. Currently the problem with this is that it leaves a lot of unused RTE images...
01988                     $fileProcObj = $this->getFileProcObj();
01989                     $origDestName = $fileProcObj->getUniqueName($rteOrigName, PATH_site.$dirPrefix);
01990 
01991                         // Create copy file name:
01992                     $pI = pathinfo($relFileName);
01993                     $copyDestName = dirname($origDestName).'/RTEmagicC_'.substr(basename($origDestName),10).'.'.$pI['extension'];
01994                     if (!@is_file($copyDestName) && !@is_file($origDestName)
01995                         && $origDestName===t3lib_div::getFileAbsFileName($origDestName) && $copyDestName===t3lib_div::getFileAbsFileName($copyDestName))    {
01996 
01997                         if ($this->dat['header']['files'][$fileHeaderInfo['RTE_ORIG_ID']])  {
01998 
01999                                 // Write the copy and original RTE file to the respective filenames:
02000                             $this->writeFileVerify($copyDestName, $cfg['file_ID'], TRUE);
02001                             $this->writeFileVerify($origDestName, $fileHeaderInfo['RTE_ORIG_ID'], TRUE);
02002 
02003                                 // Return the relative path of the copy file name:
02004                             return substr($copyDestName, strlen(PATH_site));
02005                         } else $this->error('ERROR: Could not find original file ID');
02006                     } else $this->error('ERROR: The destination filenames "'.$copyDestName.'" and "'.$origDestName.'" either existed or have non-valid names');
02007                 } else $this->error('ERROR: "'.PATH_site.$dirPrefix.'" was not a directory, so could not process file "'.$relFileName.'"');
02008 
02009 
02010             } elseif (t3lib_div::isFirstPartOfStr($dirPrefix, $this->fileadminFolderName.'/'))  {   // File in fileadmin/ folder:
02011 
02012                     // Create file (and possible resources)
02013                 $newFileName = $this->processSoftReferences_saveFile_createRelFile($dirPrefix,basename($relFileName),$cfg['file_ID'], $table, $uid);
02014 
02015                 if (strlen($newFileName))   {
02016                     $relFileName = $newFileName;
02017                 } else $this->error('ERROR: No new file created for "'.$relFileName.'"');
02018             } else $this->error('ERROR: Sorry, cannot operate on non-RTE files which are outside the fileadmin folder.');
02019         } else $this->error('ERROR: Could not find file ID in header.');
02020 
02021             // Return (new) filename relative to PATH_site:
02022         return $relFileName;
02023     }
02024 
02025     /**
02026      * Create file in directory and return the new (unique) filename
02027      *
02028      * @param   string      Directory prefix, relative, with trailing slash
02029      * @param   string      Filename (without path)
02030      * @param   string      File ID from import memory
02031      * @param   string      Table for which the processing occurs
02032      * @param   string      UID of record from table
02033      * @return  string      New relative filename, if any
02034      */
02035     function processSoftReferences_saveFile_createRelFile($origDirPrefix, $fileName, $fileID, $table, $uid) {
02036 
02037             // If the fileID map contains an entry for this fileID then just return the relative filename of that entry; we don't want to write another unique filename for this one!
02038         if ($this->fileIDMap[$fileID])  {
02039             return substr($this->fileIDMap[$fileID],strlen(PATH_site));
02040         }
02041 
02042             // Verify FileMount access to dir-prefix. Returns the best alternative relative path if any
02043         $dirPrefix = $this->verifyFolderAccess($origDirPrefix);
02044 
02045         if ($dirPrefix && (!$this->update || $origDirPrefix===$dirPrefix) && $this->checkOrCreateDir($dirPrefix))   {
02046             $fileHeaderInfo = $this->dat['header']['files'][$fileID];
02047             $updMode = $this->update && $this->import_mapId[$table][$uid]===$uid && $this->import_mode[$table.':'.$uid]!=='as_new';
02048                 // Create new name for file:
02049             if ($updMode)   {   // Must have same ID in map array (just for security, is not really needed) and NOT be set "as_new".
02050                 $newName = PATH_site.$dirPrefix.$fileName;
02051             } else {
02052                     // Create unique filename:
02053                 $fileProcObj = $this->getFileProcObj();
02054                 $newName = $fileProcObj->getUniqueName($fileName, PATH_site.$dirPrefix);
02055             }
02056 #debug($newName,'$newName');
02057 
02058                 // Write main file:
02059             if ($this->writeFileVerify($newName, $fileID))  {
02060 
02061                     // If the resource was an HTML/CSS file with resources attached, we will write those as well!
02062                 if (is_array($fileHeaderInfo['EXT_RES_ID']))    {
02063 #debug($fileHeaderInfo['EXT_RES_ID']);
02064                     $tokenizedContent = $this->dat['files'][$fileID]['tokenizedContent'];
02065                     $tokenSubstituted = FALSE;
02066 
02067                     $fileProcObj = $this->getFileProcObj();
02068 
02069                     if ($updMode)   {
02070                         foreach($fileHeaderInfo['EXT_RES_ID'] as $res_fileID)   {
02071                             if ($this->dat['files'][$res_fileID]['filename'])   {
02072 
02073                                     // Resolve original filename:
02074                                 $relResourceFileName = $this->dat['files'][$res_fileID]['parentRelFileName'];
02075                                 $absResourceFileName = t3lib_div::resolveBackPath(PATH_site.$origDirPrefix.$relResourceFileName);
02076                                 $absResourceFileName = t3lib_div::getFileAbsFileName($absResourceFileName);
02077                                 if ($absResourceFileName && t3lib_div::isFirstPartOfStr($absResourceFileName,PATH_site.$this->fileadminFolderName.'/')) {
02078                                     $destDir = substr(dirname($absResourceFileName).'/',strlen(PATH_site));
02079                                     if ($this->verifyFolderAccess($destDir, TRUE) && $this->checkOrCreateDir($destDir)) {
02080                                         $this->writeFileVerify($absResourceFileName, $res_fileID);
02081                                     } else $this->error('ERROR: Could not create file in directory "'.$destDir.'"');
02082                                 } else $this->error('ERROR: Could not resolve path for "'.$relResourceFileName.'"');
02083 
02084                                 $tokenizedContent = str_replace('{EXT_RES_ID:'.$res_fileID.'}', $relResourceFileName, $tokenizedContent);
02085                                 $tokenSubstituted = TRUE;
02086                             }
02087                         }
02088                     } else {
02089                             // Create the resouces directory name (filename without extension, suffixed "_FILES")
02090                         $resourceDir = dirname($newName).'/'.preg_replace('/\.[^.]*$/','',basename($newName)).'_FILES';
02091                         if (t3lib_div::mkdir($resourceDir)) {
02092                             foreach($fileHeaderInfo['EXT_RES_ID'] as $res_fileID)   {
02093                                 if ($this->dat['files'][$res_fileID]['filename'])   {
02094                                     $absResourceFileName = $fileProcObj->getUniqueName($this->dat['files'][$res_fileID]['filename'], $resourceDir);
02095                                     $relResourceFileName = substr($absResourceFileName, strlen(dirname($resourceDir))+1);
02096                                     $this->writeFileVerify($absResourceFileName, $res_fileID);
02097 
02098                                     $tokenizedContent = str_replace('{EXT_RES_ID:'.$res_fileID.'}', $relResourceFileName, $tokenizedContent);
02099                                     $tokenSubstituted = TRUE;
02100                                 }
02101                             }
02102                         }
02103                     }
02104 
02105                         // If substitutions has been made, write the content to the file again:
02106                     if ($tokenSubstituted)  {
02107                         t3lib_div::writeFile($newName, $tokenizedContent);
02108                     }
02109                 }
02110 
02111                 return substr($newName, strlen(PATH_site));
02112             }
02113         }
02114     }
02115 
02116     /**
02117      * Writes a file from the import memory having $fileID to file name $fileName which must be an absolute path inside PATH_site
02118      *
02119      * @param   string      Absolute filename inside PATH_site to write to
02120      * @param   string      File ID from import memory
02121      * @param   boolean     Bypasses the checking against filemounts - only for RTE files!
02122      * @return  boolean     Returns true if it went well. Notice that the content of the file is read again, and md5 from import memory is validated.
02123      */
02124     function writeFileVerify($fileName, $fileID, $bypassMountCheck=FALSE)   {
02125         $fileProcObj = $this->getFileProcObj();
02126 
02127         if ($fileProcObj->actionPerms['newFile'])   {
02128             if ($fileProcObj->checkPathAgainstMounts($fileName) || $bypassMountCheck)   {   // Just for security, check again. Should actually not be necessary.
02129                 $fI = t3lib_div::split_fileref($fileName);
02130                 if ($fileProcObj->checkIfAllowed($fI['fileext'], $fI['path'], $fI['file']) || ($this->allowPHPScripts && $GLOBALS['BE_USER']->isAdmin())) {
02131                     if (t3lib_div::getFileAbsFileName($fileName))   {
02132                         if ($this->dat['files'][$fileID])   {
02133                             t3lib_div::writeFile($fileName,$this->dat['files'][$fileID]['content']);
02134                             $this->fileIDMap[$fileID] = $fileName;
02135                             if (md5(t3lib_div::getUrl($fileName))==$this->dat['files'][$fileID]['content_md5']) {
02136                                 return TRUE;
02137                             } else $this->error('ERROR: File content "'.$fileName.'" was corrupted');
02138                         } else $this->error('ERROR: File ID "'.$fileID.'" could not be found');
02139                     } else $this->error('ERROR: Filename "'.$fileName.'" was not a valid relative file path!');
02140                 } else $this->error('ERROR: Filename "'.$fileName.'" failed against extension check or deny-pattern!');
02141             } else $this->error('ERROR: Filename "'.$fileName.'" was not allowed in destination path!');
02142         } else $this->error('ERROR: You did not have sufficient permissions to write the file "'.$fileName.'"');
02143     }
02144 
02145     /**
02146      * Returns true if directory exists  and if it doesn't it will create directory and return true if that succeeded.
02147      *
02148      * @param   string      Directory to create. Having a trailing slash. Must be in fileadmin/. Relative to PATH_site
02149      * @return  boolean     True, if directory exists (was created)
02150      */
02151     function checkOrCreateDir($dirPrefix)   {
02152 
02153             // Split dir path and remove first directory (which should be "fileadmin")
02154         $filePathParts = explode('/', $dirPrefix);
02155         $firstDir = array_shift($filePathParts);
02156 
02157         if ($firstDir===$this->fileadminFolderName && t3lib_div::getFileAbsFileName($dirPrefix))    {
02158 
02159             $pathAcc = '';
02160             foreach($filePathParts as $dirname) {
02161                 $pathAcc.='/'.$dirname;
02162                 if (strlen($dirname))   {
02163                     if (!@is_dir(PATH_site.$this->fileadminFolderName.$pathAcc))    {
02164                         if (!t3lib_div::mkdir(PATH_site.$this->fileadminFolderName.$pathAcc))   {
02165                             $this->error('ERROR: Directory could not be created....B');
02166                             return FALSE;
02167                         }
02168                     }
02169                 } elseif ($dirPrefix===$this->fileadminFolderName.$pathAcc) {
02170                     return TRUE;
02171                 } else $this->error('ERROR: Directory could not be created....A');
02172             }
02173         }
02174     }
02175 
02176     /**
02177      * Verifies that the input path (relative to PATH_site) is found in the backend users filemounts.
02178      * If it doesn't it will try to find another relative filemount for the user and return an alternative path prefix for the file.
02179      *
02180      * @param   string      Path relative to PATH_site
02181      * @param   boolean     If set, Do not look for alternative path! Just return false
02182      * @return  string      If a path is available that will be returned, otherwise false.
02183      */
02184     function verifyFolderAccess($dirPrefix, $noAlternative=FALSE)   {
02185         $fileProcObj = $this->getFileProcObj();
02186 
02187 #$fileProcObj->mounts['1f390e42e1dc46f125310ead30c7bd9d']['path'] = '/var/www/typo3/dev/testsite-3.6.0/fileadmin/user_upload/';
02188 
02189             // Check, if dirPrefix is inside a valid Filemount for user:
02190         $result = $fileProcObj->checkPathAgainstMounts(PATH_site.$dirPrefix);
02191 
02192             // If not, try to find another relative filemount and use that instead:
02193         if (!$result)   {
02194             if ($noAlternative) return FALSE;
02195 
02196                 // Find first web folder:
02197             $result = $fileProcObj->findFirstWebFolder();
02198 
02199                 // If that succeeded, return the path to it:
02200             if ($result)    {
02201                     // Remove the "fileadmin/" prefix of input path - and append the rest to the return value:
02202                 if (t3lib_div::isFirstPartOfStr($dirPrefix,$this->fileadminFolderName.'/')) {
02203                     $dirPrefix = substr($dirPrefix,strlen($this->fileadminFolderName.'/'));
02204                 }
02205                 return substr($fileProcObj->mounts[$result]['path'].$dirPrefix,strlen(PATH_site));
02206             }
02207         } else {
02208             return $dirPrefix;
02209         }
02210     }
02211 
02212 
02213 
02214 
02215 
02216 
02217 
02218 
02219 
02220 
02221     /**************************
02222      *
02223      * File Input
02224      *
02225      *************************/
02226 
02227     /**
02228      * Loads the header section/all of the $filename into memory
02229      *
02230      * @param   string      Filename, absolute
02231      * @param   boolean     If set, all information is loaded (header, records and files). Otherwise the default is to read only the header information
02232      * @return  boolean     True if the operation went well
02233      */
02234     function loadFile($filename,$all=0) {
02235         if (@is_file($filename))    {
02236             $fI = pathinfo($filename);
02237             if (strtolower($fI['extension'])=='xml')    {
02238                     // XML:
02239                 $xmlContent = t3lib_div::getUrl($filename);
02240                 if (strlen($xmlContent))    {
02241                     $this->dat = t3lib_div::xml2array($xmlContent,'',TRUE);
02242                     if (is_array($this->dat))   {
02243                         if ($this->dat['_DOCUMENT_TAG']==='T3RecordDocument' && is_array($this->dat['header']) && is_array($this->dat['records']))  {
02244                             $this->loadInit();
02245                             return TRUE;
02246                         } else $this->error('XML file did not contain proper XML for TYPO3 Import');
02247                     } else $this->error('XML could not be parsed: '.$this->dat);
02248                 } else $this->error('Error opening file: '.$filename);
02249             } else {
02250                     // T3D
02251                 if($fd = fopen($filename,'rb')) {
02252                     $this->dat['header'] = $this->getNextFilePart($fd,1,'header');
02253                     if ($all)   {
02254                         $this->dat['records'] = $this->getNextFilePart($fd,1,'records');
02255                         $this->dat['files'] = $this->getNextFilePart($fd,1,'files');
02256                     }
02257                     $this->loadInit();
02258                     return TRUE;
02259                 } else $this->error('Error opening file: '.$filename);
02260                 fclose($fd);
02261             }
02262         } else $this->error('Filename not found: '.$filename);
02263 
02264         return FALSE;
02265     }
02266 
02267     /**
02268      * Returns the next content part form the fileresource (t3d), $fd
02269      *
02270      * @param   pointer     File pointer
02271      * @param   boolean     If set, the returned content is unserialized into an array, otherwise you get the raw string
02272      * @param   string      For error messages this indicates the section of the problem.
02273      * @return  string      Data string
02274      * @access private
02275      * @see loadFile()
02276      */
02277     function getNextFilePart($fd,$unserialize=0,$name='')   {
02278         $initStrLen = 32+1+1+1+10+1;
02279 
02280             // getting header data
02281         $initStr = fread($fd, $initStrLen);
02282         $initStrDat = explode(':',$initStr);
02283         if (strstr($initStrDat[0],'Warning') == FALSE)  {
02284             if (!strcmp($initStrDat[3],'')) {
02285                 $datString = fread($fd,intval($initStrDat[2]));
02286                 fread($fd,1);
02287                 if (!strcmp(md5($datString), $initStrDat[0]))   {
02288                     if ($initStrDat[1]) {
02289                         if ($this->compress)    {
02290                             $datString = gzuncompress($datString);
02291                         } else $this->error('Content read error: This file requires decompression, but this server does not offer gzcompress()/gzuncompress() functions.',1);
02292                     }
02293                     return $unserialize ? unserialize($datString) : $datString;
02294                 } else $this->error('MD5 check failed ('.$name.')');
02295             } else $this->error('File read error: InitString had a wrong length. ('.$name.')');
02296         } else $this->error('File read error: Warning message in file. ('.$initStr.fgets($fd).')');
02297     }
02298 
02299     /**
02300      * Loads T3D file content into the $this->dat array
02301      * (This function can be used to test the output strings from ->compileMemoryToFileContent())
02302      *
02303      * @param   string      File content
02304      * @return  void
02305      */
02306     function loadContent($filecontent)  {
02307         $pointer = 0;
02308 
02309         $this->dat['header'] = $this->getNextContentPart($filecontent,$pointer,1,'header');
02310         $this->dat['records'] = $this->getNextContentPart($filecontent,$pointer,1,'records');
02311         $this->dat['files'] = $this->getNextContentPart($filecontent,$pointer,1,'files');
02312         $this->loadInit();
02313     }
02314 
02315     /**
02316      * Returns the next content part from the $filecontent
02317      *
02318      * @param   string      File content string
02319      * @param   integer     File pointer (where to read from)
02320      * @param   boolean     If set, the returned content is unserialized into an array, otherwise you get the raw string
02321      * @param   string      For error messages this indicates the section of the problem.
02322      * @return  string      Data string
02323      */
02324     function getNextContentPart($filecontent,&$pointer,$unserialize=0,$name='') {
02325         $initStrLen = 32+1+1+1+10+1;
02326             // getting header data
02327         $initStr = substr($filecontent,$pointer,$initStrLen);
02328         $pointer+= $initStrLen;
02329         $initStrDat = explode(':',$initStr);
02330         if (!strcmp($initStrDat[3],'')) {
02331             $datString = substr($filecontent,$pointer,intval($initStrDat[2]));
02332             $pointer+= intval($initStrDat[2])+1;
02333             if (!strcmp(md5($datString),$initStrDat[0]))    {
02334                 if ($initStrDat[1]) {
02335                     if ($this->compress)    {
02336                         $datString = gzuncompress($datString);
02337                     } else $this->error('Content read error: This file requires decompression, but this server does not offer gzcompress()/gzuncompress() functions.',1);
02338                 }
02339                 return $unserialize ? unserialize($datString) : $datString;
02340             } else $this->error('MD5 check failed ('.$name.')');
02341         } else $this->error('Content read error: InitString had a wrong length. ('.$name.')');
02342     }
02343 
02344     /**
02345      * Setting up the object based on the recently loaded ->dat array
02346      *
02347      * @return  void
02348      */
02349     function loadInit() {
02350         $this->relStaticTables = (array)$this->dat['header']['relStaticTables'];
02351         $this->excludeMap = (array)$this->dat['header']['excludeMap'];
02352 
02353         $this->softrefCfg = (array)$this->dat['header']['softrefCfg'];
02354         $this->extensionDependencies = (array)$this->dat['header']['extensionDependencies'];
02355 
02356         $this->fixCharsets();
02357     }
02358 
02359     /**
02360      * Fix charset of import memory if different from system charset
02361      *
02362      * @return  void
02363      * @see loadInit()
02364      */
02365     function fixCharsets()  {
02366         global $LANG;
02367 
02368         $importCharset = $this->dat['header']['charset'];
02369         if ($importCharset) {
02370             if ($importCharset!==$LANG->charSet)    {
02371                 $this->error('CHARSET: Converting charset of input file ('.$importCharset.') to the system charset ('.$LANG->charSet.')');
02372 
02373                     // convert meta data:
02374                 if (is_array($this->dat['header']['meta'])) {
02375                     $LANG->csConvObj->convArray($this->dat['header']['meta'],$importCharset,$LANG->charSet);
02376                 }
02377                     // convert record headers:
02378                 if (is_array($this->dat['header']['records']))  {
02379                     $LANG->csConvObj->convArray($this->dat['header']['records'],$importCharset,$LANG->charSet);
02380                 }
02381                     // convert records themselves:
02382                 if (is_array($this->dat['records']))    {
02383                     $LANG->csConvObj->convArray($this->dat['records'],$importCharset,$LANG->charSet);
02384                 }
02385             }
02386         } else {
02387             $this->error('CHARSET: No charset found in import file!');
02388         }
02389     }
02390 
02391 
02392 
02393 
02394 
02395 
02396 
02397 
02398 
02399 
02400 
02401 
02402 
02403 
02404 
02405 
02406 
02407 
02408 
02409     /********************************************************
02410      *
02411      * Visual rendering of import/export memory, $this->dat
02412      *
02413      ********************************************************/
02414 
02415     /**
02416      * Displays an overview of the header-content.
02417      *
02418      * @return  string      HTML content
02419      */
02420     function displayContentOverview()   {
02421         global $LANG;
02422 
02423             // Check extension dependencies:
02424         if (is_array($this->dat['header']['extensionDependencies']))    {
02425             foreach($this->dat['header']['extensionDependencies'] as $extKey)   {
02426                 if (!t3lib_extMgm::isLoaded($extKey))   {
02427                     $this->error('DEPENDENCY: The extension with key "'.$extKey.'" must be installed!');
02428                 }
02429             }
02430         }
02431 
02432             // Probably this is done to save memory space?
02433         unset($this->dat['files']);
02434 
02435             // Traverse header:
02436         $this->remainHeader = $this->dat['header'];
02437         if (is_array($this->remainHeader))  {
02438 
02439                 // If there is a page tree set, show that:
02440             if (is_array($this->dat['header']['pagetree'])) {
02441                 reset($this->dat['header']['pagetree']);
02442                 $lines = array();
02443                 $this->traversePageTree($this->dat['header']['pagetree'],$lines);
02444 
02445                 $rows = array();
02446                 $rows[] = '
02447                 <tr class="bgColor5 tableheader">
02448                     <td>'.$LANG->getLL('impexpcore_displaycon_controls',1).'</td>
02449                     <td>'.$LANG->getLL('impexpcore_displaycon_title',1).'</td>
02450                     <td>'.$LANG->getLL('impexpcore_displaycon_size',1).'</td>
02451                     <td>'.$LANG->getLL('impexpcore_displaycon_message',1).'</td>
02452                     '.($this->update ? '<td>'.$LANG->getLL('impexpcore_displaycon_updateMode',1).'</td>' : '').'
02453                     '.($this->update ? '<td>'.$LANG->getLL('impexpcore_displaycon_currentPath',1).'</td>' : '').'
02454                     '.($this->showDiff ? '<td>'.$LANG->getLL('impexpcore_displaycon_result',1).'</td>' : '').'
02455                 </tr>';
02456 
02457                 foreach($lines as $r)   {
02458                     $rows[] = '
02459                     <tr class="'.$r['class'].'">
02460                         <td>'.$this->renderControls($r).'</td>
02461                         <td nowrap="nowrap">'.$r['preCode'].$r['title'].'</td>
02462                         <td nowrap="nowrap">'.t3lib_div::formatSize($r['size']).'</td>
02463                         <td nowrap="nowrap">'.($r['msg'] && !$this->doesImport ? '<span class="typo3-red">'.htmlspecialchars($r['msg']).'</span>' : '').'</td>
02464                         '.($this->update ? '<td nowrap="nowrap">'.$r['updateMode'].'</td>' : '').'
02465                         '.($this->update ? '<td nowrap="nowrap">'.$r['updatePath'].'</td>' : '').'
02466                         '.($this->showDiff ? '<td>'.$r['showDiffContent'].'</td>' : '').'
02467                     </tr>';
02468                 }
02469 
02470                 $out = '
02471                     <strong>'.$LANG->getLL('impexpcore_displaycon_insidePagetree',1).'</strong>
02472                     <br /><br />
02473                     <table border="0" cellpadding="0" cellspacing="1">'.implode('',$rows).'</table>
02474                     <br /><br />';
02475             }
02476 
02477                 // Print remaining records that were not contained inside the page tree:
02478             $lines = array();
02479             if (is_array($this->remainHeader['records']))   {
02480                 if (is_array($this->remainHeader['records']['pages']))  {
02481                     $this->traversePageRecords($this->remainHeader['records']['pages'], $lines);
02482                 }
02483                 $this->traverseAllRecords($this->remainHeader['records'], $lines);
02484 
02485                 if (count($lines))  {
02486                     $rows = array();
02487                     $rows[] = '
02488                     <tr class="bgColor5 tableheader">
02489                         <td>'.$LANG->getLL('impexpcore_displaycon_controls',1).'</td>
02490                         <td>'.$LANG->getLL('impexpcore_displaycon_title',1).'</td>
02491                         <td>'.$LANG->getLL('impexpcore_displaycon_size',1).'</td>
02492                         <td>'.$LANG->getLL('impexpcore_displaycon_message',1).'</td>
02493                         '.($this->update ? '<td>'.$LANG->getLL('impexpcore_displaycon_updateMode',1).'</td>' : '').'
02494                         '.($this->update ? '<td>'.$LANG->getLL('impexpcore_displaycon_currentPath',1).'</td>' : '').'
02495                         '.($this->showDiff ? '<td>'.$LANG->getLL('impexpcore_displaycon_result',1).'</td>' : '').'
02496                     </tr>';
02497 
02498                     foreach($lines as $r)   {
02499                         $rows[] = '<tr class="'.$r['class'].'">
02500                             <td>'.$this->renderControls($r).'</td>
02501                             <td nowrap="nowrap">'.$r['preCode'].$r['title'].'</td>
02502                             <td nowrap="nowrap">'.t3lib_div::formatSize($r['size']).'</td>
02503                             <td nowrap="nowrap">'.($r['msg'] && !$this->doesImport ? '<span class="typo3-red">'.htmlspecialchars($r['msg']).'</span>' : '').'</td>
02504                             '.($this->update ? '<td nowrap="nowrap">'.$r['updateMode'].'</td>' : '').'
02505                             '.($this->update ? '<td nowrap="nowrap">'.$r['updatePath'].'</td>' : '').'
02506                             '.($this->showDiff ? '<td>'.$r['showDiffContent'].'</td>' : '').'
02507                         </tr>';
02508                     }
02509 
02510                     $out.= '
02511                         <strong>'.$LANG->getLL('impexpcore_singlereco_outsidePagetree',1).'</strong>
02512                         <br /><br />
02513                         <table border="0" cellpadding="0" cellspacing="1">'.implode('',$rows).'</table>';
02514                 }
02515             }
02516         }
02517         return $out;
02518     }
02519 
02520     /**
02521      * Go through page tree for display
02522      *
02523      * @param   array       Page tree array with uid/subrow (from ->dat[header][pagetree]
02524      * @param   array       Output lines array (is passed by reference and modified)
02525      * @param   string      Pre-HTML code
02526      * @return  void
02527      */
02528     function traversePageTree($pT,&$lines,$preCode='')  {
02529         foreach ($pT as $k => $v) {
02530 
02531                 // Add this page:
02532             $this->singleRecordLines('pages',$k,$lines,$preCode);
02533 
02534                 // Subrecords:
02535             if (is_array($this->dat['header']['pid_lookup'][$k]))   {
02536                 foreach ($this->dat['header']['pid_lookup'][$k] as $t => $recUidArr) {
02537                     if ($t!='pages')    {
02538                         foreach ($recUidArr as $ruid => $value) {
02539                             $this->singleRecordLines($t,$ruid,$lines,$preCode.'&nbsp;&nbsp;&nbsp;&nbsp;');
02540                         }
02541                     }
02542                 }
02543                 unset($this->remainHeader['pid_lookup'][$k]);
02544             }
02545 
02546                 // Subpages, called recursively:
02547             if (is_array($v['subrow']))     {
02548                 $this->traversePageTree($v['subrow'],$lines,$preCode.'&nbsp;&nbsp;&nbsp;&nbsp;');
02549             }
02550         }
02551     }
02552 
02553     /**
02554      * Go through remaining pages (not in tree)
02555      *
02556      * @param   array       Page tree array with uid/subrow (from ->dat[header][pagetree]
02557      * @param   array       Output lines array (is passed by reference and modified)
02558      * @return  void
02559      */
02560     function traversePageRecords($pT,&$lines)   {
02561         foreach ($pT as $k => $rHeader) {
02562             $this->singleRecordLines('pages',$k,$lines,'',1);
02563                 // Subrecords:
02564             if (is_array($this->dat['header']['pid_lookup'][$k]))   {
02565                 foreach ($this->dat['header']['pid_lookup'][$k] as $t => $recUidArr) {
02566                     if ($t!='pages')    {
02567                         foreach ($recUidArr as $ruid => $value) {
02568                             $this->singleRecordLines($t,$ruid,$lines,'&nbsp;&nbsp;&nbsp;&nbsp;');
02569                         }
02570                     }
02571                 }
02572                 unset($this->remainHeader['pid_lookup'][$k]);
02573             }
02574         }
02575     }
02576 
02577     /**
02578      * Go through ALL records (if the pages are displayed first, those will not be amoung these!)
02579      *
02580      * @param   array       Page tree array with uid/subrow (from ->dat[header][pagetree]
02581      * @param   array       Output lines array (is passed by reference and modified)
02582      * @return  void
02583      */
02584     function traverseAllRecords($pT,&$lines)    {
02585         foreach ($pT as $t => $recUidArr) {
02586             if ($t!='pages')    {
02587                 foreach ($recUidArr as $ruid => $value) {
02588                     $this->singleRecordLines($t,$ruid,$lines,$preCode,1);
02589                 }
02590             }
02591         }
02592     }
02593 
02594     /**
02595      * Add entries for a single record
02596      *
02597      * @param   string      Table name
02598      * @param   integer     Record uid
02599      * @param   array       Output lines array (is passed by reference and modified)
02600      * @param   string      Pre-HTML code
02601      * @param   boolean     If you want import validation, you can set this so it checks if the import can take place on the specified page.
02602      * @return  void
02603      */
02604     function singleRecordLines($table,$uid,&$lines,$preCode,$checkImportInPidRecord=0)  {
02605         global $TCA,$BE_USER,$LANG;
02606 
02607             // Get record:
02608         $record = $this->dat['header']['records'][$table][$uid];
02609         unset($this->remainHeader['records'][$table][$uid]);
02610         if (!is_array($record) && !($table==='pages' && !$uid)) $this->error('MISSING RECORD: '.$table.':'.$uid,1);
02611 
02612             // Begin to create the line arrays information record, pInfo:
02613         $pInfo = array();
02614         $pInfo['ref'] = $table.':'.$uid;
02615         if ($table==='_SOFTREF_')   {   // Unknown table name:
02616             $pInfo['preCode'] = $preCode;
02617             $pInfo['title'] = '<em>'.$LANG->getLL('impexpcore_singlereco_softReferencesFiles',1).'</em>';
02618         } elseif (!isset($TCA[$table])) {   // Unknown table name:
02619             $pInfo['preCode'] = $preCode;
02620             $pInfo['msg'] = "UNKNOWN TABLE '".$pInfo['ref']."'";
02621             $pInfo['title'] = '<em>'.htmlspecialchars($record['title']).'</em>';
02622         } else {    // Otherwise, set table icon and title.
02623 
02624                 // Import Validation (triggered by $this->display_import_pid_record) will show messages if import is not possible of various items.
02625             if (is_array($this->display_import_pid_record)) {
02626                 if ($checkImportInPidRecord)    {
02627                     if (!$BE_USER->doesUserHaveAccess($this->display_import_pid_record, $table=='pages'?8:16))  {
02628                         $pInfo['msg'].="'".$pInfo['ref']."' cannot be INSERTED on this page! ";
02629                     }
02630                     if (!$this->checkDokType($table, $this->display_import_pid_record['doktype']) && !$TCA[$table]['ctrl']['rootLevel'])    {
02631                         $pInfo['msg'].="'".$table."' cannot be INSERTED on this page type (change page type to 'Folder'.) ";
02632                     }
02633                 }
02634                 if (!$BE_USER->check('tables_modify',$table))   {$pInfo['msg'].="You are not allowed to CREATE '".$table."' tables! ";}
02635 
02636                 if ($TCA[$table]['ctrl']['readOnly'])   {$pInfo['msg'].="TABLE '".$table."' is READ ONLY! ";}
02637                 if ($TCA[$table]['ctrl']['adminOnly'] && !$BE_USER->isAdmin())  {$pInfo['msg'].="TABLE '".$table."' is ADMIN ONLY! ";}
02638                 if ($TCA[$table]['ctrl']['is_static'])  {$pInfo['msg'].="TABLE '".$table."' is a STATIC TABLE! ";}
02639                 if ($TCA[$table]['ctrl']['rootLevel'])  {$pInfo['msg'].="TABLE '".$table."' will be inserted on ROOT LEVEL! ";}
02640 
02641                 $diffInverse = FALSE;
02642                 if ($this->update)  {
02643                     $diffInverse = TRUE;    // In case of update-PREVIEW we swap the diff-sources.
02644                     $recInf = $this->doesRecordExist($table, $uid, $this->showDiff ? '*' : '');
02645                     $pInfo['updatePath']= $recInf ? htmlspecialchars($this->getRecordPath($recInf['pid'])) : '<strong>NEW!</strong>';
02646 
02647                         // Mode selector:
02648                     $optValues = array();
02649                     $optValues[] = $recInf ? $LANG->getLL('impexpcore_singlereco_update') : $LANG->getLL('impexpcore_singlereco_insert');
02650                     if ($recInf) $optValues['as_new'] = $LANG->getLL('impexpcore_singlereco_importAsNew');
02651                     if ($recInf) {
02652                         if (!$this->global_ignore_pid)  {
02653                             $optValues['ignore_pid'] = $LANG->getLL('impexpcore_singlereco_ignorePid');
02654                         } else {
02655                             $optValues['respect_pid'] = $LANG->getLL('impexpcore_singlereco_respectPid');
02656                         }
02657                     }
02658                     if (!$recInf && $GLOBALS['BE_USER']->isAdmin()) $optValues['force_uid'] = sprintf($LANG->getLL('impexpcore_singlereco_forceUidSAdmin'),$uid);
02659                     $optValues['exclude'] = $LANG->getLL('impexpcore_singlereco_exclude');
02660 
02661                     $pInfo['updateMode'] = $this->renderSelectBox('tx_impexp[import_mode]['.$table.':'.$uid.']',$this->import_mode[$table.':'.$uid],$optValues);
02662                 }
02663 
02664                     // Diff vieiw:
02665                 if ($this->showDiff)    {
02666                         // For IMPORTS, get new id:
02667                     if ($newUid = $this->import_mapId[$table][$uid])    {
02668                         $diffInverse = FALSE;
02669                         $recInf = $this->doesRecordExist($table, $newUid, '*');
02670                         t3lib_BEfunc::workspaceOL($table,$recInf);
02671                     }
02672                     if (is_array($recInf))  {
02673                         $pInfo['showDiffContent'] = $this->compareRecords($recInf, $this->dat['records'][$table.':'.$uid]['data'], $table, $diffInverse);
02674                     }
02675                 }
02676             }
02677 
02678             $pInfo['preCode'] = $preCode.t3lib_iconworks::getSpriteIconForRecord($table, (array)$this->dat['records'][$table . ':' . $uid]['data'], array('title' => htmlspecialchars($table . ':' . $uid)));
02679             $pInfo['title'] = htmlspecialchars($record['title']);
02680 
02681                 // View page:
02682             if ($table==='pages')   {
02683                 $viewID = $this->mode === 'export' ? $uid : ($this->doesImport ? $this->import_mapId['pages'][$uid] : 0);
02684                 if ($viewID)    {
02685                     $pInfo['title'] = '<a href="#" onclick="'.htmlspecialchars(t3lib_BEfunc::viewOnClick($viewID, $GLOBALS['BACK_PATH'])).'return false;">'.$pInfo['title'].'</a>';
02686                 }
02687             }
02688         }
02689         $pInfo['class'] = $table=='pages' ? 'bgColor4-20' : 'bgColor4';
02690         $pInfo['type'] = 'record';
02691         $pInfo['size'] = $record['size'];
02692         $lines[] = $pInfo;
02693 
02694             // File relations:
02695         if (is_array($record['filerefs']))  {
02696             $this->addFiles($record['filerefs'],$lines,$preCode);
02697         }
02698 
02699             // DB relations
02700         if (is_array($record['rels']))  {
02701             $this->addRelations($record['rels'],$lines,$preCode);
02702         }
02703 
02704             // Soft ref
02705         if (count($record['softrefs']))     {
02706             $preCode_A = $preCode.'&nbsp;&nbsp;&nbsp;&nbsp;';
02707             $preCode_B = $preCode.'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
02708             foreach($record['softrefs'] as $info)   {
02709                 $pInfo = array();
02710                 $pInfo['preCode'] = $preCode_A. t3lib_iconWorks::getSpriteIcon('status-status-reference-soft');
02711                 $pInfo['title'] = '<em>'.$info['field'].', "'.$info['spKey'].'" </em>: <span title="'.htmlspecialchars($info['matchString']).'">'.htmlspecialchars(t3lib_div::fixed_lgd_cs($info['matchString'],60)).'</span>';
02712                 if ($info['subst']['type']) {
02713                     if (strlen($info['subst']['title']))    {
02714                         $pInfo['title'].= '<br/>'.$preCode_B.'<strong>'.$LANG->getLL('impexpcore_singlereco_title',1).'</strong> '.htmlspecialchars(t3lib_div::fixed_lgd_cs($info['subst']['title'],60));
02715                     }
02716                     if (strlen($info['subst']['description']))  {
02717                         $pInfo['title'].= '<br/>'.$preCode_B.'<strong>'.$LANG->getLL('impexpcore_singlereco_descr',1).'</strong> '.htmlspecialchars(t3lib_div::fixed_lgd_cs($info['subst']['description'],60));
02718                     }
02719                     $pInfo['title'].= '<br/>'.$preCode_B.
02720                                             ($info['subst']['type'] == 'file' ? $LANG->getLL('impexpcore_singlereco_filename',1).' <strong>'.$info['subst']['relFileName'].'</strong>' : '').
02721                                             ($info['subst']['type'] == 'string' ? $LANG->getLL('impexpcore_singlereco_value',1).' <strong>'.$info['subst']['tokenValue'].'</strong>' : '').
02722                                             ($info['subst']['type'] == 'db' ? $LANG->getLL('impexpcore_softrefsel_record',1).' <strong>'.$info['subst']['recordRef'].'</strong>' : '');
02723                 }
02724                 $pInfo['ref'] = 'SOFTREF';
02725                 $pInfo['size'] = '';
02726                 $pInfo['class'] = 'bgColor3';
02727                 $pInfo['type'] = 'softref';
02728                 $pInfo['_softRefInfo'] = $info;
02729                 $pInfo['type'] = 'softref';
02730                 if ($info['error'] && !t3lib_div::inList('editable,exclude',$this->softrefCfg[$info['subst']['tokenID']]['mode']))  {
02731                     $pInfo['msg'].= $info['error'];
02732                 }
02733                 $lines[] = $pInfo;
02734 
02735                     // Add relations:
02736                 if ($info['subst']['type'] == 'db') {
02737                     list($tempTable, $tempUid) = explode(':', $info['subst']['recordRef']);
02738                     $this->addRelations(array(array('table' => $tempTable, 'id' => $tempUid, 'tokenID' => $info['subst']['tokenID'])),$lines,$preCode_B,array(), '');
02739                 }
02740 
02741                     // Add files:
02742                 if ($info['subst']['type'] == 'file')   {
02743 #debug($info);
02744                     $this->addFiles(array($info['file_ID']),$lines,$preCode_B, '', $info['subst']['tokenID']);
02745                 }
02746             }
02747         }
02748     }
02749 
02750     /**
02751      * Add DB relations entries for a record's rels-array
02752      *
02753      * @param   array       Array of relations
02754      * @param   array       Output lines array (is passed by reference and modified)
02755      * @param   string      Pre-HTML code
02756      * @param   array       Recursivity check stack
02757      * @param   string      Alternative HTML color class to use.
02758      * @return  void
02759      * @access private
02760      * @see singleRecordLines()
02761      */
02762     function addRelations($rels,&$lines,$preCode,$recurCheck=array(),$htmlColorClass='')    {
02763 
02764         foreach($rels as $dat)  {
02765             $table = $dat['table'];
02766             $uid = $dat['id'];
02767             $pInfo = array();
02768             $Iprepend = '';
02769             $staticFixed = FALSE;
02770             $pInfo['ref'] = $table.':'.$uid;
02771             if (!in_array($pInfo['ref'],$recurCheck))   {
02772                 if ($uid > 0)   {
02773                     $record = $this->dat['header']['records'][$table][$uid];
02774                     if (!is_array($record)) {
02775                         if ($this->isTableStatic($table) || $this->isExcluded($table, $uid) || ($dat['tokenID'] && !$this->includeSoftref($dat['tokenID'])))    {
02776                             $pInfo['title'] = htmlspecialchars('STATIC: '.$pInfo['ref']);
02777                             $Iprepend = '_static';
02778                             $staticFixed = TRUE;
02779                         } else {
02780                             $doesRE = $this->doesRecordExist($table,$uid);
02781                             $lostPath = $this->getRecordPath($table==='pages' ? $doesRE['uid'] : $doesRE['pid']);
02782 
02783                             $pInfo['title'] = htmlspecialchars($pInfo['ref']);
02784                             $pInfo['title'] = '<span title="'.htmlspecialchars($lostPath).'">'.$pInfo['title'].'</span>';
02785 
02786                             $pInfo['msg'] = 'LOST RELATION'.(!$doesRE ? ' (Record not found!)' : ' (Path: '.$lostPath.')');
02787                             $Iprepend = '_lost';
02788     #                       debug('MISSING relation: '.$table.':'.$uid);
02789                         }
02790                     } else {
02791                         $pInfo['title'] = htmlspecialchars($record['title']);
02792                         $pInfo['title'] = '<span title="'.htmlspecialchars($this->getRecordPath($table==='pages' ? $record['uid'] : $record['pid'])).'">'.$pInfo['title'].'</span>';
02793 
02794                     #   $pInfo['size'] = $record['size'];
02795                     }
02796                 } else {    // Negative values in relation fields. This is typically sys_language fields, fe_users fields etc. They are static values. They CAN theoretically be negative pointers to uids in other tables but this is so rarely used that it is not supported
02797                     $pInfo['title'] = htmlspecialchars('FIXED: '.$pInfo['ref']);
02798                     $staticFixed = TRUE;
02799                 }
02800 
02801                 $pInfo['preCode'] = $preCode.'&nbsp;&nbsp;&nbsp;&nbsp;<img'.t3lib_iconWorks::skinImg($GLOBALS['BACK_PATH'],'gfx/rel_db'.$Iprepend.'.gif','width="13" height="12"').' align="top" title="'.htmlspecialchars($pInfo['ref']).'" alt="" />';
02802                 $pInfo['class'] = $htmlColorClass ? $htmlColorClass : 'bgColor3';
02803                 $pInfo['type'] = 'rel';
02804 
02805                 if (!$staticFixed || $this->showStaticRelations)    {
02806                     $lines[] = $pInfo;
02807                     if (is_array($record) && is_array($record['rels'])) {
02808                         $this->addRelations($record['rels'], $lines, $preCode.'&nbsp;&nbsp;', array_merge($recurCheck,array($pInfo['ref'])), $htmlColorClass);
02809                     }
02810                 }
02811             } else $this->error($pInfo['ref'].' was recursive...');
02812         }
02813     }
02814 
02815     /**
02816      * Add file relation entries for a record's rels-array
02817      *
02818      * @param   array       Array of file IDs
02819      * @param   array       Output lines array (is passed by reference and modified)
02820      * @param   string      Pre-HTML code
02821      * @param   string      Alternative HTML color class to use.
02822      * @param   string      Token ID if this is a softreference (in which case it only makes sense with a single element in the $rels array!)
02823      * @return  void
02824      * @access private
02825      * @see singleRecordLines()
02826      */
02827     function addFiles($rels,&$lines,$preCode,$htmlColorClass='',$tokenID='')    {
02828 
02829         foreach($rels as $ID)   {
02830 
02831                 // Process file:
02832             $pInfo = array();
02833             $fI = $this->dat['header']['files'][$ID];
02834             if (!is_array($fI)) {
02835                 if (!$tokenID || $this->includeSoftref($tokenID))   {
02836                     $pInfo['msg'] = 'MISSING FILE: '.$ID;
02837                     $this->error('MISSING FILE: '.$ID,1);
02838                 } else {
02839                     return;
02840                 }
02841             }
02842             $pInfo['preCode'] = $preCode.'&nbsp;&nbsp;&nbsp;&nbsp;'.t3lib_iconWorks::getSpriteIcon('status-status-reference-hard');
02843             $pInfo['title'] = htmlspecialchars($fI['filename']);
02844             $pInfo['ref'] = 'FILE';
02845             $pInfo['size'] = $fI['filesize'];
02846             $pInfo['class'] = $htmlColorClass ? $htmlColorClass : 'bgColor3';
02847             $pInfo['type'] = 'file';
02848 
02849                 // If import mode and there is a non-RTE softreference, check the destination directory:
02850             if ($this->mode==='import' && $tokenID && !$fI['RTE_ORIG_ID'])  {
02851                 if (isset($fI['parentRelFileName']))    {
02852                     $pInfo['msg'] = 'Seems like this file is already referenced from within an HTML/CSS file. That takes precedence. ';
02853                 } else {
02854                     $testDirPrefix = dirname($fI['relFileName']).'/';
02855                     $testDirPrefix2 = $this->verifyFolderAccess($testDirPrefix);
02856 
02857                     if (!$testDirPrefix2)   {
02858                         $pInfo['msg'] = 'ERROR: There are no available filemounts to write file in! ';
02859                     } elseif (strcmp($testDirPrefix,$testDirPrefix2))   {
02860                         $pInfo['msg'] = 'File will be attempted written to "'.$testDirPrefix2.'". ';
02861                     }
02862                 }
02863 
02864 
02865                     // Check if file exists:
02866                 if (file_exists(PATH_site.$fI['relFileName']))  {
02867                     if ($this->update)  {
02868                         $pInfo['updatePath'].= 'File exists.';
02869                     } else {
02870                         $pInfo['msg'].= 'File already exists! ';
02871                     }
02872                 }
02873 
02874                     // Check extension:
02875                 $fileProcObj = $this->getFileProcObj();
02876                 if ($fileProcObj->actionPerms['newFile'])   {
02877                     $testFI = t3lib_div::split_fileref(PATH_site.$fI['relFileName']);
02878                     if (!$this->allowPHPScripts && !$fileProcObj->checkIfAllowed($testFI['fileext'], $testFI['path'], $testFI['file'])) {
02879                         $pInfo['msg'].= 'File extension was not allowed!';
02880                     }
02881                 } else $pInfo['msg'] = 'You user profile does not allow you to create files on the server!';
02882             }
02883 
02884             $pInfo['showDiffContent'] = substr($this->fileIDMap[$ID],strlen(PATH_site));
02885 
02886             $lines[] = $pInfo;
02887             unset($this->remainHeader['files'][$ID]);
02888 
02889                 // RTE originals:
02890             if ($fI['RTE_ORIG_ID']) {
02891                 $ID = $fI['RTE_ORIG_ID'];
02892                 $pInfo = array();
02893                 $fI = $this->dat['header']['files'][$ID];
02894                 if (!is_array($fI)) {
02895                     $pInfo['msg'] = 'MISSING RTE original FILE: '.$ID;
02896                     $this->error('MISSING RTE original FILE: '.$ID,1);
02897                 }
02898 
02899                 $pInfo['showDiffContent'] = substr($this->fileIDMap[$ID],strlen(PATH_site));
02900 
02901                 $pInfo['preCode'] = $preCode.'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'.t3lib_iconWorks::getSpriteIcon('actions-reference-file');
02902                 $pInfo['title'] = htmlspecialchars($fI['filename']).' <em>(Original)</em>';
02903                 $pInfo['ref'] = 'FILE';
02904                 $pInfo['size'] = $fI['filesize'];
02905                 $pInfo['class'] = $htmlColorClass ? $htmlColorClass : 'bgColor3';
02906                 $pInfo['type'] = 'file';
02907                 $lines[] = $pInfo;
02908                 unset($this->remainHeader['files'][$ID]);
02909             }
02910 
02911                 // External resources:
02912             if (is_array($fI['EXT_RES_ID']))    {
02913                 foreach($fI['EXT_RES_ID'] as $ID)   {
02914                     $pInfo = array();
02915                     $fI = $this->dat['header']['files'][$ID];
02916                     if (!is_array($fI)) {
02917                         $pInfo['msg'] = 'MISSING External Resource FILE: '.$ID;
02918                         $this->error('MISSING External Resource FILE: '.$ID,1);
02919                     } else {
02920                         $pInfo['updatePath'] = $fI['parentRelFileName'];
02921                     }
02922 
02923                     $pInfo['showDiffContent'] = substr($this->fileIDMap[$ID],strlen(PATH_site));
02924 
02925                     $pInfo['preCode'] = $preCode.'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'.t3lib_iconWorks::getSpriteIcon('actions-insert-reference');
02926                     $pInfo['title'] = htmlspecialchars($fI['filename']).' <em>(Resource)</em>';
02927                     $pInfo['ref'] = 'FILE';
02928                     $pInfo['size'] = $fI['filesize'];
02929                     $pInfo['class'] = $htmlColorClass ? $htmlColorClass : 'bgColor3';
02930                     $pInfo['type'] = 'file';
02931                     $lines[] = $pInfo;
02932                     unset($this->remainHeader['files'][$ID]);
02933                 }
02934             }
02935         }
02936     }
02937 
02938     /**
02939      * Verifies that a table is allowed on a certain doktype of a page
02940      *
02941      * @param   string      Table name to check
02942      * @param   integer     doktype value.
02943      * @return  boolean     True if OK
02944      */
02945     function checkDokType($checkTable,$doktype) {
02946         global $PAGES_TYPES;
02947         $allowedTableList = isset($PAGES_TYPES[$doktype]['allowedTables']) ? $PAGES_TYPES[$doktype]['allowedTables'] : $PAGES_TYPES['default']['allowedTables'];
02948         $allowedArray = t3lib_div::trimExplode(',',$allowedTableList,1);
02949         if (strstr($allowedTableList,'*') || in_array($checkTable,$allowedArray))   {       // If all tables or the table is listed as a allowed type, return true
02950             return true;
02951         }
02952     }
02953 
02954     /**
02955      * Render input controls for import or export
02956      *
02957      * @param   array       Configuration for element
02958      * @param   boolean     Set if export situation
02959      * @return  string      HTML
02960      */
02961     function renderControls($r) {
02962         global $LANG;
02963 
02964         if ($this->mode==='export') {
02965             return ($r['type']=='record' ? '<input type="checkbox" name="tx_impexp[exclude]['.$r['ref'].']" id="checkExclude'.$r['ref'].'" value="1" /> <label for="checkExclude'.$r['ref'].'">'.$LANG->getLL('impexpcore_singlereco_exclude',1).'</label>' :
02966                                 ($r['type']=='softref' ? $this->softrefSelector($r['_softRefInfo']) : ''));
02967         } else {    // During import
02968 
02969                 // For softreferences with editable fields:
02970             if ($r['type']=='softref' && is_array($r['_softRefInfo']['subst']) && $r['_softRefInfo']['subst']['tokenID'])   {
02971                 $tokenID = $r['_softRefInfo']['subst']['tokenID'];
02972                 $cfg = $this->softrefCfg[$tokenID];
02973                 if ($cfg['mode'] === 'editable')    {
02974                     return
02975                         (strlen($cfg['title']) ? '<strong>'.htmlspecialchars($cfg['title']).'</strong><br/>' : '').
02976                         htmlspecialchars($cfg['description']).'<br/>
02977                         <input type="text" name="tx_impexp[softrefInputValues]['.$tokenID.']" value="'.htmlspecialchars(isset($this->softrefInputValues[$tokenID]) ? $this->softrefInputValues[$tokenID] : $cfg['defValue']).'" />';
02978                 }
02979             }
02980         }
02981     }
02982 
02983     /**
02984      * Selectorbox with export options for soft references
02985      *
02986      * @param   array       softref configuration array. An export box is shown only if a substitution scheme is found for the soft reference.
02987      * @return  string      Selector box HTML
02988      */
02989     function softrefSelector($cfg) {
02990         global $LANG;
02991 
02992             // Looking for file ID if any:
02993         $fI = $cfg['file_ID'] ? $this->dat['header']['files'][$cfg['file_ID']] : array();
02994 
02995             // Substitution scheme has to be around and RTE images MUST be exported.
02996         if (is_array($cfg['subst']) && $cfg['subst']['tokenID'] && !$fI['RTE_ORIG_ID']) {
02997 
02998                 // Create options:
02999             $optValues = array();
03000             $optValues[''] = '';
03001             $optValues['editable'] = $LANG->getLL('impexpcore_softrefsel_editable');
03002             $optValues['exclude'] = $LANG->getLL('impexpcore_softrefsel_exclude');
03003 
03004                 // Get current value:
03005             $value = $this->softrefCfg[$cfg['subst']['tokenID']]['mode'];
03006 
03007                 // Render options selector:
03008             $selectorbox = $this->renderSelectBox('tx_impexp[softrefCfg]['.$cfg['subst']['tokenID'].'][mode]',$value,$optValues).'<br/>';
03009 
03010             if ($value === 'editable')  {
03011 
03012                 $descriptionField = '';
03013 
03014                     // Title:
03015                 if (strlen($cfg['subst']['title'])) {
03016                     $descriptionField.= '
03017                     <input type="hidden" name="tx_impexp[softrefCfg]['.$cfg['subst']['tokenID'].'][title]" value="'.htmlspecialchars($cfg['subst']['title']).'" />
03018                     <strong>'.htmlspecialchars($cfg['subst']['title']).'</strong><br/>';
03019                 }
03020 
03021                     // Description:
03022                 if (!strlen($cfg['subst']['description']))  {
03023                     $descriptionField.= '
03024                     '.$LANG->getLL('impexpcore_printerror_description',1).'<br/>
03025                     <input type="text" name="tx_impexp[softrefCfg]['.$cfg['subst']['tokenID'].'][description]" value="'.htmlspecialchars($this->softrefCfg[$cfg['subst']['tokenID']]['description']).'" />';
03026                 } else {
03027                     $descriptionField.= '
03028 
03029                     <input type="hidden" name="tx_impexp[softrefCfg]['.$cfg['subst']['tokenID'].'][description]" value="'.htmlspecialchars($cfg['subst']['description']).'" />'.
03030                     htmlspecialchars($cfg['subst']['description']);
03031                 }
03032 
03033                     // Default Value:
03034                 $descriptionField.= '<input type="hidden" name="tx_impexp[softrefCfg]['.$cfg['subst']['tokenID'].'][defValue]" value="'.htmlspecialchars($cfg['subst']['tokenValue']).'" />';
03035 
03036             } else $descriptionField = '';
03037 
03038             return $selectorbox.$descriptionField;
03039         }
03040     }
03041 
03042 
03043 
03044 
03045 
03046 
03047 
03048 
03049 
03050 
03051 
03052 
03053     /*****************************
03054      *
03055      * Helper functions of kinds
03056      *
03057      *****************************/
03058 
03059     /**
03060      * Returns true if the input table name is to be regarded as a static relation (that is, not exported etc).
03061      *
03062      * @param   string      Table name
03063      * @return  boolean     True, if table is marked static
03064      */
03065     function isTableStatic($table)  {
03066         global $TCA;
03067 
03068         if (is_array($TCA[$table])) {
03069             return $TCA[$table]['ctrl']['is_static'] || in_array($table, $this->relStaticTables) || in_array('_ALL', $this->relStaticTables);
03070         }
03071     }
03072 
03073     /**
03074      * Returns true if the input table name is to be included as relation
03075      *
03076      * @param   string      Table name
03077      * @return  boolean     True, if table is marked static
03078      */
03079     function inclRelation($table)   {
03080         global $TCA;
03081 
03082         if (is_array($TCA[$table])) {
03083             return (in_array($table, $this->relOnlyTables) || in_array('_ALL', $this->relOnlyTables)) && $GLOBALS['BE_USER']->check('tables_select',$table);
03084         }
03085     }
03086 
03087     /**
03088      * Returns true if the element should be excluded as static record.
03089      *
03090      * @param   string      Table name
03091      * @param   integer     UID value
03092      * @return  boolean     True, if table is marked static
03093      */
03094     function isExcluded($table,$uid)    {
03095         global $TCA;
03096 
03097         return $this->excludeMap[$table.':'.$uid] ? TRUE : FALSE;
03098     }
03099 
03100     /**
03101      * Returns true if soft reference should be included in exported file.
03102      *
03103      * @param   string      Token ID for soft reference
03104      * @return  boolean     True if softreference media should be included
03105      */
03106     function includeSoftref($tokenID)   {
03107         return $tokenID && !t3lib_div::inList('exclude,editable', $this->softrefCfg[$tokenID]['mode']);
03108     }
03109 
03110     /**
03111      * Checking if a PID is in the webmounts of the user
03112      *
03113      * @param   integer     Page ID to check
03114      * @return  boolean     True if OK
03115      */
03116     function checkPID($pid) {
03117         global $BE_USER;
03118 
03119         if (!isset($this->checkPID_cache[$pid]))    {
03120             $this->checkPID_cache[$pid] = (boolean)$BE_USER->isInWebMount($pid);
03121         }
03122 
03123         return $this->checkPID_cache[$pid];
03124     }
03125 
03126     /**
03127      * Checks if the position of an updated record is configured to be corrected. This can be disabled globally and changed for elements individually.
03128      *
03129      * @param   string      Table name
03130      * @param   integer     Uid or record
03131      * @return  boolean     True if the position of the record should be updated to match the one in the import structure
03132      */
03133     function dontIgnorePid($table, $uid)    {
03134         return $this->import_mode[$table.':'.$uid]!=='ignore_pid' &&
03135                 (!$this->global_ignore_pid || $this->import_mode[$table.':'.$uid]==='respect_pid');
03136     }
03137 
03138     /**
03139      * Checks if the record exists
03140      *
03141      * @param   string      Table name
03142      * @param   integer     UID of record
03143      * @param   string      Field list to select. Default is "uid,pid"
03144      * @return  array       Result of t3lib_BEfunc::getRecord() which means the record if found, otherwise false
03145      */
03146     function doesRecordExist($table,$uid,$fields='')    {
03147         return t3lib_BEfunc::getRecord($table, $uid, $fields ? $fields : 'uid,pid');
03148     }
03149 
03150     /**
03151      * Returns the page title path of a PID value. Results are cached internally
03152      *
03153      * @param   integer     Record PID to check
03154      * @return  string      The path for the input PID
03155      */
03156     function getRecordPath($pid)    {
03157         if (!isset($this->cache_getRecordPath[$pid]))   {
03158             $clause = $GLOBALS['BE_USER']->getPagePermsClause(1);
03159             $this->cache_getRecordPath[$pid] = (string)t3lib_BEfunc::getRecordPath($pid, $clause, 20);
03160         }
03161 
03162         return $this->cache_getRecordPath[$pid];
03163     }
03164 
03165     /**
03166      * Makes a selector-box from optValues
03167      *
03168      * @param   string      Form element name
03169      * @param   string      Current value
03170      * @param   array       Options to display (key/value pairs)
03171      * @return  string      HTML select element
03172      */
03173     function renderSelectBox($prefix,$value,$optValues) {
03174         $opt = array();
03175         $isSelFlag = 0;
03176         foreach ($optValues as $k => $v) {
03177             $sel = (!strcmp($k,$value) ? ' selected="selected"' : '');
03178             if ($sel)   $isSelFlag++;
03179             $opt[] = '<option value="'.htmlspecialchars($k).'"'.$sel.'>'.htmlspecialchars($v).'</option>';
03180         }
03181         if (!$isSelFlag && strcmp('',$value))   {
03182             $opt[] = '<option value="'.htmlspecialchars($value).'" selected="selected">'.htmlspecialchars("['".$value."']").'</option>';
03183         }
03184         return '<select name="'.$prefix.'">'.implode('',$opt).'</select>';
03185     }
03186 
03187     /**
03188      * Compares two records, the current database record and the one from the import memory. Will return HTML code to show any differences between them!
03189      *
03190      * @param   array       Database record, all fields (new values)
03191      * @param   array       Import memorys record for the same table/uid, all fields (old values)
03192      * @param   string      The table name of the record
03193      * @param   boolean     Inverse the diff view (switch red/green, needed for pre-update difference view)
03194      * @return  string      HTML
03195      */
03196     function compareRecords($databaseRecord, $importRecord, $table, $inverseDiff=FALSE) {
03197         global $TCA, $LANG;
03198 
03199             // Initialize:
03200         $output = array();
03201         $t3lib_diff_Obj = t3lib_div::makeInstance('t3lib_diff');
03202 
03203             // Check if both inputs are records:
03204         if (is_array($databaseRecord) && is_array($importRecord))   {
03205 
03206                 // Traverse based on database record
03207             foreach($databaseRecord as $fN => $value)   {
03208                 if (is_array($TCA[$table]['columns'][$fN]) && $TCA[$table]['columns'][$fN]['config']['type']!='passthrough')    {
03209                     if (isset($importRecord[$fN]))  {
03210                         if (strcmp(trim($databaseRecord[$fN]), trim($importRecord[$fN])))   {
03211 
03212                                 // Create diff-result:
03213                             $output[$fN] = $t3lib_diff_Obj->makeDiffDisplay(
03214                                 t3lib_BEfunc::getProcessedValue($table,$fN,!$inverseDiff ? $importRecord[$fN] : $databaseRecord[$fN] ,0,1,1),
03215                                 t3lib_BEfunc::getProcessedValue($table,$fN,!$inverseDiff ? $databaseRecord[$fN] : $importRecord[$fN] ,0,1,1)
03216                             );
03217                         }
03218                         unset($importRecord[$fN]);
03219                     } else {
03220                             // This will tell us if the field is not in the import file, but who cares? It is totally ok that the database contains fields that are not in the import, isn't it (extensions could be installed that added these fields!)?
03221                         #$output[$fN] = '<strong>Field missing</strong> in import file';
03222                     }
03223                 }
03224             }
03225 
03226                 // Traverse remaining in import record:
03227             foreach($importRecord as $fN => $value) {
03228                 if (is_array($TCA[$table]['columns'][$fN]) && $TCA[$table]['columns'][$fN]['config']['type']!='passthrough')    {
03229                     $output[$fN] = '<strong>Field missing</strong> in database';
03230                 }
03231             }
03232 
03233                 // Create output:
03234             if (count($output)) {
03235                 $tRows = array();
03236                 foreach($output as $fN => $state)   {
03237                     $tRows[] = '
03238                         <tr>
03239                             <td class="bgColor5">'.$LANG->sL($TCA[$table]['columns'][$fN]['label'],1).' ('.htmlspecialchars($fN).')</td>
03240                             <td class="bgColor4">'.$state.'</td>
03241                         </tr>
03242                     ';
03243                 }
03244 
03245                 $output = '<table border="0" cellpadding="0" cellspacing="1">'.implode('',$tRows).'</table>';
03246             } else {
03247                 $output = 'Match';
03248             }
03249 
03250             return '<strong class="nobr">['.htmlspecialchars($table.':'.$importRecord['uid'].' => '.$databaseRecord['uid']).']:</strong> '.$output;
03251         }
03252 
03253 
03254         return 'ERROR: One of the inputs were not an array!';
03255     }
03256 
03257     /**
03258      * Creates the original file name for a copy-RTE image (magic type)
03259      *
03260      * @param   string      RTE copy filename, eg. "RTEmagicC_user_pm_icon_01.gif.gif"
03261      * @return  string      RTE original filename, eg. "RTEmagicP_user_pm_icon_01.gif". IF the input filename was NOT prefixed RTEmagicC_ as RTE images would be, nothing is returned!
03262      */
03263     function getRTEoriginalFilename($string)    {
03264             // If "magic image":
03265         if (t3lib_div::isFirstPartOfStr($string,'RTEmagicC_'))  {
03266                 // Find original file:
03267             $pI = pathinfo(substr($string,strlen('RTEmagicC_')));
03268             $filename = substr($pI['basename'],0,-strlen('.'.$pI['extension']));
03269             $origFilePath = 'RTEmagicP_'.$filename;
03270 
03271             return $origFilePath;
03272         }
03273     }
03274 
03275     /**
03276      * Returns file processing object, initialized only once.
03277      *
03278      * @return  object      File processor object
03279      */
03280     function getFileProcObj() {
03281         if (!is_object($this->fileProcObj)) {
03282             $this->fileProcObj = t3lib_div::makeInstance('t3lib_extFileFunctions');
03283             $this->fileProcObj->init($GLOBALS['FILEMOUNTS'], $GLOBALS['TYPO3_CONF_VARS']['BE']['fileExtensions']);
03284             $this->fileProcObj->init_actionPerms($GLOBALS['BE_USER']->getFileoperationPermissions());
03285         }
03286         return $this->fileProcObj;
03287     }
03288 
03289     /**
03290      * Call Hook
03291      *
03292      * @param string $name name of the hook
03293      * @param array $params array with params
03294      * @return void
03295      */
03296     public function callHook($name, $params) {
03297         if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/impexp/class.tx_impexp.php'][$name])) {
03298             foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/impexp/class.tx_impexp.php'][$name] as $hook) {
03299                 t3lib_div::callUserFunction($hook, $params, $this);
03300             }
03301         }
03302     }
03303 
03304 
03305 
03306 
03307 
03308 
03309 
03310     /*****************************
03311      *
03312      * Error handling
03313      *
03314      *****************************/
03315 
03316     /**
03317      * Sets error message in the internal error log
03318      *
03319      * @param   string      Error message
03320      * @return  void
03321      */
03322     function error($msg)    {
03323         $this->errorLog[]=$msg;
03324     }
03325 
03326     /**
03327      * Returns a table with the error-messages.
03328      *
03329      * @return  string      HTML print of error log
03330      */
03331     function printErrorLog()    {
03332         return count($this->errorLog) ? t3lib_utility_Debug::viewArray($this->errorLog) : '';
03333     }
03334 }
03335 
03336 
03337 
03338 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/impexp/class.tx_impexp.php'])) {
03339     include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/impexp/class.tx_impexp.php']);
03340 }
03341 ?>