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