Documentation TYPO3 par Ameos |
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 (!strcmp($initStrDat[3],'')) { 02270 $datString = fread($fd,intval($initStrDat[2])); 02271 fread($fd,1); 02272 if (!strcmp(md5($datString), $initStrDat[0])) { 02273 if ($initStrDat[1]) { 02274 if ($this->compress) { 02275 $datString = gzuncompress($datString); 02276 } else $this->error('Content read error: This file requires decompression, but this server does not offer gzcompress()/gzuncompress() functions.',1); 02277 } 02278 return $unserialize ? unserialize($datString) : $datString; 02279 } else $this->error('MD5 check failed ('.$name.')'); 02280 } else $this->error('File read error: InitString had a wrong length. ('.$name.')'); 02281 } 02282 02290 function loadContent($filecontent) { 02291 $pointer = 0; 02292 02293 $this->dat['header'] = $this->getNextContentPart($filecontent,$pointer,1,'header'); 02294 $this->dat['records'] = $this->getNextContentPart($filecontent,$pointer,1,'records'); 02295 $this->dat['files'] = $this->getNextContentPart($filecontent,$pointer,1,'files'); 02296 $this->loadInit(); 02297 } 02298 02308 function getNextContentPart($filecontent,&$pointer,$unserialize=0,$name='') { 02309 $initStrLen = 32+1+1+1+10+1; 02310 // getting header data 02311 $initStr = substr($filecontent,$pointer,$initStrLen); 02312 $pointer+= $initStrLen; 02313 $initStrDat = explode(':',$initStr); 02314 if (!strcmp($initStrDat[3],'')) { 02315 $datString = substr($filecontent,$pointer,intval($initStrDat[2])); 02316 $pointer+= intval($initStrDat[2])+1; 02317 if (!strcmp(md5($datString),$initStrDat[0])) { 02318 if ($initStrDat[1]) { 02319 if ($this->compress) { 02320 $datString = gzuncompress($datString); 02321 } else $this->error('Content read error: This file requires decompression, but this server does not offer gzcompress()/gzuncompress() functions.',1); 02322 } 02323 return $unserialize ? unserialize($datString) : $datString; 02324 } else $this->error('MD5 check failed ('.$name.')'); 02325 } else $this->error('Content read error: InitString had a wrong length. ('.$name.')'); 02326 } 02327 02333 function loadInit() { 02334 $this->relStaticTables = (array)$this->dat['header']['relStaticTables']; 02335 $this->excludeMap = (array)$this->dat['header']['excludeMap']; 02336 02337 $this->softrefCfg = (array)$this->dat['header']['softrefCfg']; 02338 $this->extensionDependencies = (array)$this->dat['header']['extensionDependencies']; 02339 02340 $this->fixCharsets(); 02341 } 02342 02349 function fixCharsets() { 02350 global $LANG; 02351 02352 $importCharset = $this->dat['header']['charset']; 02353 if ($importCharset) { 02354 if ($importCharset!==$LANG->charSet) { 02355 $this->error('CHARSET: Converting charset of input file ('.$importCharset.') to the system charset ('.$LANG->charSet.')'); 02356 02357 // convert meta data: 02358 if (is_array($this->dat['header']['meta'])) { 02359 $LANG->csConvObj->convArray($this->dat['header']['meta'],$importCharset,$LANG->charSet); 02360 } 02361 // convert record headers: 02362 if (is_array($this->dat['header']['records'])) { 02363 $LANG->csConvObj->convArray($this->dat['header']['records'],$importCharset,$LANG->charSet); 02364 } 02365 // convert records themselves: 02366 if (is_array($this->dat['records'])) { 02367 $LANG->csConvObj->convArray($this->dat['records'],$importCharset,$LANG->charSet); 02368 } 02369 } 02370 } else { 02371 $this->error('CHARSET: No charset found in import file!'); 02372 } 02373 } 02374 02375 02376 02377 02378 02379 02380 02381 02382 02383 02384 02385 02386 02387 02388 02389 02390 02391 02392 02393 /******************************************************** 02394 * 02395 * Visual rendering of import/export memory, $this->dat 02396 * 02397 ********************************************************/ 02398 02404 function displayContentOverview() { 02405 global $LANG; 02406 02407 // Check extension dependencies: 02408 if (is_array($this->dat['header']['extensionDependencies'])) { 02409 foreach($this->dat['header']['extensionDependencies'] as $extKey) { 02410 if (!t3lib_extMgm::isLoaded($extKey)) { 02411 $this->error('DEPENDENCY: The extension with key "'.$extKey.'" must be installed!'); 02412 } 02413 } 02414 } 02415 02416 // Probably this is done to save memory space? 02417 unset($this->dat['files']); 02418 02419 // Traverse header: 02420 $this->remainHeader = $this->dat['header']; 02421 if (is_array($this->remainHeader)) { 02422 02423 // If there is a page tree set, show that: 02424 if (is_array($this->dat['header']['pagetree'])) { 02425 reset($this->dat['header']['pagetree']); 02426 $lines = array(); 02427 $this->traversePageTree($this->dat['header']['pagetree'],$lines); 02428 02429 $rows = array(); 02430 $rows[] = ' 02431 <tr class="bgColor5 tableheader"> 02432 <td>'.$LANG->getLL('impexpcore_displaycon_controls',1).'</td> 02433 <td>'.$LANG->getLL('impexpcore_displaycon_title',1).'</td> 02434 <td>'.$LANG->getLL('impexpcore_displaycon_size',1).'</td> 02435 <td>'.$LANG->getLL('impexpcore_displaycon_message',1).'</td> 02436 '.($this->update ? '<td>'.$LANG->getLL('impexpcore_displaycon_updateMode',1).'</td>' : '').' 02437 '.($this->update ? '<td>'.$LANG->getLL('impexpcore_displaycon_currentPath',1).'</td>' : '').' 02438 '.($this->showDiff ? '<td>'.$LANG->getLL('impexpcore_displaycon_result',1).'</td>' : '').' 02439 </tr>'; 02440 02441 foreach($lines as $r) { 02442 $rows[] = ' 02443 <tr class="'.$r['class'].'"> 02444 <td>'.$this->renderControls($r).'</td> 02445 <td nowrap="nowrap">'.$r['preCode'].$r['title'].'</td> 02446 <td nowrap="nowrap">'.t3lib_div::formatSize($r['size']).'</td> 02447 <td nowrap="nowrap">'.($r['msg'] && !$this->doesImport ? '<span class="typo3-red">'.htmlspecialchars($r['msg']).'</span>' : '').'</td> 02448 '.($this->update ? '<td nowrap="nowrap">'.$r['updateMode'].'</td>' : '').' 02449 '.($this->update ? '<td nowrap="nowrap">'.$r['updatePath'].'</td>' : '').' 02450 '.($this->showDiff ? '<td>'.$r['showDiffContent'].'</td>' : '').' 02451 </tr>'; 02452 } 02453 02454 $out = ' 02455 <strong>'.$LANG->getLL('impexpcore_displaycon_insidePagetree',1).'</strong> 02456 <br /><br /> 02457 <table border="0" cellpadding="0" cellspacing="1">'.implode('',$rows).'</table> 02458 <br /><br />'; 02459 } 02460 02461 // Print remaining records that were not contained inside the page tree: 02462 $lines = array(); 02463 if (is_array($this->remainHeader['records'])) { 02464 if (is_array($this->remainHeader['records']['pages'])) { 02465 $this->traversePageRecords($this->remainHeader['records']['pages'], $lines); 02466 } 02467 $this->traverseAllRecords($this->remainHeader['records'], $lines); 02468 02469 if (count($lines)) { 02470 $rows = array(); 02471 $rows[] = ' 02472 <tr class="bgColor5 tableheader"> 02473 <td>'.$LANG->getLL('impexpcore_displaycon_controls',1).'</td> 02474 <td>'.$LANG->getLL('impexpcore_displaycon_title',1).'</td> 02475 <td>'.$LANG->getLL('impexpcore_displaycon_size',1).'</td> 02476 <td>'.$LANG->getLL('impexpcore_displaycon_message',1).'</td> 02477 '.($this->update ? '<td>'.$LANG->getLL('impexpcore_displaycon_updateMode',1).'</td>' : '').' 02478 '.($this->update ? '<td>'.$LANG->getLL('impexpcore_displaycon_currentPath',1).'</td>' : '').' 02479 '.($this->showDiff ? '<td>'.$LANG->getLL('impexpcore_displaycon_result',1).'</td>' : '').' 02480 </tr>'; 02481 02482 foreach($lines as $r) { 02483 $rows[] = '<tr class="'.$r['class'].'"> 02484 <td>'.$this->renderControls($r).'</td> 02485 <td nowrap="nowrap">'.$r['preCode'].$r['title'].'</td> 02486 <td nowrap="nowrap">'.t3lib_div::formatSize($r['size']).'</td> 02487 <td nowrap="nowrap">'.($r['msg'] && !$this->doesImport ? '<span class="typo3-red">'.htmlspecialchars($r['msg']).'</span>' : '').'</td> 02488 '.($this->update ? '<td nowrap="nowrap">'.$r['updateMode'].'</td>' : '').' 02489 '.($this->update ? '<td nowrap="nowrap">'.$r['updatePath'].'</td>' : '').' 02490 '.($this->showDiff ? '<td>'.$r['showDiffContent'].'</td>' : '').' 02491 </tr>'; 02492 } 02493 02494 $out.= ' 02495 <strong>'.$LANG->getLL('impexpcore_singlereco_outsidePagetree',1).'</strong> 02496 <br /><br /> 02497 <table border="0" cellpadding="0" cellspacing="1">'.implode('',$rows).'</table>'; 02498 } 02499 } 02500 } 02501 return $out; 02502 } 02503 02512 function traversePageTree($pT,&$lines,$preCode='') { 02513 reset($pT); 02514 while(list($k,$v) = each($pT)) { 02515 02516 // Add this page: 02517 $this->singleRecordLines('pages',$k,$lines,$preCode); 02518 02519 // Subrecords: 02520 if (is_array($this->dat['header']['pid_lookup'][$k])) { 02521 reset($this->dat['header']['pid_lookup'][$k]); 02522 while(list($t,$recUidArr)=each($this->dat['header']['pid_lookup'][$k])) { 02523 if ($t!='pages') { 02524 reset($recUidArr); 02525 while(list($ruid)=each($recUidArr)) { 02526 $this->singleRecordLines($t,$ruid,$lines,$preCode.' '); 02527 } 02528 } 02529 } 02530 unset($this->remainHeader['pid_lookup'][$k]); 02531 } 02532 02533 // Subpages, called recursively: 02534 if (is_array($v['subrow'])) { 02535 $this->traversePageTree($v['subrow'],$lines,$preCode.' '); 02536 } 02537 } 02538 } 02539 02547 function traversePageRecords($pT,&$lines) { 02548 reset($pT); 02549 while(list($k,$rHeader)=each($pT)) { 02550 $this->singleRecordLines('pages',$k,$lines,'',1); 02551 // Subrecords: 02552 if (is_array($this->dat['header']['pid_lookup'][$k])) { 02553 reset($this->dat['header']['pid_lookup'][$k]); 02554 while(list($t,$recUidArr)=each($this->dat['header']['pid_lookup'][$k])) { 02555 if ($t!='pages') { 02556 reset($recUidArr); 02557 while(list($ruid)=each($recUidArr)) { 02558 $this->singleRecordLines($t,$ruid,$lines,' '); 02559 } 02560 } 02561 } 02562 unset($this->remainHeader['pid_lookup'][$k]); 02563 } 02564 } 02565 } 02566 02574 function traverseAllRecords($pT,&$lines) { 02575 reset($pT); 02576 while(list($t,$recUidArr)=each($pT)) { 02577 if ($t!='pages') { 02578 reset($recUidArr); 02579 while(list($ruid)=each($recUidArr)) { 02580 $this->singleRecordLines($t,$ruid,$lines,$preCode,1); 02581 } 02582 } 02583 } 02584 } 02585 02596 function singleRecordLines($table,$uid,&$lines,$preCode,$checkImportInPidRecord=0) { 02597 global $TCA,$BE_USER,$LANG; 02598 02599 // Get record: 02600 $record = $this->dat['header']['records'][$table][$uid]; 02601 unset($this->remainHeader['records'][$table][$uid]); 02602 if (!is_array($record) && !($table==='pages' && !$uid)) $this->error('MISSING RECORD: '.$table.':'.$uid,1); 02603 02604 // Begin to create the line arrays information record, pInfo: 02605 $pInfo = array(); 02606 $pInfo['ref'] = $table.':'.$uid; 02607 if ($table==='_SOFTREF_') { // Unknown table name: 02608 $pInfo['preCode'] = $preCode; 02609 $pInfo['title'] = '<em>'.$LANG->getLL('impexpcore_singlereco_softReferencesFiles',1).'</em>'; 02610 } elseif (!isset($TCA[$table])) { // Unknown table name: 02611 $pInfo['preCode'] = $preCode; 02612 $pInfo['msg'] = "UNKNOWN TABLE '".$pInfo['ref']."'"; 02613 $pInfo['title'] = '<em>'.htmlspecialchars($record['title']).'</em>'; 02614 } else { // Otherwise, set table icon and title. 02615 02616 // Import Validation (triggered by $this->display_import_pid_record) will show messages if import is not possible of various items. 02617 if (is_array($this->display_import_pid_record)) { 02618 if ($checkImportInPidRecord) { 02619 if (!$BE_USER->doesUserHaveAccess($this->display_import_pid_record, $table=='pages'?8:16)) { 02620 $pInfo['msg'].="'".$pInfo['ref']."' cannot be INSERTED on this page! "; 02621 } 02622 if (!$this->checkDokType($table, $this->display_import_pid_record['doktype']) && !$TCA[$table]['ctrl']['rootLevel']) { 02623 $pInfo['msg'].="'".$table."' cannot be INSERTED on this page type (change to 'sysFolder'!) "; 02624 } 02625 } 02626 if (!$BE_USER->check('tables_modify',$table)) {$pInfo['msg'].="You are not allowed to CREATE '".$table."' tables! ";} 02627 02628 if ($TCA[$table]['ctrl']['readOnly']) {$pInfo['msg'].="TABLE '".$table."' is READ ONLY! ";} 02629 if ($TCA[$table]['ctrl']['adminOnly'] && !$BE_USER->isAdmin()) {$pInfo['msg'].="TABLE '".$table."' is ADMIN ONLY! ";} 02630 if ($TCA[$table]['ctrl']['is_static']) {$pInfo['msg'].="TABLE '".$table."' is a STATIC TABLE! ";} 02631 if ($TCA[$table]['ctrl']['rootLevel']) {$pInfo['msg'].="TABLE '".$table."' will be inserted on ROOT LEVEL! ";} 02632 02633 $diffInverse = FALSE; 02634 if ($this->update) { 02635 $diffInverse = TRUE; // In case of update-PREVIEW we swap the diff-sources. 02636 $recInf = $this->doesRecordExist($table, $uid, $this->showDiff ? '*' : ''); 02637 $pInfo['updatePath']= $recInf ? htmlspecialchars($this->getRecordPath($recInf['pid'])) : '<b>NEW!</b>'; 02638 02639 // Mode selector: 02640 $optValues = array(); 02641 $optValues[] = $recInf ? $LANG->getLL('impexpcore_singlereco_update') : $LANG->getLL('impexpcore_singlereco_insert'); 02642 if ($recInf) $optValues['as_new'] = $LANG->getLL('impexpcore_singlereco_importAsNew'); 02643 if ($recInf) { 02644 if (!$this->global_ignore_pid) { 02645 $optValues['ignore_pid'] = $LANG->getLL('impexpcore_singlereco_ignorePid'); 02646 } else { 02647 $optValues['respect_pid'] = $LANG->getLL('impexpcore_singlereco_respectPid'); 02648 } 02649 } 02650 if (!$recInf && $GLOBALS['BE_USER']->isAdmin()) $optValues['force_uid'] = sprintf($LANG->getLL('impexpcore_singlereco_forceUidSAdmin'),$uid); 02651 $optValues['exclude'] = $LANG->getLL('impexpcore_singlereco_exclude'); 02652 02653 $pInfo['updateMode'] = $this->renderSelectBox('tx_impexp[import_mode]['.$table.':'.$uid.']',$this->import_mode[$table.':'.$uid],$optValues); 02654 } 02655 02656 // Diff vieiw: 02657 if ($this->showDiff) { 02658 // For IMPORTS, get new id: 02659 if ($newUid = $this->import_mapId[$table][$uid]) { 02660 $diffInverse = FALSE; 02661 $recInf = $this->doesRecordExist($table, $newUid, '*'); 02662 t3lib_BEfunc::workspaceOL($table,$recInf); 02663 } 02664 if (is_array($recInf)) { 02665 $pInfo['showDiffContent'] = $this->compareRecords($recInf, $this->dat['records'][$table.':'.$uid]['data'], $table, $diffInverse); 02666 } 02667 } 02668 } 02669 02670 $pInfo['preCode'] = $preCode.t3lib_iconworks::getIconImage($table,$this->dat['records'][$table.':'.$uid]['data'],$GLOBALS['BACK_PATH'],'align="top" title="'.htmlspecialchars($table.':'.$uid).'"'); 02671 $pInfo['title'] = htmlspecialchars($record['title']); 02672 02673 // View page: 02674 if ($table==='pages') { 02675 $viewID = $this->mode === 'export' ? $uid : ($this->doesImport ? $this->import_mapId['pages'][$uid] : 0); 02676 if ($viewID) { 02677 $pInfo['title'] = '<a href="#" onclick="'.htmlspecialchars(t3lib_BEfunc::viewOnClick($viewID, $GLOBALS['BACK_PATH'])).'return false;">'.$pInfo['title'].'</a>'; 02678 } 02679 } 02680 } 02681 $pInfo['class'] = $table=='pages' ? 'bgColor4-20' : 'bgColor4'; 02682 $pInfo['type'] = 'record'; 02683 $pInfo['size'] = $record['size']; 02684 $lines[] = $pInfo; 02685 02686 // File relations: 02687 if (is_array($record['filerefs'])) { 02688 $this->addFiles($record['filerefs'],$lines,$preCode); 02689 } 02690 02691 // DB relations 02692 if (is_array($record['rels'])) { 02693 $this->addRelations($record['rels'],$lines,$preCode); 02694 } 02695 02696 // Soft ref 02697 if (count($record['softrefs'])) { 02698 $preCode_A = $preCode.' '; 02699 $preCode_B = $preCode.' '; 02700 foreach($record['softrefs'] as $info) { 02701 $pInfo = array(); 02702 $pInfo['preCode'] = $preCode_A.'<img'.t3lib_iconWorks::skinImg($GLOBALS['BACK_PATH'],'gfx/rel_softref.png','width="13" height="12"').' align="top" alt="" />'; 02703 $pInfo['title'] = '<em>'.$info['field'].', "'.$info['spKey'].'" </em>: <span title="'.htmlspecialchars($info['matchString']).'">'.htmlspecialchars(t3lib_div::fixed_lgd_cs($info['matchString'],60)).'</span>'; 02704 if ($info['subst']['type']) { 02705 if (strlen($info['subst']['title'])) { 02706 $pInfo['title'].= '<br/>'.$preCode_B.'<b>'.$LANG->getLL('impexpcore_singlereco_title',1).'</b> '.htmlspecialchars(t3lib_div::fixed_lgd_cs($info['subst']['title'],60)); 02707 } 02708 if (strlen($info['subst']['description'])) { 02709 $pInfo['title'].= '<br/>'.$preCode_B.'<b>'.$LANG->getLL('impexpcore_singlereco_descr',1).'</b> '.htmlspecialchars(t3lib_div::fixed_lgd_cs($info['subst']['description'],60)); 02710 } 02711 $pInfo['title'].= '<br/>'.$preCode_B. 02712 ($info['subst']['type'] == 'file' ? $LANG->getLL('impexpcore_singlereco_filename',1).' <b>'.$info['subst']['relFileName'].'</b>' : ''). 02713 ($info['subst']['type'] == 'string' ? $LANG->getLL('impexpcore_singlereco_value',1).' <b>'.$info['subst']['tokenValue'].'</b>' : ''). 02714 ($info['subst']['type'] == 'db' ? $LANG->getLL('impexpcore_softrefsel_record',1).' <b>'.$info['subst']['recordRef'].'</b>' : ''); 02715 } 02716 $pInfo['ref'] = 'SOFTREF'; 02717 $pInfo['size'] = ''; 02718 $pInfo['class'] = 'bgColor3'; 02719 $pInfo['type'] = 'softref'; 02720 $pInfo['_softRefInfo'] = $info; 02721 $pInfo['type'] = 'softref'; 02722 if ($info['error'] && !t3lib_div::inList('editable,exclude',$this->softrefCfg[$info['subst']['tokenID']]['mode'])) { 02723 $pInfo['msg'].= $info['error']; 02724 } 02725 $lines[] = $pInfo; 02726 02727 // Add relations: 02728 if ($info['subst']['type'] == 'db') { 02729 list($tempTable, $tempUid) = explode(':', $info['subst']['recordRef']); 02730 $this->addRelations(array(array('table' => $tempTable, 'id' => $tempUid, 'tokenID' => $info['subst']['tokenID'])),$lines,$preCode_B,array(), ''); 02731 } 02732 02733 // Add files: 02734 if ($info['subst']['type'] == 'file') { 02735 #debug($info); 02736 $this->addFiles(array($info['file_ID']),$lines,$preCode_B, '', $info['subst']['tokenID']); 02737 } 02738 } 02739 } 02740 } 02741 02754 function addRelations($rels,&$lines,$preCode,$recurCheck=array(),$htmlColorClass='') { 02755 02756 foreach($rels as $dat) { 02757 $table = $dat['table']; 02758 $uid = $dat['id']; 02759 $pInfo = array(); 02760 $Iprepend = ''; 02761 $staticFixed = FALSE; 02762 $pInfo['ref'] = $table.':'.$uid; 02763 if (!in_array($pInfo['ref'],$recurCheck)) { 02764 if ($uid > 0) { 02765 $record = $this->dat['header']['records'][$table][$uid]; 02766 if (!is_array($record)) { 02767 if ($this->isTableStatic($table) || $this->isExcluded($table, $uid) || ($dat['tokenID'] && !$this->includeSoftref($dat['tokenID']))) { 02768 $pInfo['title'] = htmlspecialchars('STATIC: '.$pInfo['ref']); 02769 $Iprepend = '_static'; 02770 $staticFixed = TRUE; 02771 } else { 02772 $doesRE = $this->doesRecordExist($table,$uid); 02773 $lostPath = $this->getRecordPath($table==='pages' ? $doesRE['uid'] : $doesRE['pid']); 02774 02775 $pInfo['title'] = htmlspecialchars($pInfo['ref']); 02776 $pInfo['title'] = '<span title="'.htmlspecialchars($lostPath).'">'.$pInfo['title'].'</span>'; 02777 02778 $pInfo['msg'] = 'LOST RELATION'.(!$doesRE ? ' (Record not found!)' : ' (Path: '.$lostPath.')'); 02779 $Iprepend = '_lost'; 02780 # debug('MISSING relation: '.$table.':'.$uid,1); 02781 } 02782 } else { 02783 $pInfo['title'] = htmlspecialchars($record['title']); 02784 $pInfo['title'] = '<span title="'.htmlspecialchars($this->getRecordPath($table==='pages' ? $record['uid'] : $record['pid'])).'">'.$pInfo['title'].'</span>'; 02785 02786 # $pInfo['size'] = $record['size']; 02787 } 02788 } 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 02789 $pInfo['title'] = htmlspecialchars('FIXED: '.$pInfo['ref']); 02790 $staticFixed = TRUE; 02791 } 02792 02793 $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="" />'; 02794 $pInfo['class'] = $htmlColorClass ? $htmlColorClass : 'bgColor3'; 02795 $pInfo['type'] = 'rel'; 02796 02797 if (!$staticFixed || $this->showStaticRelations) { 02798 $lines[] = $pInfo; 02799 if (is_array($record) && is_array($record['rels'])) { 02800 $this->addRelations($record['rels'], $lines, $preCode.' ', array_merge($recurCheck,array($pInfo['ref'])), $htmlColorClass); 02801 } 02802 } 02803 } else $this->error($pInfo['ref'].' was recursive...'); 02804 } 02805 } 02806 02819 function addFiles($rels,&$lines,$preCode,$htmlColorClass='',$tokenID='') { 02820 02821 foreach($rels as $ID) { 02822 02823 // Process file: 02824 $pInfo = array(); 02825 $fI = $this->dat['header']['files'][$ID]; 02826 if (!is_array($fI)) { 02827 if (!$tokenID || $this->includeSoftref($tokenID)) { 02828 $pInfo['msg'] = 'MISSING FILE: '.$ID; 02829 $this->error('MISSING FILE: '.$ID,1); 02830 } else { 02831 return; 02832 } 02833 } 02834 $pInfo['preCode'] = $preCode.' <img'.t3lib_iconWorks::skinImg($GLOBALS['BACK_PATH'],'gfx/rel_file.gif','width="13" height="12"').' align="top" alt="" />'; 02835 $pInfo['title'] = htmlspecialchars($fI['filename']); 02836 $pInfo['ref'] = 'FILE'; 02837 $pInfo['size'] = $fI['filesize']; 02838 $pInfo['class'] = $htmlColorClass ? $htmlColorClass : 'bgColor3'; 02839 $pInfo['type'] = 'file'; 02840 02841 // If import mode and there is a non-RTE softreference, check the destination directory: 02842 if ($this->mode==='import' && $tokenID && !$fI['RTE_ORIG_ID']) { 02843 if (isset($fI['parentRelFileName'])) { 02844 $pInfo['msg'] = 'Seems like this file is already referenced from within an HTML/CSS file. That takes precedence. '; 02845 } else { 02846 $testDirPrefix = dirname($fI['relFileName']).'/'; 02847 $testDirPrefix2 = $this->verifyFolderAccess($testDirPrefix); 02848 02849 if (!$testDirPrefix2) { 02850 $pInfo['msg'] = 'ERROR: There are no available filemounts to write file in! '; 02851 } elseif (strcmp($testDirPrefix,$testDirPrefix2)) { 02852 $pInfo['msg'] = 'File will be attempted written to "'.$testDirPrefix2.'". '; 02853 } 02854 } 02855 02856 02857 // Check if file exists: 02858 if (@file_exists(PATH_site.$fI['relFileName'])) { 02859 if ($this->update) { 02860 $pInfo['updatePath'].= 'File exists.'; 02861 } else { 02862 $pInfo['msg'].= 'File already exists! '; 02863 } 02864 } 02865 02866 // Check extension: 02867 $fileProcObj = &$this->getFileProcObj(); 02868 if ($fileProcObj->actionPerms['newFile']) { 02869 $testFI = t3lib_div::split_fileref(PATH_site.$fI['relFileName']); 02870 if (!$this->allowPHPScripts && !$fileProcObj->checkIfAllowed($testFI['fileext'], $testFI['path'], $testFI['file'])) { 02871 $pInfo['msg'].= 'File extension was not allowed!'; 02872 } 02873 } else $pInfo['msg'] = 'You user profile does not allow you to create files on the server!'; 02874 } 02875 02876 $pInfo['showDiffContent'] = substr($this->fileIDMap[$ID],strlen(PATH_site)); 02877 02878 $lines[] = $pInfo; 02879 unset($this->remainHeader['files'][$ID]); 02880 02881 // RTE originals: 02882 if ($fI['RTE_ORIG_ID']) { 02883 $ID = $fI['RTE_ORIG_ID']; 02884 $pInfo = array(); 02885 $fI = $this->dat['header']['files'][$ID]; 02886 if (!is_array($fI)) { 02887 $pInfo['msg'] = 'MISSING RTE original FILE: '.$ID; 02888 $this->error('MISSING RTE original FILE: '.$ID,1); 02889 } 02890 02891 $pInfo['showDiffContent'] = substr($this->fileIDMap[$ID],strlen(PATH_site)); 02892 02893 $pInfo['preCode'] = $preCode.' <img'.t3lib_iconWorks::skinImg($GLOBALS['BACK_PATH'],'gfx/rel_file.gif','width="13" height="12"').' align="top" alt="" />'; 02894 $pInfo['title'] = htmlspecialchars($fI['filename']).' <em>(Original)</em>'; 02895 $pInfo['ref'] = 'FILE'; 02896 $pInfo['size'] = $fI['filesize']; 02897 $pInfo['class'] = $htmlColorClass ? $htmlColorClass : 'bgColor3'; 02898 $pInfo['type'] = 'file'; 02899 $lines[] = $pInfo; 02900 unset($this->remainHeader['files'][$ID]); 02901 } 02902 02903 // External resources: 02904 if (is_array($fI['EXT_RES_ID'])) { 02905 foreach($fI['EXT_RES_ID'] as $ID) { 02906 $pInfo = array(); 02907 $fI = $this->dat['header']['files'][$ID]; 02908 if (!is_array($fI)) { 02909 $pInfo['msg'] = 'MISSING External Resource FILE: '.$ID; 02910 $this->error('MISSING External Resource FILE: '.$ID,1); 02911 } else { 02912 $pInfo['updatePath'] = $fI['parentRelFileName']; 02913 } 02914 02915 $pInfo['showDiffContent'] = substr($this->fileIDMap[$ID],strlen(PATH_site)); 02916 02917 $pInfo['preCode'] = $preCode.' <img'.t3lib_iconWorks::skinImg($GLOBALS['BACK_PATH'],'gfx/rel_file.gif','width="13" height="12"').' align="top" alt="" />'; 02918 $pInfo['title'] = htmlspecialchars($fI['filename']).' <em>(Resource)</em>'; 02919 $pInfo['ref'] = 'FILE'; 02920 $pInfo['size'] = $fI['filesize']; 02921 $pInfo['class'] = $htmlColorClass ? $htmlColorClass : 'bgColor3'; 02922 $pInfo['type'] = 'file'; 02923 $lines[] = $pInfo; 02924 unset($this->remainHeader['files'][$ID]); 02925 } 02926 } 02927 } 02928 } 02929 02937 function checkDokType($checkTable,$doktype) { 02938 global $PAGES_TYPES; 02939 $allowedTableList = isset($PAGES_TYPES[$doktype]['allowedTables']) ? $PAGES_TYPES[$doktype]['allowedTables'] : $PAGES_TYPES['default']['allowedTables']; 02940 $allowedArray = t3lib_div::trimExplode(',',$allowedTableList,1); 02941 if (strstr($allowedTableList,'*') || in_array($checkTable,$allowedArray)) { // If all tables or the table is listed as a allowed type, return true 02942 return true; 02943 } 02944 } 02945 02953 function renderControls($r) { 02954 global $LANG; 02955 02956 if ($this->mode==='export') { 02957 return ($r['type']=='record' ? '<input type="checkbox" name="tx_impexp[exclude]['.$r['ref'].']" value="1" /> '.$LANG->getLL('impexpcore_singlereco_exclude',1) : 02958 ($r['type']=='softref' ? $this->softrefSelector($r['_softRefInfo']) : '')); 02959 } else { // During import 02960 02961 // For softreferences with editable fields: 02962 if ($r['type']=='softref' && is_array($r['_softRefInfo']['subst']) && $r['_softRefInfo']['subst']['tokenID']) { 02963 $tokenID = $r['_softRefInfo']['subst']['tokenID']; 02964 $cfg = $this->softrefCfg[$tokenID]; 02965 if ($cfg['mode'] === 'editable') { 02966 return 02967 (strlen($cfg['title']) ? '<b>'.htmlspecialchars($cfg['title']).'</b><br/>' : ''). 02968 htmlspecialchars($cfg['description']).'<br/> 02969 <input type="text" name="tx_impexp[softrefInputValues]['.$tokenID.']" value="'.htmlspecialchars(isset($this->softrefInputValues[$tokenID]) ? $this->softrefInputValues[$tokenID] : $cfg['defValue']).'" />'; 02970 } 02971 } 02972 } 02973 } 02974 02981 function softrefSelector($cfg) { 02982 global $LANG; 02983 02984 // Looking for file ID if any: 02985 $fI = $cfg['file_ID'] ? $this->dat['header']['files'][$cfg['file_ID']] : array(); 02986 02987 // Substitution scheme has to be around and RTE images MUST be exported. 02988 if (is_array($cfg['subst']) && $cfg['subst']['tokenID'] && !$fI['RTE_ORIG_ID']) { 02989 02990 // Create options: 02991 $optValues = array(); 02992 $optValues[''] = ''; 02993 $optValues['editable'] = $LANG->getLL('impexpcore_softrefsel_editable'); 02994 $optValues['exclude'] = $LANG->getLL('impexpcore_softrefsel_exclude'); 02995 02996 // Get current value: 02997 $value = $this->softrefCfg[$cfg['subst']['tokenID']]['mode']; 02998 02999 // Render options selector: 03000 $selectorbox = $this->renderSelectBox('tx_impexp[softrefCfg]['.$cfg['subst']['tokenID'].'][mode]',$value,$optValues).'<br/>'; 03001 03002 if ($value === 'editable') { 03003 03004 $descriptionField = ''; 03005 03006 // Title: 03007 if (strlen($cfg['subst']['title'])) { 03008 $descriptionField.= ' 03009 <input type="hidden" name="tx_impexp[softrefCfg]['.$cfg['subst']['tokenID'].'][title]" value="'.htmlspecialchars($cfg['subst']['title']).'" /> 03010 <b>'.htmlspecialchars($cfg['subst']['title']).'</b><br/>'; 03011 } 03012 03013 // Description: 03014 if (!strlen($cfg['subst']['description'])) { 03015 $descriptionField.= ' 03016 '.$LANG->getLL('impexpcore_printerror_description',1).'<br/> 03017 <input type="text" name="tx_impexp[softrefCfg]['.$cfg['subst']['tokenID'].'][description]" value="'.htmlspecialchars($this->softrefCfg[$cfg['subst']['tokenID']]['description']).'" />'; 03018 } else { 03019 $descriptionField.= ' 03020 03021 <input type="hidden" name="tx_impexp[softrefCfg]['.$cfg['subst']['tokenID'].'][description]" value="'.htmlspecialchars($cfg['subst']['description']).'" />'. 03022 htmlspecialchars($cfg['subst']['description']); 03023 } 03024 03025 // Default Value: 03026 $descriptionField.= '<input type="hidden" name="tx_impexp[softrefCfg]['.$cfg['subst']['tokenID'].'][defValue]" value="'.htmlspecialchars($cfg['subst']['tokenValue']).'" />'; 03027 03028 } else $descriptionField = ''; 03029 03030 return $selectorbox.$descriptionField; 03031 } 03032 } 03033 03034 03035 03036 03037 03038 03039 03040 03041 03042 03043 03044 03045 /***************************** 03046 * 03047 * Helper functions of kinds 03048 * 03049 *****************************/ 03050 03057 function isTableStatic($table) { 03058 global $TCA; 03059 03060 if (is_array($TCA[$table])) { 03061 return $TCA[$table]['ctrl']['is_static'] || in_array($table, $this->relStaticTables) || in_array('_ALL', $this->relStaticTables); 03062 } 03063 } 03064 03071 function inclRelation($table) { 03072 global $TCA; 03073 03074 if (is_array($TCA[$table])) { 03075 return (in_array($table, $this->relOnlyTables) || in_array('_ALL', $this->relOnlyTables)) && $GLOBALS['BE_USER']->check('tables_select',$table); 03076 } 03077 } 03078 03086 function isExcluded($table,$uid) { 03087 global $TCA; 03088 03089 return $this->excludeMap[$table.':'.$uid] ? TRUE : FALSE; 03090 } 03091 03098 function includeSoftref($tokenID) { 03099 return $tokenID && !t3lib_div::inList('exclude,editable', $this->softrefCfg[$tokenID]['mode']); 03100 } 03101 03108 function checkPID($pid) { 03109 global $BE_USER; 03110 03111 if (!isset($this->checkPID_cache[$pid])) { 03112 $this->checkPID_cache[$pid] = (boolean)$BE_USER->isInWebMount($pid); 03113 } 03114 03115 return $this->checkPID_cache[$pid]; 03116 } 03117 03125 function dontIgnorePid($table, $uid) { 03126 return $this->import_mode[$table.':'.$uid]!=='ignore_pid' && 03127 (!$this->global_ignore_pid || $this->import_mode[$table.':'.$uid]==='respect_pid'); 03128 } 03129 03138 function doesRecordExist($table,$uid,$fields='') { 03139 return t3lib_BEfunc::getRecord($table, $uid, $fields ? $fields : 'uid,pid'); 03140 } 03141 03148 function getRecordPath($pid) { 03149 if (!isset($this->cache_getRecordPath[$pid])) { 03150 $clause = $GLOBALS['BE_USER']->getPagePermsClause(1); 03151 $this->cache_getRecordPath[$pid] = (string)t3lib_BEfunc::getRecordPath($pid, $clause, 20); 03152 } 03153 03154 return $this->cache_getRecordPath[$pid]; 03155 } 03156 03165 function renderSelectBox($prefix,$value,$optValues) { 03166 $opt = array(); 03167 $isSelFlag = 0; 03168 reset($optValues); 03169 while(list($k,$v) = each($optValues)) { 03170 $sel = (!strcmp($k,$value) ? ' selected="selected"' : ''); 03171 if ($sel) $isSelFlag++; 03172 $opt[] = '<option value="'.htmlspecialchars($k).'"'.$sel.'>'.htmlspecialchars($v).'</option>'; 03173 } 03174 if (!$isSelFlag && strcmp('',$value)) { 03175 $opt[] = '<option value="'.htmlspecialchars($value).'" selected="selected">'.htmlspecialchars("['".$value."']").'</option>'; 03176 } 03177 return '<select name="'.$prefix.'">'.implode('',$opt).'</select>'; 03178 } 03179 03189 function compareRecords($databaseRecord, $importRecord, $table, $inverseDiff=FALSE) { 03190 global $TCA, $LANG; 03191 03192 // Initialize: 03193 $output = array(); 03194 $t3lib_diff_Obj = t3lib_div::makeInstance('t3lib_diff'); 03195 03196 // Check if both inputs are records: 03197 if (is_array($databaseRecord) && is_array($importRecord)) { 03198 03199 // Traverse based on database record 03200 foreach($databaseRecord as $fN => $value) { 03201 if (is_array($TCA[$table]['columns'][$fN]) && $TCA[$table]['columns'][$fN]['config']['type']!='passthrough') { 03202 if (isset($importRecord[$fN])) { 03203 if (strcmp(trim($databaseRecord[$fN]), trim($importRecord[$fN]))) { 03204 03205 // Create diff-result: 03206 $output[$fN] = $t3lib_diff_Obj->makeDiffDisplay( 03207 t3lib_BEfunc::getProcessedValue($table,$fN,!$inverseDiff ? $importRecord[$fN] : $databaseRecord[$fN] ,0,1,1), 03208 t3lib_BEfunc::getProcessedValue($table,$fN,!$inverseDiff ? $databaseRecord[$fN] : $importRecord[$fN] ,0,1,1) 03209 ); 03210 } 03211 unset($importRecord[$fN]); 03212 } else { 03213 // 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!)? 03214 #$output[$fN] = '<b>Field missing</b> in import file'; 03215 } 03216 } 03217 } 03218 03219 // Traverse remaining in import record: 03220 foreach($importRecord as $fN => $value) { 03221 if (is_array($TCA[$table]['columns'][$fN]) && $TCA[$table]['columns'][$fN]['config']['type']!='passthrough') { 03222 $output[$fN] = '<b>Field missing</b> in database'; 03223 } 03224 } 03225 03226 // Create output: 03227 if (count($output)) { 03228 $tRows = array(); 03229 foreach($output as $fN => $state) { 03230 $tRows[] = ' 03231 <tr> 03232 <td class="bgColor5">'.$LANG->sL($TCA[$table]['columns'][$fN]['label'],1).' ('.htmlspecialchars($fN).')</td> 03233 <td class="bgColor4">'.$state.'</td> 03234 </tr> 03235 '; 03236 } 03237 03238 $output = '<table border="0" cellpadding="0" cellspacing="1">'.implode('',$tRows).'</table>'; 03239 } else { 03240 $output = 'Match'; 03241 } 03242 03243 return '<b class="nobr">['.htmlspecialchars($table.':'.$importRecord['uid'].' => '.$databaseRecord['uid']).']:</b> '.$output; 03244 } 03245 03246 03247 return 'ERROR: One of the inputs were not an array!'; 03248 } 03249 03256 function getRTEoriginalFilename($string) { 03257 // If "magic image": 03258 if (t3lib_div::isFirstPartOfStr($string,'RTEmagicC_')) { 03259 // Find original file: 03260 $pI = pathinfo(substr($string,strlen('RTEmagicC_'))); 03261 $filename = substr($pI['basename'],0,-strlen('.'.$pI['extension'])); 03262 $origFilePath = 'RTEmagicP_'.$filename; 03263 03264 return $origFilePath; 03265 } 03266 } 03267 03273 function &getFileProcObj() { 03274 global $FILEMOUNTS, $TYPO3_CONF_VARS, $BE_USER; 03275 03276 if (!is_object($this->fileProcObj)) { 03277 $this->fileProcObj = t3lib_div::makeInstance('t3lib_extFileFunctions'); 03278 $this->fileProcObj->init($FILEMOUNTS, $TYPO3_CONF_VARS['BE']['fileExtensions']); 03279 $this->fileProcObj->init_actionPerms($BE_USER->user['fileoper_perms']); 03280 } 03281 03282 return $this->fileProcObj; 03283 } 03284 03285 03286 03287 03288 03289 03290 03291 03292 03293 /***************************** 03294 * 03295 * Error handling 03296 * 03297 *****************************/ 03298 03305 function error($msg) { 03306 $this->errorLog[]=$msg; 03307 } 03308 03314 function printErrorLog() { 03315 return count($this->errorLog) ? t3lib_div::view_array($this->errorLog) : ''; 03316 } 03317 } 03318 03319 03320 03321 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/impexp/class.tx_impexp.php']) { 03322 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/impexp/class.tx_impexp.php']); 03323 } 03324 ?>