TYPO3CMS  8
 All Classes Namespaces Files Functions Variables Pages
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 
138  public function init($dontCompress = false)
139  {
140  parent::init();
141  $this->dontCompress = $dontCompress;
142  $this->mode = 'export';
143  }
144 
145  /**************************
146  * Export / Init + Meta Data
147  *************************/
148 
154  public function setHeaderBasics()
155  {
156  // Initializing:
157  if (is_array($this->softrefCfg)) {
158  foreach ($this->softrefCfg as $key => $value) {
159  if (!strlen($value['mode'])) {
160  unset($this->softrefCfg[$key]);
161  }
162  }
163  }
164  // Setting in header memory:
165  // Version of file format
166  $this->dat['header']['XMLversion'] = '1.0';
167  // Initialize meta data array (to put it in top of file)
168  $this->dat['header']['meta'] = [];
169  // Add list of tables to consider static
170  $this->dat['header']['relStaticTables'] = $this->relStaticTables;
171  // The list of excluded records
172  $this->dat['header']['excludeMap'] = $this->excludeMap;
173  // Soft Reference mode for elements
174  $this->dat['header']['softrefCfg'] = $this->softrefCfg;
175  // List of extensions the import depends on.
176  $this->dat['header']['extensionDependencies'] = $this->extensionDependencies;
177  $this->dat['header']['charset'] = 'utf-8';
178  }
179 
186  public function setCharset($charset)
187  {
188  $this->dat['header']['charset'] = $charset;
189  }
190 
202  public function setMetaData($title, $description, $notes, $packager_username, $packager_name, $packager_email)
203  {
204  $this->dat['header']['meta'] = [
205  'title' => $title,
206  'description' => $description,
207  'notes' => $notes,
208  'packager_username' => $packager_username,
209  'packager_name' => $packager_name,
210  'packager_email' => $packager_email,
211  'TYPO3_version' => TYPO3_version,
212  'created' => strftime('%A %e. %B %Y', $GLOBALS['EXEC_TIME'])
213  ];
214  }
215 
224  {
225  $this->saveFilesOutsideExportFile = $saveFilesOutsideExportFile;
226  }
227 
228  /**************************
229  * Export / Init Page tree
230  *************************/
231 
238  public function setPageTree($idH)
239  {
240  $this->dat['header']['pagetree'] = $this->unsetExcludedSections($idH);
241  return $this->flatInversePageTree($this->dat['header']['pagetree']);
242  }
243 
252  public function unsetExcludedSections($idH)
253  {
254  if (is_array($idH)) {
255  foreach ($idH as $k => $v) {
256  if ($this->excludeMap['pages:' . $idH[$k]['uid']]) {
257  unset($idH[$k]);
258  } elseif (is_array($idH[$k]['subrow'])) {
259  $idH[$k]['subrow'] = $this->unsetExcludedSections($idH[$k]['subrow']);
260  }
261  }
262  }
263  return $idH;
264  }
265 
266  /**************************
267  * Export
268  *************************/
269 
278  {
279  foreach ($recordTypesIncludeFields as $table => $fields) {
280  if (!is_array($fields)) {
281  throw new Exception('The include fields for record type ' . htmlspecialchars($table) . ' are not defined by an array.', 1391440658);
282  }
283  $this->setRecordTypeIncludeFields($table, $fields);
284  }
285  }
286 
294  public function setRecordTypeIncludeFields($table, array $fields)
295  {
296  $this->recordTypesIncludeFields[$table] = $fields;
297  }
298 
308  public function export_addRecord($table, $row, $relationLevel = 0)
309  {
310  BackendUtility::workspaceOL($table, $row);
311  if ($this->excludeDisabledRecords && !$this->isActive($table, $row['uid'])) {
312  return;
313  }
314  if ((string)$table !== '' && is_array($row) && $row['uid'] > 0 && !$this->excludeMap[$table . ':' . $row['uid']]) {
315  if ($this->checkPID($table === 'pages' ? $row['uid'] : $row['pid'])) {
316  if (!isset($this->dat['records'][$table . ':' . $row['uid']])) {
317  // Prepare header info:
318  $row = $this->filterRecordFields($table, $row);
319  $headerInfo = [];
320  $headerInfo['uid'] = $row['uid'];
321  $headerInfo['pid'] = $row['pid'];
322  $headerInfo['title'] = GeneralUtility::fixed_lgd_cs(BackendUtility::getRecordTitle($table, $row), 40);
323  $headerInfo['size'] = strlen(serialize($row));
324  if ($relationLevel) {
325  $headerInfo['relationLevel'] = $relationLevel;
326  }
327  // If record content is not too large in size, set the header content and add the rest:
328  if ($headerInfo['size'] < $this->maxRecordSize) {
329  // Set the header summary:
330  $this->dat['header']['records'][$table][$row['uid']] = $headerInfo;
331  // Create entry in the PID lookup:
332  $this->dat['header']['pid_lookup'][$row['pid']][$table][$row['uid']] = 1;
333  // Initialize reference index object:
334  $refIndexObj = GeneralUtility::makeInstance(ReferenceIndex::class);
335  // Yes to workspace overlays for exporting....
336  $refIndexObj->WSOL = true;
337  $relations = $refIndexObj->getRelations($table, $row);
338  $relations = $this->fixFileIDsInRelations($relations);
339  $relations = $this->removeSoftrefsHavingTheSameDatabaseRelation($relations);
340  // Data:
341  $this->dat['records'][$table . ':' . $row['uid']] = [];
342  $this->dat['records'][$table . ':' . $row['uid']]['data'] = $row;
343  $this->dat['records'][$table . ':' . $row['uid']]['rels'] = $relations;
344  // Add information about the relations in the record in the header:
345  $this->dat['header']['records'][$table][$row['uid']]['rels'] = $this->flatDBrels($this->dat['records'][$table . ':' . $row['uid']]['rels']);
346  // Add information about the softrefs to header:
347  $this->dat['header']['records'][$table][$row['uid']]['softrefs'] = $this->flatSoftRefs($this->dat['records'][$table . ':' . $row['uid']]['rels']);
348  } else {
349  $this->error('Record ' . $table . ':' . $row['uid'] . ' was larger than maxRecordSize (' . GeneralUtility::formatSize($this->maxRecordSize) . ')');
350  }
351  } else {
352  $this->error('Record ' . $table . ':' . $row['uid'] . ' already added.');
353  }
354  } else {
355  $this->error('Record ' . $table . ':' . $row['uid'] . ' was outside your DB mounts!');
356  }
357  }
358  }
359 
367  protected function fixFileIDsInRelations(array $relations)
368  {
369  foreach ($relations as $field => $relation) {
370  if (isset($relation['type']) && $relation['type'] === 'file') {
371  foreach ($relation['newValueFiles'] as $key => $fileRelationData) {
372  $absoluteFilePath = $fileRelationData['ID_absFile'];
373  if (GeneralUtility::isFirstPartOfStr($absoluteFilePath, PATH_site)) {
374  $relatedFilePath = PathUtility::stripPathSitePrefix($absoluteFilePath);
375  $relations[$field]['newValueFiles'][$key]['ID'] = md5($relatedFilePath);
376  }
377  }
378  }
379  if ($relation['type'] === 'flex') {
380  if (is_array($relation['flexFormRels']['file'])) {
381  foreach ($relation['flexFormRels']['file'] as $key => $subList) {
382  foreach ($subList as $subKey => $fileRelationData) {
383  $absoluteFilePath = $fileRelationData['ID_absFile'];
384  if (GeneralUtility::isFirstPartOfStr($absoluteFilePath, PATH_site)) {
385  $relatedFilePath = PathUtility::stripPathSitePrefix($absoluteFilePath);
386  $relations[$field]['flexFormRels']['file'][$key][$subKey]['ID'] = md5($relatedFilePath);
387  }
388  }
389  }
390  }
391  }
392  }
393  return $relations;
394  }
395 
405  protected function removeSoftrefsHavingTheSameDatabaseRelation($relations)
406  {
407  $fixedRelations = [];
408  foreach ($relations as $field => $relation) {
409  $newRelation = $relation;
410  if (isset($newRelation['type']) && $newRelation['type'] === 'db') {
411  foreach ($newRelation['itemArray'] as $key => $dbRelationData) {
412  if ($dbRelationData['table'] === 'sys_file') {
413  if (isset($newRelation['softrefs']['keys']['typolink'])) {
414  foreach ($newRelation['softrefs']['keys']['typolink'] as $softrefKey => $softRefData) {
415  if ($softRefData['subst']['type'] === 'file') {
416  $file = ResourceFactory::getInstance()->retrieveFileOrFolderObject($softRefData['subst']['relFileName']);
417  if ($file instanceof File) {
418  if ($file->getUid() == $dbRelationData['id']) {
419  unset($newRelation['softrefs']['keys']['typolink'][$softrefKey]);
420  }
421  }
422  }
423  }
424  if (empty($newRelation['softrefs']['keys']['typolink'])) {
425  unset($newRelation['softrefs']);
426  }
427  }
428  }
429  }
430  }
431  $fixedRelations[$field] = $newRelation;
432  }
433  return $fixedRelations;
434  }
435 
446  public function export_addDBRelations($relationLevel = 0)
447  {
448  // Traverse all "rels" registered for "records"
449  if (!is_array($this->dat['records'])) {
450  $this->error('There were no records available.');
451  return [];
452  }
453  $addR = [];
454  foreach ($this->dat['records'] as $k => $value) {
455  if (!is_array($this->dat['records'][$k])) {
456  continue;
457  }
458  foreach ($this->dat['records'][$k]['rels'] as $fieldname => $vR) {
459  // For all DB types of relations:
460  if ($vR['type'] == 'db') {
461  foreach ($vR['itemArray'] as $fI) {
462  $this->export_addDBRelations_registerRelation($fI, $addR);
463  }
464  }
465  // For all flex/db types of relations:
466  if ($vR['type'] == 'flex') {
467  // DB relations in flex form fields:
468  if (is_array($vR['flexFormRels']['db'])) {
469  foreach ($vR['flexFormRels']['db'] as $subList) {
470  foreach ($subList as $fI) {
471  $this->export_addDBRelations_registerRelation($fI, $addR);
472  }
473  }
474  }
475  // DB oriented soft references in flex form fields:
476  if (is_array($vR['flexFormRels']['softrefs'])) {
477  foreach ($vR['flexFormRels']['softrefs'] as $subList) {
478  foreach ($subList['keys'] as $spKey => $elements) {
479  foreach ($elements as $el) {
480  if ($el['subst']['type'] === 'db' && $this->includeSoftref($el['subst']['tokenID'])) {
481  list($tempTable, $tempUid) = explode(':', $el['subst']['recordRef']);
482  $fI = [
483  'table' => $tempTable,
484  'id' => $tempUid
485  ];
486  $this->export_addDBRelations_registerRelation($fI, $addR, $el['subst']['tokenID']);
487  }
488  }
489  }
490  }
491  }
492  }
493  // In any case, if there are soft refs:
494  if (is_array($vR['softrefs']['keys'])) {
495  foreach ($vR['softrefs']['keys'] as $spKey => $elements) {
496  foreach ($elements as $el) {
497  if ($el['subst']['type'] === 'db' && $this->includeSoftref($el['subst']['tokenID'])) {
498  list($tempTable, $tempUid) = explode(':', $el['subst']['recordRef']);
499  $fI = [
500  'table' => $tempTable,
501  'id' => $tempUid
502  ];
503  $this->export_addDBRelations_registerRelation($fI, $addR, $el['subst']['tokenID']);
504  }
505  }
506  }
507  }
508  }
509  }
510 
511  // Now, if there were new records to add, do so:
512  if (!empty($addR)) {
513  foreach ($addR as $fI) {
514  // Get and set record:
515  $row = BackendUtility::getRecord($fI['table'], $fI['id']);
516  if (is_array($row)) {
517  $this->export_addRecord($fI['table'], $row, $relationLevel + 1);
518  }
519  // Set status message
520  // Relation pointers always larger than zero except certain "select" types with
521  // negative values pointing to uids - but that is not supported here.
522  if ($fI['id'] > 0) {
523  $rId = $fI['table'] . ':' . $fI['id'];
524  if (!isset($this->dat['records'][$rId])) {
525  $this->dat['records'][$rId] = 'NOT_FOUND';
526  $this->error('Relation record ' . $rId . ' was not found!');
527  }
528  }
529  }
530  }
531  // Return overview of relations found and added
532  return $addR;
533  }
534 
544  public function export_addDBRelations_registerRelation($fI, &$addR, $tokenID = '')
545  {
546  $rId = $fI['table'] . ':' . $fI['id'];
547  if (
548  isset($GLOBALS['TCA'][$fI['table']]) && !$this->isTableStatic($fI['table']) && !$this->isExcluded($fI['table'], $fI['id'])
549  && (!$tokenID || $this->includeSoftref($tokenID)) && $this->inclRelation($fI['table'])
550  ) {
551  if (!isset($this->dat['records'][$rId])) {
552  // Set this record to be included since it is not already.
553  $addR[$rId] = $fI;
554  }
555  }
556  }
557 
566  {
567  // Traverse all "rels" registered for "records"
568  if (!is_array($this->dat['records'])) {
569  $this->error('There were no records available.');
570  return;
571  }
572  foreach ($this->dat['records'] as $k => $value) {
573  if (!isset($this->dat['records'][$k]['rels']) || !is_array($this->dat['records'][$k]['rels'])) {
574  continue;
575  }
576  foreach ($this->dat['records'][$k]['rels'] as $fieldname => $vR) {
577  // For all file type relations:
578  if ($vR['type'] == 'file') {
579  foreach ($vR['newValueFiles'] as $key => $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]['newValueFiles'][$key]['ID_absFile']);
583  }
584  }
585  // For all flex type relations:
586  if ($vR['type'] == 'flex') {
587  if (is_array($vR['flexFormRels']['file'])) {
588  foreach ($vR['flexFormRels']['file'] as $key => $subList) {
589  foreach ($subList as $subKey => $fI) {
590  $this->export_addFile($fI, $k, $fieldname);
591  // Remove the absolute reference to the file so it doesn't expose absolute paths from source server:
592  unset($this->dat['records'][$k]['rels'][$fieldname]['flexFormRels']['file'][$key][$subKey]['ID_absFile']);
593  }
594  }
595  }
596  // DB oriented soft references in flex form fields:
597  if (is_array($vR['flexFormRels']['softrefs'])) {
598  foreach ($vR['flexFormRels']['softrefs'] as $key => $subList) {
599  foreach ($subList['keys'] as $spKey => $elements) {
600  foreach ($elements as $subKey => $el) {
601  if ($el['subst']['type'] === 'file' && $this->includeSoftref($el['subst']['tokenID'])) {
602  // Create abs path and ID for file:
603  $ID_absFile = GeneralUtility::getFileAbsFileName(PATH_site . $el['subst']['relFileName']);
604  $ID = md5($el['subst']['relFileName']);
605  if ($ID_absFile) {
606  if (!$this->dat['files'][$ID]) {
607  $fI = [
608  'filename' => PathUtility::basename($ID_absFile),
609  'ID_absFile' => $ID_absFile,
610  'ID' => $ID,
611  'relFileName' => $el['subst']['relFileName']
612  ];
613  $this->export_addFile($fI, '_SOFTREF_');
614  }
615  $this->dat['records'][$k]['rels'][$fieldname]['flexFormRels']['softrefs'][$key]['keys'][$spKey][$subKey]['file_ID'] = $ID;
616  }
617  }
618  }
619  }
620  }
621  }
622  }
623  // In any case, if there are soft refs:
624  if (is_array($vR['softrefs']['keys'])) {
625  foreach ($vR['softrefs']['keys'] as $spKey => $elements) {
626  foreach ($elements as $subKey => $el) {
627  if ($el['subst']['type'] === 'file' && $this->includeSoftref($el['subst']['tokenID'])) {
628  // Create abs path and ID for file:
629  $ID_absFile = GeneralUtility::getFileAbsFileName(PATH_site . $el['subst']['relFileName']);
630  $ID = md5($el['subst']['relFileName']);
631  if ($ID_absFile) {
632  if (!$this->dat['files'][$ID]) {
633  $fI = [
634  'filename' => PathUtility::basename($ID_absFile),
635  'ID_absFile' => $ID_absFile,
636  'ID' => $ID,
637  'relFileName' => $el['subst']['relFileName']
638  ];
639  $this->export_addFile($fI, '_SOFTREF_');
640  }
641  $this->dat['records'][$k]['rels'][$fieldname]['softrefs']['keys'][$spKey][$subKey]['file_ID'] = $ID;
642  }
643  }
644  }
645  }
646  }
647  }
648  }
649  }
650 
657  {
658  if (!isset($this->dat['header']['records']['sys_file']) || !is_array($this->dat['header']['records']['sys_file'])) {
659  return;
660  }
661  foreach ($this->dat['header']['records']['sys_file'] as $sysFileUid => $_) {
662  $recordData = $this->dat['records']['sys_file:' . $sysFileUid]['data'];
663  $file = ResourceFactory::getInstance()->createFileObject($recordData);
664  $this->export_addSysFile($file);
665  }
666  }
667 
674  public function export_addSysFile(File $file)
675  {
676  if ($file->getProperty('size') >= $this->maxFileSize) {
677  $this->error('File ' . $file->getPublicUrl() . ' was larger (' . GeneralUtility::formatSize($file->getProperty('size')) . ') than the maxFileSize (' . GeneralUtility::formatSize($this->maxFileSize) . ')! Skipping.');
678  return;
679  }
680  $fileContent = '';
681  try {
682  if (!$this->saveFilesOutsideExportFile) {
683  $fileContent = $file->getContents();
684  } else {
685  $file->checkActionPermission('read');
686  }
687  } catch (\Exception $e) {
688  $this->error('Error when trying to add file ' . $file->getCombinedIdentifier() . ': ' . $e->getMessage());
689  return;
690  }
691  $fileUid = $file->getUid();
692  $fileInfo = $file->getStorage()->getFileInfo($file);
693  $fileSize = (int)$fileInfo['size'];
694  if ($fileSize !== (int)$file->getProperty('size')) {
695  $this->error('File size of ' . $file->getCombinedIdentifier() . ' is not up-to-date in index! File added with current size.');
696  $this->dat['records']['sys_file:' . $fileUid]['data']['size'] = $fileSize;
697  }
698  $fileSha1 = $file->getStorage()->hashFile($file, 'sha1');
699  if ($fileSha1 !== $file->getProperty('sha1')) {
700  $this->error('File sha1 hash of ' . $file->getCombinedIdentifier() . ' is not up-to-date in index! File added on current sha1.');
701  $this->dat['records']['sys_file:' . $fileUid]['data']['sha1'] = $fileSha1;
702  }
703 
704  $fileRec = [];
705  $fileRec['filesize'] = $fileSize;
706  $fileRec['filename'] = $file->getProperty('name');
707  $fileRec['filemtime'] = $file->getProperty('modification_date');
708 
709  // build unique id based on the storage and the file identifier
710  $fileId = md5($file->getStorage()->getUid() . ':' . $file->getProperty('identifier_hash'));
711 
712  // Setting this data in the header
713  $this->dat['header']['files_fal'][$fileId] = $fileRec;
714 
715  if (!$this->saveFilesOutsideExportFile) {
716  // ... and finally add the heavy stuff:
717  $fileRec['content'] = $fileContent;
718  } else {
720  }
721  $fileRec['content_sha1'] = $fileSha1;
722 
723  $this->dat['files_fal'][$fileId] = $fileRec;
724  }
725 
734  public function export_addFile($fI, $recordRef = '', $fieldname = '')
735  {
736  if (!@is_file($fI['ID_absFile'])) {
737  $this->error($fI['ID_absFile'] . ' was not a file! Skipping.');
738  return;
739  }
740  if (filesize($fI['ID_absFile']) >= $this->maxFileSize) {
741  $this->error($fI['ID_absFile'] . ' was larger (' . GeneralUtility::formatSize(filesize($fI['ID_absFile'])) . ') than the maxFileSize (' . GeneralUtility::formatSize($this->maxFileSize) . ')! Skipping.');
742  return;
743  }
744  $fileInfo = stat($fI['ID_absFile']);
745  $fileRec = [];
746  $fileRec['filesize'] = $fileInfo['size'];
747  $fileRec['filename'] = PathUtility::basename($fI['ID_absFile']);
748  $fileRec['filemtime'] = $fileInfo['mtime'];
749  //for internal type file_reference
750  $fileRec['relFileRef'] = PathUtility::stripPathSitePrefix($fI['ID_absFile']);
751  if ($recordRef) {
752  $fileRec['record_ref'] = $recordRef . '/' . $fieldname;
753  }
754  if ($fI['relFileName']) {
755  $fileRec['relFileName'] = $fI['relFileName'];
756  }
757  // Setting this data in the header
758  $this->dat['header']['files'][$fI['ID']] = $fileRec;
759  // ... and for the recordlisting, why not let us know WHICH relations there was...
760  if ($recordRef && $recordRef !== '_SOFTREF_') {
761  $refParts = explode(':', $recordRef, 2);
762  if (!is_array($this->dat['header']['records'][$refParts[0]][$refParts[1]]['filerefs'])) {
763  $this->dat['header']['records'][$refParts[0]][$refParts[1]]['filerefs'] = [];
764  }
765  $this->dat['header']['records'][$refParts[0]][$refParts[1]]['filerefs'][] = $fI['ID'];
766  }
767  $fileMd5 = md5_file($fI['ID_absFile']);
768  if (!$this->saveFilesOutsideExportFile) {
769  // ... and finally add the heavy stuff:
770  $fileRec['content'] = file_get_contents($fI['ID_absFile']);
771  } else {
772  GeneralUtility::upload_copy_move($fI['ID_absFile'], $this->getTemporaryFilesPathForExport() . $fileMd5);
773  }
774  $fileRec['content_md5'] = $fileMd5;
775  $this->dat['files'][$fI['ID']] = $fileRec;
776  // For soft references, do further processing:
777  if ($recordRef === '_SOFTREF_') {
778  // RTE files?
779  if ($RTEoriginal = $this->getRTEoriginalFilename(PathUtility::basename($fI['ID_absFile']))) {
780  $RTEoriginal_absPath = PathUtility::dirname($fI['ID_absFile']) . '/' . $RTEoriginal;
781  if (@is_file($RTEoriginal_absPath)) {
782  $RTEoriginal_ID = md5($RTEoriginal_absPath);
783  $fileInfo = stat($RTEoriginal_absPath);
784  $fileRec = [];
785  $fileRec['filesize'] = $fileInfo['size'];
786  $fileRec['filename'] = PathUtility::basename($RTEoriginal_absPath);
787  $fileRec['filemtime'] = $fileInfo['mtime'];
788  $fileRec['record_ref'] = '_RTE_COPY_ID:' . $fI['ID'];
789  $this->dat['header']['files'][$fI['ID']]['RTE_ORIG_ID'] = $RTEoriginal_ID;
790  // Setting this data in the header
791  $this->dat['header']['files'][$RTEoriginal_ID] = $fileRec;
792  $fileMd5 = md5_file($RTEoriginal_absPath);
793  if (!$this->saveFilesOutsideExportFile) {
794  // ... and finally add the heavy stuff:
795  $fileRec['content'] = file_get_contents($RTEoriginal_absPath);
796  } else {
797  GeneralUtility::upload_copy_move($RTEoriginal_absPath, $this->getTemporaryFilesPathForExport() . $fileMd5);
798  }
799  $fileRec['content_md5'] = $fileMd5;
800  $this->dat['files'][$RTEoriginal_ID] = $fileRec;
801  } else {
802  $this->error('RTE original file "' . PathUtility::stripPathSitePrefix($RTEoriginal_absPath) . '" was not found!');
803  }
804  }
805  // Files with external media?
806  // This is only done with files grabbed by a softreference parser since it is deemed improbable that hard-referenced files should undergo this treatment.
807  $html_fI = pathinfo(PathUtility::basename($fI['ID_absFile']));
808  if ($this->includeExtFileResources && GeneralUtility::inList($this->extFileResourceExtensions, strtolower($html_fI['extension']))) {
809  $uniquePrefix = '###' . md5($GLOBALS['EXEC_TIME']) . '###';
810  if (strtolower($html_fI['extension']) === 'css') {
811  $prefixedMedias = explode($uniquePrefix, preg_replace('/(url[[:space:]]*\\([[:space:]]*["\']?)([^"\')]*)(["\']?[[:space:]]*\\))/i', '\\1' . $uniquePrefix . '\\2' . $uniquePrefix . '\\3', $fileRec['content']));
812  } else {
813  // html, htm:
814  $htmlParser = GeneralUtility::makeInstance(HtmlParser::class);
815  $prefixedMedias = explode($uniquePrefix, $htmlParser->prefixResourcePath($uniquePrefix, $fileRec['content'], [], $uniquePrefix));
816  }
817  $htmlResourceCaptured = false;
818  foreach ($prefixedMedias as $k => $v) {
819  if ($k % 2) {
820  $EXTres_absPath = GeneralUtility::resolveBackPath(PathUtility::dirname($fI['ID_absFile']) . '/' . $v);
821  $EXTres_absPath = GeneralUtility::getFileAbsFileName($EXTres_absPath);
822  if ($EXTres_absPath && GeneralUtility::isFirstPartOfStr($EXTres_absPath, PATH_site . $this->fileadminFolderName . '/') && @is_file($EXTres_absPath)) {
823  $htmlResourceCaptured = true;
824  $EXTres_ID = md5($EXTres_absPath);
825  $this->dat['header']['files'][$fI['ID']]['EXT_RES_ID'][] = $EXTres_ID;
826  $prefixedMedias[$k] = '{EXT_RES_ID:' . $EXTres_ID . '}';
827  // Add file to memory if it is not set already:
828  if (!isset($this->dat['header']['files'][$EXTres_ID])) {
829  $fileInfo = stat($EXTres_absPath);
830  $fileRec = [];
831  $fileRec['filesize'] = $fileInfo['size'];
832  $fileRec['filename'] = PathUtility::basename($EXTres_absPath);
833  $fileRec['filemtime'] = $fileInfo['mtime'];
834  $fileRec['record_ref'] = '_EXT_PARENT_:' . $fI['ID'];
835  // Media relative to the HTML file.
836  $fileRec['parentRelFileName'] = $v;
837  // Setting this data in the header
838  $this->dat['header']['files'][$EXTres_ID] = $fileRec;
839  // ... and finally add the heavy stuff:
840  $fileRec['content'] = file_get_contents($EXTres_absPath);
841  $fileRec['content_md5'] = md5($fileRec['content']);
842  $this->dat['files'][$EXTres_ID] = $fileRec;
843  }
844  }
845  }
846  }
847  if ($htmlResourceCaptured) {
848  $this->dat['files'][$fI['ID']]['tokenizedContent'] = implode('', $prefixedMedias);
849  }
850  }
851  }
852  }
853 
863  {
864  if (!$this->saveFilesOutsideExportFile) {
865  throw new \RuntimeException('You need to set saveFilesOutsideExportFile to TRUE before you want to get the temporary files path for export.', 1401205213);
866  }
867  if ($this->temporaryFilesPathForExport === null) {
868  $temporaryFolderName = $this->getTemporaryFolderName();
869  $this->temporaryFilesPathForExport = $temporaryFolderName . '/';
870  }
872  }
873 
881  public function flatDBrels($dbrels)
882  {
883  $list = [];
884  foreach ($dbrels as $dat) {
885  if ($dat['type'] == 'db') {
886  foreach ($dat['itemArray'] as $i) {
887  $list[$i['table'] . ':' . $i['id']] = $i;
888  }
889  }
890  if ($dat['type'] == 'flex' && is_array($dat['flexFormRels']['db'])) {
891  foreach ($dat['flexFormRels']['db'] as $subList) {
892  foreach ($subList as $i) {
893  $list[$i['table'] . ':' . $i['id']] = $i;
894  }
895  }
896  }
897  }
898  return $list;
899  }
900 
907  public function flatSoftRefs($dbrels)
908  {
909  $list = [];
910  foreach ($dbrels as $field => $dat) {
911  if (is_array($dat['softrefs']['keys'])) {
912  foreach ($dat['softrefs']['keys'] as $spKey => $elements) {
913  if (is_array($elements)) {
914  foreach ($elements as $subKey => $el) {
915  $lKey = $field . ':' . $spKey . ':' . $subKey;
916  $list[$lKey] = array_merge(['field' => $field, 'spKey' => $spKey], $el);
917  // Add file_ID key to header - slightly "risky" way of doing this because if the calculation
918  // changes for the same value in $this->records[...] this will not work anymore!
919  if ($el['subst'] && $el['subst']['relFileName']) {
920  $list[$lKey]['file_ID'] = md5(PATH_site . $el['subst']['relFileName']);
921  }
922  }
923  }
924  }
925  }
926  if ($dat['type'] == 'flex' && is_array($dat['flexFormRels']['softrefs'])) {
927  foreach ($dat['flexFormRels']['softrefs'] as $structurePath => $subSoftrefs) {
928  if (is_array($subSoftrefs['keys'])) {
929  foreach ($subSoftrefs['keys'] as $spKey => $elements) {
930  foreach ($elements as $subKey => $el) {
931  $lKey = $field . ':' . $structurePath . ':' . $spKey . ':' . $subKey;
932  $list[$lKey] = array_merge(['field' => $field, 'spKey' => $spKey, 'structurePath' => $structurePath], $el);
933  // Add file_ID key to header - slightly "risky" way of doing this because if the calculation
934  // changes for the same value in $this->records[...] this will not work anymore!
935  if ($el['subst'] && $el['subst']['relFileName']) {
936  $list[$lKey]['file_ID'] = md5(PATH_site . $el['subst']['relFileName']);
937  }
938  }
939  }
940  }
941  }
942  }
943  }
944  return $list;
945  }
946 
955  protected function filterRecordFields($table, array $row)
956  {
957  if (isset($this->recordTypesIncludeFields[$table])) {
958  $includeFields = array_unique(array_merge(
959  $this->recordTypesIncludeFields[$table],
960  $this->defaultRecordIncludeFields
961  ));
962  $newRow = [];
963  foreach ($row as $key => $value) {
964  if (in_array($key, $includeFields)) {
965  $newRow[$key] = $value;
966  }
967  }
968  } else {
969  $newRow = $row;
970  }
971  return $newRow;
972  }
973 
974  /**************************
975  * File Output
976  *************************/
977 
984  public function compileMemoryToFileContent($type = '')
985  {
986  if ($type == 'xml') {
987  $out = $this->createXML();
988  } else {
989  $compress = $this->doOutputCompress();
990  $out = '';
991  // adding header:
992  $out .= $this->addFilePart(serialize($this->dat['header']), $compress);
993  // adding records:
994  $out .= $this->addFilePart(serialize($this->dat['records']), $compress);
995  // adding files:
996  $out .= $this->addFilePart(serialize($this->dat['files']), $compress);
997  // adding files_fal:
998  $out .= $this->addFilePart(serialize($this->dat['files_fal']), $compress);
999  }
1000  return $out;
1001  }
1002 
1008  public function createXML()
1009  {
1010  // Options:
1011  $options = [
1012  'alt_options' => [
1013  '/header' => [
1014  'disableTypeAttrib' => true,
1015  'clearStackPath' => true,
1016  'parentTagMap' => [
1017  'files' => 'file',
1018  'files_fal' => 'file',
1019  'records' => 'table',
1020  'table' => 'rec',
1021  'rec:rels' => 'relations',
1022  'relations' => 'element',
1023  'filerefs' => 'file',
1024  'pid_lookup' => 'page_contents',
1025  'header:relStaticTables' => 'static_tables',
1026  'static_tables' => 'tablename',
1027  'excludeMap' => 'item',
1028  'softrefCfg' => 'softrefExportMode',
1029  'extensionDependencies' => 'extkey',
1030  'softrefs' => 'softref_element'
1031  ],
1032  'alt_options' => [
1033  '/pagetree' => [
1034  'disableTypeAttrib' => true,
1035  'useIndexTagForNum' => 'node',
1036  'parentTagMap' => [
1037  'node:subrow' => 'node'
1038  ]
1039  ],
1040  '/pid_lookup/page_contents' => [
1041  'disableTypeAttrib' => true,
1042  'parentTagMap' => [
1043  'page_contents' => 'table'
1044  ],
1045  'grandParentTagMap' => [
1046  'page_contents/table' => 'item'
1047  ]
1048  ]
1049  ]
1050  ],
1051  '/records' => [
1052  'disableTypeAttrib' => true,
1053  'parentTagMap' => [
1054  'records' => 'tablerow',
1055  'tablerow:data' => 'fieldlist',
1056  'tablerow:rels' => 'related',
1057  'related' => 'field',
1058  'field:itemArray' => 'relations',
1059  'field:newValueFiles' => 'filerefs',
1060  'field:flexFormRels' => 'flexform',
1061  'relations' => 'element',
1062  'filerefs' => 'file',
1063  'flexform:db' => 'db_relations',
1064  'flexform:file' => 'file_relations',
1065  'flexform:softrefs' => 'softref_relations',
1066  'softref_relations' => 'structurePath',
1067  'db_relations' => 'path',
1068  'file_relations' => 'path',
1069  'path' => 'element',
1070  'keys' => 'softref_key',
1071  'softref_key' => 'softref_element'
1072  ],
1073  'alt_options' => [
1074  '/records/tablerow/fieldlist' => [
1075  'useIndexTagForAssoc' => 'field'
1076  ]
1077  ]
1078  ],
1079  '/files' => [
1080  'disableTypeAttrib' => true,
1081  'parentTagMap' => [
1082  'files' => 'file'
1083  ]
1084  ],
1085  '/files_fal' => [
1086  'disableTypeAttrib' => true,
1087  'parentTagMap' => [
1088  'files_fal' => 'file'
1089  ]
1090  ]
1091  ]
1092  ];
1093  // Creating XML file from $outputArray:
1094  $charset = $this->dat['header']['charset'] ?: 'utf-8';
1095  $XML = '<?xml version="1.0" encoding="' . $charset . '" standalone="yes" ?>' . LF;
1096  $XML .= GeneralUtility::array2xml($this->dat, '', 0, 'T3RecordDocument', 0, $options);
1097  return $XML;
1098  }
1099 
1105  public function doOutputCompress()
1106  {
1107  return $this->compress && !$this->dontCompress;
1108  }
1109 
1117  public function addFilePart($data, $compress = false)
1118  {
1119  if ($compress) {
1120  $data = gzcompress($data);
1121  }
1122  return md5($data) . ':' . ($compress ? '1' : '0') . ':' . str_pad(strlen($data), 10, '0', STR_PAD_LEFT) . ':' . $data . ':';
1123  }
1124 }
setSaveFilesOutsideExportFile($saveFilesOutsideExportFile)
Definition: Export.php:223
export_addSysFile(File $file)
Definition: Export.php:674
getPublicUrl($relativeToCurrentScript=false)
static isFirstPartOfStr($str, $partStr)
setMetaData($title, $description, $notes, $packager_username, $packager_name, $packager_email)
Definition: Export.php:202
compileMemoryToFileContent($type= '')
Definition: Export.php:984
static upload_copy_move($source, $destination)
fixFileIDsInRelations(array $relations)
Definition: Export.php:367
export_addDBRelations_registerRelation($fI, &$addR, $tokenID= '')
Definition: Export.php:544
addFilePart($data, $compress=false)
Definition: Export.php:1117
export_addFilesFromSysFilesRecords()
Definition: Export.php:656
static formatSize($sizeInBytes, $labels= '', $base=0)
static getRecordTitle($table, $row, $prep=false, $forceResult=true)
static array2xml(array $array, $NSprefix= '', $level=0, $docTag= 'phparray', $spaceInd=0, array $options=[], array $stackData=[])
setCharset($charset)
Definition: Export.php:186
removeSoftrefsHavingTheSameDatabaseRelation($relations)
Definition: Export.php:405
export_addRecord($table, $row, $relationLevel=0)
Definition: Export.php:308
setRecordTypesIncludeFields(array $recordTypesIncludeFields)
Definition: Export.php:277
static workspaceOL($table, &$row, $wsid=-99, $unsetMovePointers=false)
static getRecord($table, $uid, $fields= '*', $where= '', $useDeleteClause=true)
export_addDBRelations($relationLevel=0)
Definition: Export.php:446
if(TYPO3_MODE=== 'BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
static makeInstance($className,...$constructorArguments)
init($dontCompress=false)
Definition: Export.php:138
static getFileAbsFileName($filename, $_=null, $_2=null)
setRecordTypeIncludeFields($table, array $fields)
Definition: Export.php:294
export_addFile($fI, $recordRef= '', $fieldname= '')
Definition: Export.php:734
filterRecordFields($table, array $row)
Definition: Export.php:955