Test Failed
Branch master (7b1793)
by Tymoteusz
36:50 queued 18:38
created

ImportExportController::getBackendUser()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
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\ConnectionPool;
25
use TYPO3\CMS\Core\Database\Query\QueryHelper;
26
use TYPO3\CMS\Core\Database\Query\Restriction\BackendWorkspaceRestriction;
27
use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
28
use TYPO3\CMS\Core\Imaging\Icon;
29
use TYPO3\CMS\Core\Imaging\IconFactory;
30
use TYPO3\CMS\Core\Localization\LanguageService;
31
use TYPO3\CMS\Core\Messaging\FlashMessage;
32
use TYPO3\CMS\Core\Messaging\FlashMessageService;
33
use TYPO3\CMS\Core\Resource\DuplicationBehavior;
34
use TYPO3\CMS\Core\Resource\Exception;
35
use TYPO3\CMS\Core\Resource\Filter\FileExtensionFilter;
36
use TYPO3\CMS\Core\Resource\ResourceFactory;
37
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
38
use TYPO3\CMS\Core\Utility\File\ExtendedFileUtility;
39
use TYPO3\CMS\Core\Utility\GeneralUtility;
40
use TYPO3\CMS\Core\Utility\MathUtility;
41
use TYPO3\CMS\Fluid\View\StandaloneView;
42
use TYPO3\CMS\Impexp\Domain\Repository\PresetRepository;
43
use TYPO3\CMS\Impexp\Export;
44
use TYPO3\CMS\Impexp\Import;
45
use TYPO3\CMS\Impexp\View\ExportPageTreeView;
46
47
/**
48
 * Main script class for the Import / Export facility
49
 */
50
class ImportExportController extends BaseScriptClass
51
{
52
    /**
53
     * @var array|\TYPO3\CMS\Core\Resource\File[]
54
     */
55
    protected $uploadedFiles = [];
56
57
    /**
58
     * Array containing the current page.
59
     *
60
     * @var array
61
     */
62
    public $pageinfo;
63
64
    /**
65
     * @var Export
66
     */
67
    protected $export;
68
69
    /**
70
     * @var Import
71
     */
72
    protected $import;
73
74
    /**
75
     * @var ExtendedFileUtility
76
     */
77
    protected $fileProcessor;
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
     * preset repository
117
     *
118
     * @var PresetRepository
119
     */
120
    protected $presetRepository;
121
122
    /**
123
     * @var StandaloneView
124
     */
125
    protected $standaloneView = null;
126
127
    /**
128
     * @var bool
129
     */
130
    protected $excludeDisabledRecords = false;
131
132
    /**
133
     * Return URL
134
     *
135
     * @var string
136
     */
137
    protected $returnUrl;
138
139
    /**
140
     * Constructor
141
     */
142
    public function __construct()
143
    {
144
        $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
145
        $this->moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class);
146
        $this->presetRepository = GeneralUtility::makeInstance(PresetRepository::class);
147
148
        $templatePath = ExtensionManagementUtility::extPath('impexp') . 'Resources/Private/';
149
150
        /* @var $view StandaloneView */
151
        $this->standaloneView = GeneralUtility::makeInstance(StandaloneView::class);
152
        $this->standaloneView->setTemplateRootPaths([$templatePath . 'Templates/ImportExport/']);
153
        $this->standaloneView->setLayoutRootPaths([$templatePath . 'Layouts/']);
154
        $this->standaloneView->setPartialRootPaths([$templatePath . 'Partials/']);
155
        $this->standaloneView->getRequest()->setControllerExtensionName('impexp');
156
    }
157
158
    /**
159
     * Initializes the module and defining necessary variables for this module to run.
160
     */
161
    public function init()
162
    {
163
        $this->MCONF['name'] = $this->moduleName;
164
        parent::init();
165
        $this->returnUrl = GeneralUtility::sanitizeLocalUrl(GeneralUtility::_GP('returnUrl'));
166
        $this->lang = $this->getLanguageService();
167
    }
168
169
    /**
170
     * Main module function
171
     *
172
     * @throws \BadFunctionCallException
173
     * @throws \InvalidArgumentException
174
     * @throws \RuntimeException
175
     */
176
    public function main()
177
    {
178
        $this->lang->includeLLFile('EXT:impexp/Resources/Private/Language/locallang.xlf');
179
180
        // Start document template object:
181
        // We keep this here, in case somebody relies on the old doc being here
182
        $this->doc = GeneralUtility::makeInstance(DocumentTemplate::class);
183
        $this->doc->bodyTagId = 'imp-exp-mod';
184
        $this->pageinfo = BackendUtility::readPageAccess($this->id, $this->perms_clause);
185
        if (is_array($this->pageinfo)) {
186
            $this->moduleTemplate->getDocHeaderComponent()->setMetaInformation($this->pageinfo);
187
        }
188
        // Setting up the context sensitive menu:
189
        $this->moduleTemplate->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/ContextMenu');
190
        $this->moduleTemplate->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Impexp/ImportExport');
191
        $this->moduleTemplate->addJavaScriptCode(
192
            'ImpexpInLineJS',
193
            'if (top.fsMod) top.fsMod.recentIds["web"] = ' . (int)$this->id . ';'
194
        );
195
196
        // Input data grabbed:
197
        $inData = GeneralUtility::_GP('tx_impexp');
198 View Code Duplication
        if ($inData === null) {
199
            // This happens if the post request was larger than allowed on the server
200
            // We set the import action as default and output a user information
201
            $inData = [
202
                'action' => 'import',
203
            ];
204
            $flashMessage = GeneralUtility::makeInstance(
205
                FlashMessage::class,
206
                $this->getLanguageService()->getLL('importdata_upload_nodata'),
0 ignored issues
show
Bug introduced by
$this->getLanguageServic...ortdata_upload_nodata') of type string is incompatible with the type array<integer,mixed> expected by parameter $constructorArguments of TYPO3\CMS\Core\Utility\G...Utility::makeInstance(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

206
                /** @scrutinizer ignore-type */ $this->getLanguageService()->getLL('importdata_upload_nodata'),
Loading history...
207
                $this->getLanguageService()->getLL('importdata_upload_error'),
208
                FlashMessage::ERROR
0 ignored issues
show
Bug introduced by
TYPO3\CMS\Core\Messaging\FlashMessage::ERROR of type integer is incompatible with the type array<integer,mixed> expected by parameter $constructorArguments of TYPO3\CMS\Core\Utility\G...Utility::makeInstance(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

208
                /** @scrutinizer ignore-type */ FlashMessage::ERROR
Loading history...
209
            );
210
            $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
211
            $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
212
            $defaultFlashMessageQueue->enqueue($flashMessage);
213
        }
214
        if (!array_key_exists('excludeDisabled', $inData)) {
0 ignored issues
show
Bug introduced by
It seems like $inData can also be of type string; however, parameter $search of array_key_exists() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

214
        if (!array_key_exists('excludeDisabled', /** @scrutinizer ignore-type */ $inData)) {
Loading history...
215
            // flag doesn't exist initially; state is on by default
216
            $inData['excludeDisabled'] = 1;
217
        }
218
        /** @var \TYPO3\CMS\Backend\Routing\UriBuilder $uriBuilder */
219
        $uriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class);
220
        $this->standaloneView->assign('moduleUrl', (string)$uriBuilder->buildUriFromRoute('xMOD_tximpexp'));
221
        $this->standaloneView->assign('id', $this->id);
222
        $this->standaloneView->assign('inData', $inData);
223
224
        switch ((string)$inData['action']) {
225
            case 'export':
226
                $this->shortcutName = $this->lang->getLL('title_export');
227
                // Call export interface
228
                $this->exportData($inData);
0 ignored issues
show
Bug introduced by
It seems like $inData can also be of type string; however, parameter $inData of TYPO3\CMS\Impexp\Control...ontroller::exportData() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

228
                $this->exportData(/** @scrutinizer ignore-type */ $inData);
Loading history...
229
                $this->standaloneView->setTemplate('Export.html');
230
                break;
231
            case 'import':
232
                $backendUser = $this->getBackendUser();
233
                $isEnabledForNonAdmin = $backendUser->getTSConfig('options.impexp.enableImportForNonAdminUser');
234
                if (!$backendUser->isAdmin() && empty($isEnabledForNonAdmin['value'])) {
235
                    throw new \RuntimeException(
236
                        'Import module is disabled for non admin users and '
237
                        . 'userTsConfig options.impexp.enableImportForNonAdminUser is not enabled.',
238
                        1464435459
239
                    );
240
                }
241
                $this->shortcutName = $this->lang->getLL('title_import');
242
                if (GeneralUtility::_POST('_upload')) {
0 ignored issues
show
Bug Best Practice introduced by
The expression TYPO3\CMS\Core\Utility\G...ility::_POST('_upload') of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
243
                    $this->checkUpload();
244
                }
245
                // Finally: If upload went well, set the new file as the import file:
246
                if (!empty($this->uploadedFiles[0])) {
247
                    // Only allowed extensions....
248
                    $extension = $this->uploadedFiles[0]->getExtension();
249
                    if ($extension === 't3d' || $extension === 'xml') {
250
                        $inData['file'] = $this->uploadedFiles[0]->getCombinedIdentifier();
251
                    }
252
                }
253
                // Call import interface:
254
                $this->importData($inData);
0 ignored issues
show
Bug introduced by
It seems like $inData can also be of type string; however, parameter $inData of TYPO3\CMS\Impexp\Control...ontroller::importData() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

254
                $this->importData(/** @scrutinizer ignore-type */ $inData);
Loading history...
255
                $this->standaloneView->setTemplate('Import.html');
256
                break;
257
        }
258
259
        // Setting up the buttons and markers for docheader
260
        $this->getButtons();
261
    }
262
263
    /**
264
     * Injects the request object for the current request and gathers all data
265
     *
266
     * IMPORTING DATA:
267
     *
268
     * Incoming array has syntax:
269
     * GETvar 'id' = import page id (must be readable)
270
     *
271
     * file = 	(pointing to filename relative to PATH_site)
272
     *
273
     * [all relation fields are clear, but not files]
274
     * - page-tree is written first
275
     * - then remaining pages (to the root of import)
276
     * - 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)
277
     * - then all internal relations are set and non-existing relations removed, relations to static tables preserved.
278
     *
279
     * EXPORTING DATA:
280
     *
281
     * Incoming array has syntax:
282
     *
283
     * file[] = file
284
     * dir[] = dir
285
     * list[] = table:pid
286
     * record[] = table:uid
287
     *
288
     * pagetree[id] = (single id)
289
     * pagetree[levels]=1,2,3, -1 = currently unpacked tree, -2 = only tables on page
290
     * pagetree[tables][]=table/_ALL
291
     *
292
     * external_ref[tables][]=table/_ALL
293
     *
294
     * @param ServerRequestInterface $request the current request
295
     * @param ResponseInterface $response
296
     * @return ResponseInterface the response with the content
297
     */
298 View Code Duplication
    public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

298
    public function mainAction(/** @scrutinizer ignore-unused */ ServerRequestInterface $request, ResponseInterface $response)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
299
    {
300
        $GLOBALS['SOBE'] = $this;
301
        $this->init();
302
        $this->main();
303
        $this->moduleTemplate->setContent($this->standaloneView->render());
304
        $response->getBody()->write($this->moduleTemplate->renderContent());
305
306
        return $response;
307
    }
308
309
    /**
310
     * Create the panel of buttons for submitting the form or otherwise perform operations.
311
     *
312
     * @return array all available buttons as an associated array
313
     */
314
    protected function getButtons()
315
    {
316
        $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
317
        if ($this->getBackendUser()->mayMakeShortcut()) {
318
            $shortcutButton = $buttonBar->makeShortcutButton()
319
                ->setGetVariables(['tx_impexp'])
320
                ->setDisplayName($this->shortcutName)
321
                ->setModuleName($this->moduleName);
322
            $buttonBar->addButton($shortcutButton);
323
        }
324
        // back button
325
        if ($this->returnUrl) {
326
            $backButton = $buttonBar->makeLinkButton()
327
                ->setHref($this->returnUrl)
328
                ->setTitle($this->lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.goBack'))
329
                ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-view-go-back', Icon::SIZE_SMALL));
330
            $buttonBar->addButton($backButton);
331
        }
332
        // Input data grabbed:
333
        $inData = GeneralUtility::_GP('tx_impexp');
334
        if ((string)$inData['action'] === 'import') {
335
            if ($this->id && is_array($this->pageinfo) || $this->getBackendUser()->isAdmin() && !$this->id) {
336
                if (is_array($this->pageinfo) && $this->pageinfo['uid']) {
337
                    // View
338
                    $onClick = BackendUtility::viewOnClick(
339
                        $this->pageinfo['uid'],
340
                        '',
341
                        BackendUtility::BEgetRootLine($this->pageinfo['uid'])
342
                    );
343
                    $viewButton = $buttonBar->makeLinkButton()
344
                        ->setTitle($this->lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.showPage'))
345
                        ->setHref('#')
346
                        ->setIcon($this->iconFactory->getIcon('actions-view-page', Icon::SIZE_SMALL))
347
                        ->setOnClick($onClick);
348
                    $buttonBar->addButton($viewButton);
349
                }
350
            }
351
        }
352
    }
353
354
    /**************************
355
     * EXPORT FUNCTIONS
356
     **************************/
357
358
    /**
359
     * Export part of module
360
     * Setting content in $this->content
361
     *
362
     * @param array $inData Content of POST VAR tx_impexp[]..
363
     * @throws \InvalidArgumentException
364
     * @throws \RuntimeException
365
     * @throws \TYPO3\CMS\Core\Resource\Exception\ExistingTargetFileNameException
366
     */
367
    public function exportData($inData)
368
    {
369
        // BUILDING EXPORT DATA:
370
        // Processing of InData array values:
371
        $inData['pagetree']['maxNumber'] = MathUtility::forceIntegerInRange($inData['pagetree']['maxNumber'], 1, 1000000, 100);
372
        $inData['listCfg']['maxNumber'] = MathUtility::forceIntegerInRange($inData['listCfg']['maxNumber'], 1, 1000000, 100);
373
        $inData['maxFileSize'] = MathUtility::forceIntegerInRange($inData['maxFileSize'], 1, 1000000, 1000);
374
        $inData['filename'] = trim(preg_replace('/[^[:alnum:]._-]*/', '', preg_replace('/\\.(t3d|xml)$/', '', $inData['filename'])));
375
        if (strlen($inData['filename'])) {
376
            $inData['filename'] .= $inData['filetype'] === 'xml' ? '.xml' : '.t3d';
377
        }
378
        // Set exclude fields in export object:
379
        if (!is_array($inData['exclude'])) {
380
            $inData['exclude'] = [];
381
        }
382
        // Saving/Loading/Deleting presets:
383
        $this->presetRepository->processPresets($inData);
384
        // Create export object and configure it:
385
        $this->export = GeneralUtility::makeInstance(Export::class);
386
        $this->export->init(0);
387
        $this->export->maxFileSize = $inData['maxFileSize'] * 1024;
388
        $this->export->excludeMap = (array)$inData['exclude'];
389
        $this->export->softrefCfg = (array)$inData['softrefCfg'];
390
        $this->export->extensionDependencies = ($inData['extension_dep'] === '') ? [] : (array)$inData['extension_dep'];
391
        $this->export->showStaticRelations = $inData['showStaticRelations'];
392
        $this->export->includeExtFileResources = !$inData['excludeHTMLfileResources'];
393
        $this->excludeDisabledRecords = (bool)$inData['excludeDisabled'];
394
        $this->export->setExcludeDisabledRecords($this->excludeDisabledRecords);
395
396
        // Static tables:
397
        if (is_array($inData['external_static']['tables'])) {
398
            $this->export->relStaticTables = $inData['external_static']['tables'];
399
        }
400
        // Configure which tables external relations are included for:
401
        if (is_array($inData['external_ref']['tables'])) {
402
            $this->export->relOnlyTables = $inData['external_ref']['tables'];
403
        }
404
        $saveFilesOutsideExportFile = false;
405
        if (isset($inData['save_export']) && isset($inData['saveFilesOutsideExportFile']) && $inData['saveFilesOutsideExportFile'] === '1') {
406
            $this->export->setSaveFilesOutsideExportFile(true);
407
            $saveFilesOutsideExportFile = true;
408
        }
409
        $this->export->setHeaderBasics();
410
        // Meta data setting:
411
412
        $beUser = $this->getBackendUser();
413
        $this->export->setMetaData(
414
            $inData['meta']['title'],
415
            $inData['meta']['description'],
416
            $inData['meta']['notes'],
417
            $beUser->user['username'],
418
            $beUser->user['realName'],
419
            $beUser->user['email']
420
        );
421
        // Configure which records to export
422 View Code Duplication
        if (is_array($inData['record'])) {
423
            foreach ($inData['record'] as $ref) {
424
                $rParts = explode(':', $ref);
425
                $this->export->export_addRecord($rParts[0], BackendUtility::getRecord($rParts[0], $rParts[1]));
426
            }
427
        }
428
        // Configure which tables to export
429
        if (is_array($inData['list'])) {
430
            foreach ($inData['list'] as $ref) {
431
                $rParts = explode(':', $ref);
432
                if ($beUser->check('tables_select', $rParts[0])) {
433
                    $statement = $this->exec_listQueryPid($rParts[0], $rParts[1], MathUtility::forceIntegerInRange($inData['listCfg']['maxNumber'], 1));
434
                    while ($subTrow = $statement->fetch()) {
435
                        $this->export->export_addRecord($rParts[0], $subTrow);
436
                    }
437
                }
438
            }
439
        }
440
        // Pagetree
441
        if (isset($inData['pagetree']['id'])) {
442
            // Based on click-expandable tree
443
            $idH = null;
444
            if ($inData['pagetree']['levels'] == -1) {
445
                $pagetree = GeneralUtility::makeInstance(ExportPageTreeView::class);
446
                if ($this->excludeDisabledRecords) {
447
                    $pagetree->init(BackendUtility::BEenableFields('pages'));
448
                }
449
                $tree = $pagetree->ext_tree($inData['pagetree']['id'], $this->filterPageIds($this->export->excludeMap));
450
                $this->treeHTML = $pagetree->printTree($tree);
451
                $idH = $pagetree->buffer_idH;
452
            } elseif ($inData['pagetree']['levels'] == -2) {
453
                $this->addRecordsForPid($inData['pagetree']['id'], $inData['pagetree']['tables'], $inData['pagetree']['maxNumber']);
454
            } else {
455
                // Based on depth
456
                // Drawing tree:
457
                // If the ID is zero, export root
458
                if (!$inData['pagetree']['id'] && $beUser->isAdmin()) {
459
                    $sPage = [
460
                        'uid' => 0,
461
                        'title' => 'ROOT'
462
                    ];
463
                } else {
464
                    $sPage = BackendUtility::getRecordWSOL('pages', $inData['pagetree']['id'], '*', ' AND ' . $this->perms_clause);
465
                }
466
                if (is_array($sPage)) {
467
                    $pid = $inData['pagetree']['id'];
468
                    $tree = GeneralUtility::makeInstance(PageTreeView::class);
469
                    $initClause = 'AND ' . $this->perms_clause . $this->filterPageIds($this->export->excludeMap);
470
                    if ($this->excludeDisabledRecords) {
471
                        $initClause .= BackendUtility::BEenableFields('pages');
472
                    }
473
                    $tree->init($initClause);
474
                    $HTML = $this->iconFactory->getIconForRecord('pages', $sPage, Icon::SIZE_SMALL)->render();
475
                    $tree->tree[] = ['row' => $sPage, 'HTML' => $HTML];
476
                    $tree->buffer_idH = [];
477
                    if ($inData['pagetree']['levels'] > 0) {
478
                        $tree->getTree($pid, $inData['pagetree']['levels'], '');
479
                    }
480
                    $idH = [];
481
                    $idH[$pid]['uid'] = $pid;
482
                    if (!empty($tree->buffer_idH)) {
483
                        $idH[$pid]['subrow'] = $tree->buffer_idH;
484
                    }
485
                    $pagetree = GeneralUtility::makeInstance(ExportPageTreeView::class);
486
                    $this->treeHTML = $pagetree->printTree($tree->tree);
487
                    $this->shortcutName .= ' (' . $sPage['title'] . ')';
488
                }
489
            }
490
            // In any case we should have a multi-level array, $idH, with the page structure
491
            // here (and the HTML-code loaded into memory for nice display...)
492
            if (is_array($idH)) {
493
                // Sets the pagetree and gets a 1-dim array in return with the pages (in correct submission order BTW...)
494
                $flatList = $this->export->setPageTree($idH);
495
                foreach ($flatList as $k => $value) {
496
                    $this->export->export_addRecord('pages', BackendUtility::getRecord('pages', $k));
497
                    $this->addRecordsForPid($k, $inData['pagetree']['tables'], $inData['pagetree']['maxNumber']);
498
                }
499
            }
500
        }
501
        // After adding ALL records we set relations:
502
        for ($a = 0; $a < 10; $a++) {
503
            $addR = $this->export->export_addDBRelations($a);
504
            if (empty($addR)) {
505
                break;
506
            }
507
        }
508
        // Finally files are added:
509
        // MUST be after the DBrelations are set so that files from ALL added records are included!
510
        $this->export->export_addFilesFromRelations();
511
512
        $this->export->export_addFilesFromSysFilesRecords();
513
514
        // If the download button is clicked, return file
515
        if ($inData['download_export'] || $inData['save_export']) {
516
            switch ((string)$inData['filetype']) {
517
                case 'xml':
518
                    $out = $this->export->compileMemoryToFileContent('xml');
519
                    $fExt = '.xml';
520
                    break;
521
                case 't3d':
522
                    $this->export->dontCompress = 1;
523
                    // intentional fall-through
524
                    // no break
525
                default:
526
                    $out = $this->export->compileMemoryToFileContent();
527
                    $fExt = ($this->export->doOutputCompress() ? '-z' : '') . '.t3d';
528
            }
529
            // Filename:
530
            $dlFile = $inData['filename'];
531
            if (!$dlFile) {
532
                $exportName = substr(preg_replace('/[^[:alnum:]_]/', '-', $inData['download_export_name']), 0, 20);
533
                $dlFile = 'T3D_' . $exportName . '_' . date('Y-m-d_H-i') . $fExt;
0 ignored issues
show
Bug introduced by
Are you sure date('Y-m-d_H-i') of type false|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

533
                $dlFile = 'T3D_' . $exportName . '_' . /** @scrutinizer ignore-type */ date('Y-m-d_H-i') . $fExt;
Loading history...
Bug introduced by
Are you sure $exportName of type false|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

533
                $dlFile = 'T3D_' . /** @scrutinizer ignore-type */ $exportName . '_' . date('Y-m-d_H-i') . $fExt;
Loading history...
534
            }
535
536
            // Export for download:
537
            if ($inData['download_export']) {
538
                $mimeType = 'application/octet-stream';
539
                header('Content-Type: ' . $mimeType);
540
                header('Content-Length: ' . strlen($out));
541
                header('Content-Disposition: attachment; filename=' . basename($dlFile));
542
                echo $out;
543
                die;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
544
            }
545
            // Export by saving:
546
            if ($inData['save_export']) {
547
                $saveFolder = $this->getDefaultImportExportFolder();
548
                $lang = $this->getLanguageService();
549
                if ($saveFolder !== false && $saveFolder->checkActionPermission('write')) {
550
                    $temporaryFileName = GeneralUtility::tempnam('export');
551
                    file_put_contents($temporaryFileName, $out);
552
                    $file = $saveFolder->addFile($temporaryFileName, $dlFile, 'replace');
553
                    if ($saveFilesOutsideExportFile) {
554
                        $filesFolderName = $dlFile . '.files';
555
                        $filesFolder = $saveFolder->createFolder($filesFolderName);
556
                        $temporaryFolderForExport = ResourceFactory::getInstance()->retrieveFileOrFolderObject($this->export->getTemporaryFilesPathForExport());
557
                        $temporaryFilesForExport = $temporaryFolderForExport->getFiles();
0 ignored issues
show
Bug introduced by
The method getFiles() does not exist on TYPO3\CMS\Core\Resource\File. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

557
                        /** @scrutinizer ignore-call */ 
558
                        $temporaryFilesForExport = $temporaryFolderForExport->getFiles();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
558
                        foreach ($temporaryFilesForExport as $temporaryFileForExport) {
559
                            $filesFolder->getStorage()->moveFile($temporaryFileForExport, $filesFolder);
560
                        }
561
                        $temporaryFolderForExport->delete();
562
                    }
563
564
                    /** @var FlashMessage $flashMessage */
565
                    $flashMessage = GeneralUtility::makeInstance(
566
                        FlashMessage::class,
567
                        sprintf($lang->getLL('exportdata_savedInSBytes'), $file->getPublicUrl(), GeneralUtility::formatSize(strlen($out))),
0 ignored issues
show
Bug introduced by
sprintf($lang->getLL('ex...rmatSize(strlen($out))) of type string is incompatible with the type array<integer,mixed> expected by parameter $constructorArguments of TYPO3\CMS\Core\Utility\G...Utility::makeInstance(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

567
                        /** @scrutinizer ignore-type */ sprintf($lang->getLL('exportdata_savedInSBytes'), $file->getPublicUrl(), GeneralUtility::formatSize(strlen($out))),
Loading history...
568
                        $lang->getLL('exportdata_savedFile'),
569
                        FlashMessage::OK
0 ignored issues
show
Bug introduced by
TYPO3\CMS\Core\Messaging\FlashMessage::OK of type integer is incompatible with the type array<integer,mixed> expected by parameter $constructorArguments of TYPO3\CMS\Core\Utility\G...Utility::makeInstance(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

569
                        /** @scrutinizer ignore-type */ FlashMessage::OK
Loading history...
570
                    );
571 View Code Duplication
                } else {
572
                    /** @var FlashMessage $flashMessage */
573
                    $flashMessage = GeneralUtility::makeInstance(
574
                        FlashMessage::class,
575
                        sprintf($lang->getLL('exportdata_badPathS'), $saveFolder->getPublicUrl()),
576
                        $lang->getLL('exportdata_problemsSavingFile'),
577
                        FlashMessage::ERROR
578
                    );
579
                }
580
                /** @var $flashMessageService \TYPO3\CMS\Core\Messaging\FlashMessageService */
581
                $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
582
                /** @var $defaultFlashMessageQueue \TYPO3\CMS\Core\Messaging\FlashMessageQueue */
583
                $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
584
                $defaultFlashMessageQueue->enqueue($flashMessage);
585
            }
586
        }
587
588
        $this->makeConfigurationForm($inData);
589
590
        $this->makeSaveForm($inData);
591
592
        $this->makeAdvancedOptionsForm($inData);
593
594
        $this->standaloneView->assign('errors', $this->export->errorLog);
595
596
        // Generate overview:
597
        $this->standaloneView->assign(
598
            'contentOverview',
599
            $this->export->displayContentOverview()
600
        );
601
    }
602
603
    /**
604
     * Adds records to the export object for a specific page id.
605
     *
606
     * @param int $k Page id for which to select records to add
607
     * @param array $tables Array of table names to select from
608
     * @param int $maxNumber Max amount of records to select
609
     */
610
    public function addRecordsForPid($k, $tables, $maxNumber)
611
    {
612
        if (!is_array($tables)) {
613
            return;
614
        }
615
        foreach ($GLOBALS['TCA'] as $table => $value) {
616
            if ($table !== 'pages' && (in_array($table, $tables) || in_array('_ALL', $tables))) {
617
                if ($this->getBackendUser()->check('tables_select', $table) && !$GLOBALS['TCA'][$table]['ctrl']['is_static']) {
618
                    $statement = $this->exec_listQueryPid($table, $k, MathUtility::forceIntegerInRange($maxNumber, 1));
619
                    while ($subTrow = $statement->fetch()) {
620
                        $this->export->export_addRecord($table, $subTrow);
621
                    }
622
                }
623
            }
624
        }
625
    }
626
627
    /**
628
     * Selects records from table / pid
629
     *
630
     * @param string $table Table to select from
631
     * @param int $pid Page ID to select from
632
     * @param int $limit Max number of records to select
633
     * @return \Doctrine\DBAL\Driver\Statement Query statement
634
     */
635
    public function exec_listQueryPid($table, $pid, $limit)
636
    {
637
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
638
639
        $orderBy = $GLOBALS['TCA'][$table]['ctrl']['sortby'] ?: $GLOBALS['TCA'][$table]['ctrl']['default_sortby'];
640
        $queryBuilder->getRestrictions()->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
641
642
        if ($this->excludeDisabledRecords === false) {
643
            $queryBuilder->getRestrictions()
644
                ->removeAll()
645
                ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
646
                ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
647
        }
648
649
        $queryBuilder->select('*')
650
            ->from($table)
651
            ->where(
652
                $queryBuilder->expr()->eq(
653
                    'pid',
654
                    $queryBuilder->createNamedParameter($pid, \PDO::PARAM_INT)
655
                )
656
            )
657
            ->setMaxResults($limit);
658
659
        foreach (QueryHelper::parseOrderBy((string)$orderBy) as $orderPair) {
660
            list($fieldName, $order) = $orderPair;
661
            $queryBuilder->addOrderBy($fieldName, $order);
662
        }
663
664
        $statement = $queryBuilder->execute();
665
666
        // Warning about hitting limit:
667
        if ($statement->rowCount() == $limit) {
668
            $limitWarning = sprintf($this->lang->getLL('makeconfig_anSqlQueryReturned'), $limit);
669
            /** @var FlashMessage $flashMessage */
670
            $flashMessage = GeneralUtility::makeInstance(
671
                FlashMessage::class,
672
                $this->lang->getLL('execlistqu_maxNumberLimit'),
0 ignored issues
show
Bug introduced by
$this->lang->getLL('execlistqu_maxNumberLimit') of type string is incompatible with the type array<integer,mixed> expected by parameter $constructorArguments of TYPO3\CMS\Core\Utility\G...Utility::makeInstance(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

672
                /** @scrutinizer ignore-type */ $this->lang->getLL('execlistqu_maxNumberLimit'),
Loading history...
673
                $limitWarning,
674
                FlashMessage::WARNING
0 ignored issues
show
Bug introduced by
TYPO3\CMS\Core\Messaging\FlashMessage::WARNING of type integer is incompatible with the type array<integer,mixed> expected by parameter $constructorArguments of TYPO3\CMS\Core\Utility\G...Utility::makeInstance(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

674
                /** @scrutinizer ignore-type */ FlashMessage::WARNING
Loading history...
675
            );
676
            /** @var $flashMessageService \TYPO3\CMS\Core\Messaging\FlashMessageService */
677
            $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
678
            /** @var $defaultFlashMessageQueue \TYPO3\CMS\Core\Messaging\FlashMessageQueue */
679
            $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
680
            $defaultFlashMessageQueue->enqueue($flashMessage);
681
        }
682
683
        return $statement;
684
    }
685
686
    /**
687
     * Create configuration form
688
     *
689
     * @param array $inData Form configuration data
690
     */
691
    public function makeConfigurationForm($inData)
692
    {
693
        $nameSuggestion = '';
694
        // Page tree export options:
695
        if (isset($inData['pagetree']['id'])) {
696
            $this->standaloneView->assign('treeHTML', $this->treeHTML);
697
698
            $opt = [
699
                '-2' => $this->lang->getLL('makeconfig_tablesOnThisPage'),
700
                '-1' => $this->lang->getLL('makeconfig_expandedTree'),
701
                '0' => $this->lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_0'),
702
                '1' => $this->lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_1'),
703
                '2' => $this->lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_2'),
704
                '3' => $this->lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_3'),
705
                '4' => $this->lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_4'),
706
                '999' => $this->lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_infi'),
707
            ];
708
            $this->standaloneView->assign('levelSelectOptions', $opt);
709
            $this->standaloneView->assign('tableSelectOptions', $this->getTableSelectOptions('pages'));
710
            $nameSuggestion .= 'tree_PID' . $inData['pagetree']['id'] . '_L' . $inData['pagetree']['levels'];
711
        }
712
        // Single record export:
713
        if (is_array($inData['record'])) {
714
            $records = [];
715
            foreach ($inData['record'] as $ref) {
716
                $rParts = explode(':', $ref);
717
                $tName = $rParts[0];
718
                $rUid = $rParts[1];
719
                $nameSuggestion .= $tName . '_' . $rUid;
720
                $rec = BackendUtility::getRecordWSOL($tName, $rUid);
721
                if (!empty($rec)) {
722
                    $records[] = [
723
                        'icon' => $this->iconFactory->getIconForRecord($tName, $rec, Icon::SIZE_SMALL)->render(),
724
                        'title' => BackendUtility::getRecordTitle($tName, $rec, true),
725
                        'tableName' => $tName,
726
                        'recordUid' => $rUid
727
                    ];
728
                }
729
            }
730
            $this->standaloneView->assign('records', $records);
731
        }
732
        // Single tables/pids:
733
        if (is_array($inData['list'])) {
734
735
            // Display information about pages from which the export takes place
736
            $tableList = [];
737
            foreach ($inData['list'] as $reference) {
738
                $referenceParts = explode(':', $reference);
739
                $tableName = $referenceParts[0];
740
                if ($this->getBackendUser()->check('tables_select', $tableName)) {
741
                    // If the page is actually the root, handle it differently
742
                    // NOTE: we don't compare integers, because the number actually comes from the split string above
743
                    if ($referenceParts[1] === '0') {
744
                        $iconAndTitle = $this->iconFactory->getIcon('apps-pagetree-root', Icon::SIZE_SMALL)->render() . $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'];
745
                    } else {
746
                        $record = BackendUtility::getRecordWSOL('pages', $referenceParts[1]);
747
                        $iconAndTitle = $this->iconFactory->getIconForRecord('pages', $record, Icon::SIZE_SMALL)->render()
748
                            . BackendUtility::getRecordTitle('pages', $record, true);
749
                    }
750
751
                    $tableList[] = [
752
                        'iconAndTitle' => sprintf($this->lang->getLL('makeconfig_tableListEntry'), $tableName, $iconAndTitle),
753
                        'reference' => $reference
754
                    ];
755
                }
756
            }
757
            $this->standaloneView->assign('tableList', $tableList);
758
        }
759
760
        $this->standaloneView->assign('externalReferenceTableSelectOptions', $this->getTableSelectOptions());
761
        $this->standaloneView->assign('externalStaticTableSelectOptions', $this->getTableSelectOptions());
762
        $this->standaloneView->assign('nameSuggestion', $nameSuggestion);
763
    }
764
765
    /**
766
     * Create advanced options form
767
     * Sets content in $this->content
768
     *
769
     * @param array $inData Form configurat data
770
     */
771
    public function makeAdvancedOptionsForm($inData)
772
    {
773
        $loadedExtensions = ExtensionManagementUtility::getLoadedExtensionListArray();
774
        $loadedExtensions = array_combine($loadedExtensions, $loadedExtensions);
775
        $this->standaloneView->assign('extensions', $loadedExtensions);
776
        $this->standaloneView->assign('inData', $inData);
777
    }
778
779
    /**
780
     * Create configuration form
781
     *
782
     * @param array $inData Form configuration data
783
     */
784
    public function makeSaveForm($inData)
785
    {
786
        $opt = $this->presetRepository->getPresets((int)$inData['pagetree']['id']);
787
788
        $this->standaloneView->assign('presetSelectOptions', $opt);
789
790
        $saveFolder = $this->getDefaultImportExportFolder();
791
        if ($saveFolder) {
792
            $this->standaloneView->assign('saveFolder', $saveFolder->getCombinedIdentifier());
793
        }
794
795
        // Add file options:
796
        $opt = [];
797
        if ($this->export->compress) {
798
            $opt['t3d_compressed'] = $this->lang->getLL('makesavefo_t3dFileCompressed');
799
        }
800
        $opt['t3d'] = $this->lang->getLL('makesavefo_t3dFile');
801
        $opt['xml'] = $this->lang->getLL('makesavefo_xml');
802
803
        $this->standaloneView->assign('filetypeSelectOptions', $opt);
804
805
        $fileName = '';
806
        if ($saveFolder) {
807
            $this->standaloneView->assign('saveFolder', $saveFolder->getPublicUrl());
808
            $this->standaloneView->assign('hasSaveFolder', true);
809
        }
810
        $this->standaloneView->assign('fileName', $fileName);
811
    }
812
813
    /**************************
814
     * IMPORT FUNCTIONS
815
     **************************/
816
817
    /**
818
     * Import part of module
819
     *
820
     * @param array $inData Content of POST VAR tx_impexp[]..
821
     * @throws \BadFunctionCallException
822
     * @throws \InvalidArgumentException
823
     * @throws \RuntimeException
824
     */
825
    public function importData($inData)
826
    {
827
        $access = is_array($this->pageinfo);
828
        $beUser = $this->getBackendUser();
829
        if ($this->id && $access || $beUser->isAdmin() && !$this->id) {
830
            if ($beUser->isAdmin() && !$this->id) {
831
                $this->pageinfo = ['title' => '[root-level]', 'uid' => 0, 'pid' => 0];
832
            }
833
            if ($inData['new_import']) {
834
                unset($inData['import_mode']);
835
            }
836
            /** @var $import Import */
837
            $import = GeneralUtility::makeInstance(Import::class);
838
            $import->init();
839
            $import->update = $inData['do_update'];
840
            $import->import_mode = $inData['import_mode'];
841
            $import->enableLogging = $inData['enableLogging'];
842
            $import->global_ignore_pid = $inData['global_ignore_pid'];
843
            $import->force_all_UIDS = $inData['force_all_UIDS'];
844
            $import->showDiff = !$inData['notShowDiff'];
845
            $import->allowPHPScripts = $inData['allowPHPScripts'];
846
            $import->softrefInputValues = $inData['softrefInputValues'];
847
848
            // OUTPUT creation:
849
850
            // Make input selector:
851
            // must have trailing slash.
852
            $path = $this->getDefaultImportExportFolder();
853
            $exportFiles = $this->getExportFiles();
854
855
            $this->shortcutName .= ' (' . $this->pageinfo['title'] . ')';
856
857
            // Configuration
858
            $selectOptions = [''];
859
            foreach ($exportFiles as $file) {
860
                $selectOptions[$file->getCombinedIdentifier()] = $file->getPublicUrl();
861
            }
862
863
            $this->standaloneView->assign('import', $import);
864
            $this->standaloneView->assign('inData', $inData);
865
            $this->standaloneView->assign('fileSelectOptions', $selectOptions);
866
867
            if ($path) {
868
                $this->standaloneView->assign('importPath', sprintf($this->lang->getLL('importdata_fromPathS'), $path->getCombinedIdentifier()));
869
            } else {
870
                $this->standaloneView->assign('importPath', $this->lang->getLL('importdata_no_default_upload_folder'));
871
            }
872
            $this->standaloneView->assign('isAdmin', $beUser->isAdmin());
873
874
            // Upload file:
875
            $tempFolder = $this->getDefaultImportExportFolder();
876
            if ($tempFolder) {
877
                $this->standaloneView->assign('tempFolder', $tempFolder->getCombinedIdentifier());
878
                $this->standaloneView->assign('hasTempUploadFolder', true);
879
                if (GeneralUtility::_POST('_upload')) {
880
                    $this->standaloneView->assign('submitted', GeneralUtility::_POST('_upload'));
881
                    $this->standaloneView->assign('noFileUploaded', $this->fileProcessor->internalUploadMap[1]);
882
                    if ($this->uploadedFiles[0]) {
883
                        $this->standaloneView->assign('uploadedFile', $this->uploadedFiles[0]->getName());
884
                    }
885
                }
886
            }
887
888
            // Perform import or preview depending:
889
            $inFile = $this->getFile($inData['file']);
890
            if ($inFile !== null && $inFile->exists()) {
891
                $this->standaloneView->assign('metaDataInFileExists', true);
892
                $importInhibitedMessages = [];
893
                if ($import->loadFile($inFile->getForLocalProcessing(false), 1)) {
894
                    $importInhibitedMessages = $import->checkImportPrerequisites();
895
                    if ($inData['import_file']) {
896
                        if (empty($importInhibitedMessages)) {
897
                            $import->importData($this->id);
898
                            BackendUtility::setUpdateSignal('updatePageTree');
899
                        }
900
                    }
901
                    $import->display_import_pid_record = $this->pageinfo;
902
                    $this->standaloneView->assign('contentOverview', $import->displayContentOverview());
903
                }
904
                // Compile messages which are inhibiting a proper import and add them to output.
905
                if (!empty($importInhibitedMessages)) {
906
                    $flashMessageQueue = GeneralUtility::makeInstance(FlashMessageService::class)->getMessageQueueByIdentifier('impexp.errors');
907
                    foreach ($importInhibitedMessages as $message) {
908
                        $flashMessageQueue->addMessage(GeneralUtility::makeInstance(
909
                            FlashMessage::class,
910
                            $message,
911
                            '',
0 ignored issues
show
Bug introduced by
'' of type string is incompatible with the type array<integer,mixed> expected by parameter $constructorArguments of TYPO3\CMS\Core\Utility\G...Utility::makeInstance(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

911
                            /** @scrutinizer ignore-type */ '',
Loading history...
912
                            FlashMessage::ERROR
0 ignored issues
show
Bug introduced by
TYPO3\CMS\Core\Messaging\FlashMessage::ERROR of type integer is incompatible with the type array<integer,mixed> expected by parameter $constructorArguments of TYPO3\CMS\Core\Utility\G...Utility::makeInstance(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

912
                            /** @scrutinizer ignore-type */ FlashMessage::ERROR
Loading history...
913
                        ));
914
                    }
915
                }
916
            }
917
918
            $this->standaloneView->assign('errors', $import->errorLog);
919
        }
920
    }
921
922
    /****************************
923
     * Helper functions
924
     ****************************/
925
926
    /**
927
     * Returns a \TYPO3\CMS\Core\Resource\Folder object for saving export files
928
     * to the server and is also used for uploading import files.
929
     *
930
     * @throws \InvalidArgumentException
931
     * @return \TYPO3\CMS\Core\Resource\Folder|null
932
     */
933 View Code Duplication
    protected function getDefaultImportExportFolder()
934
    {
935
        $defaultImportExportFolder = null;
936
937
        $defaultTemporaryFolder = $this->getBackendUser()->getDefaultUploadTemporaryFolder();
938
        if ($defaultTemporaryFolder !== null) {
939
            $importExportFolderName = 'importexport';
940
            $createFolder = !$defaultTemporaryFolder->hasFolder($importExportFolderName);
941
            if ($createFolder === true) {
942
                try {
943
                    $defaultImportExportFolder = $defaultTemporaryFolder->createFolder($importExportFolderName);
944
                } catch (Exception $folderAccessException) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
945
                }
946
            } else {
947
                $defaultImportExportFolder = $defaultTemporaryFolder->getSubfolder($importExportFolderName);
948
            }
949
        }
950
951
        return $defaultImportExportFolder;
952
    }
953
954
    /**
955
     * Check if a file has been uploaded
956
     *
957
     * @throws \InvalidArgumentException
958
     * @throws \UnexpectedValueException
959
     */
960
    public function checkUpload()
961
    {
962
        $file = GeneralUtility::_GP('file');
963
        // Initializing:
964
        $this->fileProcessor = GeneralUtility::makeInstance(ExtendedFileUtility::class);
965
        $this->fileProcessor->setActionPermissions();
966
        $conflictMode = empty(GeneralUtility::_GP('overwriteExistingFiles')) ? DuplicationBehavior::__default : DuplicationBehavior::REPLACE;
967
        $this->fileProcessor->setExistingFilesConflictMode(DuplicationBehavior::cast($conflictMode));
968
        // Checking referer / executing:
969
        $refInfo = parse_url(GeneralUtility::getIndpEnv('HTTP_REFERER'));
970
        $httpHost = GeneralUtility::getIndpEnv('TYPO3_HOST_ONLY');
971
        if (
972
            $httpHost != $refInfo['host']
973
            && !$GLOBALS['$TYPO3_CONF_VARS']['SYS']['doNotCheckReferer']
974
        ) {
975
            $this->fileProcessor->writeLog(0, 2, 1, 'Referer host "%s" and server host "%s" did not match!', [$refInfo['host'], $httpHost]);
976
        } else {
977
            $this->fileProcessor->start($file);
978
            $result = $this->fileProcessor->processData();
979
            if (!empty($result['upload'])) {
980
                foreach ($result['upload'] as $uploadedFiles) {
981
                    $this->uploadedFiles += $uploadedFiles;
982
                }
983
            }
984
        }
985
    }
986
987
    /**
988
     * Returns option array to be used in Fluid
989
     *
990
     * @param string $excludeList Table names (and the string "_ALL") to exclude. Comma list
991
     * @return array
992
     */
993
    public function getTableSelectOptions($excludeList = '')
994
    {
995
        $optValues = [];
996
        if (!GeneralUtility::inList($excludeList, '_ALL')) {
997
            $optValues['_ALL'] = '[' . $this->lang->getLL('ALL_tables') . ']';
998
        }
999
        foreach ($GLOBALS['TCA'] as $table => $_) {
1000
            if ($this->getBackendUser()->check('tables_select', $table) && !GeneralUtility::inList($excludeList, $table)) {
1001
                $optValues[$table] = $table;
1002
            }
1003
        }
1004
        return $optValues;
1005
    }
1006
1007
    /**
1008
     * Filter page IDs by traversing exclude array, finding all
1009
     * excluded pages (if any) and making an AND NOT IN statement for the select clause.
1010
     *
1011
     * @param array $exclude Exclude array from import/export object.
1012
     * @return string AND where clause part to filter out page uids.
1013
     */
1014
    public function filterPageIds($exclude)
1015
    {
1016
        // Get keys:
1017
        $exclude = array_keys($exclude);
1018
        // Traverse
1019
        $pageIds = [];
1020
        foreach ($exclude as $element) {
1021
            list($table, $uid) = explode(':', $element);
1022
            if ($table === 'pages') {
1023
                $pageIds[] = (int)$uid;
1024
            }
1025
        }
1026
        // Add to clause:
1027
        if (!empty($pageIds)) {
1028
            return ' AND uid NOT IN (' . implode(',', $pageIds) . ')';
1029
        }
1030
        return '';
1031
    }
1032
1033
    /**
1034
     * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
1035
     */
1036
    protected function getBackendUser()
1037
    {
1038
        return $GLOBALS['BE_USER'];
1039
    }
1040
1041
    /**
1042
     * @return LanguageService
1043
     */
1044
    protected function getLanguageService()
1045
    {
1046
        return $GLOBALS['LANG'];
1047
    }
1048
1049
    /**
1050
     * Gets all export files.
1051
     *
1052
     * @throws \InvalidArgumentException
1053
     * @return array|\TYPO3\CMS\Core\Resource\File[]
1054
     */
1055
    protected function getExportFiles()
1056
    {
1057
        $exportFiles = [];
1058
1059
        $folder = $this->getDefaultImportExportFolder();
1060
        if ($folder !== null) {
1061
1062
            /** @var $filter FileExtensionFilter */
1063
            $filter = GeneralUtility::makeInstance(FileExtensionFilter::class);
1064
            $filter->setAllowedFileExtensions(['t3d', 'xml']);
1065
            $folder->getStorage()->addFileAndFolderNameFilter([$filter, 'filterFileList']);
1066
1067
            $exportFiles = $folder->getFiles();
1068
        }
1069
1070
        return $exportFiles;
1071
    }
1072
1073
    /**
1074
     * Gets a file by combined identifier.
1075
     *
1076
     * @param string $combinedIdentifier
1077
     * @return \TYPO3\CMS\Core\Resource\File|null
1078
     */
1079
    protected function getFile($combinedIdentifier)
1080
    {
1081
        try {
1082
            $file = ResourceFactory::getInstance()->getFileObjectFromCombinedIdentifier($combinedIdentifier);
1083
        } catch (\Exception $exception) {
1084
            $file = null;
1085
        }
1086
1087
        return $file;
1088
    }
1089
}
1090