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