[TASK] Remove thumbnail functionality of EXT:impexp
[Packages/TYPO3.CMS.git] / typo3 / sysext / impexp / Classes / Controller / ImportExportController.php
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
17 use Psr\Http\Message\ResponseInterface;
18 use Psr\Http\Message\ServerRequestInterface;
19 use TYPO3\CMS\Backend\Module\BaseScriptClass;
20 use TYPO3\CMS\Backend\Template\DocumentTemplate;
21 use TYPO3\CMS\Backend\Template\ModuleTemplate;
22 use TYPO3\CMS\Backend\Tree\View\PageTreeView;
23 use TYPO3\CMS\Backend\Utility\BackendUtility;
24 use TYPO3\CMS\Core\Database\DatabaseConnection;
25 use TYPO3\CMS\Core\Imaging\Icon;
26 use TYPO3\CMS\Core\Imaging\IconFactory;
27 use TYPO3\CMS\Core\Messaging\FlashMessage;
28 use TYPO3\CMS\Core\Messaging\FlashMessageService;
29 use TYPO3\CMS\Core\Resource\DuplicationBehavior;
30 use TYPO3\CMS\Core\Resource\Exception;
31 use TYPO3\CMS\Core\Resource\Filter\FileExtensionFilter;
32 use TYPO3\CMS\Core\Resource\ResourceFactory;
33 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
34 use TYPO3\CMS\Core\Utility\File\ExtendedFileUtility;
35 use TYPO3\CMS\Core\Utility\GeneralUtility;
36 use TYPO3\CMS\Core\Utility\MathUtility;
37 use TYPO3\CMS\Core\Utility\PathUtility;
38 use TYPO3\CMS\Impexp\Domain\Repository\PresetRepository;
39 use TYPO3\CMS\Impexp\ImportExport;
40 use TYPO3\CMS\Impexp\View\ExportPageTreeView;
41 use TYPO3\CMS\Lang\LanguageService;
42
43 /**
44 * Main script class for the Import / Export facility
45 */
46 class ImportExportController extends BaseScriptClass
47 {
48 /**
49 * @var array|\TYPO3\CMS\Core\Resource\File[]
50 */
51 protected $uploadedFiles = array();
52
53 /**
54 * Array containing the current page.
55 *
56 * @var array
57 */
58 public $pageinfo;
59
60 /**
61 * @var ImportExport
62 */
63 protected $export;
64
65 /**
66 * @var ImportExport
67 */
68 protected $import;
69
70 /**
71 * @var ExtendedFileUtility
72 */
73 protected $fileProcessor;
74
75 /**
76 * @var string
77 */
78 protected $vC = '';
79
80 /**
81 * @var LanguageService
82 */
83 protected $lang = null;
84
85 /**
86 * @var string
87 */
88 protected $treeHTML = '';
89
90 /**
91 * @var IconFactory
92 */
93 protected $iconFactory;
94
95 /**
96 * The name of the module
97 *
98 * @var string
99 */
100 protected $moduleName = 'xMOD_tximpexp';
101
102 /**
103 * ModuleTemplate Container
104 *
105 * @var ModuleTemplate
106 */
107 protected $moduleTemplate;
108
109 /**
110 * The name of the shortcut for this page
111 *
112 * @var string
113 */
114 protected $shortcutName;
115
116 /**
117 * preset repository
118 *
119 * @var PresetRepository
120 */
121 protected $presetRepository;
122
123 /**
124 * Constructor
125 */
126 public function __construct()
127 {
128 $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
129 $this->moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class);
130 $this->presetRepository = GeneralUtility::makeInstance(PresetRepository::class);
131 }
132
133 /**
134 * @return void
135 */
136 public function init()
137 {
138 $this->MCONF['name'] = $this->moduleName;
139 parent::init();
140 $this->vC = GeneralUtility::_GP('vC');
141 $this->lang = $this->getLanguageService();
142 }
143
144 /**
145 * Main module function
146 *
147 * @throws \BadFunctionCallException
148 * @throws \InvalidArgumentException
149 * @return void
150 */
151 public function main()
152 {
153 $this->lang->includeLLFile('EXT:impexp/Resources/Private/Language/locallang.xlf');
154 // Start document template object:
155 // We keep this here, in case somebody relies on the old doc being here
156 $this->doc = GeneralUtility::makeInstance(DocumentTemplate::class);
157 $this->doc->bodyTagId = 'imp-exp-mod';
158 $this->pageinfo = BackendUtility::readPageAccess($this->id, $this->perms_clause);
159 $this->moduleTemplate->getDocHeaderComponent()->setMetaInformation($this->pageinfo);
160 // Setting up the context sensitive menu:
161 $this->moduleTemplate->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/ClickMenu');
162 $this->moduleTemplate->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Impexp/ImportExport');
163 $this->moduleTemplate->addJavaScriptCode(
164 'ImpexpInLineJS',
165 'if (top.fsMod) top.fsMod.recentIds["web"] = ' . (int)$this->id . ';'
166 );
167 $this->content = '<form action="' . htmlspecialchars(BackendUtility::getModuleUrl('xMOD_tximpexp')) . '" method="post" id="ImportExportController" enctype="multipart/form-data">'
168 . '<input type="hidden" name="id" value="' . $this->id . '" />';
169 // Input data grabbed:
170 $inData = GeneralUtility::_GP('tx_impexp');
171 $this->content .= '<h3>' . $this->lang->getLL('title_' . (string)$inData['action'], true) . '</h3>';
172 $this->content .= '<div style="padding-top: 5px;"></div>';
173 switch ((string)$inData['action']) {
174 case 'export':
175 $this->shortcutName = $this->lang->getLL('title_export');
176 // Call export interface
177 $this->exportData($inData);
178 break;
179 case 'import':
180 $this->shortcutName = $this->lang->getLL('title_import');
181 if (GeneralUtility::_POST('_upload')) {
182 $this->checkUpload();
183 }
184 // Finally: If upload went well, set the new file as the import file:
185 if (!empty($this->uploadedFiles[0])) {
186 // Only allowed extensions....
187 $extension = $this->uploadedFiles[0]->getExtension();
188 if ($extension === 't3d' || $extension === 'xml') {
189 $inData['file'] = $this->uploadedFiles[0]->getCombinedIdentifier();
190 }
191 }
192 // Call import interface:
193 $this->importData($inData);
194 break;
195 }
196 // Setting up the buttons and markers for docheader
197 $this->getButtons();
198 $this->content .= '</form>';
199 }
200
201 /**
202 * Print the content
203 *
204 * @return void
205 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
206 */
207 public function printContent()
208 {
209 GeneralUtility::logDeprecatedFunction();
210 echo $this->content;
211 }
212
213 /**
214 * Injects the request object for the current request and gathers all data
215 *
216 * IMPORTING DATA:
217 *
218 * Incoming array has syntax:
219 * GETvar 'id' = import page id (must be readable)
220 *
221 * file = (pointing to filename relative to PATH_site)
222 *
223 * [all relation fields are clear, but not files]
224 * - page-tree is written first
225 * - then remaining pages (to the root of import)
226 * - then all other records are written either to related included pages or if not found to import-root (should be a sysFolder in most cases)
227 * - then all internal relations are set and non-existing relations removed, relations to static tables preserved.
228 *
229 * EXPORTING DATA:
230 *
231 * Incoming array has syntax:
232 *
233 * file[] = file
234 * dir[] = dir
235 * list[] = table:pid
236 * record[] = table:uid
237 *
238 * pagetree[id] = (single id)
239 * pagetree[levels]=1,2,3, -1 = currently unpacked tree, -2 = only tables on page
240 * pagetree[tables][]=table/_ALL
241 *
242 * external_ref[tables][]=table/_ALL
243 *
244 * @param ServerRequestInterface $request the current request
245 * @param ResponseInterface $response
246 * @return ResponseInterface the response with the content
247 */
248 public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
249 {
250 $GLOBALS['SOBE'] = $this;
251 $this->init();
252 $this->main();
253 $this->moduleTemplate->setContent($this->content);
254 $response->getBody()->write($this->moduleTemplate->renderContent());
255 return $response;
256 }
257
258 /**
259 * Create the panel of buttons for submitting the form or otherwise perform operations.
260 *
261 * @return array all available buttons as an associated array
262 */
263 protected function getButtons()
264 {
265 $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
266 if ($this->getBackendUser()->mayMakeShortcut()) {
267 $shortcutButton = $buttonBar->makeShortcutButton()
268 ->setGetVariables(['tx_impexp'])
269 ->setDisplayName($this->shortcutName)
270 ->setModuleName($this->moduleName);
271 $buttonBar->addButton($shortcutButton);
272 }
273 // Input data grabbed:
274 $inData = GeneralUtility::_GP('tx_impexp');
275 if ((string)$inData['action'] == 'import') {
276 if ($this->id && is_array($this->pageinfo) || $this->getBackendUser()->user['admin'] && !$this->id) {
277 if (is_array($this->pageinfo) && $this->pageinfo['uid']) {
278 // View
279 $onClick = BackendUtility::viewOnClick(
280 $this->pageinfo['uid'],
281 '',
282 BackendUtility::BEgetRootLine($this->pageinfo['uid'])
283 );
284 $viewButton = $buttonBar->makeLinkButton()
285 ->setTitle($this->lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.showPage'))
286 ->setHref('#')
287 ->setIcon($this->iconFactory->getIcon('actions-document-view', Icon::SIZE_SMALL))
288 ->setOnClick($onClick);
289 $buttonBar->addButton($viewButton);
290 }
291 }
292 }
293 }
294
295 /**************************
296 * EXPORT FUNCTIONS
297 **************************/
298
299 /**
300 * Export part of module
301 * Setting content in $this->content
302 *
303 * @param array $inData Content of POST VAR tx_impexp[]..
304 * @throws \InvalidArgumentException
305 * @throws \RuntimeException
306 * @throws \TYPO3\CMS\Core\Resource\Exception\ExistingTargetFileNameException
307 * @return void
308 */
309 public function exportData($inData)
310 {
311 // BUILDING EXPORT DATA:
312 // Processing of InData array values:
313 $inData['pagetree']['maxNumber'] = MathUtility::forceIntegerInRange($inData['pagetree']['maxNumber'], 1, 1000000, 100);
314 $inData['listCfg']['maxNumber'] = MathUtility::forceIntegerInRange($inData['listCfg']['maxNumber'], 1, 1000000, 100);
315 $inData['maxFileSize'] = MathUtility::forceIntegerInRange($inData['maxFileSize'], 1, 1000000, 1000);
316 $inData['filename'] = trim(preg_replace('/[^[:alnum:]._-]*/', '', preg_replace('/\\.(t3d|xml)$/', '', $inData['filename'])));
317 if (strlen($inData['filename'])) {
318 $inData['filename'] .= $inData['filetype'] == 'xml' ? '.xml' : '.t3d';
319 }
320 // Set exclude fields in export object:
321 if (!is_array($inData['exclude'])) {
322 $inData['exclude'] = array();
323 }
324 // Saving/Loading/Deleting presets:
325 $this->presetRepository->processPresets($inData);
326 // Create export object and configure it:
327 $this->export = GeneralUtility::makeInstance(ImportExport::class);
328 $this->export->init(0, 'export');
329 $this->export->setCharset($this->lang->charSet);
330 $this->export->maxFileSize = $inData['maxFileSize'] * 1024;
331 $this->export->excludeMap = (array)$inData['exclude'];
332 $this->export->softrefCfg = (array)$inData['softrefCfg'];
333 $this->export->extensionDependencies = (array)$inData['extension_dep'];
334 $this->export->showStaticRelations = $inData['showStaticRelations'];
335 $this->export->includeExtFileResources = !$inData['excludeHTMLfileResources'];
336 // Static tables:
337 if (is_array($inData['external_static']['tables'])) {
338 $this->export->relStaticTables = $inData['external_static']['tables'];
339 }
340 // Configure which tables external relations are included for:
341 if (is_array($inData['external_ref']['tables'])) {
342 $this->export->relOnlyTables = $inData['external_ref']['tables'];
343 }
344 $saveFilesOutsideExportFile = false;
345 if (isset($inData['save_export']) && isset($inData['saveFilesOutsideExportFile']) && $inData['saveFilesOutsideExportFile'] === '1') {
346 $this->export->setSaveFilesOutsideExportFile(true);
347 $saveFilesOutsideExportFile = true;
348 }
349 $this->export->setHeaderBasics();
350 // Meta data setting:
351
352 $beUser = $this->getBackendUser();
353 $this->export->setMetaData(
354 $inData['meta']['title'],
355 $inData['meta']['description'],
356 $inData['meta']['notes'],
357 $beUser->user['username'],
358 $beUser->user['realName'],
359 $beUser->user['email']
360 );
361 // Configure which records to export
362 if (is_array($inData['record'])) {
363 foreach ($inData['record'] as $ref) {
364 $rParts = explode(':', $ref);
365 $this->export->export_addRecord($rParts[0], BackendUtility::getRecord($rParts[0], $rParts[1]));
366 }
367 }
368 // Configure which tables to export
369 if (is_array($inData['list'])) {
370 $db = $this->getDatabaseConnection();
371 foreach ($inData['list'] as $ref) {
372 $rParts = explode(':', $ref);
373 if ($beUser->check('tables_select', $rParts[0])) {
374 $res = $this->exec_listQueryPid($rParts[0], $rParts[1], MathUtility::forceIntegerInRange($inData['listCfg']['maxNumber'], 1));
375 while ($subTrow = $db->sql_fetch_assoc($res)) {
376 $this->export->export_addRecord($rParts[0], $subTrow);
377 }
378 $db->sql_free_result($res);
379 }
380 }
381 }
382 // Pagetree
383 if (isset($inData['pagetree']['id'])) {
384 // Based on click-expandable tree
385 $idH = null;
386 if ($inData['pagetree']['levels'] == -1) {
387 $pagetree = GeneralUtility::makeInstance(ExportPageTreeView::class);
388 $tree = $pagetree->ext_tree($inData['pagetree']['id'], $this->filterPageIds($this->export->excludeMap));
389 $this->treeHTML = $pagetree->printTree($tree);
390 $idH = $pagetree->buffer_idH;
391 } elseif ($inData['pagetree']['levels'] == -2) {
392 $this->addRecordsForPid($inData['pagetree']['id'], $inData['pagetree']['tables'], $inData['pagetree']['maxNumber']);
393 } else {
394 // Based on depth
395 // Drawing tree:
396 // If the ID is zero, export root
397 if (!$inData['pagetree']['id'] && $beUser->isAdmin()) {
398 $sPage = array(
399 'uid' => 0,
400 'title' => 'ROOT'
401 );
402 } else {
403 $sPage = BackendUtility::getRecordWSOL('pages', $inData['pagetree']['id'], '*', ' AND ' . $this->perms_clause);
404 }
405 if (is_array($sPage)) {
406 $pid = $inData['pagetree']['id'];
407 $tree = GeneralUtility::makeInstance(PageTreeView::class);
408 $tree->init('AND ' . $this->perms_clause . $this->filterPageIds($this->export->excludeMap));
409 $HTML = $this->iconFactory->getIconForRecord('pages', $sPage, Icon::SIZE_SMALL)->render();
410 $tree->tree[] = array('row' => $sPage, 'HTML' => $HTML);
411 $tree->buffer_idH = array();
412 if ($inData['pagetree']['levels'] > 0) {
413 $tree->getTree($pid, $inData['pagetree']['levels'], '');
414 }
415 $idH = array();
416 $idH[$pid]['uid'] = $pid;
417 if (!empty($tree->buffer_idH)) {
418 $idH[$pid]['subrow'] = $tree->buffer_idH;
419 }
420 $pagetree = GeneralUtility::makeInstance(ExportPageTreeView::class);
421 $this->treeHTML = $pagetree->printTree($tree->tree);
422 $this->shortcutName .= ' (' . $sPage['title'] . ')';
423 }
424 }
425 // In any case we should have a multi-level array, $idH, with the page structure
426 // here (and the HTML-code loaded into memory for nice display...)
427 if (is_array($idH)) {
428 // Sets the pagetree and gets a 1-dim array in return with the pages (in correct submission order BTW...)
429 $flatList = $this->export->setPageTree($idH);
430 foreach ($flatList as $k => $value) {
431 $this->export->export_addRecord('pages', BackendUtility::getRecord('pages', $k));
432 $this->addRecordsForPid($k, $inData['pagetree']['tables'], $inData['pagetree']['maxNumber']);
433 }
434 }
435 }
436 // After adding ALL records we set relations:
437 for ($a = 0; $a < 10; $a++) {
438 $addR = $this->export->export_addDBRelations($a);
439 if (empty($addR)) {
440 break;
441 }
442 }
443 // Finally files are added:
444 // MUST be after the DBrelations are set so that files from ALL added records are included!
445 $this->export->export_addFilesFromRelations();
446
447 $this->export->export_addFilesFromSysFilesRecords();
448
449 // If the download button is clicked, return file
450 if ($inData['download_export'] || $inData['save_export']) {
451 switch ((string)$inData['filetype']) {
452 case 'xml':
453 $out = $this->export->compileMemoryToFileContent('xml');
454 $fExt = '.xml';
455 break;
456 case 't3d':
457 $this->export->dontCompress = 1;
458 // intentional fall-through
459 default:
460 $out = $this->export->compileMemoryToFileContent();
461 $fExt = ($this->export->doOutputCompress() ? '-z' : '') . '.t3d';
462 }
463 // Filename:
464 $dlFile = $inData['filename'];
465 if (!$dlFile) {
466 $exportName = substr(preg_replace('/[^[:alnum:]_]/', '-', $inData['download_export_name']), 0, 20);
467 $dlFile = 'T3D_' . $exportName . '_' . date('Y-m-d_H-i') . $fExt;
468 }
469
470 // Export for download:
471 if ($inData['download_export']) {
472 $mimeType = 'application/octet-stream';
473 Header('Content-Type: ' . $mimeType);
474 Header('Content-Length: ' . strlen($out));
475 Header('Content-Disposition: attachment; filename=' . basename($dlFile));
476 echo $out;
477 die;
478 }
479 // Export by saving:
480 if ($inData['save_export']) {
481 $saveFolder = $this->getDefaultImportExportFolder();
482 $lang = $this->getLanguageService();
483 if ($saveFolder !== false && $saveFolder->checkActionPermission('write')) {
484 $temporaryFileName = GeneralUtility::tempnam('export');
485 file_put_contents($temporaryFileName, $out);
486 $file = $saveFolder->addFile($temporaryFileName, $dlFile, 'replace');
487 if ($saveFilesOutsideExportFile) {
488 $filesFolderName = $dlFile . '.files';
489 $filesFolder = $saveFolder->createFolder($filesFolderName);
490 $temporaryFolderForExport = ResourceFactory::getInstance()->retrieveFileOrFolderObject($this->export->getTemporaryFilesPathForExport());
491 $temporaryFilesForExport = $temporaryFolderForExport->getFiles();
492 foreach ($temporaryFilesForExport as $temporaryFileForExport) {
493 $filesFolder->getStorage()->moveFile($temporaryFileForExport, $filesFolder);
494 }
495 $temporaryFolderForExport->delete();
496 }
497
498 /** @var FlashMessage $flashMessage */
499 $flashMessage = GeneralUtility::makeInstance(
500 FlashMessage::class,
501 sprintf($lang->getLL('exportdata_savedInSBytes'), $file->getPublicUrl(), GeneralUtility::formatSize(strlen($out))),
502 $lang->getLL('exportdata_savedFile'),
503 FlashMessage::OK
504 );
505 } else {
506 /** @var FlashMessage $flashMessage */
507 $flashMessage = GeneralUtility::makeInstance(
508 FlashMessage::class,
509 sprintf($lang->getLL('exportdata_badPathS'), $saveFolder->getPublicUrl()),
510 $lang->getLL('exportdata_problemsSavingFile'),
511 FlashMessage::ERROR
512 );
513 }
514 /** @var $flashMessageService \TYPO3\CMS\Core\Messaging\FlashMessageService */
515 $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
516 /** @var $defaultFlashMessageQueue \TYPO3\CMS\Core\Messaging\FlashMessageQueue */
517 $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
518 $defaultFlashMessageQueue->enqueue($flashMessage);
519 }
520 }
521 // OUTPUT to BROWSER:
522 // Now, if we didn't make download file, show configuration form based on export:
523 $menuItems = array();
524 // Export configuration
525 $row = array();
526 $this->makeConfigurationForm($inData, $row);
527 $menuItems[] = array(
528 'label' => $this->lang->getLL('tableselec_configuration'),
529 'content' => '
530 <table border="0" cellpadding="1" cellspacing="1">
531 ' . implode('
532 ', $row) . '
533 </table>
534 '
535 );
536 // File options
537 $row = array();
538 $this->makeSaveForm($inData, $row);
539 $menuItems[] = array(
540 'label' => $this->lang->getLL('exportdata_filePreset'),
541 'content' => '
542 <table border="0" cellpadding="1" cellspacing="1">
543 ' . implode('
544 ', $row) . '
545 </table>
546 '
547 );
548 // File options
549 $row = array();
550 $this->makeAdvancedOptionsForm($inData, $row);
551 $menuItems[] = array(
552 'label' => $this->lang->getLL('exportdata_advancedOptions'),
553 'content' => '
554 <table border="0" cellpadding="1" cellspacing="1">
555 ' . implode('
556 ', $row) . '
557 </table>
558 '
559 );
560 // Generate overview:
561 $overViewContent = $this->export->displayContentOverview();
562 // Print errors that might be:
563 $errors = $this->export->printErrorLog();
564 $menuItems[] = array(
565 'label' => $this->lang->getLL('exportdata_messages'),
566 'content' => $errors,
567 'stateIcon' => $errors ? 2 : 0
568 );
569 // Add hidden fields and create tabs:
570
571 $content = $this->moduleTemplate->getDynamicTabMenu($menuItems, 'tx_impexp_export', 1, false, true, false);
572 $content .= '<input type="hidden" name="tx_impexp[action]" value="export" />';
573 $this->content .= '<div>' . $content . '</div>';
574 // Output Overview:
575 $this->content .= '<h2>' . $this->lang->getLL('execlistqu_structureToBeExported', true) . '</h2><div>' . $overViewContent . '</div>';
576 }
577
578 /**
579 * Adds records to the export object for a specific page id.
580 *
581 * @param int $k Page id for which to select records to add
582 * @param array $tables Array of table names to select from
583 * @param int $maxNumber Max amount of records to select
584 * @return void
585 */
586 public function addRecordsForPid($k, $tables, $maxNumber)
587 {
588 if (!is_array($tables)) {
589 return;
590 }
591 $db = $this->getDatabaseConnection();
592 foreach ($GLOBALS['TCA'] as $table => $value) {
593 if ($table != 'pages' && (in_array($table, $tables) || in_array('_ALL', $tables))) {
594 if ($this->getBackendUser()->check('tables_select', $table) && !$GLOBALS['TCA'][$table]['ctrl']['is_static']) {
595 $res = $this->exec_listQueryPid($table, $k, MathUtility::forceIntegerInRange($maxNumber, 1));
596 while ($subTrow = $db->sql_fetch_assoc($res)) {
597 $this->export->export_addRecord($table, $subTrow);
598 }
599 $db->sql_free_result($res);
600 }
601 }
602 }
603 }
604
605 /**
606 * Selects records from table / pid
607 *
608 * @param string $table Table to select from
609 * @param int $pid Page ID to select from
610 * @param int $limit Max number of records to select
611 * @return \mysqli_result|object Database resource
612 */
613 public function exec_listQueryPid($table, $pid, $limit)
614 {
615 $db = $this->getDatabaseConnection();
616 $orderBy = $GLOBALS['TCA'][$table]['ctrl']['sortby']
617 ? 'ORDER BY ' . $GLOBALS['TCA'][$table]['ctrl']['sortby']
618 : $GLOBALS['TCA'][$table]['ctrl']['default_sortby'];
619 $res = $db->exec_SELECTquery(
620 '*',
621 $table,
622 'pid=' . (int)$pid . BackendUtility::deleteClause($table) . BackendUtility::versioningPlaceholderClause($table),
623 '',
624 $db->stripOrderBy($orderBy),
625 $limit
626 );
627 // Warning about hitting limit:
628 if ($db->sql_num_rows($res) == $limit) {
629 $limitWarning = sprintf($this->lang->getLL('makeconfig_anSqlQueryReturned'), $limit);
630 /** @var FlashMessage $flashMessage */
631 $flashMessage = GeneralUtility::makeInstance(
632 FlashMessage::class,
633 $this->lang->getLL('execlistqu_maxNumberLimit'),
634 $limitWarning,
635 FlashMessage::WARNING
636 );
637 /** @var $flashMessageService \TYPO3\CMS\Core\Messaging\FlashMessageService */
638 $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
639 /** @var $defaultFlashMessageQueue \TYPO3\CMS\Core\Messaging\FlashMessageQueue */
640 $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
641 $defaultFlashMessageQueue->enqueue($flashMessage);
642 }
643 return $res;
644 }
645
646 /**
647 * Create configuration form
648 *
649 * @param array $inData Form configurat data
650 * @param array $row Table row accumulation variable. This is filled with table rows.
651 * @return void Sets content in $this->content
652 */
653 public function makeConfigurationForm($inData, &$row)
654 {
655 $nameSuggestion = '';
656 // Page tree export options:
657 if (isset($inData['pagetree']['id'])) {
658 $nameSuggestion .= 'tree_PID' . $inData['pagetree']['id'] . '_L' . $inData['pagetree']['levels'];
659 $row[] = '
660 <tr class="tableheader bgColor5">
661 <td colspan="2">' . $this->lang->getLL('makeconfig_exportPagetreeConfiguration', true)
662 . BackendUtility::cshItem('xMOD_tx_impexp', 'pageTreeCfg') . '</td>
663 </tr>';
664 $row[] = '
665 <tr class="bgColor4">
666 <td><strong>' . $this->lang->getLL('makeconfig_pageId', true) . '</strong></td>
667 <td>' . htmlspecialchars($inData['pagetree']['id']) . '<input type="hidden" value="'
668 . htmlspecialchars($inData['pagetree']['id']) . '" name="tx_impexp[pagetree][id]" /></td>
669 </tr>';
670 $row[] = '
671 <tr class="bgColor4">
672 <td><strong>' . $this->lang->getLL('makeconfig_tree', true) . '</strong>'
673 . BackendUtility::cshItem('xMOD_tx_impexp', 'pageTreeDisplay') . '</td>
674 <td>' . ($this->treeHTML ?: $this->lang->getLL('makeconfig_noTreeExportedOnly', true)) . '</td>
675 </tr>';
676 $opt = array(
677 '-2' => $this->lang->getLL('makeconfig_tablesOnThisPage'),
678 '-1' => $this->lang->getLL('makeconfig_expandedTree'),
679 '0' => $this->lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.depth_0'),
680 '1' => $this->lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.depth_1'),
681 '2' => $this->lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.depth_2'),
682 '3' => $this->lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.depth_3'),
683 '4' => $this->lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.depth_4'),
684 '999' => $this->lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.depth_infi'),
685 );
686 $row[] = '
687 <tr class="bgColor4">
688 <td><strong>' . $this->lang->getLL('makeconfig_levels', true) . '</strong>'
689 . BackendUtility::cshItem('xMOD_tx_impexp', 'pageTreeMode') . '</td>
690 <td>' . $this->renderSelectBox('tx_impexp[pagetree][levels]', $inData['pagetree']['levels'], $opt) . '</td>
691 </tr>';
692 $row[] = '
693 <tr class="bgColor4">
694 <td><strong>' . $this->lang->getLL('makeconfig_includeTables', true) . '</strong>'
695 . BackendUtility::cshItem('xMOD_tx_impexp', 'pageTreeRecordLimit') . '</td>
696 <td>' . $this->tableSelector('tx_impexp[pagetree][tables]', $inData['pagetree']['tables'], 'pages') . '<br/>
697 ' . $this->lang->getLL('makeconfig_maxNumberOfRecords', true) . '<br/>
698 <input type="text" name="tx_impexp[pagetree][maxNumber]" value="'
699 . htmlspecialchars($inData['pagetree']['maxNumber']) . '" ' . $this->doc->formWidth(10) . ' /><br/>
700 </td>
701 </tr>';
702 }
703 // Single record export:
704 if (is_array($inData['record'])) {
705 $row[] = '
706 <tr class="tableheader bgColor5">
707 <td colspan="2">' . $this->lang->getLL('makeconfig_exportSingleRecord', true)
708 . BackendUtility::cshItem('xMOD_tx_impexp', 'singleRecord') . '</td>
709 </tr>';
710 foreach ($inData['record'] as $ref) {
711 $rParts = explode(':', $ref);
712 $tName = $rParts[0];
713 $rUid = $rParts[1];
714 $nameSuggestion .= $tName . '_' . $rUid;
715 $rec = BackendUtility::getRecordWSOL($tName, $rUid);
716 if (!empty($rec)) {
717 $row[] = '
718 <tr class="bgColor4">
719 <td><strong>' . $this->lang->getLL('makeconfig_record', true) . '</strong></td>
720 <td>' . $this->iconFactory->getIconForRecord($tName, $rec, Icon::SIZE_SMALL)->render() . BackendUtility::getRecordTitle($tName, $rec, true)
721 . '<input type="hidden" name="tx_impexp[record][]" value="' . htmlspecialchars(($tName . ':' . $rUid)) . '" /></td>
722 </tr>';
723 }
724 }
725 }
726 // Single tables/pids:
727 if (is_array($inData['list'])) {
728 $row[] = '
729 <tr class="tableheader bgColor5">
730 <td colspan="2">' . $this->lang->getLL('makeconfig_exportTablesFromPages', true) . '</td>
731 </tr>';
732 // Display information about pages from which the export takes place
733 $tblList = '';
734 foreach ($inData['list'] as $reference) {
735 $referenceParts = explode(':', $reference);
736 $tableName = $referenceParts[0];
737 if ($this->getBackendUser()->check('tables_select', $tableName)) {
738 // If the page is actually the root, handle it differently
739 // NOTE: we don't compare integers, because the number actually comes from the split string above
740 if ($referenceParts[1] === '0') {
741 $iconAndTitle = $this->iconFactory->getIcon('apps-pagetree-root', Icon::SIZE_SMALL)->render() . $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'];
742 } else {
743 $record = BackendUtility::getRecordWSOL('pages', $referenceParts[1]);
744 $iconAndTitle = $this->iconFactory->getIconForRecord('pages', $record, Icon::SIZE_SMALL)->render()
745 . BackendUtility::getRecordTitle('pages', $record, true);
746 }
747 $tblList .= 'Table "' . $tableName . '" from ' . $iconAndTitle
748 . '<input type="hidden" name="tx_impexp[list][]" value="' . htmlspecialchars($reference) . '" /><br/>';
749 }
750 }
751 $row[] = '
752 <tr class="bgColor4">
753 <td><strong>' . $this->lang->getLL('makeconfig_tablePids', true) . '</strong>'
754 . BackendUtility::cshItem('xMOD_tx_impexp', 'tableList') . '</td>
755 <td>' . $tblList . '</td>
756 </tr>';
757 $row[] = '
758 <tr class="bgColor4">
759 <td><strong>' . $this->lang->getLL('makeconfig_maxNumberOfRecords', true)
760 . BackendUtility::cshItem('xMOD_tx_impexp', 'tableListMaxNumber') . '</strong></td>
761 <td>
762 <input type="text" name="tx_impexp[listCfg][maxNumber]" value="'
763 . htmlspecialchars($inData['listCfg']['maxNumber']) . '" /><br/>
764 </td>
765 </tr>';
766 }
767 $row[] = '
768 <tr class="tableheader bgColor5">
769 <td colspan="2">' . $this->lang->getLL('makeconfig_relationsAndExclusions', true) . '</td>
770 </tr>';
771 // Add relation selector:
772 $row[] = '
773 <tr class="bgColor4">
774 <td><strong>' . $this->lang->getLL('makeconfig_includeRelationsToTables', true) . '</strong>'
775 . BackendUtility::cshItem('xMOD_tx_impexp', 'inclRelations') . '</td>
776 <td>' . $this->tableSelector('tx_impexp[external_ref][tables]', $inData['external_ref']['tables']) . '</td>
777 </tr>';
778 // Add static relation selector:
779 $row[] = '
780 <tr class="bgColor4">
781 <td><strong>' . $this->lang->getLL('makeconfig_useStaticRelationsFor', true) . '</strong>'
782 . BackendUtility::cshItem('xMOD_tx_impexp', 'staticRelations') . '</td>
783 <td>' . $this->tableSelector('tx_impexp[external_static][tables]', $inData['external_static']['tables']) . '<br/>
784 <label for="checkShowStaticRelations">' . $this->lang->getLL('makeconfig_showStaticRelations', true)
785 . '</label> <input type="checkbox" name="tx_impexp[showStaticRelations]" id="checkShowStaticRelations" value="1" '
786 . ($inData['showStaticRelations'] ? 'checked="checked" ' : '') . '/>
787 </td>
788 </tr>';
789 // Exclude:
790 $excludeHiddenFields = '';
791 if (is_array($inData['exclude'])) {
792 foreach ($inData['exclude'] as $key => $value) {
793 $excludeHiddenFields .= '<input type="hidden" name="tx_impexp[exclude][' . $key . ']" value="1" />';
794 }
795 }
796 if (!empty($inData['exclude'])) {
797 $excludedElements = '<em>' . implode(', ', array_keys($inData['exclude'])) . '</em><hr/><label for="checkExclude">'
798 . $this->lang->getLL('makeconfig_clearAllExclusions', true)
799 . '</label> <input type="checkbox" name="tx_impexp[exclude]" id="checkExclude" value="1" />';
800 } else {
801 $excludedElements = $this->lang->getLL('makeconfig_noExcludedElementsYet', true);
802 }
803 $row[] = '
804 <tr class="bgColor4">
805 <td><strong>' . $this->lang->getLL('makeconfig_excludeElements', true) . '</strong>'
806 . BackendUtility::cshItem('xMOD_tx_impexp', 'excludedElements') . '</td>
807 <td>' . $excludeHiddenFields . '
808 ' . $excludedElements . '
809 </td>
810 </tr>';
811 // Add buttons:
812 $row[] = '
813 <tr class="bgColor4">
814 <td>&nbsp;</td>
815 <td>
816 <input class="btn btn-default" type="submit" value="' . $this->lang->getLL('makeadvanc_update', true) . '" />
817 <input type="hidden" name="tx_impexp[download_export_name]" value="' . substr($nameSuggestion, 0, 30) . '" />
818 </td>
819 </tr>';
820 }
821
822 /**
823 * Create advanced options form
824 * Sets content in $this->content
825 *
826 * @param array $inData Form configurat data
827 * @param array $row Table row accumulation variable. This is filled with table rows.
828 * @return void
829 */
830 public function makeAdvancedOptionsForm($inData, &$row)
831 {
832 // Soft references
833 $row[] = '
834 <tr class="tableheader bgColor5">
835 <td colspan="2">' . $this->lang->getLL('makeadvanc_softReferences', true) . '</td>
836 </tr>';
837 $row[] = '
838 <tr class="bgColor4">
839 <td><label for="checkExcludeHTMLfileResources"><strong>'
840 . $this->lang->getLL('makeadvanc_excludeHtmlCssFile', true) . '</strong></label>'
841 . BackendUtility::cshItem('xMOD_tx_impexp', 'htmlCssResources') . '</td>
842 <td><input type="checkbox" name="tx_impexp[excludeHTMLfileResources]" id="checkExcludeHTMLfileResources" value="1" '
843 . ($inData['excludeHTMLfileResources'] ? 'checked="checked" ' : '') . '/></td>
844 </tr>';
845
846 // Files options
847 $row[] = '
848 <tr class="tableheader bgColor5">
849 <td colspan="2">' . $this->lang->getLL('makeadvanc_files', true) . '</td>
850 </tr>';
851 $row[] = '
852 <tr class="bgColor4">
853 <td><label for="saveFilesOutsideExportFile"><strong>'
854 . $this->lang->getLL('makeadvanc_saveFilesOutsideExportFile', true) . '</strong><br />'
855 . $this->lang->getLL('makeadvanc_saveFilesOutsideExportFile_limit', true) . '</label></td>
856 <td><input type="checkbox" name="tx_impexp[saveFilesOutsideExportFile]" id="saveFilesOutsideExportFile" value="1" '
857 . ($inData['saveFilesOutsideExportFile'] ? 'checked="checked" ' : '') . '/></td>
858 </tr>';
859 // Extensions
860 $row[] = '
861 <tr class="tableheader bgColor5">
862 <td colspan="2">' . $this->lang->getLL('makeadvanc_extensionDependencies', true) . '</td>
863 </tr>';
864 $row[] = '
865 <tr class="bgColor4">
866 <td><strong>' . $this->lang->getLL('makeadvanc_selectExtensionsThatThe', true) . '</strong>'
867 . BackendUtility::cshItem('xMOD_tx_impexp', 'extensionDependencies') . '</td>
868 <td>' . $this->extensionSelector('tx_impexp[extension_dep]', $inData['extension_dep']) . '</td>
869 </tr>';
870 // Add buttons:
871 $row[] = '
872 <tr class="bgColor4">
873 <td>&nbsp;</td>
874 <td>
875 <input class="btn btn-default" type="submit" value="' . $this->lang->getLL('makesavefo_update', true) . '" />
876 <input type="hidden" name="tx_impexp[download_export_name]" value="" />
877 </td>
878 </tr>';
879 }
880
881 /**
882 * Create configuration form
883 *
884 * @param array $inData Form configurat data
885 * @param array $row Table row accumulation variable. This is filled with table rows.
886 * @return void Sets content in $this->content
887 */
888 public function makeSaveForm($inData, &$row)
889 {
890 // Presets:
891 $row[] = '
892 <tr class="tableheader bgColor5">
893 <td colspan="2">' . $this->lang->getLL('makesavefo_presets', true) . '</td>
894 </tr>';
895 $row[] = '
896 <tr class="bgColor4">
897 <td><strong>' . $this->lang->getLL('makesavefo_presets', true) . '</strong>'
898 . BackendUtility::cshItem('xMOD_tx_impexp', 'presets') . '</td>
899 <td>
900 ' . $this->lang->getLL('makesavefo_selectPreset', true) . '<br/>
901 ' . $this->renderSelectBox('preset[select]', '', $this->presetRepository->getPresets($inData['pagetree']['id'])) . '
902 <br/>
903 <input type="hidden" name="not-set" value="1" id="t3js-submit-field" />
904 <input class="btn btn-default" type="submit" value="' . $this->lang->getLL('makesavefo_load', true) . '" name="preset[load]" />
905 <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) . '" />
906 <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) . '" />
907 <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) . '" />
908 <br/>
909 ' . $this->lang->getLL('makesavefo_titleOfNewPreset', true) . '
910 <input type="text" name="tx_impexp[preset][title]" value="'
911 . htmlspecialchars($inData['preset']['title']) . '" /><br/>
912 <label for="checkPresetPublic">' . $this->lang->getLL('makesavefo_public', true) . '</label>
913 <input type="checkbox" name="tx_impexp[preset][public]" id="checkPresetPublic" value="1" '
914 . ($inData['preset']['public'] ? 'checked="checked "' : '') . '/><br/>
915 </td>
916 </tr>';
917 // Output options:
918 $row[] = '
919 <tr class="tableheader bgColor5">
920 <td colspan="2">' . $this->lang->getLL('makesavefo_outputOptions', true) . '</td>
921 </tr>';
922 $saveFolder = $this->getDefaultImportExportFolder();
923
924 $row[] = '
925 <tr class="bgColor4">
926 <td><strong>' . $this->lang->getLL('makesavefo_metaData', true) . '</strong>'
927 . BackendUtility::cshItem('xMOD_tx_impexp', 'metadata') . '</td>
928 <td>
929 ' . $this->lang->getLL('makesavefo_title', true) . ' <br/>
930 <input type="text" name="tx_impexp[meta][title]" value="' . htmlspecialchars($inData['meta']['title']) . '" /><br/>
931 ' . $this->lang->getLL('makesavefo_description', true) . ' <br/>
932 <input type="text" name="tx_impexp[meta][description]" value="' . htmlspecialchars($inData['meta']['description']) . '" /><br/>
933 ' . $this->lang->getLL('makesavefo_notes', true) . ' <br/>
934 <textarea name="tx_impexp[meta][notes]">' . htmlspecialchars($inData['meta']['notes']) . '</textarea><br/>
935 ' . ($saveFolder ? '
936 <input type="hidden" name="file[upload][1][target]" value="' . htmlspecialchars($saveFolder->getCombinedIdentifier()) . '" />
937 <input type="hidden" name="file[upload][1][data]" value="1" /><br />' : '') . '
938 </td>
939 </tr>';
940 // Add file options:
941 $opt = array();
942 if ($this->export->compress) {
943 $opt['t3d_compressed'] = $this->lang->getLL('makesavefo_t3dFileCompressed');
944 }
945 $opt['t3d'] = $this->lang->getLL('makesavefo_t3dFile');
946 $opt['xml'] = $this->lang->getLL('makesavefo_xml');
947 $fileName = '';
948 if ($saveFolder) {
949 $fileName = sprintf($this->lang->getLL('makesavefo_filenameSavedInS', true), $saveFolder->getPublicUrl())
950 . '<br/>
951 <input type="text" name="tx_impexp[filename]" value="'
952 . htmlspecialchars($inData['filename']) . '" /><br/>';
953 }
954 $row[] = '
955 <tr>
956 <td>
957 <strong>' . $this->lang->getLL('makesavefo_fileFormat', true) . '</strong>'
958 . BackendUtility::cshItem('xMOD_tx_impexp', 'fileFormat') . '
959 </td>
960 <td>
961 ' . $this->renderSelectBox('tx_impexp[filetype]', $inData['filetype'], $opt) . '<br/>
962 ' . $this->lang->getLL('makesavefo_maxSizeOfFiles', true) . '<br/>
963 <input type="text" name="tx_impexp[maxFileSize]" value="' . htmlspecialchars($inData['maxFileSize']) . '" />
964 <br/>
965 ' . $fileName . '
966 </td>
967 </tr>';
968 // Add buttons:
969 $row[] = '
970 <tr>
971 <td>&nbsp;</td>
972 <td>
973 <input class="btn btn-default" type="submit" value="' . $this->lang->getLL('makesavefo_update', true) . '" /> -
974 <input class="btn btn-default" type="submit" value="' . $this->lang->getLL('makesavefo_downloadExport', true) . '" name="tx_impexp[download_export]" />
975 ' . ($saveFolder ? ' - <input class="btn btn-default" type="submit" value="' . $this->lang->getLL('importdata_saveToFilename', true) . '" name="tx_impexp[save_export]" />' : '') . '
976 </td>
977 </tr>';
978 }
979
980 /**************************
981 * IMPORT FUNCTIONS
982 **************************/
983
984 /**
985 * Import part of module
986 *
987 * @param array $inData Content of POST VAR tx_impexp[]..
988 * @throws \BadFunctionCallException
989 * @throws \InvalidArgumentException
990 * @throws \RuntimeException
991 * @return void Setting content in $this->content
992 */
993 public function importData($inData)
994 {
995 $access = is_array($this->pageinfo) ? 1 : 0;
996 $beUser = $this->getBackendUser();
997 if ($this->id && $access || $beUser->user['admin'] && !$this->id) {
998 if ($beUser->user['admin'] && !$this->id) {
999 $this->pageinfo = array('title' => '[root-level]', 'uid' => 0, 'pid' => 0);
1000 }
1001 if ($inData['new_import']) {
1002 unset($inData['import_mode']);
1003 }
1004 /** @var $import ImportExport */
1005 $import = GeneralUtility::makeInstance(ImportExport::class);
1006 $import->init(0, 'import');
1007 $import->update = $inData['do_update'];
1008 $import->import_mode = $inData['import_mode'];
1009 $import->enableLogging = $inData['enableLogging'];
1010 $import->global_ignore_pid = $inData['global_ignore_pid'];
1011 $import->force_all_UIDS = $inData['force_all_UIDS'];
1012 $import->showDiff = !$inData['notShowDiff'];
1013 $import->allowPHPScripts = $inData['allowPHPScripts'];
1014 $import->softrefInputValues = $inData['softrefInputValues'];
1015 // OUTPUT creation:
1016 $menuItems = array();
1017 // Make input selector:
1018 // must have trailing slash.
1019 $path = $this->getDefaultImportExportFolder();
1020 $exportFiles = $this->getExportFiles();
1021
1022 $this->shortcutName .= ' (' . $this->pageinfo['title'] . ')';
1023
1024 // Configuration
1025 $row = array();
1026 $selectOptions = array('');
1027 foreach ($exportFiles as $file) {
1028 $selectOptions[$file->getCombinedIdentifier()] = $file->getPublicUrl();
1029 }
1030 $row[] = '
1031 <tr>
1032 <th colspan="2">' . $this->lang->getLL('importdata_selectFileToImport', true) . '</th>
1033 </tr>';
1034 $noCompressorAvailable = !$import->compress
1035 ? '<br /><span class="text-danger">' . $this->lang->getLL('importdata_noteNoDecompressorAvailable', true) . '</span>'
1036 : '';
1037 $row[] = '
1038 <tr>
1039 <td valign="top">
1040 ' . $this->lang->getLL('importdata_file', true) . ''
1041 . BackendUtility::cshItem('xMOD_tx_impexp', 'importFile') . '
1042 </td>
1043 <td>
1044 ' . $this->renderSelectBox('tx_impexp[file]', $inData['file'], $selectOptions) . '<br />'
1045 . sprintf($this->lang->getLL('importdata_fromPathS', true), $path ? $path->getPublicUrl() : $this->lang->getLL('importdata_no_accessible_file_mount', true)) .
1046 $noCompressorAvailable . '
1047 </td>
1048 </tr>';
1049 $row[] = '
1050 <tr>
1051 <th colspan="2">
1052 ' . $this->lang->getLL('importdata_importOptions', true) . '
1053 </th>
1054 </tr>';
1055 $row[] = '
1056 <tr>
1057 <td valign="top">
1058 ' . $this->lang->getLL('importdata_update', true)
1059 . BackendUtility::cshItem('xMOD_tx_impexp', 'update') . '
1060 </td>
1061 <td>
1062 <input type="checkbox" name="tx_impexp[do_update]" id="checkDo_update" value="1" '
1063 . ($inData['do_update'] ? 'checked="checked" ' : '') . '/>
1064 <label for="checkDo_update">' . $this->lang->getLL('importdata_updateRecords', true) . '</label>
1065 <br/>
1066 <em>(' . $this->lang->getLL('importdata_thisOptionRequiresThat', true) . ')</em>' . ($inData['do_update'] ? ' <hr/>
1067 <input type="checkbox" name="tx_impexp[global_ignore_pid]" id="checkGlobal_ignore_pid" value="1" '
1068 . ($inData['global_ignore_pid'] ? 'checked="checked" ' : '') . ' />
1069 <label for="checkGlobal_ignore_pid">' . $this->lang->getLL('importdata_ignorePidDifferencesGlobally', true) . '</label><br/>
1070 <em>(' . $this->lang->getLL('importdata_ifYouSetThis', true) . ')</em>
1071 ' : '') . '
1072 </td>
1073 </tr>';
1074 $allowPhpScripts = $beUser->isAdmin()
1075 ? '
1076 <input type="checkbox" name="tx_impexp[allowPHPScripts]" id="checkAllowPHPScripts" value="1"'
1077 . ($inData['allowPHPScripts'] ? ' checked="checked"' : '') . ' />
1078 <label for="checkAllowPHPScripts">' . $this->lang->getLL('importdata_allowToWriteBanned', true) . '</label><br/>'
1079 : '';
1080 $doUpdate = !$inData['do_update'] && $beUser->isAdmin()
1081 ? '
1082 <br/>
1083 <input type="checkbox" name="tx_impexp[force_all_UIDS]" id="checkForce_all_UIDS" value="1" '
1084 . ($inData['force_all_UIDS'] ? 'checked="checked" ' : '') . '/>
1085 <label for="checkForce_all_UIDS"><span class="text-danger">'
1086 . $this->lang->getLL('importdata_force_all_UIDS', true) . '</span></label><br/>
1087 <em>(' . $this->lang->getLL('importdata_force_all_UIDS_descr', true) . ')</em>'
1088 : '';
1089 $row[] = '<tr>
1090 <td valign="top">
1091 ' . $this->lang->getLL('importdata_options', true) . BackendUtility::cshItem('xMOD_tx_impexp', 'options') . '
1092 </td>
1093 <td>
1094 <input type="checkbox" name="tx_impexp[notShowDiff]" id="checkNotShowDiff" value="1" '
1095 . ($inData['notShowDiff'] ? 'checked="checked" ' : '') . '/>
1096 <label for="checkNotShowDiff">' . $this->lang->getLL('importdata_doNotShowDifferences', true) . '</label><br/>
1097 <em>(' . $this->lang->getLL('importdata_greenValuesAreFrom', true) . ')</em>
1098 <br/><br/>
1099
1100 ' . $allowPhpScripts . $doUpdate . '
1101 </td>
1102 </tr>';
1103 $newImport = !$inData['import_file']
1104 ? '<input class="btn btn-default" type="submit" value="' . $this->lang->getLL('importdata_preview', true) . '" />' . ($inData['file']
1105 ? ' - <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']
1106 ? $this->lang->getLL('importdata_update_299e', true)
1107 : $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) . '" />'
1108 : '')
1109 : '<input class="btn btn-default" type="submit" name="tx_impexp[new_import]" value="' . $this->lang->getLL('importdata_newImport', true) . '" />';
1110 $row[] = '<tr>
1111 <td valign="top">
1112 ' . $this->lang->getLL('importdata_action', true) . BackendUtility::cshItem('xMOD_tx_impexp', 'action') . '
1113 </td>
1114 <td>
1115 ' . $newImport . '
1116 <input type="hidden" name="tx_impexp[action]" value="import" />
1117 </td>
1118 </tr>';
1119 $row[] = '<tr>
1120 <td valign="top">
1121 ' . $this->lang->getLL('importdata_enableLogging', true)
1122 . BackendUtility::cshItem('xMOD_tx_impexp', 'enableLogging') . '
1123 </td>
1124 <td>
1125 <input type="checkbox" name="tx_impexp[enableLogging]" id="checkEnableLogging" value="1" '
1126 . ($inData['enableLogging'] ? 'checked="checked" ' : '') . '/>
1127 <label for="checkEnableLogging">' . $this->lang->getLL('importdata_writeIndividualDbActions', true) . '</label><br/>
1128 <em>(' . $this->lang->getLL('importdata_thisIsDisabledBy', true) . ')</em>
1129 </td>
1130 </tr>';
1131 $menuItems[] = array(
1132 'label' => $this->lang->getLL('importdata_import', true),
1133 'content' => '
1134 <table border="0" cellpadding="1" cellspacing="1">
1135 ' . implode('
1136 ', $row) . '
1137 </table>
1138 '
1139 );
1140 // Upload file:
1141 $tempFolder = $this->getDefaultImportExportFolder();
1142 if ($tempFolder) {
1143 $row = array();
1144 $row[] = '
1145 <tr>
1146 <th colspan="2">' . $this->lang->getLL('importdata_uploadFileFromLocal', true) . '</th>
1147 </tr>';
1148 $row[] = '
1149 <tr>
1150 <td valign="top">
1151 ' . $this->lang->getLL('importdata_browse', true) . BackendUtility::cshItem('xMOD_tx_impexp', 'upload') . '
1152 </td>
1153 <td>
1154 <input type="file" name="upload_1" size="40" />
1155 <input type="hidden" name="file[upload][1][target]" value="' . htmlspecialchars($tempFolder->getCombinedIdentifier()) . '" />
1156 <input type="hidden" name="file[upload][1][data]" value="1" />
1157 <br />
1158 <input class="btn btn-default" type="submit" name="_upload" value="' . $this->lang->sL('LLL:EXT:lang/locallang_core.xlf:file_upload.php.submit', true) . '" />
1159 <input type="checkbox" name="overwriteExistingFiles" id="checkOverwriteExistingFiles" value="1" checked="checked" />
1160 <label for="checkOverwriteExistingFiles">' . $this->lang->sL('LLL:EXT:lang/locallang_misc.xlf:overwriteExistingFiles', true) . '</label>
1161 </td>
1162 </tr>';
1163 if (GeneralUtility::_POST('_upload')) {
1164 $noFileUploaded = $this->fileProcessor->internalUploadMap[1]
1165 ? $this->lang->getLL('importdata_success', true) . ' ' . $this->uploadedFiles[0]->getName()
1166 : '<span class="text-danger">' . $this->lang->getLL('importdata_failureNoFileUploaded', true) . '</span>';
1167 $row[] = '<tr class="bgColor4">
1168 <td>' . $this->lang->getLL('importdata_uploadStatus', true) . '</td>
1169 <td>' . $noFileUploaded . '</td>
1170 </tr>';
1171 }
1172 $menuItems[] = array(
1173 'label' => $this->lang->getLL('importdata_upload'),
1174 'content' => '
1175 <table border="0" cellpadding="1" cellspacing="1">
1176 ' . implode('
1177 ', $row) . '
1178 </table>
1179 '
1180 );
1181 }
1182 // Perform import or preview depending:
1183 $overviewContent = '';
1184 $extensionInstallationMessage = '';
1185 $inFile = $this->getFile($inData['file']);
1186 if ($inFile !== null && $inFile->exists()) {
1187 $trow = array();
1188 if ($import->loadFile($inFile->getForLocalProcessing(false), 1)) {
1189 // Check extension dependencies:
1190 $extKeysToInstall = array();
1191 if (is_array($import->dat['header']['extensionDependencies'])) {
1192 foreach ($import->dat['header']['extensionDependencies'] as $extKey) {
1193 if (!ExtensionManagementUtility::isLoaded($extKey)) {
1194 $extKeysToInstall[] = $extKey;
1195 }
1196 }
1197 }
1198 if (!empty($extKeysToInstall)) {
1199 $extensionInstallationMessage = 'Before you can install this T3D file you need to install the extensions "'
1200 . implode('", "', $extKeysToInstall) . '".';
1201 }
1202 if ($inData['import_file']) {
1203 if (empty($extKeysToInstall)) {
1204 $import->importData($this->id);
1205 BackendUtility::setUpdateSignal('updatePageTree');
1206 }
1207 }
1208 $import->display_import_pid_record = $this->pageinfo;
1209 $overviewContent = $import->displayContentOverview();
1210 }
1211 // Meta data output:
1212 $trow[] = '<tr class="bgColor5">
1213 <td colspan="2"><strong>' . $this->lang->getLL('importdata_metaData', true) . '</strong></td>
1214 </tr>';
1215 $trow[] = '<tr class="bgColor4">
1216 <td><strong>' . $this->lang->getLL('importdata_title', true) . '</strong></td>
1217 <td width="95%">' . nl2br(htmlspecialchars($import->dat['header']['meta']['title'])) . '</td>
1218 </tr>';
1219 $trow[] = '<tr class="bgColor4">
1220 <td><strong>' . $this->lang->getLL('importdata_description', true) . '</strong></td>
1221 <td width="95%">' . nl2br(htmlspecialchars($import->dat['header']['meta']['description'])) . '</td>
1222 </tr>';
1223 $trow[] = '<tr class="bgColor4">
1224 <td><strong>' . $this->lang->getLL('importdata_notes', true) . '</strong></td>
1225 <td width="95%">' . nl2br(htmlspecialchars($import->dat['header']['meta']['notes'])) . '</td>
1226 </tr>';
1227 $trow[] = '<tr class="bgColor4">
1228 <td><strong>' . $this->lang->getLL('importdata_packager', true) . '</strong></td>
1229 <td width="95%">' . nl2br(htmlspecialchars(($import->dat['header']['meta']['packager_name']
1230 . ' (' . $import->dat['header']['meta']['packager_username'] . ')'))) . '<br/>
1231 ' . $this->lang->getLL('importdata_email', true) . ' '
1232 . $import->dat['header']['meta']['packager_email'] . '</td>
1233 </tr>';
1234 $menuItems[] = array(
1235 'label' => $this->lang->getLL('importdata_metaData_1387'),
1236 'content' => '
1237 <table border="0" cellpadding="1" cellspacing="1">
1238 ' . implode('
1239 ', $trow) . '
1240 </table>
1241 '
1242 );
1243 }
1244 // Print errors that might be:
1245 $errors = $import->printErrorLog();
1246 $menuItems[] = array(
1247 'label' => $this->lang->getLL('importdata_messages'),
1248 'content' => $errors,
1249 'stateIcon' => $errors ? 2 : 0
1250 );
1251 // Output tabs:
1252 $content = $this->moduleTemplate->getDynamicTabMenu($menuItems, 'tx_impexp_import', 1, false, true, false);
1253 if ($extensionInstallationMessage) {
1254 $content = '<div style="border: 1px black solid; margin: 10px 10px 10px 10px; padding: 10px 10px 10px 10px;">'
1255 . $this->moduleTemplate->icons(1) . htmlspecialchars($extensionInstallationMessage) . '</div>' . $content;
1256 }
1257 $this->content .= '<div>' . $content . '</div>';
1258 // Print overview:
1259 if ($overviewContent) {
1260 $this->content .= '<h2>' . ($inData['import_file']
1261 ? $this->lang->getLL('importdata_structureHasBeenImported', true)
1262 : $this->lang->getLL('filterpage_structureToBeImported', true)) . '</h2><div>' . $overviewContent . '</div>';
1263 }
1264 }
1265 }
1266
1267 /****************************
1268 * Helper functions
1269 ****************************/
1270
1271 /**
1272 * Returns a \TYPO3\CMS\Core\Resource\Folder object for saving export files
1273 * to the server and is also used for uploading import files.
1274 *
1275 * @throws \InvalidArgumentException
1276 * @return NULL|\TYPO3\CMS\Core\Resource\Folder
1277 */
1278 protected function getDefaultImportExportFolder()
1279 {
1280 $defaultImportExportFolder = null;
1281
1282 $defaultTemporaryFolder = $this->getBackendUser()->getDefaultUploadTemporaryFolder();
1283 if ($defaultTemporaryFolder !== null) {
1284 $importExportFolderName = 'importexport';
1285 $createFolder = !$defaultTemporaryFolder->hasFolder($importExportFolderName);
1286 if ($createFolder === true) {
1287 try {
1288 $defaultImportExportFolder = $defaultTemporaryFolder->createFolder($importExportFolderName);
1289 } catch (Exception $folderAccessException) {
1290 }
1291 } else {
1292 $defaultImportExportFolder = $defaultTemporaryFolder->getSubfolder($importExportFolderName);
1293 }
1294 }
1295
1296 return $defaultImportExportFolder;
1297 }
1298
1299 /**
1300 * Check if a file has been uploaded
1301 *
1302 * @throws \InvalidArgumentException
1303 * @throws \UnexpectedValueException
1304 * @return void
1305 */
1306 public function checkUpload()
1307 {
1308 $file = GeneralUtility::_GP('file');
1309 // Initializing:
1310 $this->fileProcessor = GeneralUtility::makeInstance(ExtendedFileUtility::class);
1311 $this->fileProcessor->init(array(), $GLOBALS['TYPO3_CONF_VARS']['BE']['fileExtensions']);
1312 $this->fileProcessor->setActionPermissions();
1313 $this->fileProcessor->setExistingFilesConflictMode((int)GeneralUtility::_GP('overwriteExistingFiles') === 1 ? DuplicationBehavior::REPLACE : DuplicationBehavior::CANCEL);
1314 // Checking referer / executing:
1315 $refInfo = parse_url(GeneralUtility::getIndpEnv('HTTP_REFERER'));
1316 $httpHost = GeneralUtility::getIndpEnv('TYPO3_HOST_ONLY');
1317 if (
1318 $httpHost != $refInfo['host']
1319 && !$GLOBALS['$TYPO3_CONF_VARS']['SYS']['doNotCheckReferer']
1320 && $this->vC != $this->getBackendUser()->veriCode()
1321 ) {
1322 $this->fileProcessor->writeLog(0, 2, 1, 'Referer host "%s" and server host "%s" did not match!', array($refInfo['host'], $httpHost));
1323 } else {
1324 $this->fileProcessor->start($file);
1325 $result = $this->fileProcessor->processData();
1326 if (!empty($result['upload'])) {
1327 foreach ($result['upload'] as $uploadedFiles) {
1328 $this->uploadedFiles += $uploadedFiles;
1329 }
1330 }
1331 }
1332 }
1333
1334 /**
1335 * Makes a selector-box from optValues
1336 *
1337 * @param string $prefix Form element name
1338 * @param string $value Current value
1339 * @param array $optValues Options to display (key/value pairs)
1340 * @return string HTML select element
1341 */
1342 public function renderSelectBox($prefix, $value, $optValues)
1343 {
1344 $opt = array();
1345 $isSelFlag = 0;
1346 foreach ($optValues as $k => $v) {
1347 $sel = (string)$k === (string)$value ? ' selected="selected"' : '';
1348 if ($sel) {
1349 $isSelFlag++;
1350 }
1351 $opt[] = '<option value="' . htmlspecialchars($k) . '"' . $sel . '>' . htmlspecialchars($v) . '</option>';
1352 }
1353 if (!$isSelFlag && (string)$value !== '') {
1354 $opt[] = '<option value="' . htmlspecialchars($value) . '" selected="selected">'
1355 . htmlspecialchars(('[\'' . $value . '\']')) . '</option>';
1356 }
1357 return '<select name="' . $prefix . '">' . implode('', $opt) . '</select>';
1358 }
1359
1360 /**
1361 * Returns a selector-box with TCA tables
1362 *
1363 * @param string $prefix Form element name prefix
1364 * @param array $value The current values selected
1365 * @param string $excludeList Table names (and the string "_ALL") to exclude. Comma list
1366 * @return string HTML select element
1367 */
1368 public function tableSelector($prefix, $value, $excludeList = '')
1369 {
1370 $optValues = array();
1371 if (!GeneralUtility::inList($excludeList, '_ALL')) {
1372 $optValues['_ALL'] = '[' . $this->lang->getLL('ALL_tables') . ']';
1373 }
1374 foreach ($GLOBALS['TCA'] as $table => $_) {
1375 if ($this->getBackendUser()->check('tables_select', $table) && !GeneralUtility::inList($excludeList, $table)) {
1376 $optValues[$table] = $table;
1377 }
1378 }
1379 // make box:
1380 $opt = array();
1381 $opt[] = '<option value=""></option>';
1382 $sel = '';
1383 foreach ($optValues as $k => $v) {
1384 if (is_array($value)) {
1385 $sel = in_array($k, $value) ? ' selected="selected"' : '';
1386 }
1387 $opt[] = '<option value="' . htmlspecialchars($k) . '"' . $sel . '>' . htmlspecialchars($v) . '</option>';
1388 }
1389 return '<select name="' . $prefix . '[]" multiple="multiple" size="'
1390 . MathUtility::forceIntegerInRange(count($opt), 5, 10) . '">' . implode('', $opt) . '</select>';
1391 }
1392
1393 /**
1394 * Returns a selector-box with loaded extension keys
1395 *
1396 * @param string $prefix Form element name prefix
1397 * @param array $value The current values selected
1398 * @return string HTML select element
1399 */
1400 public function extensionSelector($prefix, $value)
1401 {
1402 $loadedExtensions = ExtensionManagementUtility::getLoadedExtensionListArray();
1403
1404 // make box:
1405 $opt = array();
1406 $opt[] = '<option value=""></option>';
1407 foreach ($loadedExtensions as $extensionKey) {
1408 $sel = '';
1409 if (is_array($value)) {
1410 $sel = in_array($extensionKey, $value) ? ' selected="selected"' : '';
1411 }
1412 $opt[] = '<option value="' . htmlspecialchars($extensionKey) . '"' . $sel . '>'
1413 . htmlspecialchars($extensionKey) . '</option>';
1414 }
1415 return '<select name="' . $prefix . '[]" multiple="multiple" size="'
1416 . MathUtility::forceIntegerInRange(count($opt), 5, 10) . '">' . implode('', $opt) . '</select>';
1417 }
1418
1419 /**
1420 * Filter page IDs by traversing exclude array, finding all
1421 * excluded pages (if any) and making an AND NOT IN statement for the select clause.
1422 *
1423 * @param array $exclude Exclude array from import/export object.
1424 * @return string AND where clause part to filter out page uids.
1425 */
1426 public function filterPageIds($exclude)
1427 {
1428 // Get keys:
1429 $exclude = array_keys($exclude);
1430 // Traverse
1431 $pageIds = array();
1432 foreach ($exclude as $element) {
1433 list($table, $uid) = explode(':', $element);
1434 if ($table === 'pages') {
1435 $pageIds[] = (int)$uid;
1436 }
1437 }
1438 // Add to clause:
1439 if (!empty($pageIds)) {
1440 return ' AND uid NOT IN (' . implode(',', $pageIds) . ')';
1441 }
1442 return '';
1443 }
1444
1445 /**
1446 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
1447 */
1448 protected function getBackendUser()
1449 {
1450 return $GLOBALS['BE_USER'];
1451 }
1452
1453 /**
1454 * @return DatabaseConnection
1455 */
1456 protected function getDatabaseConnection()
1457 {
1458 return $GLOBALS['TYPO3_DB'];
1459 }
1460
1461 /**
1462 * @return LanguageService
1463 */
1464 protected function getLanguageService()
1465 {
1466 return $GLOBALS['LANG'];
1467 }
1468
1469 /**
1470 * Gets all export files.
1471 *
1472 * @throws \InvalidArgumentException
1473 * @return array|\TYPO3\CMS\Core\Resource\File[]
1474 */
1475 protected function getExportFiles()
1476 {
1477 $exportFiles = array();
1478
1479 $folder = $this->getDefaultImportExportFolder();
1480 if ($folder !== null) {
1481
1482 /** @var $filter FileExtensionFilter */
1483 $filter = GeneralUtility::makeInstance(FileExtensionFilter::class);
1484 $filter->setAllowedFileExtensions(array('t3d', 'xml'));
1485 $folder->getStorage()->addFileAndFolderNameFilter(array($filter, 'filterFileList'));
1486
1487 $exportFiles = $folder->getFiles();
1488 }
1489
1490 return $exportFiles;
1491 }
1492
1493 /**
1494 * Gets a file by combined identifier.
1495 *
1496 * @param string $combinedIdentifier
1497 * @return NULL|\TYPO3\CMS\Core\Resource\File
1498 */
1499 protected function getFile($combinedIdentifier)
1500 {
1501 try {
1502 $file = ResourceFactory::getInstance()->getFileObjectFromCombinedIdentifier($combinedIdentifier);
1503 } catch (\Exception $exception) {
1504 $file = null;
1505 }
1506
1507 return $file;
1508 }
1509 }