"TYPO3 4.0.1: typo3_src-4.0.1/typo3/sysext/impexp/class.tx_impexp.php Source File", "datetime" => "Sat Dec 2 19:22:32 2006", "date" => "2 Dec 2006", "doxygenversion" => "1.4.6", "projectname" => "TYPO3 4.0.1", "projectnumber" => "4.0.1" ); get_header($doxygen_vars); ?>
00001 <?php 00002 /*************************************************************** 00003 * Copyright notice 00004 * 00005 * (c) 1999-2005 Kasper Skaarhoj (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 ***************************************************************/ 00174 require_once(PATH_t3lib.'class.t3lib_tcemain.php'); 00175 require_once (PATH_t3lib.'class.t3lib_diff.php'); 00176 require_once (PATH_t3lib.'class.t3lib_parsehtml.php'); 00177 00178 require_once (PATH_t3lib.'class.t3lib_basicfilefunc.php'); 00179 require_once (PATH_t3lib.'class.t3lib_extfilefunc.php'); 00180 require_once (PATH_t3lib.'class.t3lib_refindex.php'); 00181 00182 @ini_set('max_execution_time',600); 00183 @ini_set('memory_limit','256m'); 00184 00185 00186 00187 00188 00189 00190 00198 class tx_impexp { 00199 00200 // Configuration, general 00201 var $showStaticRelations = FALSE; // If set, static relations (not exported) will be shown in overview as well 00202 var $fileadminFolderName = 'fileadmin'; // Name of the "fileadmin" folder where files for export/import should be located 00203 00204 var $mode = ''; // Whether "import" or "export" mode of object. Set through init() function 00205 var $update = FALSE; // Updates all records that has same UID instead of creating new! 00206 var $doesImport = FALSE; // Is set by importData() when an import has been done. 00207 00208 // Configuration, import 00209 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 00210 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. 00211 var $import_mode = array(); // Setting import modes during update state: as_new, exclude, force_uid 00212 var $global_ignore_pid = FALSE; // If set, PID correct is ignored globally 00213 var $force_all_UIDS = FALSE; // If set, all UID values are forced! (update or import) 00214 var $showDiff = FALSE; // If set, a diff-view column is added to the overview. 00215 var $allowPHPScripts = FALSE; // If set, and if the user is admin, allow the writing of PHP scripts to fileadmin/ area. 00216 var $enableLogging = FALSE; // Disable logging when importing 00217 var $softrefInputValues = array(); // Array of values to substitute in editable softreferences. 00218 var $fileIDMap = array(); // Mapping between the fileID from import memory and the final filenames they are written to. 00219 00220 // Configuration, export 00221 var $maxFileSize = 1000000; // 1MB max file size 00222 var $maxRecordSize = 1000000; // 1MB max record size 00223 var $maxExportSize = 10000000; // 10MB max export size 00224 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. 00225 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). 00226 var $excludeMap = array(); // Exclude map. Keys are table:uid pairs and if set, records are not added to the export. 00227 var $softrefCfg = array(); // Soft Reference Token ID modes. 00228 var $extensionDependencies = array(); // Listing extension dependencies. 00229 var $dontCompress = 0; // Set by user: If set, compression in t3d files is disabled 00230 var $includeExtFileResources = 0; // Boolean, if set, HTML file resources are included. 00231 var $extFileResourceExtensions = 'html,htm,css'; // Files with external media (HTML/css style references inside) 00232 00233 // Internal, dynamic: 00234 var $import_mapId = array(); // After records are written this array is filled with [table][original_uid] = [new_uid] 00235 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 00236 var $import_newId_pids = array(); // Page id map for page tree (import) 00237 var $import_data = array(); // Internal data accumulation for writing records during import 00238 var $errorLog = array(); // Error log. 00239 var $cache_getRecordPath = array(); // Cache for record paths 00240 var $checkPID_cache = array(); // Cache of checkPID values. 00241 00242 var $compress = 0; // Set internally if the gzcompress function exists 00243 var $dat = array(); // Internal import/export memory 00244 var $fileProcObj = ''; // File processing object 00245 00246 00247 00248 /************************** 00249 * 00250 * Initialize 00251 * 00252 *************************/ 00253 00261 function init($dontCompress=0,$mode='') { 00262 $this->compress = function_exists('gzcompress'); 00263 $this->dontCompress = $dontCompress; 00264 00265 $this->mode = $mode; 00266 } 00267 00268 00269 00270 00271 00272 00273 00274 00275 00276 00277 00278 00279 00280 00281 /************************** 00282 * 00283 * Export / Init + Meta Data 00284 * 00285 *************************/ 00286 00292 function setHeaderBasics() { 00293 00294 // Initializing: 00295 if (is_array($this->softrefCfg)) { 00296 foreach($this->softrefCfg as $key => $value) { 00297 if (!strlen($value['mode'])) unset($this->softrefCfg[$key]); 00298 } 00299 } 00300 00301 // Setting in header memory: 00302 $this->dat['header']['XMLversion'] = '1.0'; // Version of file format 00303 $this->dat['header']['meta'] = array(); // Initialize meta data array (to put it in top of file) 00304 $this->dat['header']['relStaticTables'] = $this->relStaticTables; // Add list of tables to consider static 00305 $this->dat['header']['excludeMap'] = $this->excludeMap; // The list of excluded records 00306 $this->dat['header']['softrefCfg'] = $this->softrefCfg; // Soft Reference mode for elements 00307 $this->dat['header']['extensionDependencies'] = $this->extensionDependencies; // List of extensions the import depends on. 00308 } 00309 00316 function setCharset($charset) { 00317 $this->dat['header']['charset'] = $charset; 00318 } 00319 00331 function setMetaData($title,$description,$notes,$packager_username,$packager_name,$packager_email) { 00332 $this->dat['header']['meta'] = array( 00333 'title' => $title, 00334 'description' => $description, 00335 'notes' => $notes, 00336 'packager_username' => $packager_username, 00337 'packager_name' => $packager_name, 00338 'packager_email' => $packager_email, 00339 'TYPO3_version' => TYPO3_version, 00340 # 'loaded_extensions' => $GLOBALS['TYPO3_CONF_VARS']['EXT']['extList'], 00341 'created' => strftime('%A %e. %B %Y', time()) 00342 ); 00343 } 00344 00351 function addThumbnail($imgFilepath) { 00352 if (@is_file($imgFilepath)) { 00353 $imgInfo = @getimagesize($imgFilepath); 00354 if (is_array($imgInfo)) { 00355 $fileContent = t3lib_div::getUrl($imgFilepath); 00356 $this->dat['header']['thumbnail'] = array( 00357 'imgInfo' => $imgInfo, 00358 'content' => $fileContent, 00359 'filesize' => strlen($fileContent), 00360 'filemtime' => filemtime($imgFilepath), 00361 'filename' => basename($imgFilepath) 00362 ); 00363 } 00364 } 00365 } 00366 00367 00368 00369 00370 00371 00372 00373 00374 00375 00376 00377 /************************** 00378 * 00379 * Export / Init Page tree 00380 * 00381 *************************/ 00382 00389 function setPageTree($idH) { 00390 $this->dat['header']['pagetree'] = $this->unsetExcludedSections($idH); 00391 return $this->flatInversePageTree($this->dat['header']['pagetree']); 00392 } 00393 00402 function unsetExcludedSections($idH) { 00403 if (is_array($idH)) { 00404 reset($idH); 00405 while(list($k,$v) = each($idH)) { 00406 if ($this->excludeMap['pages:'.$idH[$k]['uid']]) { 00407 unset($idH[$k]); 00408 } elseif (is_array($idH[$k]['subrow'])) { 00409 $idH[$k]['subrow'] = $this->unsetExcludedSections($idH[$k]['subrow']); 00410 } 00411 } 00412 } 00413 return $idH; 00414 } 00415 00424 function flatInversePageTree($idH,$a=array()) { 00425 if (is_array($idH)) { 00426 $idH = array_reverse($idH); 00427 reset($idH); 00428 while(list($k,$v) = each($idH)) { 00429 $a[$v['uid']] = $v['uid']; 00430 if (is_array($v['subrow'])) { 00431 $a = $this->flatInversePageTree($v['subrow'],$a); 00432 } 00433 } 00434 } 00435 return $a; 00436 } 00437 00447 function flatInversePageTree_pid($idH,$a=array(),$pid=-1) { 00448 if (is_array($idH)) { 00449 $idH = array_reverse($idH); 00450 reset($idH); 00451 while(list($k,$v) = each($idH)) { 00452 $a[$v['uid']] = $pid; 00453 if (is_array($v['subrow'])) { 00454 $a = $this->flatInversePageTree_pid($v['subrow'],$a,$v['uid']); 00455 } 00456 } 00457 } 00458 return $a; 00459 } 00460 00461 00462 00463 00464 00465 00466 00467 00468 00469 00470 00471 /************************** 00472 * 00473 * Export 00474 * 00475 *************************/ 00476 00486 function export_addRecord($table,$row,$relationLevel=0) { 00487 00488 t3lib_BEfunc::workspaceOL($table,$row); 00489 00490 if (strcmp($table,'') && is_array($row) && $row['uid']>0 && !$this->excludeMap[$table.':'.$row['uid']]) { 00491 if ($this->checkPID($table==='pages' ? $row['uid'] : $row['pid'])) { 00492 if (!isset($this->dat['records'][$table.':'.$row['uid']])) { 00493 00494 // Prepare header info: 00495 $headerInfo = array(); 00496 $headerInfo['uid'] = $row['uid']; 00497 $headerInfo['pid'] = $row['pid']; 00498 $headerInfo['title'] = t3lib_div::fixed_lgd_cs(t3lib_BEfunc::getRecordTitle($table,$row),40); 00499 $headerInfo['size'] = strlen(serialize($row)); 00500 if ($relationLevel) { 00501 $headerInfo['relationLevel'] = $relationLevel; 00502 } 00503 00504 // If record content is not too large in size, set the header content and add the rest: 00505 if ($headerInfo['size']<$this->maxRecordSize) { 00506 00507 // Set the header summary: 00508 $this->dat['header']['records'][$table][$row['uid']] = $headerInfo; 00509 00510 // Create entry in the PID lookup: 00511 $this->dat['header']['pid_lookup'][$row['pid']][$table][$row['uid']]=1; 00512 00513 // Initialize reference index object: 00514 $refIndexObj = t3lib_div::makeInstance('t3lib_refindex'); 00515 $refIndexObj->WSOL = TRUE; // Yes to workspace overlays for exporting.... 00516 00517 // Data: 00518 $this->dat['records'][$table.':'.$row['uid']] = array(); 00519 $this->dat['records'][$table.':'.$row['uid']]['data'] = $row; 00520 $this->dat['records'][$table.':'.$row['uid']]['rels'] = $refIndexObj->getRelations($table,$row); 00521 $this->errorLog = array_merge($this->errorLog,$refIndexObj->errorLog); // Merge error logs. 00522 00523 // Add information about the relations in the record in the header: 00524 $this->dat['header']['records'][$table][$row['uid']]['rels'] = $this->flatDBrels($this->dat['records'][$table.':'.$row['uid']]['rels']); 00525 00526 // Add information about the softrefs to header: 00527 $this->dat['header']['records'][$table][$row['uid']]['softrefs'] = $this->flatSoftRefs($this->dat['records'][$table.':'.$row['uid']]['rels']); 00528 00529 } else $this->error('Record '.$table.':'.$row['uid'].' was larger than maxRecordSize ('.t3lib_div::formatSize($this->maxRecordSize).')'); 00530 } else $this->error('Record '.$table.':'.$row['uid'].' already added.'); 00531 } else $this->error('Record '.$table.':'.$row['uid'].' was outside your DB mounts!'); 00532 } 00533 } 00534 00544 function export_addDBRelations($relationLevel=0) { 00545 global $TCA; 00546 00547 // Initialize: 00548 $addR = array(); 00549 00550 // Traverse all "rels" registered for "records" 00551 if (is_array($this->dat['records'])) { 00552 reset($this->dat['records']); 00553 while(list($k) = each($this->dat['records'])) { 00554 if (is_array($this->dat['records'][$k])) { 00555 reset($this->dat['records'][$k]['rels']); 00556 while(list($fieldname,$vR) = each($this->dat['records'][$k]['rels'])) { 00557 #debug($vR); 00558 // For all DB types of relations: 00559 if ($vR['type']=='db') { 00560 foreach($vR['itemArray'] as $fI) { 00561 $this->export_addDBRelations_registerRelation($fI, $addR); 00562 } 00563 } 00564 00565 // For all flex/db types of relations: 00566 if ($vR['type']=='flex') { 00567 // DB relations in flex form fields: 00568 if (is_array($vR['flexFormRels']['db'])) { 00569 foreach($vR['flexFormRels']['db'] as $subList) { 00570 foreach($subList as $fI) { 00571 $this->export_addDBRelations_registerRelation($fI, $addR); 00572 } 00573 } 00574 } 00575 // DB oriented soft references in flex form fields: 00576 if (is_array($vR['flexFormRels']['softrefs'])) { 00577 foreach($vR['flexFormRels']['softrefs'] as $subList) { 00578 foreach($subList['keys'] as $spKey => $elements) { 00579 foreach($elements as $el) { 00580 if ($el['subst']['type'] === 'db' && $this->includeSoftref($el['subst']['tokenID'])) { 00581 list($tempTable, $tempUid) = explode(':', $el['subst']['recordRef']); 00582 $fI = array( 00583 'table' => $tempTable, 00584 'id' => $tempUid 00585 ); 00586 $this->export_addDBRelations_registerRelation($fI, $addR, $el['subst']['tokenID']); 00587 } 00588 } 00589 } 00590 } 00591 } 00592 } 00593 00594 // In any case, if there are soft refs: 00595 if (is_array($vR['softrefs']['keys'])) { 00596 foreach($vR['softrefs']['keys'] as $spKey => $elements) { 00597 foreach($elements as $el) { 00598 if ($el['subst']['type'] === 'db' && $this->includeSoftref($el['subst']['tokenID'])) { 00599 list($tempTable, $tempUid) = explode(':', $el['subst']['recordRef']); 00600 $fI = array( 00601 'table' => $tempTable, 00602 'id' => $tempUid 00603 ); 00604 $this->export_addDBRelations_registerRelation($fI, $addR, $el['subst']['tokenID']); 00605 } 00606 } 00607 } 00608 } 00609 } 00610 } 00611 } 00612 } else $this->error('There were no records available.'); 00613 00614 // Now, if there were new records to add, do so: 00615 if (count($addR)) { 00616 foreach($addR as $fI) { 00617 00618 // Get and set record: 00619 $row = t3lib_BEfunc::getRecord($fI['table'],$fI['id']); 00620 if (is_array($row)) { 00621 $this->export_addRecord($fI['table'],$row,$relationLevel+1); 00622 } 00623 00624 // Set status message 00625 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. 00626 $rId = $fI['table'].':'.$fI['id']; 00627 if (!isset($this->dat['records'][$rId])) { 00628 $this->dat['records'][$rId] = 'NOT_FOUND'; 00629 $this->error('Relation record '.$rId.' was not found!'); 00630 } 00631 } 00632 } 00633 } 00634 00635 // Return overview of relations found and added 00636 return $addR; 00637 } 00638 00648 function export_addDBRelations_registerRelation($fI, &$addR, $tokenID='') { 00649 global $TCA; 00650 00651 $rId = $fI['table'].':'.$fI['id']; 00652 if (isset($TCA[$fI['table']]) 00653 && !$this->isTableStatic($fI['table']) 00654 && !$this->isExcluded($fI['table'],$fI['id']) 00655 && (!$tokenID || $this->includeSoftref($tokenID)) 00656 && $this->inclRelation($fI['table']) 00657 ) { 00658 if (!isset($this->dat['records'][$rId])) { 00659 // Set this record to be included since it is not already. 00660 $addR[$rId] = $fI; 00661 } 00662 } 00663 } 00664 00672 function export_addFilesFromRelations() { 00673 00674 // Traverse all "rels" registered for "records" 00675 if (is_array($this->dat['records'])) { 00676 reset($this->dat['records']); 00677 while(list($k)=each($this->dat['records'])) { 00678 if (is_array($this->dat['records'][$k]['rels'])) { 00679 reset($this->dat['records'][$k]['rels']); 00680 while(list($fieldname,$vR)=each($this->dat['records'][$k]['rels'])) { 00681 00682 // For all file type relations: 00683 if ($vR['type']=='file') { 00684 foreach($vR['newValueFiles'] as $key => $fI) { 00685 $this->export_addFile($fI, $k, $fieldname); 00686 // Remove the absolute reference to the file so it doesn't expose absolute paths from source server: 00687 unset($this->dat['records'][$k]['rels'][$fieldname]['newValueFiles'][$key]['ID_absFile']); 00688 } 00689 } 00690 00691 // For all flex type relations: 00692 if ($vR['type']=='flex') { 00693 if (is_array($vR['flexFormRels']['file'])) { 00694 foreach($vR['flexFormRels']['file'] as $key => $subList) { 00695 foreach($subList as $subKey => $fI) { 00696 $this->export_addFile($fI, $k, $fieldname); 00697 // Remove the absolute reference to the file so it doesn't expose absolute paths from source server: 00698 unset($this->dat['records'][$k]['rels'][$fieldname]['flexFormRels']['file'][$key][$subKey]['ID_absFile']); 00699 } 00700 } 00701 } 00702 00703 // DB oriented soft references in flex form fields: 00704 if (is_array($vR['flexFormRels']['softrefs'])) { 00705 foreach($vR['flexFormRels']['softrefs'] as $key => $subList) { 00706 foreach($subList['keys'] as $spKey => $elements) { 00707 foreach($elements as $subKey => $el) { 00708 if ($el['subst']['type'] === 'file' && $this->includeSoftref($el['subst']['tokenID'])) { 00709 00710 // Create abs path and ID for file: 00711 $ID_absFile = t3lib_div::getFileAbsFileName(PATH_site.$el['subst']['relFileName']); 00712 $ID = md5($ID_absFile); 00713 00714 if ($ID_absFile) { 00715 if (!$this->dat['files'][$ID]) { 00716 $fI = array( 00717 'filename' => basename($ID_absFile), 00718 'ID_absFile' => $ID_absFile, 00719 'ID' => $ID, 00720 'relFileName' => $el['subst']['relFileName'] 00721 ); 00722 $this->export_addFile($fI, '_SOFTREF_'); 00723 } 00724 $this->dat['records'][$k]['rels'][$fieldname]['flexFormRels']['softrefs'][$key]['keys'][$spKey][$subKey]['file_ID'] = $ID; 00725 } 00726 } 00727 } 00728 } 00729 } 00730 } 00731 } 00732 00733 // In any case, if there are soft refs: 00734 if (is_array($vR['softrefs']['keys'])) { 00735 foreach($vR['softrefs']['keys'] as $spKey => $elements) { 00736 foreach($elements as $subKey => $el) { 00737 if ($el['subst']['type'] === 'file' && $this->includeSoftref($el['subst']['tokenID'])) { 00738 00739 // Create abs path and ID for file: 00740 $ID_absFile = t3lib_div::getFileAbsFileName(PATH_site.$el['subst']['relFileName']); 00741 $ID = md5($ID_absFile); 00742 00743 if ($ID_absFile) { 00744 if (!$this->dat['files'][$ID]) { 00745 $fI = array( 00746 'filename' => basename($ID_absFile), 00747 'ID_absFile' => $ID_absFile, 00748 'ID' => $ID, 00749 'relFileName' => $el['subst']['relFileName'] 00750 ); 00751 $this->export_addFile($fI, '_SOFTREF_'); 00752 } 00753 $this->dat['records'][$k]['rels'][$fieldname]['softrefs']['keys'][$spKey][$subKey]['file_ID'] = $ID; 00754 } 00755 } 00756 } 00757 } 00758 } 00759 } 00760 } 00761 } 00762 } else $this->error('There were no records available.'); 00763 } 00764 00773 function export_addFile($fI, $recordRef='', $fieldname='') { 00774 if (@is_file($fI['ID_absFile'])) { 00775 if (filesize($fI['ID_absFile']) < $this->maxFileSize) { 00776 $fileRec = array(); 00777 $fileRec['filesize'] = filesize($fI['ID_absFile']); 00778 $fileRec['filename'] = basename($fI['ID_absFile']); 00779 $fileRec['filemtime'] = filemtime($fI['ID_absFile']); 00780 if ($recordRef) { 00781 $fileRec['record_ref'] = $recordRef.'/'.$fieldname; 00782 } 00783 if ($fI['relFileName']) { 00784 $fileRec['relFileName'] = $fI['relFileName']; 00785 } 00786 00787 // Setting this data in the header 00788 $this->dat['header']['files'][$fI['ID']] = $fileRec; 00789 00790 // ... and for the recordlisting, why not let us know WHICH relations there was... 00791 if ($recordRef && $recordRef!=='_SOFTREF_') { 00792 $refParts = explode(':',$recordRef,2); 00793 if (!is_array($this->dat['header']['records'][$refParts[0]][$refParts[1]]['filerefs'])) { 00794 $this->dat['header']['records'][$refParts[0]][$refParts[1]]['filerefs'] = array(); 00795 } 00796 $this->dat['header']['records'][$refParts[0]][$refParts[1]]['filerefs'][] = $fI['ID']; 00797 } 00798 00799 // ... and finally add the heavy stuff: 00800 $fileRec['content'] = t3lib_div::getUrl($fI['ID_absFile']); 00801 $fileRec['content_md5'] = md5($fileRec['content']); 00802 $this->dat['files'][$fI['ID']] = $fileRec; 00803 00804 00805 // For soft references, do further processing: 00806 if ($recordRef === '_SOFTREF_') { 00807 00808 // RTE files? 00809 if ($RTEoriginal = $this->getRTEoriginalFilename(basename($fI['ID_absFile']))) { 00810 $RTEoriginal_absPath = dirname($fI['ID_absFile']).'/'.$RTEoriginal; 00811 if (@is_file($RTEoriginal_absPath)) { 00812 00813 $RTEoriginal_ID = md5($RTEoriginal_absPath); 00814 00815 $fileRec = array(); 00816 $fileRec['filesize'] = filesize($RTEoriginal_absPath); 00817 $fileRec['filename'] = basename($RTEoriginal_absPath); 00818 $fileRec['filemtime'] = filemtime($RTEoriginal_absPath); 00819 $fileRec['record_ref'] = '_RTE_COPY_ID:'.$fI['ID']; 00820 $this->dat['header']['files'][$fI['ID']]['RTE_ORIG_ID'] = $RTEoriginal_ID; 00821 00822 // Setting this data in the header 00823 $this->dat['header']['files'][$RTEoriginal_ID] = $fileRec; 00824 00825 // ... and finally add the heavy stuff: 00826 $fileRec['content'] = t3lib_div::getUrl($RTEoriginal_absPath); 00827 $fileRec['content_md5'] = md5($fileRec['content']); 00828 $this->dat['files'][$RTEoriginal_ID] = $fileRec; 00829 } else { 00830 $this->error('RTE original file "'.substr($RTEoriginal_absPath,strlen(PATH_site)).'" was not found!'); 00831 } 00832 } 00833 00834 // Files with external media? 00835 // This is only done with files grabbed by a softreference parser since it is deemed improbable that hard-referenced files should undergo this treatment. 00836 $html_fI = pathinfo(basename($fI['ID_absFile'])); 00837 if ($this->includeExtFileResources && t3lib_div::inList($this->extFileResourceExtensions,strtolower($html_fI['extension']))) { 00838 $uniquePrefix = '###'.md5(time()).'###'; 00839 00840 if (strtolower($html_fI['extension'])==='css') { 00841 $prefixedMedias = explode($uniquePrefix, eregi_replace('(url[[:space:]]*\([[:space:]]*["\']?)([^"\')]*)(["\']?[[:space:]]*\))', '\1'.$uniquePrefix.'\2'.$uniquePrefix.'\3', $fileRec['content'])); 00842 } else { // html, htm: 00843 $htmlParser = t3lib_div::makeInstance('t3lib_parsehtml'); 00844 $prefixedMedias = explode($uniquePrefix, $htmlParser->prefixResourcePath($uniquePrefix,$fileRec['content'],array(),$uniquePrefix)); 00845 } 00846 00847 $htmlResourceCaptured = FALSE; 00848 foreach($prefixedMedias as $k => $v) { 00849 if ($k%2) { 00850 $EXTres_absPath = t3lib_div::resolveBackPath(dirname($fI['ID_absFile']).'/'.$v); 00851 $EXTres_absPath = t3lib_div::getFileAbsFileName($EXTres_absPath); 00852 if ($EXTres_absPath && t3lib_div::isFirstPartOfStr($EXTres_absPath,PATH_site.$this->fileadminFolderName.'/') && @is_file($EXTres_absPath)) { 00853 00854 $htmlResourceCaptured = TRUE; 00855 $EXTres_ID = md5($EXTres_absPath); 00856 $this->dat['header']['files'][$fI['ID']]['EXT_RES_ID'][] = $EXTres_ID; 00857 $prefixedMedias[$k] = '{EXT_RES_ID:'.$EXTres_ID.'}'; 00858 00859 // Add file to memory if it is not set already: 00860 if (!isset($this->dat['header']['files'][$EXTres_ID])) { 00861 $fileRec = array(); 00862 $fileRec['filesize'] = filesize($EXTres_absPath); 00863 $fileRec['filename'] = basename($EXTres_absPath); 00864 $fileRec['filemtime'] = filemtime($EXTres_absPath); 00865 $fileRec['record_ref'] = '_EXT_PARENT_:'.$fI['ID']; 00866 00867 $fileRec['parentRelFileName'] = $v; // Media relative to the HTML file. 00868 00869 // Setting this data in the header 00870 $this->dat['header']['files'][$EXTres_ID] = $fileRec; 00871 00872 // ... and finally add the heavy stuff: 00873 $fileRec['content'] = t3lib_div::getUrl($EXTres_absPath); 00874 $fileRec['content_md5'] = md5($fileRec['content']); 00875 $this->dat['files'][$EXTres_ID] = $fileRec; 00876 } 00877 } 00878 } 00879 } 00880 00881 if ($htmlResourceCaptured) { 00882 $this->dat['files'][$fI['ID']]['tokenizedContent'] = implode('', $prefixedMedias); 00883 } 00884 } 00885 } 00886 00887 } else $this->error($fI['ID_absFile'].' was larger ('.t3lib_div::formatSize(filesize($fI['ID_absFile'])).') than the maxFileSize ('.t3lib_div::formatSize($this->maxFileSize).')! Skipping.'); 00888 } else $this->error($fI['ID_absFile'].' was not a file! Skipping.'); 00889 } 00890 00898 function flatDBrels($dbrels) { 00899 $list = array(); 00900 00901 foreach($dbrels as $dat) { 00902 if ($dat['type']=='db') { 00903 foreach($dat['itemArray'] as $i) { 00904 $list[$i['table'].':'.$i['id']] = $i; 00905 } 00906 } 00907 if ($dat['type']=='flex' && is_array($dat['flexFormRels']['db'])) { 00908 foreach($dat['flexFormRels']['db'] as $subList) { 00909 foreach($subList as $i) { 00910 $list[$i['table'].':'.$i['id']] = $i; 00911 } 00912 } 00913 } 00914 } 00915 return $list; 00916 } 00917 00924 function flatSoftRefs($dbrels) { 00925 $list = array(); 00926 #debug($dbrels); 00927 foreach($dbrels as $field => $dat) { 00928 if (is_array($dat['softrefs']['keys'])) { 00929 foreach($dat['softrefs']['keys'] as $spKey => $elements) { 00930 if (is_array($elements)) { 00931 foreach($elements as $subKey => $el) { 00932 $lKey = $field.':'.$spKey.':'.$subKey; 00933 $list[$lKey] = array_merge(array('field' => $field, 'spKey' => $spKey),$el); 00934 00935 // 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! 00936 if ($el['subst'] && $el['subst']['relFileName']) { 00937 $list[$lKey]['file_ID'] = md5(PATH_site.$el['subst']['relFileName']); 00938 } 00939 } 00940 } 00941 } 00942 } 00943 if ($dat['type']=='flex' && is_array($dat['flexFormRels']['softrefs'])) { 00944 foreach($dat['flexFormRels']['softrefs'] as $structurePath => $subSoftrefs) { 00945 if (is_array($subSoftrefs['keys'])) { 00946 foreach($subSoftrefs['keys'] as $spKey => $elements) { 00947 foreach($elements as $subKey => $el) { 00948 $lKey = $field.':'.$structurePath.':'.$spKey.':'.$subKey; 00949 $list[$lKey] = array_merge(array('field' => $field, 'spKey' => $spKey, 'structurePath' => $structurePath),$el); 00950 00951 // 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! 00952 if ($el['subst'] && $el['subst']['relFileName']) { 00953 $list[$lKey]['file_ID'] = md5(PATH_site.$el['subst']['relFileName']); 00954 } 00955 } 00956 } 00957 } 00958 } 00959 } 00960 } 00961 00962 #debug($list); 00963 return $list; 00964 } 00965 00966 00967 00968 00969 00970 00971 00972 00973 00974 00975 00976 /************************** 00977 * 00978 * File Output 00979 * 00980 *************************/ 00981 00988 function compileMemoryToFileContent($type='') { 00989 00990 if ($type=='xml') { 00991 $out = $this->createXML(); 00992 } else { 00993 $compress = $this->doOutputCompress(); 00994 $out = ''; 00995 00996 // adding header: 00997 $out.= $this->addFilePart(serialize($this->dat['header']),$compress); 00998 00999 // adding records: 01000 $out.= $this->addFilePart(serialize($this->dat['records']),$compress); 01001 01002 // adding files: 01003 $out.= $this->addFilePart(serialize($this->dat['files']),$compress); 01004 } 01005 01006 return $out; 01007 } 01008 01014 function createXML() { 01015 01016 // Options: 01017 $options = array( 01018 'alt_options' => array( 01019 '/header' => array( 01020 'disableTypeAttrib' => TRUE, 01021 'clearStackPath' => TRUE, 01022 'parentTagMap' => array( 01023 'files' => 'file', 01024 'records' => 'table', 01025 'table' => 'rec', 01026 'rec:rels' => 'relations', 01027 'relations' => 'element', 01028 'filerefs' => 'file', 01029 'pid_lookup' => 'page_contents', 01030 'header:relStaticTables' => 'static_tables', 01031 'static_tables' => 'tablename', 01032 'excludeMap' => 'item', 01033 'softrefCfg' => 'softrefExportMode', 01034 'extensionDependencies' => 'extkey', 01035 'softrefs' => 'softref_element', 01036 ), 01037 'alt_options' => array( 01038 '/pagetree' => array( 01039 'disableTypeAttrib' => TRUE, 01040 'useIndexTagForNum' => 'node', 01041 'parentTagMap' => array( 01042 'node:subrow' => 'node' 01043 ) 01044 ), 01045 '/pid_lookup/page_contents' => array( 01046 'disableTypeAttrib' => TRUE, 01047 'parentTagMap' => array( 01048 'page_contents' => 'table' 01049 ), 01050 'grandParentTagMap' => array( 01051 'page_contents/table' => 'item' 01052 ) 01053 ) 01054 ) 01055 ), 01056 '/records' => array( 01057 'disableTypeAttrib' => TRUE, 01058 'parentTagMap' => array( 01059 'records' => 'tablerow', 01060 'tablerow:data' => 'fieldlist', 01061 'tablerow:rels' => 'related', 01062 'related' => 'field', 01063 'field:itemArray' => 'relations', 01064 'field:newValueFiles' => 'filerefs', 01065 'field:flexFormRels' => 'flexform', 01066 'relations' => 'element', 01067 'filerefs' => 'file', 01068 'flexform:db' => 'db_relations', 01069 'flexform:file' => 'file_relations', 01070 'flexform:softrefs' => 'softref_relations', 01071 'softref_relations' => 'structurePath', 01072 'db_relations' => 'path', 01073 'file_relations' => 'path', 01074 'path' => 'element', 01075 'keys' => 'softref_key', 01076 'softref_key' => 'softref_element', 01077 ), 01078 'alt_options' => array( 01079 '/records/tablerow/fieldlist' => array( 01080 'useIndexTagForAssoc' => 'field', 01081 ) 01082 ) 01083 ), 01084 '/files' => array( 01085 'disableTypeAttrib' => TRUE, 01086 'parentTagMap' => array( 01087 'files' => 'file', 01088 ), 01089 ), 01090 ) 01091 ); 01092 01093 // Creating XML file from $outputArray: 01094 $charset = $this->dat['header']['charset'] ? $this->dat['header']['charset'] : 'iso-8859-1'; 01095 $XML = '<?xml version="1.0" encoding="'.$charset.'" standalone="yes" ?>'.chr(10); 01096 $XML.= t3lib_div::array2xml($this->dat,'',0,'T3RecordDocument',0,$options); 01097 01098 return $XML; 01099 } 01100 01106 function doOutputCompress() { 01107 return $this->compress && !$this->dontCompress; 01108 } 01109 01117 function addFilePart($data, $compress=FALSE) { 01118 if ($compress) $data = gzcompress($data); 01119 return md5($data).':'. 01120 ($compress?'1':'0').':'. 01121 str_pad(strlen($data),10,'0',STR_PAD_LEFT).':'. 01122 $data.':'; 01123 } 01124 01125 01126 01127 01128 01129 01130 01131 01132 01133 01134 01135 01136 01137 01138 /*********************** 01139 * 01140 * Import 01141 * 01142 ***********************/ 01143 01150 function importData($pid) { 01151 01152 // Set this flag to indicate that an import is being/has been done. 01153 $this->doesImport = 1; 01154 01155 // Initialize: 01156 // 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. 01157 $this->import_mapId = array(); 01158 $this->import_newId = array(); 01159 $this->import_newId_pids = array(); 01160 01161 // Temporary files stack initialized: 01162 $this->unlinkFiles = array(); 01163 $this->alternativeFileName = array(); 01164 01165 // Write records, first pages, then the rest 01166 // Fields with "hard" relations to database, files and flexform fields are kept empty during this run 01167 $this->writeRecords_pages($pid); 01168 $this->writeRecords_records($pid); 01169 01170 // Finally all the file and DB record references must be fixed. This is done after all records have supposedly been written to database: 01171 // $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. 01172 $this->setRelations(); 01173 01174 // 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): 01175 $this->setFlexFormRelations(); 01176 01177 // Unlink temporary files: 01178 $this->unlinkTempFiles(); 01179 01180 // Finally, traverse all records and process softreferences with substitution attributes. 01181 $this->processSoftReferences(); 01182 } 01183 01191 function writeRecords_pages($pid) { 01192 01193 // First, write page structure if any: 01194 if (is_array($this->dat['header']['records']['pages'])) { 01195 01196 // $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. 01197 $pageRecords = $this->dat['header']['records']['pages']; 01198 $this->import_data = array(); 01199 #debug($pageRecords); 01200 // First add page tree if any 01201 if (is_array($this->dat['header']['pagetree'])) { 01202 $pagesFromTree = $this->flatInversePageTree($this->dat['header']['pagetree']); 01203 foreach($pagesFromTree as $uid) { 01204 $thisRec = $this->dat['header']['records']['pages'][$uid]; 01205 // PID: Set the main $pid, unless a NEW-id is found 01206 $setPid = isset($this->import_newId_pids[$thisRec['pid']]) ? $this->import_newId_pids[$thisRec['pid']] : $pid; 01207 $this->addSingle('pages',$uid,$setPid); 01208 unset($pageRecords[$uid]); 01209 } 01210 } 01211 #debug($pageRecords); 01212 // Then add all remaining pages not in tree on root level: 01213 if (count($pageRecords)) { 01214 $remainingPageUids = array_keys($pageRecords); 01215 foreach($remainingPageUids as $pUid) { 01216 $this->addSingle('pages',$pUid,$pid); 01217 } 01218 } 01219 01220 // Now write to database: 01221 $tce = $this->getNewTCE(); 01222 $tce->suggestedInsertUids = $this->suggestedInsertUids; 01223 $tce->start($this->import_data,Array()); 01224 $tce->process_datamap(); 01225 #debug($this->import_data,'PAGES'); 01226 01227 // post-processing: Registering new ids (end all tcemain sessions with this) 01228 $this->addToMapId($tce->substNEWwithIDs); 01229 01230 // In case of an update, order pages from the page tree correctly: 01231 if ($this->update && is_array($this->dat['header']['pagetree'])) { 01232 $this->writeRecords_pages_order($pid); 01233 } 01234 } 01235 } 01236 01246 function writeRecords_pages_order($pid) { 01247 $cmd_data = array(); 01248 01249 // Get uid-pid relations and traverse them in order to map to possible new IDs 01250 $pidsFromTree = $this->flatInversePageTree_pid($this->dat['header']['pagetree']); 01251 #debug($this->dat['header']['pagetree'],'pagetree'); 01252 #debug($pidsFromTree,'$pidsFromTree'); 01253 #debug($this->import_newId_pids,'import_newId_pids'); 01254 foreach($pidsFromTree as $origPid => $newPid) { 01255 if ($newPid>=0 && $this->dontIgnorePid('pages', $origPid)) { 01256 if (substr($this->import_newId_pids[$origPid],0,3)==='NEW') { // If the page had a new id (because it was created) use that instead! 01257 01258 if ($this->import_mapId['pages'][$origPid]) { 01259 $mappedPid = $this->import_mapId['pages'][$origPid]; 01260 $cmd_data['pages'][$mappedPid]['move'] = $newPid; 01261 } 01262 } else { 01263 $cmd_data['pages'][$origPid]['move'] = $newPid; 01264 } 01265 } 01266 } 01267 01268 // Execute the move commands if any: 01269 if (count($cmd_data)) { 01270 $tce = $this->getNewTCE(); 01271 $tce->start(Array(),$cmd_data); 01272 $tce->process_cmdmap(); 01273 } 01274 #debug($cmd_data,'$cmd_data'); 01275 } 01276 01284 function writeRecords_records($pid) { 01285 global $TCA; 01286 01287 // Write the rest of the records 01288 $this->import_data = array(); 01289 if (is_array($this->dat['header']['records'])) { 01290 reset($this->dat['header']['records']); 01291 while(list($table,$recs) = each($this->dat['header']['records'])) { 01292 if ($table!='pages') { 01293 reset($recs); 01294 while(list($uid,$thisRec)=each($recs)) { 01295 // PID: Set the main $pid, unless a NEW-id is found 01296 $setPid = isset($this->import_mapId['pages'][$thisRec['pid']]) ? $this->import_mapId['pages'][$thisRec['pid']] : $pid; 01297 if (is_array($TCA[$table]) && $TCA[$table]['ctrl']['rootLevel']) { 01298 $setPid = 0; 01299 } 01300 01301 // Add record: 01302 $this->addSingle($table,$uid,$setPid); 01303 } 01304 } 01305 } 01306 } else $this->error('Error: No records defined in internal data array.'); 01307 01308 // Now write to database: 01309 $tce = $this->getNewTCE(); 01310 $tce->suggestedInsertUids = $this->suggestedInsertUids; 01311 $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. 01312 $tce->start($this->import_data,Array()); 01313 $tce->process_datamap(); 01314 #debug($this->import_data,'RECORDS'); 01315 01316 // post-processing: Removing files and registering new ids (end all tcemain sessions with this) 01317 $this->addToMapId($tce->substNEWwithIDs); 01318 01319 // In case of an update, order pages from the page tree correctly: 01320 if ($this->update) { 01321 $this->writeRecords_records_order($pid); 01322 } 01323 } 01324 01334 function writeRecords_records_order($mainPid) { 01335 $cmd_data = array(); 01336 01337 if (is_array($this->dat['header']['pagetree'])) { 01338 $pagesFromTree = $this->flatInversePageTree($this->dat['header']['pagetree']); 01339 } else $pagesFromTree = array(); 01340 01341 #debug($this->dat['header']['pid_lookup'],'pid_lookup'); 01342 if (is_array($this->dat['header']['pid_lookup'])) { 01343 foreach($this->dat['header']['pid_lookup'] as $pid => $recList) { 01344 $newPid = isset($this->import_mapId['pages'][$pid]) ? $this->import_mapId['pages'][$pid] : $mainPid; 01345 #debug(array($pid,$newPid),'$pid / $newPid'); 01346 01347 if (t3lib_div::testInt($newPid)) { 01348 foreach($recList as $tableName => $uidList) { 01349 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!) 01350 $uidList = array_reverse(array_keys($uidList)); 01351 foreach($uidList as $uid) { 01352 if ($this->dontIgnorePid($tableName, $uid)) { 01353 $cmd_data[$tableName][$uid]['move'] = $newPid; 01354 } else { 01355 #debug($tableName.':'.$uid,'removed'); 01356 } 01357 } 01358 } 01359 } 01360 } 01361 } 01362 } 01363 01364 // Execute the move commands if any: 01365 if (count($cmd_data)) { 01366 $tce = $this->getNewTCE(); 01367 $tce->start(Array(),$cmd_data); 01368 $tce->process_cmdmap(); 01369 } 01370 #debug($cmd_data,'$cmd_data'); 01371 } 01372 01383 function addSingle($table,$uid,$pid) { 01384 if ($this->import_mode[$table.':'.$uid]!=='exclude') { 01385 $record = $this->dat['records'][$table.':'.$uid]['data']; 01386 if (is_array($record)) { 01387 01388 if ($this->update && $this->doesRecordExist($table,$uid) && $this->import_mode[$table.':'.$uid]!=='as_new') { 01389 $ID = $uid; 01390 } else { 01391 #debug($this->import_mode[$table.':'.$uid],$table.':'.$uid); 01392 $ID = uniqid('NEW'); 01393 } 01394 $this->import_newId[$table.':'.$ID] = array('table' => $table, 'uid' => $uid); 01395 if ($table=='pages') $this->import_newId_pids[$uid] = $ID; 01396 01397 // Set main record data: 01398 $this->import_data[$table][$ID] = $record; 01399 $this->import_data[$table][$ID]['tx_impexp_origuid'] = $this->import_data[$table][$ID]['uid']; 01400 01401 // Reset permission data: 01402 if ($table==='pages') { 01403 // Have to reset the user/group IDs so pages are owned by importing user. Otherwise strange things may happen for non-admins! 01404 unset($this->import_data[$table][$ID]['perms_userid']); 01405 unset($this->import_data[$table][$ID]['perms_groupid']); 01406 01407 // user/group/everybody settings is kept - but these might still conflict with possibilities for writing the content!" 01408 #unset($this->import_data[$table][$ID]['perms_user']); 01409 #unset($this->import_data[$table][$ID]['perms_group']); 01410 #unset($this->import_data[$table][$ID]['perms_everybody']); 01411 } 01412 01413 // PID and UID: 01414 unset($this->import_data[$table][$ID]['uid']); 01415 if (t3lib_div::testInt($ID)) { // Updates: 01416 unset($this->import_data[$table][$ID]['pid']); 01417 } else { // Inserts: 01418 $this->import_data[$table][$ID]['pid'] = $pid; 01419 01420 if ((($this->import_mode[$table.':'.$uid]==='force_uid' && $this->update) || $this->force_all_UIDS) && $GLOBALS['BE_USER']->isAdmin()) { 01421 #debug($this->import_mode[$table.':'.$uid],$table.':'.$uid); 01422 $this->import_data[$table][$ID]['uid'] = $uid; 01423 $this->suggestedInsertUids[$table.':'.$uid] = 'DELETE'; 01424 } 01425 } 01426 01427 // Setting db/file blank: 01428 reset($this->dat['records'][$table.':'.$uid]['rels']); 01429 while(list($field,$config) = each($this->dat['records'][$table.':'.$uid]['rels'])) { 01430 switch((string)$config['type']) { 01431 case 'db': 01432 case 'file': 01433 // Fixed later in ->setRelations() [because we need to know ALL newly created IDs before we can map relations!] 01434 // In the meantime we set NO values for relations: 01435 $this->import_data[$table][$ID][$field] = ''; 01436 break; 01437 case 'flex': 01438 // Fixed later in setFlexFormRelations() 01439 // 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!) 01440 $this->import_data[$table][$ID][$field] = ''; 01441 break; 01442 } 01443 } 01444 } elseif ($table.':'.$uid != 'pages:0') { // On root level we don't want this error message. 01445 $this->error('Error: no record was found in data array!',1); 01446 } 01447 } 01448 } 01449 01457 function addToMapId($substNEWwithIDs) { 01458 reset($this->import_data); 01459 while(list($table,$recs)=each($this->import_data)) { 01460 reset($recs); 01461 while(list($id)=each($recs)) { 01462 $old_uid = $this->import_newId[$table.':'.$id]['uid']; 01463 if (isset($substNEWwithIDs[$id])) { 01464 $this->import_mapId[$table][$old_uid] = $substNEWwithIDs[$id]; 01465 } elseif ($this->update) { 01466 $this->import_mapId[$table][$old_uid] = $id; // Map same ID to same ID.... 01467 } 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); 01468 } 01469 } 01470 } 01471 01477 function getNewTCE() { 01478 $tce = t3lib_div::makeInstance('t3lib_TCEmain'); 01479 $tce->stripslashes_values = 0; 01480 $tce->dontProcessTransformations = 1; 01481 $tce->enableLogging = $this->enableLogging; 01482 $tce->alternativeFileName = $this->alternativeFileName; 01483 return $tce; 01484 } 01485 01491 function unlinkTempFiles() { 01492 foreach($this->unlinkFiles as $fileName) { 01493 if (t3lib_div::isFirstPartOfStr($fileName, PATH_site.'typo3temp/')) { 01494 t3lib_div::unlink_tempfile($fileName); 01495 clearstatcache(); 01496 if (is_file($fileName)) { 01497 $this->error('Error: '.$fileName.' was NOT unlinked as it should have been!',1); 01498 } 01499 } else $this->error('Error: '.$fileName.' was not in temp-path. Not removed!',1); 01500 } 01501 $this->unlinkFiles = array(); 01502 } 01503 01504 01505 01506 01507 01508 01509 01510 01511 01512 01513 01514 01515 01516 /*************************** 01517 * 01518 * Import / Relations setting 01519 * 01520 ***************************/ 01521 01529 function setRelations() { 01530 global $TCA; 01531 01532 $updateData = array(); 01533 01534 // import_newId contains a register of all records that was in the import memorys "records" key 01535 reset($this->import_newId); 01536 while(list($nId,$dat) = each($this->import_newId)) { 01537 $table = $dat['table']; 01538 $uid = $dat['uid']; // original UID - NOT the new one! 01539 01540 // If the record has been written and received a new id, then proceed: 01541 if (is_array($this->import_mapId[$table]) && isset($this->import_mapId[$table][$uid])) { 01542 $thisNewUid = t3lib_BEfunc::wsMapId($table,$this->import_mapId[$table][$uid]); 01543 01544 if (is_array($this->dat['records'][$table.':'.$uid]['rels'])) { 01545 reset($this->dat['records'][$table.':'.$uid]['rels']); 01546 01547 // Traverse relation fields of each record 01548 while(list($field,$config) = each($this->dat['records'][$table.':'.$uid]['rels'])) { 01549 switch((string)$config['type']) { 01550 case 'db': 01551 if (is_array($config['itemArray']) && count($config['itemArray'])) { 01552 $valArray = $this->setRelations_db($config['itemArray']); 01553 $updateData[$table][$thisNewUid][$field] = implode(',',$valArray); // List of [table]_[uid] 01554 } 01555 break; 01556 case 'file': 01557 if (is_array($config['newValueFiles']) && count($config['newValueFiles'])) { 01558 $valArr = array(); 01559 foreach($config['newValueFiles'] as $fI) { 01560 $valArr[] = $this->import_addFileNameToBeCopied($fI); 01561 } 01562 $updateData[$table][$thisNewUid][$field] = implode(',',$valArr); // List of absolute files 01563 } 01564 break; 01565 } 01566 } 01567 } else $this->error('Error: no record was found in data array!',1); 01568 } else $this->error('Error: this records is NOT created it seems! ('.$table.':'.$uid.')',1); 01569 } 01570 if (count($updateData)) { 01571 $tce = $this->getNewTCE(); 01572 $tce->start($updateData,Array()); 01573 $tce->process_datamap(); 01574 #debug($updateData,'setRelations()'); 01575 } 01576 } 01577 01584 function setRelations_db($itemArray) { 01585 $valArray = array(); 01586 01587 foreach($itemArray as $relDat) { 01588 if (is_array($this->import_mapId[$relDat['table']]) && isset($this->import_mapId[$relDat['table']][$relDat['id']])) { 01589 01590 #debug('FOUND: '.$relDat['table'].':'.$relDat['id'],1); 01591 $valArray[] = $relDat['table'].'_'.$this->import_mapId[$relDat['table']][$relDat['id']]; 01592 } 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. 01593 01594 #debug('STATIC: '.$relDat['table'].':'.$relDat['id'],1); 01595 $valArray[] = $relDat['table'].'_'.$relDat['id']; 01596 } else { 01597 01598 $this->error('Lost relation: '.$relDat['table'].':'.$relDat['id'],1); 01599 } 01600 } 01601 01602 return $valArray; 01603 } 01604 01611 function import_addFileNameToBeCopied($fI) { 01612 if (is_array($this->dat['files'][$fI['ID']])) { 01613 $tmpFile = t3lib_div::tempnam('import_temp_'); 01614 t3lib_div::writeFile($tmpFile,$this->dat['files'][$fI['ID']]['content']); 01615 clearstatcache(); 01616 if (@is_file($tmpFile)) { 01617 $this->unlinkFiles[] = $tmpFile; 01618 if (filesize($tmpFile)==$this->dat['files'][$fI['ID']]['filesize']) { 01619 $this->alternativeFileName[$tmpFile] = $fI['filename']; 01620 01621 return $tmpFile; 01622 } else $this->error('Error: temporary file '.$tmpFile.' had a size ('.filesize($tmpFile).') different from the original ('.$this->dat['files'][$fI['ID']]['filesize'].')',1); 01623 } else $this->error('Error: temporary file '.$tmpFile.' was not written as it should have been!',1); 01624 } else $this->error('Error: No file found for ID '.$fI['ID'],1); 01625 } 01626 01634 function setFlexFormRelations() { 01635 global $TCA; 01636 01637 $updateData = array(); 01638 #debug($this->import_newId); 01639 // import_newId contains a register of all records that was in the import memorys "records" key 01640 reset($this->import_newId); 01641 while(list($nId,$dat) = each($this->import_newId)) { 01642 $table = $dat['table']; 01643 $uid = $dat['uid']; // original UID - NOT the new one! 01644 01645 // If the record has been written and received a new id, then proceed: 01646 if (is_array($this->import_mapId[$table]) && isset($this->import_mapId[$table][$uid])) { 01647 $thisNewUid = t3lib_BEfunc::wsMapId($table,$this->import_mapId[$table][$uid]); 01648 #debug($thisNewUid,'$thisNewUid'); 01649 #debug($this->dat['records'][$table.':'.$uid]['rels']); 01650 if (is_array($this->dat['records'][$table.':'.$uid]['rels'])) { 01651 reset($this->dat['records'][$table.':'.$uid]['rels']); 01652 t3lib_div::loadTCA($table); 01653 01654 // Traverse relation fields of each record 01655 while(list($field,$config) = each($this->dat['records'][$table.':'.$uid]['rels'])) { 01656 switch((string)$config['type']) { 01657 case 'flex': 01658 // Get XML content and set as default value (string, non-processed): 01659 $updateData[$table][$thisNewUid][$field] = $this->dat['records'][$table.':'.$uid]['data'][$field]; 01660 01661 // If there has been registered relations inside the flex form field, run processing on the content: 01662 if (count($config['flexFormRels']['db']) || count($config['flexFormRels']['file'])) { 01663 $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.) 01664 #debug(array($updateData[$table][$thisNewUid][$field]),'flexXML'); 01665 $conf = $TCA[$table]['columns'][$field]['config']; 01666 if (is_array($origRecordRow) && is_array($conf) && $conf['type']==='flex') { 01667 #debug($conf,'***'); 01668 // Get current data structure and value array: 01669 $dataStructArray = t3lib_BEfunc::getFlexFormDS($conf, $origRecordRow, $table); 01670 $currentValueArray = t3lib_div::xml2array($updateData[$table][$thisNewUid][$field]); 01671 # debug($dataStructArray); 01672 # debug($currentValueArray); 01673 # debug($origRecordRow); 01674 # debug($currentValueArray['data'],'BE'); 01675 // Do recursive processing of the XML data: 01676 $iteratorObj = t3lib_div::makeInstance('t3lib_TCEmain'); 01677 $iteratorObj->callBackObj = &$this; 01678 $currentValueArray['data'] = $iteratorObj->checkValue_flex_procInData( 01679 $currentValueArray['data'], 01680 array(), // Not used. 01681 array(), // Not used. 01682 $dataStructArray, 01683 array($table,$thisNewUid,$field,$config), // Parameters. 01684 'remapListedDBRecords_flexFormCallBack' 01685 ); 01686 #debug($currentValueArray['data'],'AF'); 01687 // The return value is set as an array which means it will be processed by tcemain for file and DB references! 01688 if (is_array($currentValueArray['data'])) { 01689 $updateData[$table][$thisNewUid][$field] = $currentValueArray; 01690 } 01691 } 01692 } 01693 break; 01694 } 01695 } 01696 } else $this->error('Error: no record was found in data array!',1); 01697 } else $this->error('Error: this records is NOT created it seems! ('.$table.':'.$uid.')',1); 01698 } 01699 if (count($updateData)) { 01700 $tce = $this->getNewTCE(); 01701 $tce->start($updateData,Array()); 01702 $tce->process_datamap(); 01703 #debug($updateData,'setFlexFormRelations()'); 01704 } 01705 } 01706 01719 function remapListedDBRecords_flexFormCallBack($pParams, $dsConf, $dataValue, $dataValue_ext1, $dataValue_ext2, $path) { 01720 01721 // Extract parameters: 01722 list($table,$uid,$field,$config) = $pParams; 01723 01724 // In case the $path is used as index without a trailing slash we will remove that 01725 if (!is_array($config['flexFormRels']['db'][$path]) && is_array($config['flexFormRels']['db'][ereg_replace('\/$','',$path)])) { 01726 $path = ereg_replace('\/$','',$path); 01727 } 01728 if (is_array($config['flexFormRels']['db'][$path])) { 01729 $valArray = $this->setRelations_db($config['flexFormRels']['db'][$path]); 01730 $dataValue = implode(',',$valArray); 01731 # debug(array('value' => $dataValue)); 01732 } 01733 01734 if (is_array($config['flexFormRels']['file'][$path])) { 01735 foreach($config['flexFormRels']['file'][$path] as $fI) { 01736 $valArr[] = $this->import_addFileNameToBeCopied($fI); 01737 } 01738 $dataValue = implode(',',$valArr); 01739 } 01740 01741 // Return 01742 return array('value' => $dataValue); 01743 } 01744 01745 01746 01747 01748 01749 01750 01751 01752 01753 01754 01755 /************************** 01756 * 01757 * Import / Soft References 01758 * 01759 *************************/ 01760 01766 function processSoftReferences() { 01767 global $TCA; 01768 01769 // Initialize: 01770 $inData = array(); 01771 01772 // Traverse records: 01773 if (is_array($this->dat['header']['records'])) { 01774 foreach($this->dat['header']['records'] as $table => $recs) { 01775 foreach($recs as $uid => $thisRec) { 01776 01777 // If there are soft references defined, traverse those: 01778 if (isset($TCA[$table]) && is_array($thisRec['softrefs'])) { 01779 t3lib_div::loadTCA($table); 01780 01781 // 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. 01782 $fieldsIndex = array(); 01783 foreach($thisRec['softrefs'] as $softrefDef) { 01784 01785 // If a substitution token is set: 01786 if ($softrefDef['field'] && is_array($softrefDef['subst']) && $softrefDef['subst']['tokenID']) { 01787 $fieldsIndex[$softrefDef['field']][$softrefDef['subst']['tokenID']] = $softrefDef; 01788 } 01789 } 01790 01791 // The new id: 01792 $thisNewUid = t3lib_BEfunc::wsMapId($table,$this->import_mapId[$table][$uid]); 01793 01794 // Now, if there are any fields that require substitution to be done, lets go for that: 01795 foreach($fieldsIndex as $field => $softRefCfgs) { 01796 if (is_array($TCA[$table]['columns'][$field])) { 01797 $conf = $TCA[$table]['columns'][$field]['config']; 01798 if ($conf['type']==='flex') { 01799 01800 $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.) 01801 if (is_array($origRecordRow)) { 01802 01803 // Get current data structure and value array: 01804 $dataStructArray = t3lib_BEfunc::getFlexFormDS($conf, $origRecordRow, $table); 01805 $currentValueArray = t3lib_div::xml2array($origRecordRow[$field]); 01806 01807 // Do recursive processing of the XML data: 01808 $iteratorObj = t3lib_div::makeInstance('t3lib_TCEmain'); 01809 $iteratorObj->callBackObj = &$this; 01810 $currentValueArray['data'] = $iteratorObj->checkValue_flex_procInData( 01811 $currentValueArray['data'], 01812 array(), // Not used. 01813 array(), // Not used. 01814 $dataStructArray, 01815 array($table,$uid,$field,$softRefCfgs), // Parameters (using old UID on purpose!) 01816 'processSoftReferences_flexFormCallBack' 01817 ); 01818 01819 // The return value is set as an array which means it will be processed by tcemain for file and DB references! 01820 if (is_array($currentValueArray['data'])) { 01821 $inData[$table][$thisNewUid][$field] = $currentValueArray; 01822 } 01823 } 01824 } else { 01825 // Get tokenizedContent string and proceed only if that is not blank: 01826 $tokenizedContent = $this->dat['records'][$table.':'.$uid]['rels'][$field]['softrefs']['tokenizedContent']; 01827 if (strlen($tokenizedContent) && is_array($softRefCfgs)) { 01828 $inData[$table][$thisNewUid][$field] = $this->processSoftReferences_substTokens($tokenizedContent, $softRefCfgs, $table, $uid); 01829 } 01830 } 01831 } 01832 } 01833 } 01834 } 01835 } 01836 } 01837 01838 // Now write to database: 01839 $tce = $this->getNewTCE(); 01840 $tce->enableLogging = TRUE; 01841 $tce->start($inData, Array()); 01842 $tce->process_datamap(); 01843 } 01844 01857 function processSoftReferences_flexFormCallBack($pParams, $dsConf, $dataValue, $dataValue_ext1, $dataValue_ext2, $path) { 01858 01859 // Extract parameters: 01860 list($table,$origUid,$field,$softRefCfgs) = $pParams; 01861 01862 if (is_array($softRefCfgs)) { 01863 01864 // First, find all soft reference configurations for this structure path (they are listed flat in the header): 01865 $thisSoftRefCfgList = array(); 01866 foreach($softRefCfgs as $sK => $sV) { 01867 if ($sV['structurePath']===$path) { 01868 $thisSoftRefCfgList[$sK] = $sV; 01869 } 01870 } 01871 01872 // If any was found, do processing: 01873 if (count($thisSoftRefCfgList)) { 01874 01875 // Get tokenizedContent string and proceed only if that is not blank: 01876 $tokenizedContent = $this->dat['records'][$table.':'.$origUid]['rels'][$field]['flexFormRels']['softrefs'][$path]['tokenizedContent']; 01877 if (strlen($tokenizedContent)) { 01878 $dataValue = $this->processSoftReferences_substTokens($tokenizedContent, $thisSoftRefCfgList, $table, $origUid); 01879 } 01880 } 01881 } 01882 01883 // Return 01884 return array('value' => $dataValue); 01885 } 01886 01896 function processSoftReferences_substTokens($tokenizedContent, $softRefCfgs, $table, $uid) { 01897 01898 // traverse each softref type for this field: 01899 foreach($softRefCfgs as $cfg) { 01900 01901 // Get token ID: 01902 $tokenID = $cfg['subst']['tokenID']; 01903 01904 // Default is current token value: 01905 $insertValue = $cfg['subst']['tokenValue']; 01906 01907 // Based on mode: 01908 switch((string)$this->softrefCfg[$tokenID]['mode']) { 01909 case 'exclude': 01910 // Exclude is a simple passthrough of the value 01911 break; 01912 case 'editable': 01913 // Editable always picks up the value from this input array: 01914 $insertValue = $this->softrefInputValues[$tokenID]; 01915 break; 01916 default: 01917 // Mapping IDs/creating files: Based on type, look up new value: 01918 switch((string)$cfg['subst']['type']) { 01919 case 'db': 01920 default: 01921 // Trying to map database element if found in the mapID array: 01922 list($tempTable,$tempUid) = explode(':',$cfg['subst']['recordRef']); 01923 if (isset($this->import_mapId[$tempTable][$tempUid])) { 01924 $insertValue = t3lib_BEfunc::wsMapId($tempTable,$this->import_mapId[$tempTable][$tempUid]); 01925 01926 // 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! 01927 if ($tempTable==='pages' && !t3lib_div::testInt($cfg['subst']['tokenValue'])) { 01928 $recWithUniqueValue = t3lib_BEfunc::getRecord($tempTable,$insertValue, 'alias'); 01929 if ($recWithUniqueValue['alias']) { 01930 $insertValue = $recWithUniqueValue['alias']; 01931 } 01932 } 01933 } 01934 break; 01935 break; 01936 case 'file': 01937 // Create / Overwrite file: 01938 $insertValue = $this->processSoftReferences_saveFile($cfg['subst']['relFileName'], $cfg, $table, $uid); 01939 break; 01940 } 01941 break; 01942 } 01943 01944 // Finally, swap the soft reference token in tokenized content with the insert value: 01945 $tokenizedContent = str_replace('{softref:'.$tokenID.'}', $insertValue, $tokenizedContent); 01946 } 01947 01948 return $tokenizedContent; 01949 } 01950 01960 function processSoftReferences_saveFile($relFileName, $cfg, $table, $uid) { 01961 01962 if ($fileHeaderInfo = $this->dat['header']['files'][$cfg['file_ID']]) { 01963 // Initialize; Get directory prefix for file and find possible RTE filename 01964 $dirPrefix = dirname($relFileName).'/'; 01965 $rteOrigName = $this->getRTEoriginalFilename(basename($relFileName)); 01966 01967 // If filename looks like an RTE file, and the directory is in "uploads/", then process as a RTE file! 01968 if ($rteOrigName && t3lib_div::isFirstPartOfStr($dirPrefix,'uploads/')) { // RTE: 01969 01970 // First, find unique RTE file name: 01971 if (@is_dir(PATH_site.$dirPrefix)) { 01972 01973 // 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... 01974 $fileProcObj = &$this->getFileProcObj(); 01975 $origDestName = $fileProcObj->getUniqueName($rteOrigName, PATH_site.$dirPrefix); 01976 01977 // Create copy file name: 01978 $pI = pathinfo($relFileName); 01979 $copyDestName = dirname($origDestName).'/RTEmagicC_'.substr(basename($origDestName),10).'.'.$pI['extension']; 01980 if (!@is_file($copyDestName) && !@is_file($origDestName) 01981 && $origDestName===t3lib_div::getFileAbsFileName($origDestName) && $copyDestName===t3lib_div::getFileAbsFileName($copyDestName)) { 01982 01983 if ($this->dat['header']['files'][$fileHeaderInfo['RTE_ORIG_ID']]) { 01984 01985 // Write the copy and original RTE file to the respective filenames: 01986 $this->writeFileVerify($copyDestName, $cfg['file_ID'], TRUE); 01987 $this->writeFileVerify($origDestName, $fileHeaderInfo['RTE_ORIG_ID'], TRUE); 01988 01989 // Return the relative path of the copy file name: 01990 return substr($copyDestName, strlen(PATH_site)); 01991 } else $this->error('ERROR: Could not find original file ID'); 01992 } else $this->error('ERROR: The destination filenames "'.$copyDestName.'" and "'.$origDestName.'" either existed or have non-valid names'); 01993 } else $this->error('ERROR: "'.PATH_site.$dirPrefix.'" was not a directory, so could not process file "'.$relFileName.'"'); 01994 01995 01996 } elseif (t3lib_div::isFirstPartOfStr($dirPrefix, $this->fileadminFolderName.'/')) { // File in fileadmin/ folder: 01997 01998 // Create file (and possible resources) 01999 $newFileName = $this->processSoftReferences_saveFile_createRelFile($dirPrefix,basename($relFileName),$cfg['file_ID'], $table, $uid); 02000 02001 if (strlen($newFileName)) { 02002 $relFileName = $newFileName; 02003 } else $this->error('ERROR: No new file created for "'.$relFileName.'"'); 02004 } else $this->error('ERROR: Sorry, cannot operate on non-RTE files which are outside the fileadmin folder.'); 02005 } else $this->error('ERROR: Could not find file ID in header.'); 02006 02007 // Return (new) filename relative to PATH_site: 02008 return $relFileName; 02009 } 02010 02021 function processSoftReferences_saveFile_createRelFile($origDirPrefix, $fileName, $fileID, $table, $uid) { 02022 02023 // 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! 02024 if ($this->fileIDMap[$fileID]) { 02025 return substr($this->fileIDMap[$fileID],strlen(PATH_site)); 02026 } 02027 02028 // Verify FileMount access to dir-prefix. Returns the best alternative relative path if any 02029 $dirPrefix = $this->verifyFolderAccess($origDirPrefix); 02030 02031 if ($dirPrefix && (!$this->update || $origDirPrefix===$dirPrefix) && $this->checkOrCreateDir($dirPrefix)) { 02032 $fileHeaderInfo = $this->dat['header']['files'][$fileID]; 02033 $updMode = $this->update && $this->import_mapId[$table][$uid]===$uid && $this->import_mode[$table.':'.$uid]!=='as_new'; 02034 // Create new name for file: 02035 if ($updMode) { // Must have same ID in map array (just for security, is not really needed) and NOT be set "as_new". 02036 $newName = PATH_site.$dirPrefix.$fileName; 02037 } else { 02038 // Create unique filename: 02039 $fileProcObj = &$this->getFileProcObj(); 02040 $newName = $fileProcObj->getUniqueName($fileName, PATH_site.$dirPrefix); 02041 } 02042 #debug($newName,'$newName'); 02043 02044 // Write main file: 02045 if ($this->writeFileVerify($newName, $fileID)) { 02046 02047 // If the resource was an HTML/CSS file with resources attached, we will write those as well! 02048 if (is_array($fileHeaderInfo['EXT_RES_ID'])) { 02049 #debug($fileHeaderInfo['EXT_RES_ID']); 02050 $tokenizedContent = $this->dat['files'][$fileID]['tokenizedContent']; 02051 $tokenSubstituted = FALSE; 02052 02053 $fileProcObj = &$this->getFileProcObj(); 02054 02055 if ($updMode) { 02056 foreach($fileHeaderInfo['EXT_RES_ID'] as $res_fileID) { 02057 if ($this->dat['files'][$res_fileID]['filename']) { 02058 02059 // Resolve original filename: 02060 $relResourceFileName = $this->dat['files'][$res_fileID]['parentRelFileName']; 02061 $absResourceFileName = t3lib_div::resolveBackPath(PATH_site.$origDirPrefix.$relResourceFileName); 02062 $absResourceFileName = t3lib_div::getFileAbsFileName($absResourceFileName); 02063 if ($absResourceFileName && t3lib_div::isFirstPartOfStr($absResourceFileName,PATH_site.$this->fileadminFolderName.'/')) { 02064 $destDir = substr(dirname($absResourceFileName).'/',strlen(PATH_site)); 02065 if ($this->verifyFolderAccess($destDir, TRUE) && $this->checkOrCreateDir($destDir)) { 02066 $this->writeFileVerify($absResourceFileName, $res_fileID); 02067 } else $this->error('ERROR: Could not create file in directory "'.$destDir.'"'); 02068 } else $this->error('ERROR: Could not resolve path for "'.$relResourceFileName.'"'); 02069 02070 $tokenizedContent = str_replace('{EXT_RES_ID:'.$res_fileID.'}', $relResourceFileName, $tokenizedContent); 02071 $tokenSubstituted = TRUE; 02072 } 02073 } 02074 } else { 02075 // Create the resouces directory name (filename without extension, suffixed "_FILES") 02076 $resourceDir = dirname($newName).'/'.ereg_replace('\.[^.]*$','',basename($newName)).'_FILES'; 02077 if (t3lib_div::mkdir($resourceDir)) { 02078 foreach($fileHeaderInfo['EXT_RES_ID'] as $res_fileID) { 02079 if ($this->dat['files'][$res_fileID]['filename']) { 02080 $absResourceFileName = $fileProcObj->getUniqueName($this->dat['files'][$res_fileID]['filename'], $resourceDir); 02081 $relResourceFileName = substr($absResourceFileName, strlen(dirname($resourceDir))+1); 02082 $this->writeFileVerify($absResourceFileName, $res_fileID); 02083 02084 $tokenizedContent = str_replace('{EXT_RES_ID:'.$res_fileID.'}', $relResourceFileName, $tokenizedContent); 02085 $tokenSubstituted = TRUE; 02086 } 02087 } 02088 } 02089 } 02090 02091 // If substitutions has been made, write the content to the file again: 02092 if ($tokenSubstituted) { 02093 t3lib_div::writeFile($newName, $tokenizedContent); 02094 } 02095 } 02096 02097 return substr($newName, strlen(PATH_site)); 02098 } 02099 } 02100 } 02101 02110 function writeFileVerify($fileName, $fileID, $bypassMountCheck=FALSE) { 02111 $fileProcObj = &$this->getFileProcObj(); 02112 02113 if ($fileProcObj->actionPerms['newFile']) { 02114 if ($fileProcObj->checkPathAgainstMounts($fileName) || $bypassMountCheck) { // Just for security, check again. Should actually not be necessary. 02115 $fI = t3lib_div::split_fileref($fileName); 02116 if ($fileProcObj->checkIfAllowed($fI['fileext'], $fI['path'], $fI['file']) || ($this->allowPHPScripts && $GLOBALS['BE_USER']->isAdmin())) { 02117 if (t3lib_div::getFileAbsFileName($fileName)) { 02118 if ($this->dat['files'][$fileID]) { 02119 t3lib_div::writeFile($fileName,$this->dat['files'][$fileID]['content']); 02120 $this->fileIDMap[$fileID] = $fileName; 02121 if (md5(t3lib_div::getUrl($fileName))==$this->dat['files'][$fileID]['content_md5']) { 02122 return TRUE; 02123 } else $this->error('ERROR: File content "'.$fileName.'" was corrupted'); 02124 } else $this->error('ERROR: File ID "'.$fileID.'" could not be found'); 02125 } else $this->error('ERROR: Filename "'.$fileName.'" was not a valid relative file path!'); 02126 } else $this->error('ERROR: Filename "'.$fileName.'" failed against extension check or deny-pattern!'); 02127 } else $this->error('ERROR: Filename "'.$fileName.'" was not allowed in destination path!'); 02128 } else $this->error('ERROR: You did not have sufficient permissions to write the file "'.$fileName.'"'); 02129 } 02130 02137 function checkOrCreateDir($dirPrefix) { 02138 02139 // Split dir path and remove first directory (which should be "fileadmin") 02140 $filePathParts = explode('/', $dirPrefix); 02141 $firstDir = array_shift($filePathParts); 02142 02143 if ($firstDir===$this->fileadminFolderName && t3lib_div::getFileAbsFileName($dirPrefix)) { 02144 02145 $pathAcc = ''; 02146 foreach($filePathParts as $dirname) { 02147 $pathAcc.='/'.$dirname; 02148 if (strlen($dirname)) { 02149 if (!@is_dir(PATH_site.$this->fileadminFolderName.$pathAcc)) { 02150 if (!t3lib_div::mkdir(PATH_site.$this->fileadminFolderName.$pathAcc)) { 02151 $this->error('ERROR: Directory could not be created....B'); 02152 return FALSE; 02153 } 02154 } 02155 } elseif ($dirPrefix===$this->fileadminFolderName.$pathAcc) { 02156 return TRUE; 02157 } else $this->error('ERROR: Directory could not be created....A'); 02158 } 02159 } 02160 } 02161 02170 function verifyFolderAccess($dirPrefix, $noAlternative=FALSE) { 02171 $fileProcObj = &$this->getFileProcObj(); 02172 02173 #$fileProcObj->mounts['1f390e42e1dc46f125310ead30c7bd9d']['path'] = '/var/www/typo3/dev/testsite-3.6.0/fileadmin/user_upload/'; 02174 02175 // Check, if dirPrefix is inside a valid Filemount for user: 02176 $result = $fileProcObj->checkPathAgainstMounts(PATH_site.$dirPrefix); 02177 02178 // If not, try to find another relative filemount and use that instead: 02179 if (!$result) { 02180 if ($noAlternative) return FALSE; 02181 02182 // Find first web folder: 02183 $result = $fileProcObj->findFirstWebFolder(); 02184 02185 // If that succeeded, return the path to it: 02186 if ($result) { 02187 // Remove the "fileadmin/" prefix of input path - and append the rest to the return value: 02188 if (t3lib_div::isFirstPartOfStr($dirPrefix,$this->fileadminFolderName.'/')) { 02189 $dirPrefix = substr($dirPrefix,strlen($this->fileadminFolderName.'/')); 02190 } 02191 return substr($fileProcObj->mounts[$result]['path'].$dirPrefix,strlen(PATH_site)); 02192 } 02193 } else { 02194 return $dirPrefix; 02195 } 02196 } 02197 02198 02199 02200 02201 02202 02203 02204 02205 02206 02207 /************************** 02208 * 02209 * File Input 02210 * 02211 *************************/ 02212 02220 function loadFile($filename,$all=0) { 02221 if (@is_file($filename)) { 02222 $fI = pathinfo($filename); 02223 if (strtolower($fI['extension'])=='xml') { 02224 // XML: 02225 $xmlContent = t3lib_div::getUrl($filename); 02226 if (strlen($xmlContent)) { 02227 $this->dat = t3lib_div::xml2array($xmlContent,'',TRUE); 02228 if (is_array($this->dat)) { 02229 if ($this->dat['_DOCUMENT_TAG']==='T3RecordDocument' && is_array($this->dat['header']) && is_array($this->dat['records'])) { 02230 $this->loadInit(); 02231 return TRUE; 02232 } else $this->error('XML file did not contain proper XML for TYPO3 Import'); 02233 } else $this->error('XML could not be parsed: '.$this->dat); 02234 } else $this->error('Error opening file: '.$filename); 02235 } else { 02236 // T3D 02237 if($fd = fopen($filename,'rb')) { 02238 $this->dat['header'] = $this->getNextFilePart($fd,1,'header'); 02239 if ($all) { 02240 $this->dat['records'] = $this->getNextFilePart($fd,1,'records'); 02241 $this->dat['files'] = $this->getNextFilePart($fd,1,'files'); 02242 } 02243 $this->loadInit(); 02244 return TRUE; 02245 } else $this->error('Error opening file: '.$filename); 02246 fclose($fd); 02247 } 02248 } else $this->error('Filename not found: '.$filename); 02249 02250 return FALSE; 02251 } 02252 02263 function getNextFilePart($fd,$unserialize=0,$name='') { 02264 $initStrLen = 32+1+1+1+10+1; 02265 02266 // getting header data 02267 $initStr = fread($fd, $initStrLen); 02268 $initStrDat = explode(':',$initStr); 02269 if (strstr($initStrDat[0],'Warning') == FALSE) { 02270 if (!strcmp($initStrDat[3],'')) { 02271 $datString = fread($fd,intval($initStrDat[2])); 02272 fread($fd,1); 02273 if (!strcmp(md5($datString), $initStrDat[0])) { 02274 if ($initStrDat[1]) { 02275 if ($this->compress) { 02276 $datString = gzuncompress($datString); 02277 } else $this->error('Content read error: This file requires decompression, but this server does not offer gzcompress()/gzuncompress() functions.',1); 02278 } 02279 return $unserialize ? unserialize($datString) : $datString; 02280 } else $this->error('MD5 check failed ('.$name.')'); 02281 } else $this->error('File read error: InitString had a wrong length. ('.$name.')'); 02282 } else $this->error('File read error: Warning message in file. ('.$initStr.fgets($fd).')'); 02283 } 02284 02292 function loadContent($filecontent) { 02293 $pointer = 0; 02294 02295 $this->dat['header'] = $this->getNextContentPart($filecontent,$pointer,1,'header'); 02296 $this->dat['records'] = $this->getNextContentPart($filecontent,$pointer,1,'records'); 02297 $this->dat['files'] = $this->getNextContentPart($filecontent,$pointer,1,'files'); 02298 $this->loadInit(); 02299 } 02300 02310 function getNextContentPart($filecontent,&$pointer,$unserialize=0,$name='') { 02311 $initStrLen = 32+1+1+1+10+1; 02312 // getting header data 02313 $initStr = substr($filecontent,$pointer,$initStrLen); 02314 $pointer+= $initStrLen; 02315 $initStrDat = explode(':',$initStr); 02316 if (!strcmp($initStrDat[3],'')) { 02317 $datString = substr($filecontent,$pointer,intval($initStrDat[2])); 02318 $pointer+= intval($initStrDat[2])+1; 02319 if (!strcmp(md5($datString),$initStrDat[0])) { 02320 if ($initStrDat[1]) { 02321 if ($this->compress) { 02322 $datString = gzuncompress($datString); 02323 } else $this->error('Content read error: This file requires decompression, but this server does not offer gzcompress()/gzuncompress() functions.',1); 02324 } 02325 return $unserialize ? unserialize($datString) : $datString; 02326 } else $this->error('MD5 check failed ('.$name.')'); 02327 } else $this->error('Content read error: InitString had a wrong length. ('.$name.')'); 02328 } 02329 02335 function loadInit() { 02336 $this->relStaticTables = (array)$this->dat['header']['relStaticTables']; 02337 $this->excludeMap = (array)$this->dat['header']['excludeMap']; 02338 02339 $this->softrefCfg = (array)$this->dat['header']['softrefCfg']; 02340 $this->extensionDependencies = (array)$this->dat['header']['extensionDependencies']; 02341 02342 $this->fixCharsets(); 02343 } 02344 02351 function fixCharsets() { 02352 global $LANG; 02353 02354 $importCharset = $this->dat['header']['charset']; 02355 if ($importCharset) { 02356 if ($importCharset!==$LANG->charSet) { 02357 $this->error('CHARSET: Converting charset of input file ('.$importCharset.') to the system charset ('.$LANG->charSet.')'); 02358 02359 // convert meta data: 02360 if (is_array($this->dat['header']['meta'])) { 02361 $LANG->csConvObj->convArray($this->dat['header']['meta'],$importCharset,$LANG->charSet); 02362 } 02363 // convert record headers: 02364 if (is_array($this->dat['header']['records'])) { 02365 $LANG->csConvObj->convArray($this->dat['header']['records'],$importCharset,$LANG->charSet); 02366 } 02367 // convert records themselves: 02368 if (is_array($this->dat['records'])) { 02369 $LANG->csConvObj->convArray($this->dat['records'],$importCharset,$LANG->charSet); 02370 } 02371 } 02372 } else { 02373 $this->error('CHARSET: No charset found in import file!'); 02374 } 02375 } 02376 02377 02378 02379 02380 02381 02382 02383 02384 02385 02386 02387 02388 02389 02390 02391 02392 02393 02394 02395 /******************************************************** 02396 * 02397 * Visual rendering of import/export memory, $this->dat 02398 * 02399 ********************************************************/ 02400 02406 function displayContentOverview() { 02407 global $LANG; 02408 02409 // Check extension dependencies: 02410 if (is_array($this->dat['header']['extensionDependencies'])) { 02411 foreach($this->dat['header']['extensionDependencies'] as $extKey) { 02412 if (!t3lib_extMgm::isLoaded($extKey)) { 02413 $this->error('DEPENDENCY: The extension with key "'.$extKey.'" must be installed!'); 02414 } 02415 } 02416 } 02417 02418 // Probably this is done to save memory space? 02419 unset($this->dat['files']); 02420 02421 // Traverse header: 02422 $this->remainHeader = $this->dat['header']; 02423 if (is_array($this->remainHeader)) { 02424 02425 // If there is a page tree set, show that: 02426 if (is_array($this->dat['header']['pagetree'])) { 02427 reset($this->dat['header']['pagetree']); 02428 $lines = array(); 02429 $this->traversePageTree($this->dat['header']['pagetree'],$lines); 02430 02431 $rows = array(); 02432 $rows[] = ' 02433 <tr class="bgColor5 tableheader"> 02434 <td>'.$LANG->getLL('impexpcore_displaycon_controls',1).'</td> 02435 <td>'.$LANG->getLL('impexpcore_displaycon_title',1).'</td> 02436 <td>'.$LANG->getLL('impexpcore_displaycon_size',1).'</td> 02437 <td>'.$LANG->getLL('impexpcore_displaycon_message',1).'</td> 02438 '.($this->update ? '<td>'.$LANG->getLL('impexpcore_displaycon_updateMode',1).'</td>' : '').' 02439 '.($this->update ? '<td>'.$LANG->getLL('impexpcore_displaycon_currentPath',1).'</td>' : '').' 02440 '.($this->showDiff ? '<td>'.$LANG->getLL('impexpcore_displaycon_result',1).'</td>' : '').' 02441 </tr>'; 02442 02443 foreach($lines as $r) { 02444 $rows[] = ' 02445 <tr class="'.$r['class'].'"> 02446 <td>'.$this->renderControls($r).'</td> 02447 <td nowrap="nowrap">'.$r['preCode'].$r['title'].'</td> 02448 <td nowrap="nowrap">'.t3lib_div::formatSize($r['size']).'</td> 02449 <td nowrap="nowrap">'.($r['msg'] && !$this->doesImport ? '<span class="typo3-red">'.htmlspecialchars($r['msg']).'</span>' : '').'</td> 02450 '.($this->update ? '<td nowrap="nowrap">'.$r['updateMode'].'</td>' : '').' 02451 '.($this->update ? '<td nowrap="nowrap">'.$r['updatePath'].'</td>' : '').' 02452 '.($this->showDiff ? '<td>'.$r['showDiffContent'].'</td>' : '').' 02453 </tr>'; 02454 } 02455 02456 $out = ' 02457 <strong>'.$LANG->getLL('impexpcore_displaycon_insidePagetree',1).'</strong> 02458 <br /><br /> 02459 <table border="0" cellpadding="0" cellspacing="1">'.implode('',$rows).'</table> 02460 <br /><br />'; 02461 } 02462 02463 // Print remaining records that were not contained inside the page tree: 02464 $lines = array(); 02465 if (is_array($this->remainHeader['records'])) { 02466 if (is_array($this->remainHeader['records']['pages'])) { 02467 $this->traversePageRecords($this->remainHeader['records']['pages'], $lines); 02468 } 02469 $this->traverseAllRecords($this->remainHeader['records'], $lines); 02470 02471 if (count($lines)) { 02472 $rows = array(); 02473 $rows[] = ' 02474 <tr class="bgColor5 tableheader"> 02475 <td>'.$LANG->getLL('impexpcore_displaycon_controls',1).'</td> 02476 <td>'.$LANG->getLL('impexpcore_displaycon_title',1).'</td> 02477 <td>'.$LANG->getLL('impexpcore_displaycon_size',1).'</td> 02478 <td>'.$LANG->getLL('impexpcore_displaycon_message',1).'</td> 02479 '.($this->update ? '<td>'.$LANG->getLL('impexpcore_displaycon_updateMode',1).'</td>' : '').' 02480 '.($this->update ? '<td>'.$LANG->getLL('impexpcore_displaycon_currentPath',1).'</td>' : '').' 02481 '.($this->showDiff ? '<td>'.$LANG->getLL('impexpcore_displaycon_result',1).'</td>' : '').' 02482 </tr>'; 02483 02484 foreach($lines as $r) { 02485 $rows[] = '<tr class="'.$r['class'].'"> 02486 <td>'.$this->renderControls($r).'</td> 02487 <td nowrap="nowrap">'.$r['preCode'].$r['title'].'</td> 02488 <td nowrap="nowrap">'.t3lib_div::formatSize($r['size']).'</td> 02489 <td nowrap="nowrap">'.($r['msg'] && !$this->doesImport ? '<span class="typo3-red">'.htmlspecialchars($r['msg']).'</span>' : '').'</td> 02490 '.($this->update ? '<td nowrap="nowrap">'.$r['updateMode'].'</td>' : '').' 02491 '.($this->update ? '<td nowrap="nowrap">'.$r['updatePath'].'</td>' : '').' 02492 '.($this->showDiff ? '<td>'.$r['showDiffContent'].'</td>' : '').' 02493 </tr>'; 02494 } 02495 02496 $out.= ' 02497 <strong>'.$LANG->getLL('impexpcore_singlereco_outsidePagetree',1).'</strong> 02498 <br /><br /> 02499 <table border="0" cellpadding="0" cellspacing="1">'.implode('',$rows).'</table>'; 02500 } 02501 } 02502 } 02503 return $out; 02504 } 02505 02514 function traversePageTree($pT,&$lines,$preCode='') { 02515 reset($pT); 02516 while(list($k,$v) = each($pT)) { 02517 02518 // Add this page: 02519 $this->singleRecordLines('pages',$k,$lines,$preCode); 02520 02521 // Subrecords: 02522 if (is_array($this->dat['header']['pid_lookup'][$k])) { 02523 reset($this->dat['header']['pid_lookup'][$k]); 02524 while(list($t,$recUidArr)=each($this->dat['header']['pid_lookup'][$k])) { 02525 if ($t!='pages') { 02526 reset($recUidArr); 02527 while(list($ruid)=each($recUidArr)) { 02528 $this->singleRecordLines($t,$ruid,$lines,$preCode.' '); 02529 } 02530 } 02531 } 02532 unset($this->remainHeader['pid_lookup'][$k]); 02533 } 02534 02535 // Subpages, called recursively: 02536 if (is_array($v['subrow'])) { 02537 $this->traversePageTree($v['subrow'],$lines,$preCode.' '); 02538 } 02539 } 02540 } 02541 02549 function traversePageRecords($pT,&$lines) { 02550 reset($pT); 02551 while(list($k,$rHeader)=each($pT)) { 02552 $this->singleRecordLines('pages',$k,$lines,'',1); 02553 // Subrecords: 02554 if (is_array($this->dat['header']['pid_lookup'][$k])) { 02555 reset($this->dat['header']['pid_lookup'][$k]); 02556 while(list($t,$recUidArr)=each($this->dat['header']['pid_lookup'][$k])) { 02557 if ($t!='pages') { 02558 reset($recUidArr); 02559 while(list($ruid)=each($recUidArr)) { 02560 $this->singleRecordLines($t,$ruid,$lines,' '); 02561 } 02562 } 02563 } 02564 unset($this->remainHeader['pid_lookup'][$k]); 02565 } 02566 } 02567 } 02568 02576 function traverseAllRecords($pT,&$lines) { 02577 reset($pT); 02578 while(list($t,$recUidArr)=each($pT)) { 02579 if ($t!='pages') { 02580 reset($recUidArr); 02581 while(list($ruid)=each($recUidArr)) { 02582 $this->singleRecordLines($t,$ruid,$lines,$preCode,1); 02583 } 02584 } 02585 } 02586 } 02587 02598 function singleRecordLines($table,$uid,&$lines,$preCode,$checkImportInPidRecord=0) { 02599 global $TCA,$BE_USER,$LANG; 02600 02601 // Get record: 02602 $record = $this->dat['header']['records'][$table][$uid]; 02603 unset($this->remainHeader['records'][$table][$uid]); 02604 if (!is_array($record) && !($table==='pages' && !$uid)) $this->error('MISSING RECORD: '.$table.':'.$uid,1); 02605 02606 // Begin to create the line arrays information record, pInfo: 02607 $pInfo = array(); 02608 $pInfo['ref'] = $table.':'.$uid; 02609 if ($table==='_SOFTREF_') { // Unknown table name: 02610 $pInfo['preCode'] = $preCode; 02611 $pInfo['title'] = '<em>'.$LANG->getLL('impexpcore_singlereco_softReferencesFiles',1).'</em>'; 02612 } elseif (!isset($TCA[$table])) { // Unknown table name: 02613 $pInfo['preCode'] = $preCode; 02614 $pInfo['msg'] = "UNKNOWN TABLE '".$pInfo['ref']."'"; 02615 $pInfo['title'] = '<em>'.htmlspecialchars($record['title']).'</em>'; 02616 } else { // Otherwise, set table icon and title. 02617 02618 // Import Validation (triggered by $this->display_import_pid_record) will show messages if import is not possible of various items. 02619 if (is_array($this->display_import_pid_record)) { 02620 if ($checkImportInPidRecord) { 02621 if (!$BE_USER->doesUserHaveAccess($this->display_import_pid_record, $table=='pages'?8:16)) { 02622 $pInfo['msg'].="'".$pInfo['ref']."' cannot be INSERTED on this page! "; 02623 } 02624 if (!$this->checkDokType($table, $this->display_import_pid_record['doktype']) && !$TCA[$table]['ctrl']['rootLevel']) { 02625 $pInfo['msg'].="'".$table."' cannot be INSERTED on this page type (change to 'sysFolder'!) "; 02626 } 02627 } 02628 if (!$BE_USER->check('tables_modify',$table)) {$pInfo['msg'].="You are not allowed to CREATE '".$table."' tables! ";} 02629 02630 if ($TCA[$table]['ctrl']['readOnly']) {$pInfo['msg'].="TABLE '".$table."' is READ ONLY! ";} 02631 if ($TCA[$table]['ctrl']['adminOnly'] && !$BE_USER->isAdmin()) {$pInfo['msg'].="TABLE '".$table."' is ADMIN ONLY! ";} 02632 if ($TCA[$table]['ctrl']['is_static']) {$pInfo['msg'].="TABLE '".$table."' is a STATIC TABLE! ";} 02633 if ($TCA[$table]['ctrl']['rootLevel']) {$pInfo['msg'].="TABLE '".$table."' will be inserted on ROOT LEVEL! ";} 02634 02635 $diffInverse = FALSE; 02636 if ($this->update) { 02637 $diffInverse = TRUE; // In case of update-PREVIEW we swap the diff-sources. 02638 $recInf = $this->doesRecordExist($table, $uid, $this->showDiff ? '*' : ''); 02639 $pInfo['updatePath']= $recInf ? htmlspecialchars($this->getRecordPath($recInf['pid'])) : '<b>NEW!</b>'; 02640 02641 // Mode selector: 02642 $optValues = array(); 02643 $optValues[] = $recInf ? $LANG->getLL('impexpcore_singlereco_update') : $LANG->getLL('impexpcore_singlereco_insert'); 02644 if ($recInf) $optValues['as_new'] = $LANG->getLL('impexpcore_singlereco_importAsNew'); 02645 if ($recInf) { 02646 if (!$this->global_ignore_pid) { 02647 $optValues['ignore_pid'] = $LANG->getLL('impexpcore_singlereco_ignorePid'); 02648 } else { 02649 $optValues['respect_pid'] = $LANG->getLL('impexpcore_singlereco_respectPid'); 02650 } 02651 } 02652 if (!$recInf && $GLOBALS['BE_USER']->isAdmin()) $optValues['force_uid'] = sprintf($LANG->getLL('impexpcore_singlereco_forceUidSAdmin'),$uid); 02653 $optValues['exclude'] = $LANG->getLL('impexpcore_singlereco_exclude'); 02654 02655 $pInfo['updateMode'] = $this->renderSelectBox('tx_impexp[import_mode]['.$table.':'.$uid.']',$this->import_mode[$table.':'.$uid],$optValues); 02656 } 02657 02658 // Diff vieiw: 02659 if ($this->showDiff) { 02660 // For IMPORTS, get new id: 02661 if ($newUid = $this->import_mapId[$table][$uid]) { 02662 $diffInverse = FALSE; 02663 $recInf = $this->doesRecordExist($table, $newUid, '*'); 02664 t3lib_BEfunc::workspaceOL($table,$recInf); 02665 } 02666 if (is_array($recInf)) { 02667 $pInfo['showDiffContent'] = $this->compareRecords($recInf, $this->dat['records'][$table.':'.$uid]['data'], $table, $diffInverse); 02668 } 02669 } 02670 } 02671 02672 $pInfo['preCode'] = $preCode.t3lib_iconworks::getIconImage($table,$this->dat['records'][$table.':'.$uid]['data'],$GLOBALS['BACK_PATH'],'align="top" title="'.htmlspecialchars($table.':'.$uid).'"'); 02673 $pInfo['title'] = htmlspecialchars($record['title']); 02674 02675 // View page: 02676 if ($table==='pages') { 02677 $viewID = $this->mode === 'export' ? $uid : ($this->doesImport ? $this->import_mapId['pages'][$uid] : 0); 02678 if ($viewID) { 02679 $pInfo['title'] = '<a href="#" onclick="'.htmlspecialchars(t3lib_BEfunc::viewOnClick($viewID, $GLOBALS['BACK_PATH'])).'return false;">'.$pInfo['title'].'</a>'; 02680 } 02681 } 02682 } 02683 $pInfo['class'] = $table=='pages' ? 'bgColor4-20' : 'bgColor4'; 02684 $pInfo['type'] = 'record'; 02685 $pInfo['size'] = $record['size']; 02686 $lines[] = $pInfo; 02687 02688 // File relations: 02689 if (is_array($record['filerefs'])) { 02690 $this->addFiles($record['filerefs'],$lines,$preCode); 02691 } 02692 02693 // DB relations 02694 if (is_array($record['rels'])) { 02695 $this->addRelations($record['rels'],$lines,$preCode); 02696 } 02697 02698 // Soft ref 02699 if (count($record['softrefs'])) { 02700 $preCode_A = $preCode.' '; 02701 $preCode_B = $preCode.' '; 02702 foreach($record['softrefs'] as $info) { 02703 $pInfo = array(); 02704 $pInfo['preCode'] = $preCode_A.'<img'.t3lib_iconWorks::skinImg($GLOBALS['BACK_PATH'],'gfx/rel_softref.png','width="13" height="12"').' align="top" alt="" />'; 02705 $pInfo['title'] = '<em>'.$info['field'].', "'.$info['spKey'].'" </em>: <span title="'.htmlspecialchars($info['matchString']).'">'.htmlspecialchars(t3lib_div::fixed_lgd_cs($info['matchString'],60)).'</span>'; 02706 if ($info['subst']['type']) { 02707 if (strlen($info['subst']['title'])) { 02708 $pInfo['title'].= '<br/>'.$preCode_B.'<b>'.$LANG->getLL('impexpcore_singlereco_title',1).'</b> '.htmlspecialchars(t3lib_div::fixed_lgd_cs($info['subst']['title'],60)); 02709 } 02710 if (strlen($info['subst']['description'])) { 02711 $pInfo['title'].= '<br/>'.$preCode_B.'<b>'.$LANG->getLL('impexpcore_singlereco_descr',1).'</b> '.htmlspecialchars(t3lib_div::fixed_lgd_cs($info['subst']['description'],60)); 02712 } 02713 $pInfo['title'].= '<br/>'.$preCode_B. 02714 ($info['subst']['type'] == 'file' ? $LANG->getLL('impexpcore_singlereco_filename',1).' <b>'.$info['subst']['relFileName'].'</b>' : ''). 02715 ($info['subst']['type'] == 'string' ? $LANG->getLL('impexpcore_singlereco_value',1).' <b>'.$info['subst']['tokenValue'].'</b>' : ''). 02716 ($info['subst']['type'] == 'db' ? $LANG->getLL('impexpcore_softrefsel_record',1).' <b>'.$info['subst']['recordRef'].'</b>' : ''); 02717 } 02718 $pInfo['ref'] = 'SOFTREF'; 02719 $pInfo['size'] = ''; 02720 $pInfo['class'] = 'bgColor3'; 02721 $pInfo['type'] = 'softref'; 02722 $pInfo['_softRefInfo'] = $info; 02723 $pInfo['type'] = 'softref'; 02724 if ($info['error'] && !t3lib_div::inList('editable,exclude',$this->softrefCfg[$info['subst']['tokenID']]['mode'])) { 02725 $pInfo['msg'].= $info['error']; 02726 } 02727 $lines[] = $pInfo; 02728 02729 // Add relations: 02730 if ($info['subst']['type'] == 'db') { 02731 list($tempTable, $tempUid) = explode(':', $info['subst']['recordRef']); 02732 $this->addRelations(array(array('table' => $tempTable, 'id' => $tempUid, 'tokenID' => $info['subst']['tokenID'])),$lines,$preCode_B,array(), ''); 02733 } 02734 02735 // Add files: 02736 if ($info['subst']['type'] == 'file') { 02737 #debug($info); 02738 $this->addFiles(array($info['file_ID']),$lines,$preCode_B, '', $info['subst']['tokenID']); 02739 } 02740 } 02741 } 02742 } 02743 02756 function addRelations($rels,&$lines,$preCode,$recurCheck=array(),$htmlColorClass='') { 02757 02758 foreach($rels as $dat) { 02759 $table = $dat['table']; 02760 $uid = $dat['id']; 02761 $pInfo = array(); 02762 $Iprepend = ''; 02763 $staticFixed = FALSE; 02764 $pInfo['ref'] = $table.':'.$uid; 02765 if (!in_array($pInfo['ref'],$recurCheck)) { 02766 if ($uid > 0) { 02767 $record = $this->dat['header']['records'][$table][$uid]; 02768 if (!is_array($record)) { 02769 if ($this->isTableStatic($table) || $this->isExcluded($table, $uid) || ($dat['tokenID'] && !$this->includeSoftref($dat['tokenID']))) { 02770 $pInfo['title'] = htmlspecialchars('STATIC: '.$pInfo['ref']); 02771 $Iprepend = '_static'; 02772 $staticFixed = TRUE; 02773 } else { 02774 $doesRE = $this->doesRecordExist($table,$uid); 02775 $lostPath = $this->getRecordPath($table==='pages' ? $doesRE['uid'] : $doesRE['pid']); 02776 02777 $pInfo['title'] = htmlspecialchars($pInfo['ref']); 02778 $pInfo['title'] = '<span title="'.htmlspecialchars($lostPath).'">'.$pInfo['title'].'</span>'; 02779 02780 $pInfo['msg'] = 'LOST RELATION'.(!$doesRE ? ' (Record not found!)' : ' (Path: '.$lostPath.')'); 02781 $Iprepend = '_lost'; 02782 # debug('MISSING relation: '.$table.':'.$uid,1); 02783 } 02784 } else { 02785 $pInfo['title'] = htmlspecialchars($record['title']); 02786 $pInfo['title'] = '<span title="'.htmlspecialchars($this->getRecordPath($table==='pages' ? $record['uid'] : $record['pid'])).'">'.$pInfo['title'].'</span>'; 02787 02788 # $pInfo['size'] = $record['size']; 02789 } 02790 } 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 02791 $pInfo['title'] = htmlspecialchars('FIXED: '.$pInfo['ref']); 02792 $staticFixed = TRUE; 02793 } 02794 02795 $pInfo['preCode'] = $preCode.' <img'.t3lib_iconWorks::skinImg($GLOBALS['BACK_PATH'],'gfx/rel_db'.$Iprepend.'.gif','width="13" height="12"').' align="top" title="'.htmlspecialchars($pInfo['ref']).'" alt="" />'; 02796 $pInfo['class'] = $htmlColorClass ? $htmlColorClass : 'bgColor3'; 02797 $pInfo['type'] = 'rel'; 02798 02799 if (!$staticFixed || $this->showStaticRelations) { 02800 $lines[] = $pInfo; 02801 if (is_array($record) && is_array($record['rels'])) { 02802 $this->addRelations($record['rels'], $lines, $preCode.' ', array_merge($recurCheck,array($pInfo['ref'])), $htmlColorClass); 02803 } 02804 } 02805 } else $this->error($pInfo['ref'].' was recursive...'); 02806 } 02807 } 02808 02821 function addFiles($rels,&$lines,$preCode,$htmlColorClass='',$tokenID='') { 02822 02823 foreach($rels as $ID) { 02824 02825 // Process file: 02826 $pInfo = array(); 02827 $fI = $this->dat['header']['files'][$ID]; 02828 if (!is_array($fI)) { 02829 if (!$tokenID || $this->includeSoftref($tokenID)) { 02830 $pInfo['msg'] = 'MISSING FILE: '.$ID; 02831 $this->error('MISSING FILE: '.$ID,1); 02832 } else { 02833 return; 02834 } 02835 } 02836 $pInfo['preCode'] = $preCode.' <img'.t3lib_iconWorks::skinImg($GLOBALS['BACK_PATH'],'gfx/rel_file.gif','width="13" height="12"').' align="top" alt="" />'; 02837 $pInfo['title'] = htmlspecialchars($fI['filename']); 02838 $pInfo['ref'] = 'FILE'; 02839 $pInfo['size'] = $fI['filesize']; 02840 $pInfo['class'] = $htmlColorClass ? $htmlColorClass : 'bgColor3'; 02841 $pInfo['type'] = 'file'; 02842 02843 // If import mode and there is a non-RTE softreference, check the destination directory: 02844 if ($this->mode==='import' && $tokenID && !$fI['RTE_ORIG_ID']) { 02845 if (isset($fI['parentRelFileName'])) { 02846 $pInfo['msg'] = 'Seems like this file is already referenced from within an HTML/CSS file. That takes precedence. '; 02847 } else { 02848 $testDirPrefix = dirname($fI['relFileName']).'/'; 02849 $testDirPrefix2 = $this->verifyFolderAccess($testDirPrefix); 02850 02851 if (!$testDirPrefix2) { 02852 $pInfo['msg'] = 'ERROR: There are no available filemounts to write file in! '; 02853 } elseif (strcmp($testDirPrefix,$testDirPrefix2)) { 02854 $pInfo['msg'] = 'File will be attempted written to "'.$testDirPrefix2.'". '; 02855 } 02856 } 02857 02858 02859 // Check if file exists: 02860 if (@file_exists(PATH_site.$fI['relFileName'])) { 02861 if ($this->update) { 02862 $pInfo['updatePath'].= 'File exists.'; 02863 } else { 02864 $pInfo['msg'].= 'File already exists! '; 02865 } 02866 } 02867 02868 // Check extension: 02869 $fileProcObj = &$this->getFileProcObj(); 02870 if ($fileProcObj->actionPerms['newFile']) { 02871 $testFI = t3lib_div::split_fileref(PATH_site.$fI['relFileName']); 02872 if (!$this->allowPHPScripts && !$fileProcObj->checkIfAllowed($testFI['fileext'], $testFI['path'], $testFI['file'])) { 02873 $pInfo['msg'].= 'File extension was not allowed!'; 02874 } 02875 } else $pInfo['msg'] = 'You user profile does not allow you to create files on the server!'; 02876 } 02877 02878 $pInfo['showDiffContent'] = substr($this->fileIDMap[$ID],strlen(PATH_site)); 02879 02880 $lines[] = $pInfo; 02881 unset($this->remainHeader['files'][$ID]); 02882 02883 // RTE originals: 02884 if ($fI['RTE_ORIG_ID']) { 02885 $ID = $fI['RTE_ORIG_ID']; 02886 $pInfo = array(); 02887 $fI = $this->dat['header']['files'][$ID]; 02888 if (!is_array($fI)) { 02889 $pInfo['msg'] = 'MISSING RTE original FILE: '.$ID; 02890 $this->error('MISSING RTE original FILE: '.$ID,1); 02891 } 02892 02893 $pInfo['showDiffContent'] = substr($this->fileIDMap[$ID],strlen(PATH_site)); 02894 02895 $pInfo['preCode'] = $preCode.' <img'.t3lib_iconWorks::skinImg($GLOBALS['BACK_PATH'],'gfx/rel_file.gif','width="13" height="12"').' align="top" alt="" />'; 02896 $pInfo['title'] = htmlspecialchars($fI['filename']).' <em>(Original)</em>'; 02897 $pInfo['ref'] = 'FILE'; 02898 $pInfo['size'] = $fI['filesize']; 02899 $pInfo['class'] = $htmlColorClass ? $htmlColorClass : 'bgColor3'; 02900 $pInfo['type'] = 'file'; 02901 $lines[] = $pInfo; 02902 unset($this->remainHeader['files'][$ID]); 02903 } 02904 02905 // External resources: 02906 if (is_array($fI['EXT_RES_ID'])) { 02907 foreach($fI['EXT_RES_ID'] as $ID) { 02908 $pInfo = array(); 02909 $fI = $this->dat['header']['files'][$ID]; 02910 if (!is_array($fI)) { 02911 $pInfo['msg'] = 'MISSING External Resource FILE: '.$ID; 02912 $this->error('MISSING External Resource FILE: '.$ID,1); 02913 } else { 02914 $pInfo['updatePath'] = $fI['parentRelFileName']; 02915 } 02916 02917 $pInfo['showDiffContent'] = substr($this->fileIDMap[$ID],strlen(PATH_site)); 02918 02919 $pInfo['preCode'] = $preCode.' <img'.t3lib_iconWorks::skinImg($GLOBALS['BACK_PATH'],'gfx/rel_file.gif','width="13" height="12"').' align="top" alt="" />'; 02920 $pInfo['title'] = htmlspecialchars($fI['filename']).' <em>(Resource)</em>'; 02921 $pInfo['ref'] = 'FILE'; 02922 $pInfo['size'] = $fI['filesize']; 02923 $pInfo['class'] = $htmlColorClass ? $htmlColorClass : 'bgColor3'; 02924 $pInfo['type'] = 'file'; 02925 $lines[] = $pInfo; 02926 unset($this->remainHeader['files'][$ID]); 02927 } 02928 } 02929 } 02930 } 02931 02939 function checkDokType($checkTable,$doktype) { 02940 global $PAGES_TYPES; 02941 $allowedTableList = isset($PAGES_TYPES[$doktype]['allowedTables']) ? $PAGES_TYPES[$doktype]['allowedTables'] : $PAGES_TYPES['default']['allowedTables']; 02942 $allowedArray = t3lib_div::trimExplode(',',$allowedTableList,1); 02943 if (strstr($allowedTableList,'*') || in_array($checkTable,$allowedArray)) { // If all tables or the table is listed as a allowed type, return true 02944 return true; 02945 } 02946 } 02947 02955 function renderControls($r) { 02956 global $LANG; 02957 02958 if ($this->mode==='export') { 02959 return ($r['type']=='record' ? '<input type="checkbox" name="tx_impexp[exclude]['.$r['ref'].']" value="1" /> '.$LANG->getLL('impexpcore_singlereco_exclude',1) : 02960 ($r['type']=='softref' ? $this->softrefSelector($r['_softRefInfo']) : '')); 02961 } else { // During import 02962 02963 // For softreferences with editable fields: 02964 if ($r['type']=='softref' && is_array($r['_softRefInfo']['subst']) && $r['_softRefInfo']['subst']['tokenID']) { 02965 $tokenID = $r['_softRefInfo']['subst']['tokenID']; 02966 $cfg = $this->softrefCfg[$tokenID]; 02967 if ($cfg['mode'] === 'editable') { 02968 return 02969 (strlen($cfg['title']) ? '<b>'.htmlspecialchars($cfg['title']).'</b><br/>' : ''). 02970 htmlspecialchars($cfg['description']).'<br/> 02971 <input type="text" name="tx_impexp[softrefInputValues]['.$tokenID.']" value="'.htmlspecialchars(isset($this->softrefInputValues[$tokenID]) ? $this->softrefInputValues[$tokenID] : $cfg['defValue']).'" />'; 02972 } 02973 } 02974 } 02975 } 02976 02983 function softrefSelector($cfg) { 02984 global $LANG; 02985 02986 // Looking for file ID if any: 02987 $fI = $cfg['file_ID'] ? $this->dat['header']['files'][$cfg['file_ID']] : array(); 02988 02989 // Substitution scheme has to be around and RTE images MUST be exported. 02990 if (is_array($cfg['subst']) && $cfg['subst']['tokenID'] && !$fI['RTE_ORIG_ID']) { 02991 02992 // Create options: 02993 $optValues = array(); 02994 $optValues[''] = ''; 02995 $optValues['editable'] = $LANG->getLL('impexpcore_softrefsel_editable'); 02996 $optValues['exclude'] = $LANG->getLL('impexpcore_softrefsel_exclude'); 02997 02998 // Get current value: 02999 $value = $this->softrefCfg[$cfg['subst']['tokenID']]['mode']; 03000 03001 // Render options selector: 03002 $selectorbox = $this->renderSelectBox('tx_impexp[softrefCfg]['.$cfg['subst']['tokenID'].'][mode]',$value,$optValues).'<br/>'; 03003 03004 if ($value === 'editable') { 03005 03006 $descriptionField = ''; 03007 03008 // Title: 03009 if (strlen($cfg['subst']['title'])) { 03010 $descriptionField.= ' 03011 <input type="hidden" name="tx_impexp[softrefCfg]['.$cfg['subst']['tokenID'].'][title]" value="'.htmlspecialchars($cfg['subst']['title']).'" /> 03012 <b>'.htmlspecialchars($cfg['subst']['title']).'</b><br/>'; 03013 } 03014 03015 // Description: 03016 if (!strlen($cfg['subst']['description'])) { 03017 $descriptionField.= ' 03018 '.$LANG->getLL('impexpcore_printerror_description',1).'<br/> 03019 <input type="text" name="tx_impexp[softrefCfg]['.$cfg['subst']['tokenID'].'][description]" value="'.htmlspecialchars($this->softrefCfg[$cfg['subst']['tokenID']]['description']).'" />'; 03020 } else { 03021 $descriptionField.= ' 03022 03023 <input type="hidden" name="tx_impexp[softrefCfg]['.$cfg['subst']['tokenID'].'][description]" value="'.htmlspecialchars($cfg['subst']['description']).'" />'. 03024 htmlspecialchars($cfg['subst']['description']); 03025 } 03026 03027 // Default Value: 03028 $descriptionField.= '<input type="hidden" name="tx_impexp[softrefCfg]['.$cfg['subst']['tokenID'].'][defValue]" value="'.htmlspecialchars($cfg['subst']['tokenValue']).'" />'; 03029 03030 } else $descriptionField = ''; 03031 03032 return $selectorbox.$descriptionField; 03033 } 03034 } 03035 03036 03037 03038 03039 03040 03041 03042 03043 03044 03045 03046 03047 /***************************** 03048 * 03049 * Helper functions of kinds 03050 * 03051 *****************************/ 03052 03059 function isTableStatic($table) { 03060 global $TCA; 03061 03062 if (is_array($TCA[$table])) { 03063 return $TCA[$table]['ctrl']['is_static'] || in_array($table, $this->relStaticTables) || in_array('_ALL', $this->relStaticTables); 03064 } 03065 } 03066 03073 function inclRelation($table) { 03074 global $TCA; 03075 03076 if (is_array($TCA[$table])) { 03077 return (in_array($table, $this->relOnlyTables) || in_array('_ALL', $this->relOnlyTables)) && $GLOBALS['BE_USER']->check('tables_select',$table); 03078 } 03079 } 03080 03088 function isExcluded($table,$uid) { 03089 global $TCA; 03090 03091 return $this->excludeMap[$table.':'.$uid] ? TRUE : FALSE; 03092 } 03093 03100 function includeSoftref($tokenID) { 03101 return $tokenID && !t3lib_div::inList('exclude,editable', $this->softrefCfg[$tokenID]['mode']); 03102 } 03103 03110 function checkPID($pid) { 03111 global $BE_USER; 03112 03113 if (!isset($this->checkPID_cache[$pid])) { 03114 $this->checkPID_cache[$pid] = (boolean)$BE_USER->isInWebMount($pid); 03115 } 03116 03117 return $this->checkPID_cache[$pid]; 03118 } 03119 03127 function dontIgnorePid($table, $uid) { 03128 return $this->import_mode[$table.':'.$uid]!=='ignore_pid' && 03129 (!$this->global_ignore_pid || $this->import_mode[$table.':'.$uid]==='respect_pid'); 03130 } 03131 03140 function doesRecordExist($table,$uid,$fields='') { 03141 return t3lib_BEfunc::getRecord($table, $uid, $fields ? $fields : 'uid,pid'); 03142 } 03143 03150 function getRecordPath($pid) { 03151 if (!isset($this->cache_getRecordPath[$pid])) { 03152 $clause = $GLOBALS['BE_USER']->getPagePermsClause(1); 03153 $this->cache_getRecordPath[$pid] = (string)t3lib_BEfunc::getRecordPath($pid, $clause, 20); 03154 } 03155 03156 return $this->cache_getRecordPath[$pid]; 03157 } 03158 03167 function renderSelectBox($prefix,$value,$optValues) { 03168 $opt = array(); 03169 $isSelFlag = 0; 03170 reset($optValues); 03171 while(list($k,$v) = each($optValues)) { 03172 $sel = (!strcmp($k,$value) ? ' selected="selected"' : ''); 03173 if ($sel) $isSelFlag++; 03174 $opt[] = '<option value="'.htmlspecialchars($k).'"'.$sel.'>'.htmlspecialchars($v).'</option>'; 03175 } 03176 if (!$isSelFlag && strcmp('',$value)) { 03177 $opt[] = '<option value="'.htmlspecialchars($value).'" selected="selected">'.htmlspecialchars("['".$value."']").'</option>'; 03178 } 03179 return '<select name="'.$prefix.'">'.implode('',$opt).'</select>'; 03180 } 03181 03191 function compareRecords($databaseRecord, $importRecord, $table, $inverseDiff=FALSE) { 03192 global $TCA, $LANG; 03193 03194 // Initialize: 03195 $output = array(); 03196 $t3lib_diff_Obj = t3lib_div::makeInstance('t3lib_diff'); 03197 03198 // Check if both inputs are records: 03199 if (is_array($databaseRecord) && is_array($importRecord)) { 03200 03201 // Traverse based on database record 03202 foreach($databaseRecord as $fN => $value) { 03203 if (is_array($TCA[$table]['columns'][$fN]) && $TCA[$table]['columns'][$fN]['config']['type']!='passthrough') { 03204 if (isset($importRecord[$fN])) { 03205 if (strcmp(trim($databaseRecord[$fN]), trim($importRecord[$fN]))) { 03206 03207 // Create diff-result: 03208 $output[$fN] = $t3lib_diff_Obj->makeDiffDisplay( 03209 t3lib_BEfunc::getProcessedValue($table,$fN,!$inverseDiff ? $importRecord[$fN] : $databaseRecord[$fN] ,0,1,1), 03210 t3lib_BEfunc::getProcessedValue($table,$fN,!$inverseDiff ? $databaseRecord[$fN] : $importRecord[$fN] ,0,1,1) 03211 ); 03212 } 03213 unset($importRecord[$fN]); 03214 } else { 03215 // 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!)? 03216 #$output[$fN] = '<b>Field missing</b> in import file'; 03217 } 03218 } 03219 } 03220 03221 // Traverse remaining in import record: 03222 foreach($importRecord as $fN => $value) { 03223 if (is_array($TCA[$table]['columns'][$fN]) && $TCA[$table]['columns'][$fN]['config']['type']!='passthrough') { 03224 $output[$fN] = '<b>Field missing</b> in database'; 03225 } 03226 } 03227 03228 // Create output: 03229 if (count($output)) { 03230 $tRows = array(); 03231 foreach($output as $fN => $state) { 03232 $tRows[] = ' 03233 <tr> 03234 <td class="bgColor5">'.$LANG->sL($TCA[$table]['columns'][$fN]['label'],1).' ('.htmlspecialchars($fN).')</td> 03235 <td class="bgColor4">'.$state.'</td> 03236 </tr> 03237 '; 03238 } 03239 03240 $output = '<table border="0" cellpadding="0" cellspacing="1">'.implode('',$tRows).'</table>'; 03241 } else { 03242 $output = 'Match'; 03243 } 03244 03245 return '<b class="nobr">['.htmlspecialchars($table.':'.$importRecord['uid'].' => '.$databaseRecord['uid']).']:</b> '.$output; 03246 } 03247 03248 03249 return 'ERROR: One of the inputs were not an array!'; 03250 } 03251 03258 function getRTEoriginalFilename($string) { 03259 // If "magic image": 03260 if (t3lib_div::isFirstPartOfStr($string,'RTEmagicC_')) { 03261 // Find original file: 03262 $pI = pathinfo(substr($string,strlen('RTEmagicC_'))); 03263 $filename = substr($pI['basename'],0,-strlen('.'.$pI['extension'])); 03264 $origFilePath = 'RTEmagicP_'.$filename; 03265 03266 return $origFilePath; 03267 } 03268 } 03269 03275 function &getFileProcObj() { 03276 global $FILEMOUNTS, $TYPO3_CONF_VARS, $BE_USER; 03277 03278 if (!is_object($this->fileProcObj)) { 03279 $this->fileProcObj = t3lib_div::makeInstance('t3lib_extFileFunctions'); 03280 $this->fileProcObj->init($FILEMOUNTS, $TYPO3_CONF_VARS['BE']['fileExtensions']); 03281 $this->fileProcObj->init_actionPerms($BE_USER->user['fileoper_perms']); 03282 } 03283 03284 return $this->fileProcObj; 03285 } 03286 03287 03288 03289 03290 03291 03292 03293 03294 03295 /***************************** 03296 * 03297 * Error handling 03298 * 03299 *****************************/ 03300 03307 function error($msg) { 03308 $this->errorLog[]=$msg; 03309 } 03310 03316 function printErrorLog() { 03317 return count($this->errorLog) ? t3lib_div::view_array($this->errorLog) : ''; 03318 } 03319 } 03320 03321 03322 03323 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/impexp/class.tx_impexp.php']) { 03324 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/impexp/class.tx_impexp.php']); 03325 } 03326 ?>