TYPO3 CMS  TYPO3_8-7
Export.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Impexp;
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
25 
59 class Export extends ImportExport
60 {
66  public $maxFileSize = 1000000;
67 
73  public $maxRecordSize = 1000000;
74 
80  public $maxExportSize = 10000000;
81 
87  public $dontCompress = false;
88 
94  public $includeExtFileResources = false;
95 
101  public $extFileResourceExtensions = 'html,htm,css';
102 
110 
116  protected $defaultRecordIncludeFields = ['uid', 'pid'];
117 
121  protected $saveFilesOutsideExportFile = false;
122 
127 
128  /**************************
129  * Initialize
130  *************************/
131 
137  public function init($dontCompress = false)
138  {
139  parent::init();
140  $this->dontCompress = $dontCompress;
141  $this->mode = 'export';
142  }
143 
144  /**************************
145  * Export / Init + Meta Data
146  *************************/
147 
151  public function setHeaderBasics()
152  {
153  // Initializing:
154  if (is_array($this->softrefCfg)) {
155  foreach ($this->softrefCfg as $key => $value) {
156  if (!strlen($value['mode'])) {
157  unset($this->softrefCfg[$key]);
158  }
159  }
160  }
161  // Setting in header memory:
162  // Version of file format
163  $this->dat['header']['XMLversion'] = '1.0';
164  // Initialize meta data array (to put it in top of file)
165  $this->dat['header']['meta'] = [];
166  // Add list of tables to consider static
167  $this->dat['header']['relStaticTables'] = $this->relStaticTables;
168  // The list of excluded records
169  $this->dat['header']['excludeMap'] = $this->excludeMap;
170  // Soft Reference mode for elements
171  $this->dat['header']['softrefCfg'] = $this->softrefCfg;
172  // List of extensions the import depends on.
173  $this->dat['header']['extensionDependencies'] = $this->extensionDependencies;
174  $this->dat['header']['charset'] = 'utf-8';
175  }
176 
182  public function setCharset($charset)
183  {
184  $this->dat['header']['charset'] = $charset;
185  }
186 
197  public function setMetaData($title, $description, $notes, $packager_username, $packager_name, $packager_email)
198  {
199  $this->dat['header']['meta'] = [
200  'title' => $title,
201  'description' => $description,
202  'notes' => $notes,
203  'packager_username' => $packager_username,
204  'packager_name' => $packager_name,
205  'packager_email' => $packager_email,
206  'TYPO3_version' => TYPO3_version,
207  'created' => strftime('%A %e. %B %Y', $GLOBALS['EXEC_TIME'])
208  ];
209  }
210 
219  {
220  $this->saveFilesOutsideExportFile = $saveFilesOutsideExportFile;
221  }
222 
223  /**************************
224  * Export / Init Page tree
225  *************************/
226 
233  public function setPageTree($idH)
234  {
235  $this->dat['header']['pagetree'] = $this->unsetExcludedSections($idH);
236  return $this->flatInversePageTree($this->dat['header']['pagetree']);
237  }
238 
247  public function unsetExcludedSections($idH)
248  {
249  if (is_array($idH)) {
250  foreach ($idH as $k => $v) {
251  if ($this->excludeMap['pages:' . $idH[$k]['uid']]) {
252  unset($idH[$k]);
253  } elseif (is_array($idH[$k]['subrow'])) {
254  $idH[$k]['subrow'] = $this->unsetExcludedSections($idH[$k]['subrow']);
255  }
256  }
257  }
258  return $idH;
259  }
260 
261  /**************************
262  * Export
263  *************************/
264 
272  {
273  foreach ($recordTypesIncludeFields as $table => $fields) {
274  if (!is_array($fields)) {
275  throw new Exception('The include fields for record type ' . htmlspecialchars($table) . ' are not defined by an array.', 1391440658);
276  }
277  $this->setRecordTypeIncludeFields($table, $fields);
278  }
279  }
280 
287  public function setRecordTypeIncludeFields($table, array $fields)
288  {
289  $this->recordTypesIncludeFields[$table] = $fields;
290  }
291 
300  public function export_addRecord($table, $row, $relationLevel = 0)
301  {
302  BackendUtility::workspaceOL($table, $row);
303  if ($this->excludeDisabledRecords && !$this->isActive($table, $row['uid'])) {
304  return;
305  }
306  if ((string)$table !== '' && is_array($row) && $row['uid'] > 0 && !$this->excludeMap[$table . ':' . $row['uid']]) {
307  if ($this->checkPID($table === 'pages' ? $row['uid'] : $row['pid'])) {
308  if (!isset($this->dat['records'][$table . ':' . $row['uid']])) {
309  // Prepare header info:
310  $row = $this->filterRecordFields($table, $row);
311  $headerInfo = [];
312  $headerInfo['uid'] = $row['uid'];
313  $headerInfo['pid'] = $row['pid'];
314  $headerInfo['title'] = GeneralUtility::fixed_lgd_cs(BackendUtility::getRecordTitle($table, $row), 40);
315  $headerInfo['size'] = strlen(serialize($row));
316  if ($relationLevel) {
317  $headerInfo['relationLevel'] = $relationLevel;
318  }
319  // If record content is not too large in size, set the header content and add the rest:
320  if ($headerInfo['size'] < $this->maxRecordSize) {
321  // Set the header summary:
322  $this->dat['header']['records'][$table][$row['uid']] = $headerInfo;
323  // Create entry in the PID lookup:
324  $this->dat['header']['pid_lookup'][$row['pid']][$table][$row['uid']] = 1;
325  // Initialize reference index object:
326  $refIndexObj = GeneralUtility::makeInstance(ReferenceIndex::class);
327  // Yes to workspace overlays for exporting....
328  $refIndexObj->WSOL = true;
329  $relations = $refIndexObj->getRelations($table, $row);
330  $relations = $this->fixFileIDsInRelations($relations);
331  $relations = $this->removeSoftrefsHavingTheSameDatabaseRelation($relations);
332  // Data:
333  $this->dat['records'][$table . ':' . $row['uid']] = [];
334  $this->dat['records'][$table . ':' . $row['uid']]['data'] = $row;
335  $this->dat['records'][$table . ':' . $row['uid']]['rels'] = $relations;
336  // Add information about the relations in the record in the header:
337  $this->dat['header']['records'][$table][$row['uid']]['rels'] = $this->flatDBrels($this->dat['records'][$table . ':' . $row['uid']]['rels']);
338  // Add information about the softrefs to header:
339  $this->dat['header']['records'][$table][$row['uid']]['softrefs'] = $this->flatSoftRefs($this->dat['records'][$table . ':' . $row['uid']]['rels']);
340  } else {
341  $this->error('Record ' . $table . ':' . $row['uid'] . ' was larger than maxRecordSize (' . GeneralUtility::formatSize($this->maxRecordSize) . ')');
342  }
343  } else {
344  $this->error('Record ' . $table . ':' . $row['uid'] . ' already added.');
345  }
346  } else {
347  $this->error('Record ' . $table . ':' . $row['uid'] . ' was outside your DB mounts!');
348  }
349  }
350  }
351 
359  protected function fixFileIDsInRelations(array $relations)
360  {
361  foreach ($relations as $field => $relation) {
362  if (isset($relation['type']) && $relation['type'] === 'file') {
363  foreach ($relation['newValueFiles'] as $key => $fileRelationData) {
364  $absoluteFilePath = $fileRelationData['ID_absFile'];
365  if (GeneralUtility::isFirstPartOfStr($absoluteFilePath, PATH_site)) {
366  $relatedFilePath = PathUtility::stripPathSitePrefix($absoluteFilePath);
367  $relations[$field]['newValueFiles'][$key]['ID'] = md5($relatedFilePath);
368  }
369  }
370  }
371  if ($relation['type'] === 'flex') {
372  if (is_array($relation['flexFormRels']['file'])) {
373  foreach ($relation['flexFormRels']['file'] as $key => $subList) {
374  foreach ($subList as $subKey => $fileRelationData) {
375  $absoluteFilePath = $fileRelationData['ID_absFile'];
376  if (GeneralUtility::isFirstPartOfStr($absoluteFilePath, PATH_site)) {
377  $relatedFilePath = PathUtility::stripPathSitePrefix($absoluteFilePath);
378  $relations[$field]['flexFormRels']['file'][$key][$subKey]['ID'] = md5($relatedFilePath);
379  }
380  }
381  }
382  }
383  }
384  }
385  return $relations;
386  }
387 
397  protected function removeSoftrefsHavingTheSameDatabaseRelation($relations)
398  {
399  $fixedRelations = [];
400  foreach ($relations as $field => $relation) {
401  $newRelation = $relation;
402  if (isset($newRelation['type']) && $newRelation['type'] === 'db') {
403  foreach ($newRelation['itemArray'] as $key => $dbRelationData) {
404  if ($dbRelationData['table'] === 'sys_file') {
405  if (isset($newRelation['softrefs']['keys']['typolink'])) {
406  foreach ($newRelation['softrefs']['keys']['typolink'] as $softrefKey => $softRefData) {
407  if ($softRefData['subst']['type'] === 'file') {
408  $file = ResourceFactory::getInstance()->retrieveFileOrFolderObject($softRefData['subst']['relFileName']);
409  if ($file instanceof File) {
410  if ($file->getUid() == $dbRelationData['id']) {
411  unset($newRelation['softrefs']['keys']['typolink'][$softrefKey]);
412  }
413  }
414  }
415  }
416  if (empty($newRelation['softrefs']['keys']['typolink'])) {
417  unset($newRelation['softrefs']);
418  }
419  }
420  }
421  }
422  }
423  $fixedRelations[$field] = $newRelation;
424  }
425  return $fixedRelations;
426  }
427 
438  public function export_addDBRelations($relationLevel = 0)
439  {
440  // Traverse all "rels" registered for "records"
441  if (!is_array($this->dat['records'])) {
442  $this->error('There were no records available.');
443  return [];
444  }
445  $addR = [];
446  foreach ($this->dat['records'] as $k => $value) {
447  if (!is_array($this->dat['records'][$k])) {
448  continue;
449  }
450  foreach ($this->dat['records'][$k]['rels'] as $fieldname => $vR) {
451  // For all DB types of relations:
452  if ($vR['type'] === 'db') {
453  foreach ($vR['itemArray'] as $fI) {
454  $this->export_addDBRelations_registerRelation($fI, $addR);
455  }
456  }
457  // For all flex/db types of relations:
458  if ($vR['type'] === 'flex') {
459  // DB relations in flex form fields:
460  if (is_array($vR['flexFormRels']['db'])) {
461  foreach ($vR['flexFormRels']['db'] as $subList) {
462  foreach ($subList as $fI) {
463  $this->export_addDBRelations_registerRelation($fI, $addR);
464  }
465  }
466  }
467  // DB oriented soft references in flex form fields:
468  if (is_array($vR['flexFormRels']['softrefs'])) {
469  foreach ($vR['flexFormRels']['softrefs'] as $subList) {
470  foreach ($subList['keys'] as $spKey => $elements) {
471  foreach ($elements as $el) {
472  if ($el['subst']['type'] === 'db' && $this->includeSoftref($el['subst']['tokenID'])) {
473  list($tempTable, $tempUid) = explode(':', $el['subst']['recordRef']);
474  $fI = [
475  'table' => $tempTable,
476  'id' => $tempUid
477  ];
478  $this->export_addDBRelations_registerRelation($fI, $addR, $el['subst']['tokenID']);
479  }
480  }
481  }
482  }
483  }
484  }
485  // In any case, if there are soft refs:
486  if (is_array($vR['softrefs']['keys'])) {
487  foreach ($vR['softrefs']['keys'] as $spKey => $elements) {
488  foreach ($elements as $el) {
489  if ($el['subst']['type'] === 'db' && $this->includeSoftref($el['subst']['tokenID'])) {
490  list($tempTable, $tempUid) = explode(':', $el['subst']['recordRef']);
491  $fI = [
492  'table' => $tempTable,
493  'id' => $tempUid
494  ];
495  $this->export_addDBRelations_registerRelation($fI, $addR, $el['subst']['tokenID']);
496  }
497  }
498  }
499  }
500  }
501  }
502 
503  // Now, if there were new records to add, do so:
504  if (!empty($addR)) {
505  foreach ($addR as $fI) {
506  // Get and set record:
507  $row = BackendUtility::getRecord($fI['table'], $fI['id']);
508  if (is_array($row)) {
509  $this->export_addRecord($fI['table'], $row, $relationLevel + 1);
510  }
511  // Set status message
512  // Relation pointers always larger than zero except certain "select" types with
513  // negative values pointing to uids - but that is not supported here.
514  if ($fI['id'] > 0) {
515  $rId = $fI['table'] . ':' . $fI['id'];
516  if (!isset($this->dat['records'][$rId])) {
517  $this->dat['records'][$rId] = 'NOT_FOUND';
518  $this->error('Relation record ' . $rId . ' was not found!');
519  }
520  }
521  }
522  }
523  // Return overview of relations found and added
524  return $addR;
525  }
526 
535  public function export_addDBRelations_registerRelation($fI, &$addR, $tokenID = '')
536  {
537  $rId = $fI['table'] . ':' . $fI['id'];
538  if (
539  isset($GLOBALS['TCA'][$fI['table']]) && !$this->isTableStatic($fI['table']) && !$this->isExcluded($fI['table'], $fI['id'])
540  && (!$tokenID || $this->includeSoftref($tokenID)) && $this->inclRelation($fI['table'])
541  ) {
542  if (!isset($this->dat['records'][$rId])) {
543  // Set this record to be included since it is not already.
544  $addR[$rId] = $fI;
545  }
546  }
547  }
548 
556  {
557  // Traverse all "rels" registered for "records"
558  if (!is_array($this->dat['records'])) {
559  $this->error('There were no records available.');
560  return;
561  }
562  foreach ($this->dat['records'] as $k => $value) {
563  if (!isset($this->dat['records'][$k]['rels']) || !is_array($this->dat['records'][$k]['rels'])) {
564  continue;
565  }
566  foreach ($this->dat['records'][$k]['rels'] as $fieldname => $vR) {
567  // For all file type relations:
568  if ($vR['type'] === 'file') {
569  foreach ($vR['newValueFiles'] as $key => $fI) {
570  $this->export_addFile($fI, $k, $fieldname);
571  // Remove the absolute reference to the file so it doesn't expose absolute paths from source server:
572  unset($this->dat['records'][$k]['rels'][$fieldname]['newValueFiles'][$key]['ID_absFile']);
573  }
574  }
575  // For all flex type relations:
576  if ($vR['type'] === 'flex') {
577  if (is_array($vR['flexFormRels']['file'])) {
578  foreach ($vR['flexFormRels']['file'] as $key => $subList) {
579  foreach ($subList as $subKey => $fI) {
580  $this->export_addFile($fI, $k, $fieldname);
581  // Remove the absolute reference to the file so it doesn't expose absolute paths from source server:
582  unset($this->dat['records'][$k]['rels'][$fieldname]['flexFormRels']['file'][$key][$subKey]['ID_absFile']);
583  }
584  }
585  }
586  // DB oriented soft references in flex form fields:
587  if (is_array($vR['flexFormRels']['softrefs'])) {
588  foreach ($vR['flexFormRels']['softrefs'] as $key => $subList) {
589  foreach ($subList['keys'] as $spKey => $elements) {
590  foreach ($elements as $subKey => $el) {
591  if ($el['subst']['type'] === 'file' && $this->includeSoftref($el['subst']['tokenID'])) {
592  // Create abs path and ID for file:
593  $ID_absFile = GeneralUtility::getFileAbsFileName(PATH_site . $el['subst']['relFileName']);
594  $ID = md5($el['subst']['relFileName']);
595  if ($ID_absFile) {
596  if (!$this->dat['files'][$ID]) {
597  $fI = [
598  'filename' => PathUtility::basename($ID_absFile),
599  'ID_absFile' => $ID_absFile,
600  'ID' => $ID,
601  'relFileName' => $el['subst']['relFileName']
602  ];
603  $this->export_addFile($fI, '_SOFTREF_');
604  }
605  $this->dat['records'][$k]['rels'][$fieldname]['flexFormRels']['softrefs'][$key]['keys'][$spKey][$subKey]['file_ID'] = $ID;
606  }
607  }
608  }
609  }
610  }
611  }
612  }
613  // In any case, if there are soft refs:
614  if (is_array($vR['softrefs']['keys'])) {
615  foreach ($vR['softrefs']['keys'] as $spKey => $elements) {
616  foreach ($elements as $subKey => $el) {
617  if ($el['subst']['type'] === 'file' && $this->includeSoftref($el['subst']['tokenID'])) {
618  // Create abs path and ID for file:
619  $ID_absFile = GeneralUtility::getFileAbsFileName(PATH_site . $el['subst']['relFileName']);
620  $ID = md5($el['subst']['relFileName']);
621  if ($ID_absFile) {
622  if (!$this->dat['files'][$ID]) {
623  $fI = [
624  'filename' => PathUtility::basename($ID_absFile),
625  'ID_absFile' => $ID_absFile,
626  'ID' => $ID,
627  'relFileName' => $el['subst']['relFileName']
628  ];
629  $this->export_addFile($fI, '_SOFTREF_');
630  }
631  $this->dat['records'][$k]['rels'][$fieldname]['softrefs']['keys'][$spKey][$subKey]['file_ID'] = $ID;
632  }
633  }
634  }
635  }
636  }
637  }
638  }
639  }
640 
645  {
646  if (!isset($this->dat['header']['records']['sys_file']) || !is_array($this->dat['header']['records']['sys_file'])) {
647  return;
648  }
649  foreach ($this->dat['header']['records']['sys_file'] as $sysFileUid => $_) {
650  $recordData = $this->dat['records']['sys_file:' . $sysFileUid]['data'];
651  $file = ResourceFactory::getInstance()->createFileObject($recordData);
652  $this->export_addSysFile($file);
653  }
654  }
655 
661  public function export_addSysFile(File $file)
662  {
663  if ($file->getProperty('size') >= $this->maxFileSize) {
664  $this->error('File ' . $file->getPublicUrl() . ' was larger (' . GeneralUtility::formatSize($file->getProperty('size')) . ') than the maxFileSize (' . GeneralUtility::formatSize($this->maxFileSize) . ')! Skipping.');
665  return;
666  }
667  $fileContent = '';
668  try {
669  if (!$this->saveFilesOutsideExportFile) {
670  $fileContent = $file->getContents();
671  } else {
672  $file->checkActionPermission('read');
673  }
674  } catch (\Exception $e) {
675  $this->error('Error when trying to add file ' . $file->getCombinedIdentifier() . ': ' . $e->getMessage());
676  return;
677  }
678  $fileUid = $file->getUid();
679  $fileInfo = $file->getStorage()->getFileInfo($file);
680  $fileSize = (int)$fileInfo['size'];
681  if ($fileSize !== (int)$file->getProperty('size')) {
682  $this->error('File size of ' . $file->getCombinedIdentifier() . ' is not up-to-date in index! File added with current size.');
683  $this->dat['records']['sys_file:' . $fileUid]['data']['size'] = $fileSize;
684  }
685  $fileSha1 = $file->getStorage()->hashFile($file, 'sha1');
686  if ($fileSha1 !== $file->getProperty('sha1')) {
687  $this->error('File sha1 hash of ' . $file->getCombinedIdentifier() . ' is not up-to-date in index! File added on current sha1.');
688  $this->dat['records']['sys_file:' . $fileUid]['data']['sha1'] = $fileSha1;
689  }
690 
691  $fileRec = [];
692  $fileRec['filesize'] = $fileSize;
693  $fileRec['filename'] = $file->getProperty('name');
694  $fileRec['filemtime'] = $file->getProperty('modification_date');
695 
696  // build unique id based on the storage and the file identifier
697  $fileId = md5($file->getStorage()->getUid() . ':' . $file->getProperty('identifier_hash'));
698 
699  // Setting this data in the header
700  $this->dat['header']['files_fal'][$fileId] = $fileRec;
701 
702  if (!$this->saveFilesOutsideExportFile) {
703  // ... and finally add the heavy stuff:
704  $fileRec['content'] = $fileContent;
705  } else {
707  }
708  $fileRec['content_sha1'] = $fileSha1;
709 
710  $this->dat['files_fal'][$fileId] = $fileRec;
711  }
712 
720  public function export_addFile($fI, $recordRef = '', $fieldname = '')
721  {
722  if (!@is_file($fI['ID_absFile'])) {
723  $this->error($fI['ID_absFile'] . ' was not a file! Skipping.');
724  return;
725  }
726  if (filesize($fI['ID_absFile']) >= $this->maxFileSize) {
727  $this->error($fI['ID_absFile'] . ' was larger (' . GeneralUtility::formatSize(filesize($fI['ID_absFile'])) . ') than the maxFileSize (' . GeneralUtility::formatSize($this->maxFileSize) . ')! Skipping.');
728  return;
729  }
730  $fileInfo = stat($fI['ID_absFile']);
731  $fileRec = [];
732  $fileRec['filesize'] = $fileInfo['size'];
733  $fileRec['filename'] = PathUtility::basename($fI['ID_absFile']);
734  $fileRec['filemtime'] = $fileInfo['mtime'];
735  //for internal type file_reference
736  $fileRec['relFileRef'] = PathUtility::stripPathSitePrefix($fI['ID_absFile']);
737  if ($recordRef) {
738  $fileRec['record_ref'] = $recordRef . '/' . $fieldname;
739  }
740  if ($fI['relFileName']) {
741  $fileRec['relFileName'] = $fI['relFileName'];
742  }
743  // Setting this data in the header
744  $this->dat['header']['files'][$fI['ID']] = $fileRec;
745  // ... and for the recordlisting, why not let us know WHICH relations there was...
746  if ($recordRef && $recordRef !== '_SOFTREF_') {
747  $refParts = explode(':', $recordRef, 2);
748  if (!is_array($this->dat['header']['records'][$refParts[0]][$refParts[1]]['filerefs'])) {
749  $this->dat['header']['records'][$refParts[0]][$refParts[1]]['filerefs'] = [];
750  }
751  $this->dat['header']['records'][$refParts[0]][$refParts[1]]['filerefs'][] = $fI['ID'];
752  }
753  $fileMd5 = md5_file($fI['ID_absFile']);
754  if (!$this->saveFilesOutsideExportFile) {
755  // ... and finally add the heavy stuff:
756  $fileRec['content'] = file_get_contents($fI['ID_absFile']);
757  } else {
758  GeneralUtility::upload_copy_move($fI['ID_absFile'], $this->getTemporaryFilesPathForExport() . $fileMd5);
759  }
760  $fileRec['content_md5'] = $fileMd5;
761  $this->dat['files'][$fI['ID']] = $fileRec;
762  // For soft references, do further processing:
763  if ($recordRef === '_SOFTREF_') {
764  // RTE files?
765  if ($RTEoriginal = $this->getRTEoriginalFilename(PathUtility::basename($fI['ID_absFile']))) {
766  $RTEoriginal_absPath = PathUtility::dirname($fI['ID_absFile']) . '/' . $RTEoriginal;
767  if (@is_file($RTEoriginal_absPath)) {
768  $RTEoriginal_ID = md5($RTEoriginal_absPath);
769  $fileInfo = stat($RTEoriginal_absPath);
770  $fileRec = [];
771  $fileRec['filesize'] = $fileInfo['size'];
772  $fileRec['filename'] = PathUtility::basename($RTEoriginal_absPath);
773  $fileRec['filemtime'] = $fileInfo['mtime'];
774  $fileRec['record_ref'] = '_RTE_COPY_ID:' . $fI['ID'];
775  $this->dat['header']['files'][$fI['ID']]['RTE_ORIG_ID'] = $RTEoriginal_ID;
776  // Setting this data in the header
777  $this->dat['header']['files'][$RTEoriginal_ID] = $fileRec;
778  $fileMd5 = md5_file($RTEoriginal_absPath);
779  if (!$this->saveFilesOutsideExportFile) {
780  // ... and finally add the heavy stuff:
781  $fileRec['content'] = file_get_contents($RTEoriginal_absPath);
782  } else {
783  GeneralUtility::upload_copy_move($RTEoriginal_absPath, $this->getTemporaryFilesPathForExport() . $fileMd5);
784  }
785  $fileRec['content_md5'] = $fileMd5;
786  $this->dat['files'][$RTEoriginal_ID] = $fileRec;
787  } else {
788  $this->error('RTE original file "' . PathUtility::stripPathSitePrefix($RTEoriginal_absPath) . '" was not found!');
789  }
790  }
791  // Files with external media?
792  // This is only done with files grabbed by a softreference parser since it is deemed improbable that hard-referenced files should undergo this treatment.
793  $html_fI = pathinfo(PathUtility::basename($fI['ID_absFile']));
794  if ($this->includeExtFileResources && GeneralUtility::inList($this->extFileResourceExtensions, strtolower($html_fI['extension']))) {
795  $uniquePrefix = '###' . md5($GLOBALS['EXEC_TIME']) . '###';
796  if (strtolower($html_fI['extension']) === 'css') {
797  $prefixedMedias = explode($uniquePrefix, preg_replace('/(url[[:space:]]*\\([[:space:]]*["\']?)([^"\')]*)(["\']?[[:space:]]*\\))/i', '\\1' . $uniquePrefix . '\\2' . $uniquePrefix . '\\3', $fileRec['content']));
798  } else {
799  // html, htm:
800  $htmlParser = GeneralUtility::makeInstance(HtmlParser::class);
801  $prefixedMedias = explode($uniquePrefix, $htmlParser->prefixResourcePath($uniquePrefix, $fileRec['content'], [], $uniquePrefix));
802  }
803  $htmlResourceCaptured = false;
804  foreach ($prefixedMedias as $k => $v) {
805  if ($k % 2) {
806  $EXTres_absPath = GeneralUtility::resolveBackPath(PathUtility::dirname($fI['ID_absFile']) . '/' . $v);
807  $EXTres_absPath = GeneralUtility::getFileAbsFileName($EXTres_absPath);
808  if ($EXTres_absPath && GeneralUtility::isFirstPartOfStr($EXTres_absPath, PATH_site . $this->fileadminFolderName . '/') && @is_file($EXTres_absPath)) {
809  $htmlResourceCaptured = true;
810  $EXTres_ID = md5($EXTres_absPath);
811  $this->dat['header']['files'][$fI['ID']]['EXT_RES_ID'][] = $EXTres_ID;
812  $prefixedMedias[$k] = '{EXT_RES_ID:' . $EXTres_ID . '}';
813  // Add file to memory if it is not set already:
814  if (!isset($this->dat['header']['files'][$EXTres_ID])) {
815  $fileInfo = stat($EXTres_absPath);
816  $fileRec = [];
817  $fileRec['filesize'] = $fileInfo['size'];
818  $fileRec['filename'] = PathUtility::basename($EXTres_absPath);
819  $fileRec['filemtime'] = $fileInfo['mtime'];
820  $fileRec['record_ref'] = '_EXT_PARENT_:' . $fI['ID'];
821  // Media relative to the HTML file.
822  $fileRec['parentRelFileName'] = $v;
823  // Setting this data in the header
824  $this->dat['header']['files'][$EXTres_ID] = $fileRec;
825  // ... and finally add the heavy stuff:
826  $fileRec['content'] = file_get_contents($EXTres_absPath);
827  $fileRec['content_md5'] = md5($fileRec['content']);
828  $this->dat['files'][$EXTres_ID] = $fileRec;
829  }
830  }
831  }
832  }
833  if ($htmlResourceCaptured) {
834  $this->dat['files'][$fI['ID']]['tokenizedContent'] = implode('', $prefixedMedias);
835  }
836  }
837  }
838  }
839 
849  {
850  if (!$this->saveFilesOutsideExportFile) {
851  throw new \RuntimeException('You need to set saveFilesOutsideExportFile to TRUE before you want to get the temporary files path for export.', 1401205213);
852  }
853  if ($this->temporaryFilesPathForExport === null) {
854  $temporaryFolderName = $this->getTemporaryFolderName();
855  $this->temporaryFilesPathForExport = $temporaryFolderName . '/';
856  }
858  }
859 
867  public function flatDBrels($dbrels)
868  {
869  $list = [];
870  foreach ($dbrels as $dat) {
871  if ($dat['type'] === 'db') {
872  foreach ($dat['itemArray'] as $i) {
873  $list[$i['table'] . ':' . $i['id']] = $i;
874  }
875  }
876  if ($dat['type'] === 'flex' && is_array($dat['flexFormRels']['db'])) {
877  foreach ($dat['flexFormRels']['db'] as $subList) {
878  foreach ($subList as $i) {
879  $list[$i['table'] . ':' . $i['id']] = $i;
880  }
881  }
882  }
883  }
884  return $list;
885  }
886 
893  public function flatSoftRefs($dbrels)
894  {
895  $list = [];
896  foreach ($dbrels as $field => $dat) {
897  if (is_array($dat['softrefs']['keys'])) {
898  foreach ($dat['softrefs']['keys'] as $spKey => $elements) {
899  if (is_array($elements)) {
900  foreach ($elements as $subKey => $el) {
901  $lKey = $field . ':' . $spKey . ':' . $subKey;
902  $list[$lKey] = array_merge(['field' => $field, 'spKey' => $spKey], $el);
903  // Add file_ID key to header - slightly "risky" way of doing this because if the calculation
904  // changes for the same value in $this->records[...] this will not work anymore!
905  if ($el['subst'] && $el['subst']['relFileName']) {
906  $list[$lKey]['file_ID'] = md5(PATH_site . $el['subst']['relFileName']);
907  }
908  }
909  }
910  }
911  }
912  if ($dat['type'] === 'flex' && is_array($dat['flexFormRels']['softrefs'])) {
913  foreach ($dat['flexFormRels']['softrefs'] as $structurePath => $subSoftrefs) {
914  if (is_array($subSoftrefs['keys'])) {
915  foreach ($subSoftrefs['keys'] as $spKey => $elements) {
916  foreach ($elements as $subKey => $el) {
917  $lKey = $field . ':' . $structurePath . ':' . $spKey . ':' . $subKey;
918  $list[$lKey] = array_merge(['field' => $field, 'spKey' => $spKey, 'structurePath' => $structurePath], $el);
919  // Add file_ID key to header - slightly "risky" way of doing this because if the calculation
920  // changes for the same value in $this->records[...] this will not work anymore!
921  if ($el['subst'] && $el['subst']['relFileName']) {
922  $list[$lKey]['file_ID'] = md5(PATH_site . $el['subst']['relFileName']);
923  }
924  }
925  }
926  }
927  }
928  }
929  }
930  return $list;
931  }
932 
941  protected function filterRecordFields($table, array $row)
942  {
943  if (isset($this->recordTypesIncludeFields[$table])) {
944  $includeFields = array_unique(array_merge(
945  $this->recordTypesIncludeFields[$table],
946  $this->defaultRecordIncludeFields
947  ));
948  $newRow = [];
949  foreach ($row as $key => $value) {
950  if (in_array($key, $includeFields)) {
951  $newRow[$key] = $value;
952  }
953  }
954  } else {
955  $newRow = $row;
956  }
957  return $newRow;
958  }
959 
960  /**************************
961  * File Output
962  *************************/
963 
970  public function compileMemoryToFileContent($type = '')
971  {
972  if ($type === 'xml') {
973  $out = $this->createXML();
974  } else {
975  $compress = $this->doOutputCompress();
976  $out = '';
977  // adding header:
978  $out .= $this->addFilePart(serialize($this->dat['header']), $compress);
979  // adding records:
980  $out .= $this->addFilePart(serialize($this->dat['records']), $compress);
981  // adding files:
982  $out .= $this->addFilePart(serialize($this->dat['files']), $compress);
983  // adding files_fal:
984  $out .= $this->addFilePart(serialize($this->dat['files_fal']), $compress);
985  }
986  return $out;
987  }
988 
994  public function createXML()
995  {
996  // Options:
997  $options = [
998  'alt_options' => [
999  '/header' => [
1000  'disableTypeAttrib' => true,
1001  'clearStackPath' => true,
1002  'parentTagMap' => [
1003  'files' => 'file',
1004  'files_fal' => 'file',
1005  'records' => 'table',
1006  'table' => 'rec',
1007  'rec:rels' => 'relations',
1008  'relations' => 'element',
1009  'filerefs' => 'file',
1010  'pid_lookup' => 'page_contents',
1011  'header:relStaticTables' => 'static_tables',
1012  'static_tables' => 'tablename',
1013  'excludeMap' => 'item',
1014  'softrefCfg' => 'softrefExportMode',
1015  'extensionDependencies' => 'extkey',
1016  'softrefs' => 'softref_element'
1017  ],
1018  'alt_options' => [
1019  '/pagetree' => [
1020  'disableTypeAttrib' => true,
1021  'useIndexTagForNum' => 'node',
1022  'parentTagMap' => [
1023  'node:subrow' => 'node'
1024  ]
1025  ],
1026  '/pid_lookup/page_contents' => [
1027  'disableTypeAttrib' => true,
1028  'parentTagMap' => [
1029  'page_contents' => 'table'
1030  ],
1031  'grandParentTagMap' => [
1032  'page_contents/table' => 'item'
1033  ]
1034  ]
1035  ]
1036  ],
1037  '/records' => [
1038  'disableTypeAttrib' => true,
1039  'parentTagMap' => [
1040  'records' => 'tablerow',
1041  'tablerow:data' => 'fieldlist',
1042  'tablerow:rels' => 'related',
1043  'related' => 'field',
1044  'field:itemArray' => 'relations',
1045  'field:newValueFiles' => 'filerefs',
1046  'field:flexFormRels' => 'flexform',
1047  'relations' => 'element',
1048  'filerefs' => 'file',
1049  'flexform:db' => 'db_relations',
1050  'flexform:file' => 'file_relations',
1051  'flexform:softrefs' => 'softref_relations',
1052  'softref_relations' => 'structurePath',
1053  'db_relations' => 'path',
1054  'file_relations' => 'path',
1055  'path' => 'element',
1056  'keys' => 'softref_key',
1057  'softref_key' => 'softref_element'
1058  ],
1059  'alt_options' => [
1060  '/records/tablerow/fieldlist' => [
1061  'useIndexTagForAssoc' => 'field'
1062  ]
1063  ]
1064  ],
1065  '/files' => [
1066  'disableTypeAttrib' => true,
1067  'parentTagMap' => [
1068  'files' => 'file'
1069  ]
1070  ],
1071  '/files_fal' => [
1072  'disableTypeAttrib' => true,
1073  'parentTagMap' => [
1074  'files_fal' => 'file'
1075  ]
1076  ]
1077  ]
1078  ];
1079  // Creating XML file from $outputArray:
1080  $charset = $this->dat['header']['charset'] ?: 'utf-8';
1081  $XML = '<?xml version="1.0" encoding="' . $charset . '" standalone="yes" ?>' . LF;
1082  $XML .= GeneralUtility::array2xml($this->dat, '', 0, 'T3RecordDocument', 0, $options);
1083  return $XML;
1084  }
1085 
1091  public function doOutputCompress()
1092  {
1093  return $this->compress && !$this->dontCompress;
1094  }
1095 
1103  public function addFilePart($data, $compress = false)
1104  {
1105  if ($compress) {
1106  $data = gzcompress($data);
1107  }
1108  return md5($data) . ':' . ($compress ? '1' : '0') . ':' . str_pad(strlen($data), 10, '0', STR_PAD_LEFT) . ':' . $data . ':';
1109  }
1110 }
export_addDBRelations($relationLevel=0)
Definition: Export.php:438
setMetaData($title, $description, $notes, $packager_username, $packager_name, $packager_email)
Definition: Export.php:197
setSaveFilesOutsideExportFile($saveFilesOutsideExportFile)
Definition: Export.php:218
export_addFilesFromSysFilesRecords()
Definition: Export.php:644
static array2xml(array $array, $NSprefix='', $level=0, $docTag='phparray', $spaceInd=0, array $options=[], array $stackData=[])
compileMemoryToFileContent($type='')
Definition: Export.php:970
init($dontCompress=false)
Definition: Export.php:137
static isFirstPartOfStr($str, $partStr)
addFilePart($data, $compress=false)
Definition: Export.php:1103
static getFileAbsFileName($filename, $_=null, $_2=null)
removeSoftrefsHavingTheSameDatabaseRelation($relations)
Definition: Export.php:397
static workspaceOL($table, &$row, $wsid=-99, $unsetMovePointers=false)
static makeInstance($className,... $constructorArguments)
$fields
Definition: pages.php:4
export_addFile($fI, $recordRef='', $fieldname='')
Definition: Export.php:720
setRecordTypesIncludeFields(array $recordTypesIncludeFields)
Definition: Export.php:271
export_addRecord($table, $row, $relationLevel=0)
Definition: Export.php:300
fixFileIDsInRelations(array $relations)
Definition: Export.php:359
setRecordTypeIncludeFields($table, array $fields)
Definition: Export.php:287
static getRecordTitle($table, $row, $prep=false, $forceResult=true)
checkActionPermission($action)
Definition: File.php:266
static fixed_lgd_cs($string, $chars, $appendString='...')
static formatSize($sizeInBytes, $labels='', $base=0)
setCharset($charset)
Definition: Export.php:182
export_addDBRelations_registerRelation($fI, &$addR, $tokenID='')
Definition: Export.php:535
static getRecord($table, $uid, $fields=' *', $where='', $useDeleteClause=true)
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
filterRecordFields($table, array $row)
Definition: Export.php:941
export_addSysFile(File $file)
Definition: Export.php:661
static upload_copy_move($source, $destination)
getPublicUrl($relativeToCurrentScript=false)
Definition: File.php:364