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