TYPO3  7.6
ImportExportController.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Impexp\Controller;
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 
33 
38 {
42  protected $uploadedFiles = array();
43 
49  public $pageinfo;
50 
54  protected $export;
55 
59  protected $import;
60 
64  protected $fileProcessor;
65 
69  protected $vC = '';
70 
74  protected $lang = null;
75 
79  protected $treeHTML = '';
80 
84  protected $iconFactory;
85 
91  protected $moduleName = 'xMOD_tximpexp';
92 
98  protected $moduleTemplate;
99 
105  protected $shortcutName;
106 
110  public function __construct()
111  {
112  $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
113  $this->moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class);
114  }
115 
119  public function init()
120  {
121  $this->MCONF['name'] = $this->moduleName;
122  parent::init();
123  $this->vC = GeneralUtility::_GP('vC');
124  $this->lang = $this->getLanguageService();
125  }
126 
134  public function main()
135  {
136  $this->lang->includeLLFile('EXT:impexp/Resources/Private/Language/locallang.xlf');
137  // Start document template object:
138  // We keep this here, in case somebody relies on the old doc being here
139  $this->doc = GeneralUtility::makeInstance(DocumentTemplate::class);
140  $this->doc->bodyTagId = 'imp-exp-mod';
141  $this->pageinfo = BackendUtility::readPageAccess($this->id, $this->perms_clause);
142  $this->moduleTemplate->getDocHeaderComponent()->setMetaInformation($this->pageinfo);
143  // Setting up the context sensitive menu:
144  $this->moduleTemplate->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/ClickMenu');
145  $this->moduleTemplate->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Impexp/ImportExport');
146  $this->moduleTemplate->addJavaScriptCode(
147  'ImpexpInLineJS',
148  'if (top.fsMod) top.fsMod.recentIds["web"] = ' . (int)$this->id . ';'
149  );
150  $this->content = '<form action="' . htmlspecialchars(BackendUtility::getModuleUrl('xMOD_tximpexp')) . '" method="post" id="ImportExportController" enctype="multipart/form-data">'
151  . '<input type="hidden" name="id" value="' . $this->id . '" />';
152  // Input data grabbed:
153  $inData = GeneralUtility::_GP('tx_impexp');
154  $this->content .= '<h3>' . $this->lang->getLL('title_' . (string)$inData['action'], true) . '</h3>';
155  $this->content .= '<div style="padding-top: 5px;"></div>';
156  $this->checkUpload();
157  switch ((string)$inData['action']) {
158  case 'export':
159  $this->shortcutName = $this->lang->getLL('title_export');
160  // Finally: If upload went well, set the new file as the thumbnail in the $inData array:
161  if (!empty($this->uploadedFiles[0])) {
162  $inData['meta']['thumbnail'] = $this->uploadedFiles[0]->getCombinedIdentifier();
163  }
164  // Call export interface
165  $this->exportData($inData);
166  break;
167  case 'import':
168  $this->shortcutName = $this->lang->getLL('title_import');
169  // Finally: If upload went well, set the new file as the import file:
170  if (!empty($this->uploadedFiles[0])) {
171  // Only allowed extensions....
172  if (GeneralUtility::inList('t3d,xml', $this->uploadedFiles[0]->getExtension())) {
173  $inData['file'] = $this->uploadedFiles[0]->getCombinedIdentifier();
174  }
175  }
176  // Call import interface:
177  $this->importData($inData);
178  break;
179  }
180  // Setting up the buttons and markers for docheader
181  $this->getButtons();
182  $this->content .= '</form>';
183  }
184 
191  public function printContent()
192  {
194  echo $this->content;
195  }
196 
233  {
234  $GLOBALS['SOBE'] = $this;
235  $this->init();
236  $this->main();
237  $this->moduleTemplate->setContent($this->content);
238  $response->getBody()->write($this->moduleTemplate->renderContent());
239  return $response;
240  }
241 
247  protected function getButtons()
248  {
249  $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
250  if ($this->getBackendUser()->mayMakeShortcut()) {
251  $shortcutButton = $buttonBar->makeShortcutButton()
252  ->setGetVariables(['tx_impexp'])
253  ->setDisplayName($this->shortcutName)
254  ->setModuleName($this->moduleName);
255  $buttonBar->addButton($shortcutButton);
256  }
257  // Input data grabbed:
258  $inData = GeneralUtility::_GP('tx_impexp');
259  if ((string)$inData['action'] == 'import') {
260  if ($this->id && is_array($this->pageinfo) || $this->getBackendUser()->user['admin'] && !$this->id) {
261  if (is_array($this->pageinfo) && $this->pageinfo['uid']) {
262  // View
263  $onClick = BackendUtility::viewOnClick(
264  $this->pageinfo['uid'],
265  '',
266  BackendUtility::BEgetRootLine($this->pageinfo['uid'])
267  );
268  $viewButton = $buttonBar->makeLinkButton()
269  ->setTitle($this->lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.showPage', true))
270  ->setHref('#')
271  ->setIcon($this->iconFactory->getIcon('actions-document-view', Icon::SIZE_SMALL))
272  ->setOnClick($onClick);
273  $buttonBar->addButton($viewButton);
274  }
275  }
276  }
277  }
278 
279  /**************************
280  * EXPORT FUNCTIONS
281  **************************/
282 
293  public function exportData($inData)
294  {
295  // BUILDING EXPORT DATA:
296  // Processing of InData array values:
297  $inData['pagetree']['maxNumber'] = MathUtility::forceIntegerInRange($inData['pagetree']['maxNumber'], 1, 1000000, 100);
298  $inData['listCfg']['maxNumber'] = MathUtility::forceIntegerInRange($inData['listCfg']['maxNumber'], 1, 1000000, 100);
299  $inData['maxFileSize'] = MathUtility::forceIntegerInRange($inData['maxFileSize'], 1, 1000000, 1000);
300  $inData['filename'] = trim(preg_replace('/[^[:alnum:]._-]*/', '', preg_replace('/\\.(t3d|xml)$/', '', $inData['filename'])));
301  if (strlen($inData['filename'])) {
302  $inData['filename'] .= $inData['filetype'] == 'xml' ? '.xml' : '.t3d';
303  }
304  // Set exclude fields in export object:
305  if (!is_array($inData['exclude'])) {
306  $inData['exclude'] = array();
307  }
308  // Saving/Loading/Deleting presets:
309  $this->processPresets($inData);
310  // Create export object and configure it:
311  $this->export = GeneralUtility::makeInstance(\TYPO3\CMS\Impexp\ImportExport::class);
312  $this->export->init(0, 'export');
313  $this->export->setCharset($this->lang->charSet);
314  $this->export->maxFileSize = $inData['maxFileSize'] * 1024;
315  $this->export->excludeMap = (array)$inData['exclude'];
316  $this->export->softrefCfg = (array)$inData['softrefCfg'];
317  $this->export->extensionDependencies = (array)$inData['extension_dep'];
318  $this->export->showStaticRelations = $inData['showStaticRelations'];
319  $this->export->includeExtFileResources = !$inData['excludeHTMLfileResources'];
320  // Static tables:
321  if (is_array($inData['external_static']['tables'])) {
322  $this->export->relStaticTables = $inData['external_static']['tables'];
323  }
324  // Configure which tables external relations are included for:
325  if (is_array($inData['external_ref']['tables'])) {
326  $this->export->relOnlyTables = $inData['external_ref']['tables'];
327  }
328  $saveFilesOutsideExportFile = false;
329  if (isset($inData['save_export']) && isset($inData['saveFilesOutsideExportFile']) && $inData['saveFilesOutsideExportFile'] === '1') {
330  $this->export->setSaveFilesOutsideExportFile(true);
331  $saveFilesOutsideExportFile = true;
332  }
333  $this->export->setHeaderBasics();
334  // Meta data setting:
335 
336  $beUser = $this->getBackendUser();
337  $this->export->setMetaData(
338  $inData['meta']['title'],
339  $inData['meta']['description'],
340  $inData['meta']['notes'],
341  $beUser->user['username'],
342  $beUser->user['realName'],
343  $beUser->user['email']
344  );
345  if ($inData['meta']['thumbnail']) {
346  $theThumb = $this->getFile($inData['meta']['thumbnail']);
347  if ($theThumb !== null && $theThumb->exists()) {
348  $this->export->addThumbnail($theThumb->getForLocalProcessing(false));
349  }
350  }
351  // Configure which records to export
352  if (is_array($inData['record'])) {
353  foreach ($inData['record'] as $ref) {
354  $rParts = explode(':', $ref);
355  $this->export->export_addRecord($rParts[0], BackendUtility::getRecord($rParts[0], $rParts[1]));
356  }
357  }
358  // Configure which tables to export
359  if (is_array($inData['list'])) {
360  $db = $this->getDatabaseConnection();
361  foreach ($inData['list'] as $ref) {
362  $rParts = explode(':', $ref);
363  if ($beUser->check('tables_select', $rParts[0])) {
364  $res = $this->exec_listQueryPid($rParts[0], $rParts[1], MathUtility::forceIntegerInRange($inData['listCfg']['maxNumber'], 1));
365  while ($subTrow = $db->sql_fetch_assoc($res)) {
366  $this->export->export_addRecord($rParts[0], $subTrow);
367  }
368  $db->sql_free_result($res);
369  }
370  }
371  }
372  // Pagetree
373  if (isset($inData['pagetree']['id'])) {
374  // Based on click-expandable tree
375  $idH = null;
376  if ($inData['pagetree']['levels'] == -1) {
377  $pagetree = GeneralUtility::makeInstance(\TYPO3\CMS\Impexp\View\ExportPageTreeView::class);
378  $tree = $pagetree->ext_tree($inData['pagetree']['id'], $this->filterPageIds($this->export->excludeMap));
379  $this->treeHTML = $pagetree->printTree($tree);
380  $idH = $pagetree->buffer_idH;
381  } elseif ($inData['pagetree']['levels'] == -2) {
382  $this->addRecordsForPid($inData['pagetree']['id'], $inData['pagetree']['tables'], $inData['pagetree']['maxNumber']);
383  } else {
384  // Based on depth
385  // Drawing tree:
386  // If the ID is zero, export root
387  if (!$inData['pagetree']['id'] && $beUser->isAdmin()) {
388  $sPage = array(
389  'uid' => 0,
390  'title' => 'ROOT'
391  );
392  } else {
393  $sPage = BackendUtility::getRecordWSOL('pages', $inData['pagetree']['id'], '*', ' AND ' . $this->perms_clause);
394  }
395  if (is_array($sPage)) {
396  $pid = $inData['pagetree']['id'];
397  $tree = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Tree\View\PageTreeView::class);
398  $tree->init('AND ' . $this->perms_clause . $this->filterPageIds($this->export->excludeMap));
399  $HTML = $this->iconFactory->getIconForRecord('pages', $sPage, Icon::SIZE_SMALL)->render();
400  $tree->tree[] = array('row' => $sPage, 'HTML' => $HTML);
401  $tree->buffer_idH = array();
402  if ($inData['pagetree']['levels'] > 0) {
403  $tree->getTree($pid, $inData['pagetree']['levels'], '');
404  }
405  $idH = array();
406  $idH[$pid]['uid'] = $pid;
407  if (!empty($tree->buffer_idH)) {
408  $idH[$pid]['subrow'] = $tree->buffer_idH;
409  }
410  $pagetree = GeneralUtility::makeInstance(\TYPO3\CMS\Impexp\View\ExportPageTreeView::class);
411  $this->treeHTML = $pagetree->printTree($tree->tree);
412  $this->shortcutName .= ' (' . $sPage['title'] . ')';
413  }
414  }
415  // In any case we should have a multi-level array, $idH, with the page structure
416  // here (and the HTML-code loaded into memory for nice display...)
417  if (is_array($idH)) {
418  // Sets the pagetree and gets a 1-dim array in return with the pages (in correct submission order BTW...)
419  $flatList = $this->export->setPageTree($idH);
420  foreach ($flatList as $k => $value) {
421  $this->export->export_addRecord('pages', BackendUtility::getRecord('pages', $k));
422  $this->addRecordsForPid($k, $inData['pagetree']['tables'], $inData['pagetree']['maxNumber']);
423  }
424  }
425  }
426  // After adding ALL records we set relations:
427  for ($a = 0; $a < 10; $a++) {
428  $addR = $this->export->export_addDBRelations($a);
429  if (empty($addR)) {
430  break;
431  }
432  }
433  // Finally files are added:
434  // MUST be after the DBrelations are set so that files from ALL added records are included!
435  $this->export->export_addFilesFromRelations();
436 
437  $this->export->export_addFilesFromSysFilesRecords();
438 
439  // If the download button is clicked, return file
440  if ($inData['download_export'] || $inData['save_export']) {
441  switch ((string)$inData['filetype']) {
442  case 'xml':
443  $out = $this->export->compileMemoryToFileContent('xml');
444  $fExt = '.xml';
445  break;
446  case 't3d':
447  $this->export->dontCompress = 1;
448  // intentional fall-through
449  default:
450  $out = $this->export->compileMemoryToFileContent();
451  $fExt = ($this->export->doOutputCompress() ? '-z' : '') . '.t3d';
452  }
453  // Filename:
454  $dlFile = $inData['filename'];
455  if (!$dlFile) {
456  $exportName = substr(preg_replace('/[^[:alnum:]_]/', '-', $inData['download_export_name']), 0, 20);
457  $dlFile = 'T3D_' . $exportName . '_' . date('Y-m-d_H-i') . $fExt;
458  }
459 
460  // Export for download:
461  if ($inData['download_export']) {
462  $mimeType = 'application/octet-stream';
463  Header('Content-Type: ' . $mimeType);
464  Header('Content-Length: ' . strlen($out));
465  Header('Content-Disposition: attachment; filename=' . basename($dlFile));
466  echo $out;
467  die;
468  }
469  // Export by saving:
470  if ($inData['save_export']) {
471  $saveFolder = $this->getDefaultImportExportFolder();
472  if ($saveFolder !== false && $saveFolder->checkActionPermission('write')) {
473  $temporaryFileName = GeneralUtility::tempnam('export');
474  file_put_contents($temporaryFileName, $out);
475  $file = $saveFolder->addFile($temporaryFileName, $dlFile, 'replace');
476  if ($saveFilesOutsideExportFile) {
477  $filesFolderName = $dlFile . '.files';
478  $filesFolder = $saveFolder->createFolder($filesFolderName);
479  $temporaryFolderForExport = ResourceFactory::getInstance()->retrieveFileOrFolderObject($this->export->getTemporaryFilesPathForExport());
480  $temporaryFilesForExport = $temporaryFolderForExport->getFiles();
481  foreach ($temporaryFilesForExport as $temporaryFileForExport) {
482  $filesFolder->getStorage()->moveFile($temporaryFileForExport, $filesFolder);
483  }
484  $temporaryFolderForExport->delete();
485  }
486 
488  $flashMessage = GeneralUtility::makeInstance(
489  FlashMessage::class,
490  sprintf($GLOBALS['LANG']->getLL('exportdata_savedInSBytes', true), $file->getPublicUrl(), GeneralUtility::formatSize(strlen($out))),
491  $GLOBALS['LANG']->getLL('exportdata_savedFile'),
493  );
494  } else {
496  $flashMessage = GeneralUtility::makeInstance(
497  FlashMessage::class,
498  sprintf($GLOBALS['LANG']->getLL('exportdata_badPathS', true), $saveFolder->getPublicUrl()),
499  $GLOBALS['LANG']->getLL('exportdata_problemsSavingFile'),
501  );
502  }
503  $this->content .= $flashMessage->render();
504  }
505  }
506  // OUTPUT to BROWSER:
507  // Now, if we didn't make download file, show configuration form based on export:
508  $menuItems = array();
509  // Export configuration
510  $row = array();
511  $this->makeConfigurationForm($inData, $row);
512  $menuItems[] = array(
513  'label' => $this->lang->getLL('tableselec_configuration'),
514  'content' => '
515  <table border="0" cellpadding="1" cellspacing="1">
516  ' . implode('
517  ', $row) . '
518  </table>
519  '
520  );
521  // File options
522  $row = array();
523  $this->makeSaveForm($inData, $row);
524  $menuItems[] = array(
525  'label' => $this->lang->getLL('exportdata_filePreset'),
526  'content' => '
527  <table border="0" cellpadding="1" cellspacing="1">
528  ' . implode('
529  ', $row) . '
530  </table>
531  '
532  );
533  // File options
534  $row = array();
535  $this->makeAdvancedOptionsForm($inData, $row);
536  $menuItems[] = array(
537  'label' => $this->lang->getLL('exportdata_advancedOptions'),
538  'content' => '
539  <table border="0" cellpadding="1" cellspacing="1">
540  ' . implode('
541  ', $row) . '
542  </table>
543  '
544  );
545  // Generate overview:
546  $overViewContent = $this->export->displayContentOverview();
547  // Print errors that might be:
548  $errors = $this->export->printErrorLog();
549  $menuItems[] = array(
550  'label' => $this->lang->getLL('exportdata_messages'),
551  'content' => $errors,
552  'stateIcon' => $errors ? 2 : 0
553  );
554  // Add hidden fields and create tabs:
555 
556  $content = $this->moduleTemplate->getDynamicTabMenu($menuItems, 'tx_impexp_export', 1, false, true, false);
557  $content .= '<input type="hidden" name="tx_impexp[action]" value="export" />';
558  $this->content .= '<div>' . $content . '</div>';
559  // Output Overview:
560  $this->content .= '<h2>' . $this->lang->getLL('execlistqu_structureToBeExported', true) . '</h2><div>' . $overViewContent . '</div>';
561  }
562 
571  public function addRecordsForPid($k, $tables, $maxNumber)
572  {
573  if (!is_array($tables)) {
574  return;
575  }
576  $db = $this->getDatabaseConnection();
577  foreach ($GLOBALS['TCA'] as $table => $value) {
578  if ($table != 'pages' && (in_array($table, $tables) || in_array('_ALL', $tables))) {
579  if ($this->getBackendUser()->check('tables_select', $table) && !$GLOBALS['TCA'][$table]['ctrl']['is_static']) {
580  $res = $this->exec_listQueryPid($table, $k, MathUtility::forceIntegerInRange($maxNumber, 1));
581  while ($subTrow = $db->sql_fetch_assoc($res)) {
582  $this->export->export_addRecord($table, $subTrow);
583  }
584  $db->sql_free_result($res);
585  }
586  }
587  }
588  }
589 
598  public function exec_listQueryPid($table, $pid, $limit)
599  {
600  $db = $this->getDatabaseConnection();
601  $orderBy = $GLOBALS['TCA'][$table]['ctrl']['sortby']
602  ? 'ORDER BY ' . $GLOBALS['TCA'][$table]['ctrl']['sortby']
603  : $GLOBALS['TCA'][$table]['ctrl']['default_sortby'];
604  $res = $db->exec_SELECTquery(
605  '*',
606  $table,
607  'pid=' . (int)$pid . BackendUtility::deleteClause($table) . BackendUtility::versioningPlaceholderClause($table),
608  '',
609  $db->stripOrderBy($orderBy),
610  $limit
611  );
612  // Warning about hitting limit:
613  if ($db->sql_num_rows($res) == $limit) {
614  $limitWarning = sprintf($this->lang->getLL('makeconfig_anSqlQueryReturned', true), $limit);
616  $flashMessage = GeneralUtility::makeInstance(
617  FlashMessage::class,
618  $this->lang->getLL('execlistqu_maxNumberLimit'),
619  $limitWarning,
621  );
622  $this->content .= $flashMessage->render();
623  }
624  return $res;
625  }
626 
634  public function makeConfigurationForm($inData, &$row)
635  {
636  $nameSuggestion = '';
637  // Page tree export options:
638  if (isset($inData['pagetree']['id'])) {
639  $nameSuggestion .= 'tree_PID' . $inData['pagetree']['id'] . '_L' . $inData['pagetree']['levels'];
640  $row[] = '
641  <tr class="tableheader bgColor5">
642  <td colspan="2">' . $this->lang->getLL('makeconfig_exportPagetreeConfiguration', true)
643  . BackendUtility::cshItem('xMOD_tx_impexp', 'pageTreeCfg') . '</td>
644  </tr>';
645  $row[] = '
646  <tr class="bgColor4">
647  <td><strong>' . $this->lang->getLL('makeconfig_pageId', true) . '</strong></td>
648  <td>' . htmlspecialchars($inData['pagetree']['id']) . '<input type="hidden" value="'
649  . htmlspecialchars($inData['pagetree']['id']) . '" name="tx_impexp[pagetree][id]" /></td>
650  </tr>';
651  $row[] = '
652  <tr class="bgColor4">
653  <td><strong>' . $this->lang->getLL('makeconfig_tree', true) . '</strong>'
654  . BackendUtility::cshItem('xMOD_tx_impexp', 'pageTreeDisplay') . '</td>
655  <td>' . ($this->treeHTML ?: $this->lang->getLL('makeconfig_noTreeExportedOnly', true)) . '</td>
656  </tr>';
657  $opt = array(
658  '-2' => $this->lang->getLL('makeconfig_tablesOnThisPage'),
659  '-1' => $this->lang->getLL('makeconfig_expandedTree'),
660  '0' => $this->lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.depth_0'),
661  '1' => $this->lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.depth_1'),
662  '2' => $this->lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.depth_2'),
663  '3' => $this->lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.depth_3'),
664  '4' => $this->lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.depth_4'),
665  '999' => $this->lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.depth_infi'),
666  );
667  $row[] = '
668  <tr class="bgColor4">
669  <td><strong>' . $this->lang->getLL('makeconfig_levels', true) . '</strong>'
670  . BackendUtility::cshItem('xMOD_tx_impexp', 'pageTreeMode') . '</td>
671  <td>' . $this->renderSelectBox('tx_impexp[pagetree][levels]', $inData['pagetree']['levels'], $opt) . '</td>
672  </tr>';
673  $row[] = '
674  <tr class="bgColor4">
675  <td><strong>' . $this->lang->getLL('makeconfig_includeTables', true) . '</strong>'
676  . BackendUtility::cshItem('xMOD_tx_impexp', 'pageTreeRecordLimit') . '</td>
677  <td>' . $this->tableSelector('tx_impexp[pagetree][tables]', $inData['pagetree']['tables'], 'pages') . '<br/>
678  ' . $this->lang->getLL('makeconfig_maxNumberOfRecords', true) . '<br/>
679  <input type="text" name="tx_impexp[pagetree][maxNumber]" value="'
680  . htmlspecialchars($inData['pagetree']['maxNumber']) . '"' . $this->doc->formWidth(10) . ' /><br/>
681  </td>
682  </tr>';
683  }
684  // Single record export:
685  if (is_array($inData['record'])) {
686  $row[] = '
687  <tr class="tableheader bgColor5">
688  <td colspan="2">' . $this->lang->getLL('makeconfig_exportSingleRecord', true)
689  . BackendUtility::cshItem('xMOD_tx_impexp', 'singleRecord') . '</td>
690  </tr>';
691  foreach ($inData['record'] as $ref) {
692  $rParts = explode(':', $ref);
693  $tName = $rParts[0];
694  $rUid = $rParts[1];
695  $nameSuggestion .= $tName . '_' . $rUid;
696  $rec = BackendUtility::getRecordWSOL($tName, $rUid);
697  if (!empty($rec)) {
698  $row[] = '
699  <tr class="bgColor4">
700  <td><strong>' . $this->lang->getLL('makeconfig_record', true) . '</strong></td>
701  <td>' . $this->iconFactory->getIconForRecord($tName, $rec, Icon::SIZE_SMALL)->render() . BackendUtility::getRecordTitle($tName, $rec, true)
702  . '<input type="hidden" name="tx_impexp[record][]" value="' . htmlspecialchars(($tName . ':' . $rUid)) . '" /></td>
703  </tr>';
704  }
705  }
706  }
707  // Single tables/pids:
708  if (is_array($inData['list'])) {
709  $row[] = '
710  <tr class="tableheader bgColor5">
711  <td colspan="2">' . $this->lang->getLL('makeconfig_exportTablesFromPages', true) . '</td>
712  </tr>';
713  // Display information about pages from which the export takes place
714  $tblList = '';
715  foreach ($inData['list'] as $reference) {
716  $referenceParts = explode(':', $reference);
717  $tableName = $referenceParts[0];
718  if ($this->getBackendUser()->check('tables_select', $tableName)) {
719  // If the page is actually the root, handle it differently
720  // NOTE: we don't compare integers, because the number actually comes from the split string above
721  if ($referenceParts[1] === '0') {
722  $iconAndTitle = $this->iconFactory->getIcon('apps-pagetree-root', Icon::SIZE_SMALL)->render() . $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'];
723  } else {
724  $record = BackendUtility::getRecordWSOL('pages', $referenceParts[1]);
725  $iconAndTitle = $this->iconFactory->getIconForRecord('pages', $record, Icon::SIZE_SMALL)->render()
726  . BackendUtility::getRecordTitle('pages', $record, true);
727  }
728  $tblList .= 'Table "' . $tableName . '" from ' . $iconAndTitle
729  . '<input type="hidden" name="tx_impexp[list][]" value="' . htmlspecialchars($reference) . '" /><br/>';
730  }
731  }
732  $row[] = '
733  <tr class="bgColor4">
734  <td><strong>' . $this->lang->getLL('makeconfig_tablePids', true) . '</strong>'
735  . BackendUtility::cshItem('xMOD_tx_impexp', 'tableList') . '</td>
736  <td>' . $tblList . '</td>
737  </tr>';
738  $row[] = '
739  <tr class="bgColor4">
740  <td><strong>' . $this->lang->getLL('makeconfig_maxNumberOfRecords', true)
741  . BackendUtility::cshItem('xMOD_tx_impexp', 'tableListMaxNumber') . '</strong></td>
742  <td>
743  <input type="text" name="tx_impexp[listCfg][maxNumber]" value="'
744  . htmlspecialchars($inData['listCfg']['maxNumber']) . '" /><br/>
745  </td>
746  </tr>';
747  }
748  $row[] = '
749  <tr class="tableheader bgColor5">
750  <td colspan="2">' . $this->lang->getLL('makeconfig_relationsAndExclusions', true) . '</td>
751  </tr>';
752  // Add relation selector:
753  $row[] = '
754  <tr class="bgColor4">
755  <td><strong>' . $this->lang->getLL('makeconfig_includeRelationsToTables', true) . '</strong>'
756  . BackendUtility::cshItem('xMOD_tx_impexp', 'inclRelations') . '</td>
757  <td>' . $this->tableSelector('tx_impexp[external_ref][tables]', $inData['external_ref']['tables']) . '</td>
758  </tr>';
759  // Add static relation selector:
760  $row[] = '
761  <tr class="bgColor4">
762  <td><strong>' . $this->lang->getLL('makeconfig_useStaticRelationsFor', true) . '</strong>'
763  . BackendUtility::cshItem('xMOD_tx_impexp', 'staticRelations') . '</td>
764  <td>' . $this->tableSelector('tx_impexp[external_static][tables]', $inData['external_static']['tables']) . '<br/>
765  <label for="checkShowStaticRelations">' . $this->lang->getLL('makeconfig_showStaticRelations', true)
766  . '</label> <input type="checkbox" name="tx_impexp[showStaticRelations]" id="checkShowStaticRelations" value="1"'
767  . ($inData['showStaticRelations'] ? ' checked="checked"' : '') . ' />
768  </td>
769  </tr>';
770  // Exclude:
771  $excludeHiddenFields = '';
772  if (is_array($inData['exclude'])) {
773  foreach ($inData['exclude'] as $key => $value) {
774  $excludeHiddenFields .= '<input type="hidden" name="tx_impexp[exclude][' . $key . ']" value="1" />';
775  }
776  }
777  if (!empty($inData['exclude'])) {
778  $excludedElements = '<em>' . implode(', ', array_keys($inData['exclude'])) . '</em><hr/><label for="checkExclude">'
779  . $this->lang->getLL('makeconfig_clearAllExclusions', true)
780  . '</label> <input type="checkbox" name="tx_impexp[exclude]" id="checkExclude" value="1" />';
781  } else {
782  $excludedElements = $this->lang->getLL('makeconfig_noExcludedElementsYet', true);
783  }
784  $row[] = '
785  <tr class="bgColor4">
786  <td><strong>' . $this->lang->getLL('makeconfig_excludeElements', true) . '</strong>'
787  . BackendUtility::cshItem('xMOD_tx_impexp', 'excludedElements') . '</td>
788  <td>' . $excludeHiddenFields . '
789  ' . $excludedElements . '
790  </td>
791  </tr>';
792  // Add buttons:
793  $row[] = '
794  <tr class="bgColor4">
795  <td>&nbsp;</td>
796  <td>
797  <input class="btn btn-default" type="submit" value="' . $this->lang->getLL('makeadvanc_update', true) . '" />
798  <input type="hidden" name="tx_impexp[download_export_name]" value="' . substr($nameSuggestion, 0, 30) . '" />
799  </td>
800  </tr>';
801  }
802 
811  public function makeAdvancedOptionsForm($inData, &$row)
812  {
813  // Soft references
814  $row[] = '
815  <tr class="tableheader bgColor5">
816  <td colspan="2">' . $this->lang->getLL('makeadvanc_softReferences', true) . '</td>
817  </tr>';
818  $row[] = '
819  <tr class="bgColor4">
820  <td><label for="checkExcludeHTMLfileResources"><strong>'
821  . $this->lang->getLL('makeadvanc_excludeHtmlCssFile', true) . '</strong></label>'
822  . BackendUtility::cshItem('xMOD_tx_impexp', 'htmlCssResources') . '</td>
823  <td><input type="checkbox" name="tx_impexp[excludeHTMLfileResources]" id="checkExcludeHTMLfileResources" value="1"'
824  . ($inData['excludeHTMLfileResources'] ? ' checked="checked"' : '') . ' /></td>
825  </tr>';
826 
827  // Files options
828  $row[] = '
829  <tr class="tableheader bgColor5">
830  <td colspan="2">' . $this->lang->getLL('makeadvanc_files', true) . '</td>
831  </tr>';
832  $row[] = '
833  <tr class="bgColor4">
834  <td><label for="saveFilesOutsideExportFile"><strong>'
835  . $this->lang->getLL('makeadvanc_saveFilesOutsideExportFile', true) . '</strong><br />'
836  . $this->lang->getLL('makeadvanc_saveFilesOutsideExportFile_limit', true) . '</label></td>
837  <td><input type="checkbox" name="tx_impexp[saveFilesOutsideExportFile]" id="saveFilesOutsideExportFile" value="1"'
838  . ($inData['saveFilesOutsideExportFile'] ? ' checked="checked"' : '') . ' /></td>
839  </tr>';
840  // Extensions
841  $row[] = '
842  <tr class="tableheader bgColor5">
843  <td colspan="2">' . $this->lang->getLL('makeadvanc_extensionDependencies', true) . '</td>
844  </tr>';
845  $row[] = '
846  <tr class="bgColor4">
847  <td><strong>' . $this->lang->getLL('makeadvanc_selectExtensionsThatThe', true) . '</strong>'
848  . BackendUtility::cshItem('xMOD_tx_impexp', 'extensionDependencies') . '</td>
849  <td>' . $this->extensionSelector('tx_impexp[extension_dep]', $inData['extension_dep']) . '</td>
850  </tr>';
851  // Add buttons:
852  $row[] = '
853  <tr class="bgColor4">
854  <td>&nbsp;</td>
855  <td>
856  <input class="btn btn-default" type="submit" value="' . $this->lang->getLL('makesavefo_update', true) . '" />
857  <input type="hidden" name="tx_impexp[download_export_name]" value="" />
858  </td>
859  </tr>';
860  }
861 
869  public function makeSaveForm($inData, &$row)
870  {
871  // Presets:
872  $row[] = '
873  <tr class="tableheader bgColor5">
874  <td colspan="2">' . $this->lang->getLL('makesavefo_presets', true) . '</td>
875  </tr>';
876  $opt = array('');
877  $where = '(public>0 OR user_uid=' . (int)$this->getBackendUser()->user['uid'] . ')'
878  . ($inData['pagetree']['id'] ? ' AND (item_uid=' . (int)$inData['pagetree']['id'] . ' OR item_uid=0)' : '');
879  $presets = $this->getDatabaseConnection()->exec_SELECTgetRows('*', 'tx_impexp_presets', $where);
880  if (is_array($presets)) {
881  foreach ($presets as $presetCfg) {
882  $opt[$presetCfg['uid']] = $presetCfg['title'] . ' [' . $presetCfg['uid'] . ']'
883  . ($presetCfg['public'] ? ' [Public]' : '')
884  . ($presetCfg['user_uid'] === $this->getBackendUser()->user['uid'] ? ' [Own]' : '');
885  }
886  }
887  $row[] = '
888  <tr class="bgColor4">
889  <td><strong>' . $this->lang->getLL('makesavefo_presets', true) . '</strong>'
890  . BackendUtility::cshItem('xMOD_tx_impexp', 'presets') . '</td>
891  <td>
892  ' . $this->lang->getLL('makesavefo_selectPreset', true) . '<br/>
893  ' . $this->renderSelectBox('preset[select]', '', $opt) . '
894  <br/>
895  <input type="hidden" name="not-set" value="1" id="t3js-submit-field" />
896  <input class="btn btn-default" type="submit" value="' . $this->lang->getLL('makesavefo_load', true) . '" name="preset[load]" />
897  <input class="btn btn-default t3js-confirm-trigger" type="button" value="' . $this->lang->getLL('makesavefo_save', true) . '" name="preset[save]" data-title="' . $this->lang->getLL('pleaseConfirm', true) . '" data-message="' . $this->lang->getLL('makesavefo_areYouSure', true) . '" />
898  <input class="btn btn-default t3js-confirm-trigger" type="button" value="' . $this->lang->getLL('makesavefo_delete', true) . '" name="preset[delete]" data-title="' . $this->lang->getLL('pleaseConfirm', true) . '" data-message="' . $this->lang->getLL('makesavefo_areYouSure', true) . '" />
899  <input class="btn btn-default t3js-confirm-trigger" type="button" value="' . $this->lang->getLL('makesavefo_merge', true) . '" name="preset[merge]" data-title="' . $this->lang->getLL('pleaseConfirm', true) . '" data-message="' . $this->lang->getLL('makesavefo_areYouSure', true) . '" />
900  <br/>
901  ' . $this->lang->getLL('makesavefo_titleOfNewPreset', true) . '
902  <input type="text" name="tx_impexp[preset][title]" value="'
903  . htmlspecialchars($inData['preset']['title']) . '" /><br/>
904  <label for="checkPresetPublic">' . $this->lang->getLL('makesavefo_public', true) . '</label>
905  <input type="checkbox" name="tx_impexp[preset][public]" id="checkPresetPublic" value="1"'
906  . ($inData['preset']['public'] ? ' checked="checked"' : '') . ' /><br/>
907  </td>
908  </tr>';
909  // Output options:
910  $row[] = '
911  <tr class="tableheader bgColor5">
912  <td colspan="2">' . $this->lang->getLL('makesavefo_outputOptions', true) . '</td>
913  </tr>';
914  // Meta data:
915  $thumbnailFiles = array();
916  foreach ($this->getThumbnailFiles() as $thumbnailFile) {
917  $thumbnailFiles[$thumbnailFile->getCombinedIdentifier()] = $thumbnailFile->getName();
918  }
919  if (!empty($thumbnailFiles)) {
920  array_unshift($thumbnailFiles, '');
921  }
922  $thumbnail = null;
923  if (!empty($inData['meta']['thumbnail'])) {
924  $thumbnail = $this->getFile($inData['meta']['thumbnail']);
925  }
926  $saveFolder = $this->getDefaultImportExportFolder();
927 
928  $row[] = '
929  <tr class="bgColor4">
930  <td><strong>' . $this->lang->getLL('makesavefo_metaData', true) . '</strong>'
931  . BackendUtility::cshItem('xMOD_tx_impexp', 'metadata') . '</td>
932  <td>
933  ' . $this->lang->getLL('makesavefo_title', true) . ' <br/>
934  <input type="text" name="tx_impexp[meta][title]" value="' . htmlspecialchars($inData['meta']['title']) . '" /><br/>
935  ' . $this->lang->getLL('makesavefo_description', true) . ' <br/>
936  <input type="text" name="tx_impexp[meta][description]" value="' . htmlspecialchars($inData['meta']['description']) . '" /><br/>
937  ' . $this->lang->getLL('makesavefo_notes', true) . ' <br/>
938  <textarea name="tx_impexp[meta][notes]">' . htmlspecialchars($inData['meta']['notes']) . '</textarea><br/>
939  ' . (!empty($thumbnailFiles) ? '
940  ' . $this->lang->getLL('makesavefo_thumbnail', true) . '<br/>
941  ' . $this->renderSelectBox('tx_impexp[meta][thumbnail]', $inData['meta']['thumbnail'], $thumbnailFiles) : '') . '<br/>
942  ' . ($thumbnail ? '<img src="' . htmlspecialchars($thumbnail->getPublicUrl(true)) . '" vspace="5" style="border: solid black 1px;" alt="" /><br/>' : '') . '
943  ' . $this->lang->getLL('makesavefo_uploadThumbnail', true) . '<br/>
944  ' . ($saveFolder ? '<input type="file" name="upload_1" size="30" /><br/>
945  <input type="hidden" name="file[upload][1][target]" value="' . htmlspecialchars($saveFolder->getCombinedIdentifier()) . '" />
946  <input type="hidden" name="file[upload][1][data]" value="1" /><br />' : '') . '
947  </td>
948  </tr>';
949  // Add file options:
950  $opt = array();
951  if ($this->export->compress) {
952  $opt['t3d_compressed'] = $this->lang->getLL('makesavefo_t3dFileCompressed');
953  }
954  $opt['t3d'] = $this->lang->getLL('makesavefo_t3dFile');
955  $opt['xml'] = $this->lang->getLL('makesavefo_xml');
956  $fileName = '';
957  if ($saveFolder) {
958  $fileName = sprintf($this->lang->getLL('makesavefo_filenameSavedInS', true), $saveFolder->getCombinedIdentifier())
959  . '<br/>
960  <input type="text" name="tx_impexp[filename]" value="'
961  . htmlspecialchars($inData['filename']) . '" /><br/>';
962  }
963  $row[] = '
964  <tr>
965  <td>
966  <strong>' . $this->lang->getLL('makesavefo_fileFormat', true) . '</strong>'
967  . BackendUtility::cshItem('xMOD_tx_impexp', 'fileFormat') . '
968  </td>
969  <td>
970  ' . $this->renderSelectBox('tx_impexp[filetype]', $inData['filetype'], $opt) . '<br/>
971  ' . $this->lang->getLL('makesavefo_maxSizeOfFiles', true) . '<br/>
972  <input type="text" name="tx_impexp[maxFileSize]" value="' . htmlspecialchars($inData['maxFileSize']) . '" />
973  <br/>
974  ' . $fileName . '
975  </td>
976  </tr>';
977  // Add buttons:
978  $row[] = '
979  <tr>
980  <td>&nbsp;</td>
981  <td>
982  <input class="btn btn-default" type="submit" value="' . $this->lang->getLL('makesavefo_update', true) . '" /> -
983  <input class="btn btn-default" type="submit" value="' . $this->lang->getLL('makesavefo_downloadExport', true) . '" name="tx_impexp[download_export]" />
984  ' . ($saveFolder ? ' - <input class="btn btn-default" type="submit" value="' . $this->lang->getLL('importdata_saveToFilename', true) . '" name="tx_impexp[save_export]" />' : '') . '
985  </td>
986  </tr>';
987  }
988 
989  /**************************
990  * IMPORT FUNCTIONS
991  **************************/
992 
1002  public function importData($inData)
1003  {
1004  $access = is_array($this->pageinfo) ? 1 : 0;
1005  $beUser = $this->getBackendUser();
1006  if ($this->id && $access || $beUser->user['admin'] && !$this->id) {
1007  if ($beUser->user['admin'] && !$this->id) {
1008  $this->pageinfo = array('title' => '[root-level]', 'uid' => 0, 'pid' => 0);
1009  }
1010  if ($inData['new_import']) {
1011  unset($inData['import_mode']);
1012  }
1014  $import = GeneralUtility::makeInstance(\TYPO3\CMS\Impexp\ImportExport::class);
1015  $import->init(0, 'import');
1016  $import->update = $inData['do_update'];
1017  $import->import_mode = $inData['import_mode'];
1018  $import->enableLogging = $inData['enableLogging'];
1019  $import->global_ignore_pid = $inData['global_ignore_pid'];
1020  $import->force_all_UIDS = $inData['force_all_UIDS'];
1021  $import->showDiff = !$inData['notShowDiff'];
1022  $import->allowPHPScripts = $inData['allowPHPScripts'];
1023  $import->softrefInputValues = $inData['softrefInputValues'];
1024  // OUTPUT creation:
1025  $menuItems = array();
1026  // Make input selector:
1027  // must have trailing slash.
1028  $path = $this->getDefaultImportExportFolder();
1029  $exportFiles = $this->getExportFiles();
1030 
1031  $this->shortcutName .= ' (' . $this->pageinfo['title'] . ')';
1032 
1033  // Configuration
1034  $row = array();
1035  $selectOptions = array('');
1036  foreach ($exportFiles as $file) {
1037  $selectOptions[$file->getCombinedIdentifier()] = $file->getPublicUrl();
1038  }
1039  $row[] = '
1040  <tr>
1041  <th colspan="2">' . $this->lang->getLL('importdata_selectFileToImport', true) . '</th>
1042  </tr>';
1043  $noCompressorAvailable = !$import->compress
1044  ? '<br /><span class="text-danger">' . $this->lang->getLL('importdata_noteNoDecompressorAvailable', true) . '</span>'
1045  : '';
1046  $row[] = '
1047  <tr>
1048  <td valign="top">
1049  ' . $this->lang->getLL('importdata_file', true) . ''
1050  . BackendUtility::cshItem('xMOD_tx_impexp', 'importFile') . '
1051  </td>
1052  <td>
1053  ' . $this->renderSelectBox('tx_impexp[file]', $inData['file'], $selectOptions) . '<br />'
1054  . sprintf($this->lang->getLL('importdata_fromPathS', true), $path ? $path->getCombinedIdentifier() : $this->lang->getLL('importdata_no_accessible_file_mount', true)) .
1055  $noCompressorAvailable . '
1056  </td>
1057  </tr>';
1058  $row[] = '
1059  <tr>
1060  <th colspan="2">
1061  ' . $this->lang->getLL('importdata_importOptions', true) . '
1062  </th>
1063  </tr>';
1064  $row[] = '
1065  <tr>
1066  <td valign="top">
1067  ' . $this->lang->getLL('importdata_update', true)
1068  . BackendUtility::cshItem('xMOD_tx_impexp', 'update') . '
1069  </td>
1070  <td>
1071  <input type="checkbox" name="tx_impexp[do_update]" id="checkDo_update" value="1"'
1072  . ($inData['do_update'] ? ' checked="checked"' : '') . ' />
1073  <label for="checkDo_update">' . $this->lang->getLL('importdata_updateRecords', true) . '</label>
1074  <br/>
1075  <em>(' . $this->lang->getLL('importdata_thisOptionRequiresThat', true) . ')</em>' . ($inData['do_update'] ? ' <hr/>
1076  <input type="checkbox" name="tx_impexp[global_ignore_pid]" id="checkGlobal_ignore_pid" value="1"'
1077  . ($inData['global_ignore_pid'] ? ' checked="checked"' : '') . ' />
1078  <label for="checkGlobal_ignore_pid">' . $this->lang->getLL('importdata_ignorePidDifferencesGlobally', true) . '</label><br/>
1079  <em>(' . $this->lang->getLL('importdata_ifYouSetThis', true) . ')</em>
1080  ' : '') . '
1081  </td>
1082  </tr>';
1083  $allowPhpScripts = $beUser->isAdmin()
1084  ? '
1085  <input type="checkbox" name="tx_impexp[allowPHPScripts]" id="checkAllowPHPScripts" value="1"'
1086  . ($inData['allowPHPScripts'] ? ' checked="checked"' : '') . ' />
1087  <label for="checkAllowPHPScripts">' . $this->lang->getLL('importdata_allowToWriteBanned', true) . '</label><br/>'
1088  : '';
1089  $doUpdate = !$inData['do_update'] && $beUser->isAdmin()
1090  ? '
1091  <br/>
1092  <input type="checkbox" name="tx_impexp[force_all_UIDS]" id="checkForce_all_UIDS" value="1"'
1093  . ($inData['force_all_UIDS'] ? ' checked="checked"' : '') . ' />
1094  <label for="checkForce_all_UIDS"><span class="text-danger">'
1095  . $this->lang->getLL('importdata_force_all_UIDS', true) . '</span></label><br/>
1096  <em>(' . $this->lang->getLL('importdata_force_all_UIDS_descr', true) . ')</em>'
1097  : '';
1098  $row[] = '<tr>
1099  <td valign="top">
1100  ' . $this->lang->getLL('importdata_options', true) . BackendUtility::cshItem('xMOD_tx_impexp', 'options') . '
1101  </td>
1102  <td>
1103  <input type="checkbox" name="tx_impexp[notShowDiff]" id="checkNotShowDiff" value="1"'
1104  . ($inData['notShowDiff'] ? ' checked="checked"' : '') . ' />
1105  <label for="checkNotShowDiff">' . $this->lang->getLL('importdata_doNotShowDifferences', true) . '</label><br/>
1106  <em>(' . $this->lang->getLL('importdata_greenValuesAreFrom', true) . ')</em>
1107  <br/><br/>
1108 
1109  ' . $allowPhpScripts . $doUpdate . '
1110  </td>
1111  </tr>';
1112  $newImport = !$inData['import_file']
1113  ? '<input class="btn btn-default" type="submit" value="' . $this->lang->getLL('importdata_preview', true) . '" />' . ($inData['file']
1114  ? ' - <input type="hidden" name="not-set" value="1" id="t3js-submit-field" /><input class="btn btn-default t3js-confirm-trigger" type="button" value="' . ($inData['do_update']
1115  ? $this->lang->getLL('importdata_update_299e', true)
1116  : $this->lang->getLL('importdata_import', true)) . '" name="tx_impexp[import_file]" data-title="' . $this->lang->getLL('pleaseConfirm', true) . '" data-message="' . $this->lang->getLL('importdata_areYouSure', true) . '" />'
1117  : '')
1118  : '<input class="btn btn-default" type="submit" name="tx_impexp[new_import]" value="' . $this->lang->getLL('importdata_newImport', true) . '" />';
1119  $row[] = '<tr>
1120  <td valign="top">
1121  ' . $this->lang->getLL('importdata_action', true) . BackendUtility::cshItem('xMOD_tx_impexp', 'action') . '
1122  </td>
1123  <td>
1124  ' . $newImport . '
1125  <input type="hidden" name="tx_impexp[action]" value="import" />
1126  </td>
1127  </tr>';
1128  $row[] = '<tr>
1129  <td valign="top">
1130  ' . $this->lang->getLL('importdata_enableLogging', true)
1131  . BackendUtility::cshItem('xMOD_tx_impexp', 'enableLogging') . '
1132  </td>
1133  <td>
1134  <input type="checkbox" name="tx_impexp[enableLogging]" id="checkEnableLogging" value="1"'
1135  . ($inData['enableLogging'] ? ' checked="checked"' : '') . ' />
1136  <label for="checkEnableLogging">' . $this->lang->getLL('importdata_writeIndividualDbActions', true) . '</label><br/>
1137  <em>(' . $this->lang->getLL('importdata_thisIsDisabledBy', true) . ')</em>
1138  </td>
1139  </tr>';
1140  $menuItems[] = array(
1141  'label' => $this->lang->getLL('importdata_import', true),
1142  'content' => '
1143  <table border="0" cellpadding="1" cellspacing="1">
1144  ' . implode('
1145  ', $row) . '
1146  </table>
1147  '
1148  );
1149  // Upload file:
1150  $tempFolder = $this->getDefaultImportExportFolder();
1151  if ($tempFolder) {
1152  $row = array();
1153  $row[] = '
1154  <tr>
1155  <th colspan="2">' . $this->lang->getLL('importdata_uploadFileFromLocal', true) . '</th>
1156  </tr>';
1157  $row[] = '
1158  <tr>
1159  <td valign="top">
1160  ' . $this->lang->getLL('importdata_browse', true) . BackendUtility::cshItem('xMOD_tx_impexp', 'upload') . '
1161  </td>
1162  <td>
1163  <input type="file" name="upload_1" size="40" />
1164  <input type="hidden" name="file[upload][1][target]" value="' . htmlspecialchars($tempFolder->getCombinedIdentifier()) . '" />
1165  <input type="hidden" name="file[upload][1][data]" value="1" />
1166  <br />
1167  <input class="btn btn-default" type="submit" name="_upload" value="' . $this->lang->sL('LLL:EXT:lang/locallang_core.xlf:file_upload.php.submit', true) . '" />
1168  <input type="checkbox" name="overwriteExistingFiles" id="checkOverwriteExistingFiles" value="1" checked="checked" />
1169  <label for="checkOverwriteExistingFiles">' . $this->lang->sL('LLL:EXT:lang/locallang_misc.xlf:overwriteExistingFiles', true) . '</label>
1170  </td>
1171  </tr>';
1172  if (GeneralUtility::_POST('_upload')) {
1173  $noFileUploaded = $this->fileProcessor->internalUploadMap[1]
1174  ? $this->lang->getLL('importdata_success', true) . ' ' . $this->uploadedFiles[0]->getName()
1175  : '<span class="text-danger">' . $this->lang->getLL('importdata_failureNoFileUploaded', true) . '</span>';
1176  $row[] = '<tr class="bgColor4">
1177  <td>' . $this->lang->getLL('importdata_uploadStatus', true) . '</td>
1178  <td>' . $noFileUploaded . '</td>
1179  </tr>';
1180  }
1181  $menuItems[] = array(
1182  'label' => $this->lang->getLL('importdata_upload'),
1183  'content' => '
1184  <table border="0" cellpadding="1" cellspacing="1">
1185  ' . implode('
1186  ', $row) . '
1187  </table>
1188  '
1189  );
1190  }
1191  // Perform import or preview depending:
1192  $overviewContent = '';
1193  $extensionInstallationMessage = '';
1194  $inFile = $this->getFile($inData['file']);
1195  if ($inFile !== null && $inFile->exists()) {
1196  $trow = array();
1197  if ($import->loadFile($inFile->getForLocalProcessing(false), 1)) {
1198  // Check extension dependencies:
1199  $extKeysToInstall = array();
1200  if (is_array($import->dat['header']['extensionDependencies'])) {
1201  foreach ($import->dat['header']['extensionDependencies'] as $extKey) {
1202  if (!\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded($extKey)) {
1203  $extKeysToInstall[] = $extKey;
1204  }
1205  }
1206  }
1207  if (!empty($extKeysToInstall)) {
1208  $extensionInstallationMessage = 'Before you can install this T3D file you need to install the extensions "'
1209  . implode('", "', $extKeysToInstall) . '".';
1210  }
1211  if ($inData['import_file']) {
1212  if (empty($extKeysToInstall)) {
1213  $import->importData($this->id);
1214  BackendUtility::setUpdateSignal('updatePageTree');
1215  }
1216  }
1217  $import->display_import_pid_record = $this->pageinfo;
1218  $overviewContent = $import->displayContentOverview();
1219  }
1220  // Meta data output:
1221  $trow[] = '<tr class="bgColor5">
1222  <td colspan="2"><strong>' . $this->lang->getLL('importdata_metaData', true) . '</strong></td>
1223  </tr>';
1224  $trow[] = '<tr class="bgColor4">
1225  <td><strong>' . $this->lang->getLL('importdata_title', true) . '</strong></td>
1226  <td width="95%">' . nl2br(htmlspecialchars($import->dat['header']['meta']['title'])) . '</td>
1227  </tr>';
1228  $trow[] = '<tr class="bgColor4">
1229  <td><strong>' . $this->lang->getLL('importdata_description', true) . '</strong></td>
1230  <td width="95%">' . nl2br(htmlspecialchars($import->dat['header']['meta']['description'])) . '</td>
1231  </tr>';
1232  $trow[] = '<tr class="bgColor4">
1233  <td><strong>' . $this->lang->getLL('importdata_notes', true) . '</strong></td>
1234  <td width="95%">' . nl2br(htmlspecialchars($import->dat['header']['meta']['notes'])) . '</td>
1235  </tr>';
1236  $trow[] = '<tr class="bgColor4">
1237  <td><strong>' . $this->lang->getLL('importdata_packager', true) . '</strong></td>
1238  <td width="95%">' . nl2br(htmlspecialchars(($import->dat['header']['meta']['packager_name']
1239  . ' (' . $import->dat['header']['meta']['packager_username'] . ')'))) . '<br/>
1240  ' . $this->lang->getLL('importdata_email', true) . ' '
1241  . $import->dat['header']['meta']['packager_email'] . '</td>
1242  </tr>';
1243  // Thumbnail icon:
1244  if (is_array($import->dat['header']['thumbnail'])) {
1245  $pI = pathinfo($import->dat['header']['thumbnail']['filename']);
1246  if (GeneralUtility::inList('gif,jpg,png,jpeg', strtolower($pI['extension']))) {
1247  // Construct filename and write it:
1248  $fileName = PATH_site . 'typo3temp/importthumb.' . $pI['extension'];
1249  GeneralUtility::writeFile($fileName, $import->dat['header']['thumbnail']['content']);
1250  // Check that the image really is an image and not a malicious PHP script...
1251  if (getimagesize($fileName)) {
1252  // Create icon tag:
1253  $iconTag = '<img src="../' . PathUtility::stripPathSitePrefix($fileName)
1254  . '" ' . $import->dat['header']['thumbnail']['imgInfo'][3]
1255  . ' vspace="5" style="border: solid black 1px;" alt="" />';
1256  $trow[] = '<tr class="bgColor4">
1257  <td><strong>' . $this->lang->getLL('importdata_icon', true) . '</strong></td>
1258  <td>' . $iconTag . '</td>
1259  </tr>';
1260  } else {
1262  }
1263  }
1264  }
1265  $menuItems[] = array(
1266  'label' => $this->lang->getLL('importdata_metaData_1387'),
1267  'content' => '
1268  <table border="0" cellpadding="1" cellspacing="1">
1269  ' . implode('
1270  ', $trow) . '
1271  </table>
1272  '
1273  );
1274  }
1275  // Print errors that might be:
1276  $errors = $import->printErrorLog();
1277  $menuItems[] = array(
1278  'label' => $this->lang->getLL('importdata_messages'),
1279  'content' => $errors,
1280  'stateIcon' => $errors ? 2 : 0
1281  );
1282  // Output tabs:
1283  $content = $this->moduleTemplate->getDynamicTabMenu($menuItems, 'tx_impexp_import', 1, false, true, false);
1284  if ($extensionInstallationMessage) {
1285  $content = '<div style="border: 1px black solid; margin: 10px 10px 10px 10px; padding: 10px 10px 10px 10px;">'
1286  . $this->moduleTemplate->icons(1) . htmlspecialchars($extensionInstallationMessage) . '</div>' . $content;
1287  }
1288  $this->content .= '<div>' . $content . '</div>';
1289  // Print overview:
1290  if ($overviewContent) {
1291  $this->content .= '<h2>' . ($inData['import_file']
1292  ? $this->lang->getLL('importdata_structureHasBeenImported', true)
1293  : $this->lang->getLL('filterpage_structureToBeImported', true)) . '</h2><div>' . $overviewContent . '</div>';
1294  }
1295  }
1296  }
1297 
1298  /****************************
1299  * Preset functions
1300  ****************************/
1301 
1308  public function processPresets(&$inData)
1309  {
1310  $presetData = GeneralUtility::_GP('preset');
1311  $err = false;
1312  $msg = '';
1313  // Save preset
1314  $beUser = $this->getBackendUser();
1315  // cast public checkbox to int, since this is an int field and NULL is not allowed
1316  $inData['preset']['public'] = (int)$inData['preset']['public'];
1317  if (isset($presetData['save'])) {
1318  $preset = $this->getPreset($presetData['select']);
1319  // Update existing
1320  if (is_array($preset)) {
1321  if ($beUser->isAdmin() || $preset['user_uid'] === $beUser->user['uid']) {
1322  $fields_values = array(
1323  'public' => $inData['preset']['public'],
1324  'title' => $inData['preset']['title'],
1325  'item_uid' => $inData['pagetree']['id'],
1326  'preset_data' => serialize($inData)
1327  );
1328  $this->getDatabaseConnection()->exec_UPDATEquery('tx_impexp_presets', 'uid=' . (int)$preset['uid'], $fields_values);
1329  $msg = 'Preset #' . $preset['uid'] . ' saved!';
1330  } else {
1331  $msg = 'ERROR: The preset was not saved because you were not the owner of it!';
1332  $err = true;
1333  }
1334  } else {
1335  // Insert new:
1336  $fields_values = array(
1337  'user_uid' => $beUser->user['uid'],
1338  'public' => $inData['preset']['public'],
1339  'title' => $inData['preset']['title'],
1340  'item_uid' => $inData['pagetree']['id'],
1341  'preset_data' => serialize($inData)
1342  );
1343  $this->getDatabaseConnection()->exec_INSERTquery('tx_impexp_presets', $fields_values);
1344  $msg = 'New preset "' . htmlspecialchars($inData['preset']['title']) . '" is created';
1345  }
1346  }
1347  // Delete preset:
1348  if (isset($presetData['delete'])) {
1349  $preset = $this->getPreset($presetData['select']);
1350  if (is_array($preset)) {
1351  // Update existing
1352  if ($beUser->isAdmin() || $preset['user_uid'] === $beUser->user['uid']) {
1353  $this->getDatabaseConnection()->exec_DELETEquery('tx_impexp_presets', 'uid=' . (int)$preset['uid']);
1354  $msg = 'Preset #' . $preset['uid'] . ' deleted!';
1355  } else {
1356  $msg = 'ERROR: You were not the owner of the preset so you could not delete it.';
1357  $err = true;
1358  }
1359  } else {
1360  $msg = 'ERROR: No preset selected for deletion.';
1361  $err = true;
1362  }
1363  }
1364  // Load preset
1365  if (isset($presetData['load']) || isset($presetData['merge'])) {
1366  $preset = $this->getPreset($presetData['select']);
1367  if (is_array($preset)) {
1368  // Update existing
1369  $inData_temp = unserialize($preset['preset_data']);
1370  if (is_array($inData_temp)) {
1371  if (isset($presetData['merge'])) {
1372  // Merge records in:
1373  if (is_array($inData_temp['record'])) {
1374  $inData['record'] = array_merge((array)$inData['record'], $inData_temp['record']);
1375  }
1376  // Merge lists in:
1377  if (is_array($inData_temp['list'])) {
1378  $inData['list'] = array_merge((array)$inData['list'], $inData_temp['list']);
1379  }
1380  } else {
1381  $msg = 'Preset #' . $preset['uid'] . ' loaded!';
1382  $inData = $inData_temp;
1383  }
1384  } else {
1385  $msg = 'ERROR: No configuratio data found in preset record!';
1386  $err = true;
1387  }
1388  } else {
1389  $msg = 'ERROR: No preset selected for loading.';
1390  $err = true;
1391  }
1392  }
1393  // Show message:
1394  if ($msg !== '') {
1396  $flashMessage = GeneralUtility::makeInstance(
1397  FlashMessage::class,
1398  'Presets',
1399  $msg,
1401  );
1402  $this->content .= $flashMessage->render();
1403  }
1404  }
1405 
1412  public function getPreset($uid)
1413  {
1414  return $this->getDatabaseConnection()->exec_SELECTgetSingleRow('*', 'tx_impexp_presets', 'uid=' . (int)$uid);
1415  }
1416 
1417  /****************************
1418  * Helper functions
1419  ****************************/
1420 
1428  protected function getDefaultImportExportFolder()
1429  {
1430  $defaultImportExportFolder = null;
1431 
1432  $defaultTemporaryFolder = $this->getBackendUser()->getDefaultUploadTemporaryFolder();
1433  if ($defaultTemporaryFolder !== null) {
1434  $importExportFolderName = 'importexport';
1435  $createFolder = !$defaultTemporaryFolder->hasFolder($importExportFolderName);
1436  if ($createFolder === true) {
1437  try {
1438  $defaultImportExportFolder = $defaultTemporaryFolder->createFolder($importExportFolderName);
1439  } catch (\TYPO3\CMS\Core\Resource\Exception $folderAccessException) {
1440  }
1441  } else {
1442  $defaultImportExportFolder = $defaultTemporaryFolder->getSubfolder($importExportFolderName);
1443  }
1444  }
1445 
1446  return $defaultImportExportFolder;
1447  }
1448 
1449 
1457  public function checkUpload()
1458  {
1459  $file = GeneralUtility::_GP('file');
1460  // Initializing:
1461  $this->fileProcessor = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Utility\File\ExtendedFileUtility::class);
1462  $this->fileProcessor->init(array(), $GLOBALS['TYPO3_CONF_VARS']['BE']['fileExtensions']);
1463  $this->fileProcessor->setActionPermissions();
1464  $this->fileProcessor->setExistingFilesConflictMode((int)GeneralUtility::_GP('overwriteExistingFiles') === 1 ? DuplicationBehavior::REPLACE : DuplicationBehavior::CANCEL);
1465  // Checking referer / executing:
1466  $refInfo = parse_url(GeneralUtility::getIndpEnv('HTTP_REFERER'));
1467  $httpHost = GeneralUtility::getIndpEnv('TYPO3_HOST_ONLY');
1468  if (
1469  $httpHost != $refInfo['host']
1470  && !$GLOBALS['$TYPO3_CONF_VARS']['SYS']['doNotCheckReferer']
1471  && $this->vC != $this->getBackendUser()->veriCode()
1472  ) {
1473  $this->fileProcessor->writeLog(0, 2, 1, 'Referer host "%s" and server host "%s" did not match!', array($refInfo['host'], $httpHost));
1474  } else {
1475  $this->fileProcessor->start($file);
1476  $result = $this->fileProcessor->processData();
1477  if (!empty($result['upload'])) {
1478  foreach ($result['upload'] as $uploadedFiles) {
1479  $this->uploadedFiles += $uploadedFiles;
1480  }
1481  }
1482  }
1483  }
1484 
1493  public function renderSelectBox($prefix, $value, $optValues)
1494  {
1495  $opt = array();
1496  $isSelFlag = 0;
1497  foreach ($optValues as $k => $v) {
1498  $sel = (string)$k === (string)$value ? ' selected="selected"' : '';
1499  if ($sel) {
1500  $isSelFlag++;
1501  }
1502  $opt[] = '<option value="' . htmlspecialchars($k) . '"' . $sel . '>' . htmlspecialchars($v) . '</option>';
1503  }
1504  if (!$isSelFlag && (string)$value !== '') {
1505  $opt[] = '<option value="' . htmlspecialchars($value) . '" selected="selected">'
1506  . htmlspecialchars(('[\'' . $value . '\']')) . '</option>';
1507  }
1508  return '<select name="' . $prefix . '">' . implode('', $opt) . '</select>';
1509  }
1510 
1519  public function tableSelector($prefix, $value, $excludeList = '')
1520  {
1521  $optValues = array();
1522  if (!GeneralUtility::inList($excludeList, '_ALL')) {
1523  $optValues['_ALL'] = '[' . $this->lang->getLL('ALL_tables') . ']';
1524  }
1525  foreach ($GLOBALS['TCA'] as $table => $_) {
1526  if ($this->getBackendUser()->check('tables_select', $table) && !GeneralUtility::inList($excludeList, $table)) {
1527  $optValues[$table] = $table;
1528  }
1529  }
1530  // make box:
1531  $opt = array();
1532  $opt[] = '<option value=""></option>';
1533  $sel = '';
1534  foreach ($optValues as $k => $v) {
1535  if (is_array($value)) {
1536  $sel = in_array($k, $value) ? ' selected="selected"' : '';
1537  }
1538  $opt[] = '<option value="' . htmlspecialchars($k) . '"' . $sel . '>' . htmlspecialchars($v) . '</option>';
1539  }
1540  return '<select name="' . $prefix . '[]" multiple="multiple" size="'
1541  . MathUtility::forceIntegerInRange(count($opt), 5, 10) . '">' . implode('', $opt) . '</select>';
1542  }
1543 
1551  public function extensionSelector($prefix, $value)
1552  {
1553  $loadedExtensions = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getLoadedExtensionListArray();
1554 
1555  // make box:
1556  $opt = array();
1557  $opt[] = '<option value=""></option>';
1558  foreach ($loadedExtensions as $extensionKey) {
1559  $sel = '';
1560  if (is_array($value)) {
1561  $sel = in_array($extensionKey, $value) ? ' selected="selected"' : '';
1562  }
1563  $opt[] = '<option value="' . htmlspecialchars($extensionKey) . '"' . $sel . '>'
1564  . htmlspecialchars($extensionKey) . '</option>';
1565  }
1566  return '<select name="' . $prefix . '[]" multiple="multiple" size="'
1567  . MathUtility::forceIntegerInRange(count($opt), 5, 10) . '">' . implode('', $opt) . '</select>';
1568  }
1569 
1577  public function filterPageIds($exclude)
1578  {
1579  // Get keys:
1580  $exclude = array_keys($exclude);
1581  // Traverse
1582  $pageIds = array();
1583  foreach ($exclude as $element) {
1584  list($table, $uid) = explode(':', $element);
1585  if ($table === 'pages') {
1586  $pageIds[] = (int)$uid;
1587  }
1588  }
1589  // Add to clause:
1590  if (!empty($pageIds)) {
1591  return ' AND uid NOT IN (' . implode(',', $pageIds) . ')';
1592  }
1593  return '';
1594  }
1595 
1599  protected function getBackendUser()
1600  {
1601  return $GLOBALS['BE_USER'];
1602  }
1603 
1607  protected function getDatabaseConnection()
1608  {
1609  return $GLOBALS['TYPO3_DB'];
1610  }
1611 
1615  protected function getLanguageService()
1616  {
1617  return $GLOBALS['LANG'];
1618  }
1619 
1626  protected function getThumbnailFiles()
1627  {
1628  $thumbnailFiles = array();
1629  $defaultTemporaryFolder = $this->getDefaultImportExportFolder();
1630 
1631  if ($defaultTemporaryFolder === null) {
1632  return $thumbnailFiles;
1633  }
1634 
1636  $filter = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Resource\Filter\FileExtensionFilter::class);
1637  $filter->setAllowedFileExtensions(array('png', 'gif', 'jpg'));
1638  $defaultTemporaryFolder->getStorage()->addFileAndFolderNameFilter(array($filter, 'filterFileList'));
1639  $thumbnailFiles = $defaultTemporaryFolder->getFiles();
1640 
1641  return $thumbnailFiles;
1642  }
1643 
1650  protected function getExportFiles()
1651  {
1652  $exportFiles = array();
1653 
1654  $folder = $this->getDefaultImportExportFolder();
1655  if ($folder !== null) {
1656 
1658  $filter = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Resource\Filter\FileExtensionFilter::class);
1659  $filter->setAllowedFileExtensions(array('t3d', 'xml'));
1660  $folder->getStorage()->addFileAndFolderNameFilter(array($filter, 'filterFileList'));
1661 
1662  $exportFiles = $folder->getFiles();
1663  }
1664 
1665  return $exportFiles;
1666  }
1667 
1674  protected function getFile($combinedIdentifier)
1675  {
1676  try {
1677  $file = \TYPO3\CMS\Core\Resource\ResourceFactory::getInstance()->getFileObjectFromCombinedIdentifier($combinedIdentifier);
1678  } catch (\Exception $exception) {
1679  $file = null;
1680  }
1681 
1682  return $file;
1683  }
1684 }