Passed
Push — master ( 6f0002...d39f54 )
by
unknown
19:15
created

ImportController::getFile()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 1
dl 0
loc 9
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the TYPO3 CMS project.
7
 *
8
 * It is free software; you can redistribute it and/or modify it under
9
 * the terms of the GNU General Public License, either version 2
10
 * of the License, or any later version.
11
 *
12
 * For the full copyright and license information, please read the
13
 * LICENSE.txt file that was distributed with this source code.
14
 *
15
 * The TYPO3 project - inspiring people to share!
16
 */
17
18
namespace TYPO3\CMS\Impexp\Controller;
19
20
use Psr\Http\Message\ResponseInterface;
21
use Psr\Http\Message\ServerRequestInterface;
22
use TYPO3\CMS\Backend\Routing\Exception\RouteNotFoundException;
23
use TYPO3\CMS\Backend\Routing\PreviewUriBuilder;
24
use TYPO3\CMS\Backend\Utility\BackendUtility;
25
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
26
use TYPO3\CMS\Core\Exception;
27
use TYPO3\CMS\Core\Http\HtmlResponse;
28
use TYPO3\CMS\Core\Imaging\Icon;
29
use TYPO3\CMS\Core\Messaging\FlashMessage;
30
use TYPO3\CMS\Core\Messaging\FlashMessageService;
31
use TYPO3\CMS\Core\Resource\DuplicationBehavior;
32
use TYPO3\CMS\Core\Resource\File;
33
use TYPO3\CMS\Core\Resource\Filter\FileExtensionFilter;
34
use TYPO3\CMS\Core\Resource\ResourceFactory;
35
use TYPO3\CMS\Core\Utility\File\ExtendedFileUtility;
36
use TYPO3\CMS\Core\Utility\GeneralUtility;
37
use TYPO3\CMS\Impexp\Import;
38
39
/**
40
 * Main script class for the Import facility
41
 *
42
 * @internal this is a TYPO3 Backend controller implementation and not part of TYPO3's Core API.
43
 */
44
class ImportController extends ImportExportController
45
{
46
    /**
47
     * The name of the module
48
     *
49
     * @var string
50
     */
51
    protected $moduleName = 'tx_impexp_import';
52
53
    /**
54
     * @var array|File[]
55
     */
56
    protected $uploadedFiles = [];
57
58
    /**
59
     * @var Import
60
     */
61
    protected $import;
62
63
    /**
64
     * @var ExtendedFileUtility
65
     */
66
    protected $fileProcessor;
67
68
    /**
69
     * @param ServerRequestInterface $request
70
     * @return ResponseInterface
71
     * @throws Exception
72
     * @throws RouteNotFoundException
73
     * @throws \TYPO3\CMS\Core\Resource\Exception
74
     */
75
    public function mainAction(ServerRequestInterface $request): ResponseInterface
76
    {
77
        $this->moduleTemplate = $this->moduleTemplateFactory->create($request);
78
        $this->lang->includeLLFile('EXT:impexp/Resources/Private/Language/locallang.xlf');
79
80
        $this->pageinfo = BackendUtility::readPageAccess($this->id, $this->perms_clause) ?: [];
81
        if ($this->pageinfo !== []) {
82
            $this->moduleTemplate->getDocHeaderComponent()->setMetaInformation($this->pageinfo);
83
        }
84
        // Setting up the context sensitive menu:
85
        $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/ContextMenu');
86
        $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Impexp/ImportExport');
87
        $this->moduleTemplate->addJavaScriptCode(
88
            'ImpexpInLineJS',
89
            'if (top.fsMod) top.fsMod.recentIds["web"] = ' . (int)$this->id . ';'
90
        );
91
92
        // Input data grabbed:
93
        $inData = $request->getParsedBody()['tx_impexp'] ?? $request->getQueryParams()['tx_impexp'] ?? [];
94
        if ($request->getMethod() === 'POST' && empty($request->getParsedBody())) {
95
            // This happens if the post request was larger than allowed on the server
96
            // We set the import action as default and output a user information
97
            $flashMessage = GeneralUtility::makeInstance(
98
                FlashMessage::class,
99
                $this->lang->getLL('importdata_upload_nodata'),
100
                $this->lang->getLL('importdata_upload_error'),
101
                FlashMessage::ERROR
102
            );
103
            $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
104
            $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
105
            $defaultFlashMessageQueue->enqueue($flashMessage);
106
        }
107
        $this->standaloneView->assign('moduleUrl', (string)$this->uriBuilder->buildUriFromRoute($this->moduleName));
108
        $this->standaloneView->assign('id', $this->id);
109
        $this->standaloneView->assign('inData', $inData);
110
111
        $backendUser = $this->getBackendUser();
112
        $isEnabledForNonAdmin = (bool)($backendUser->getTSConfig()['options.']['impexp.']['enableImportForNonAdminUser'] ?? false);
113
        if (!$backendUser->isAdmin() && !$isEnabledForNonAdmin) {
114
            throw new \RuntimeException(
115
                'Import module is disabled for non admin users and '
116
                . 'userTsConfig options.impexp.enableImportForNonAdminUser is not enabled.',
117
                1464435459
118
            );
119
        }
120
        $this->shortcutName = $this->lang->getLL('title_import');
121
        if (GeneralUtility::_POST('_upload')) {
122
            $this->checkUpload();
123
        }
124
        // Finally: If upload went well, set the new file as the import file:
125
        if (!empty($this->uploadedFiles[0])) {
126
            // Only allowed extensions....
127
            $extension = $this->uploadedFiles[0]->getExtension();
128
            if ($extension === 't3d' || $extension === 'xml') {
129
                $inData['file'] = $this->uploadedFiles[0]->getCombinedIdentifier();
130
            }
131
        }
132
        // Call import interface:
133
        $this->importData($inData);
134
        $this->standaloneView->setTemplate('Import.html');
135
136
        // Setting up the buttons and markers for docheader
137
        $this->getButtons();
138
139
        $this->moduleTemplate->setContent($this->standaloneView->render());
140
        return new HtmlResponse($this->moduleTemplate->renderContent());
141
    }
142
143
    /**
144
     * Import part of module
145
     *
146
     * @param array $inData Content of POST VAR tx_impexp[]..
147
     * @throws \BadFunctionCallException
148
     * @throws \InvalidArgumentException
149
     * @throws \RuntimeException
150
     */
151
    protected function importData(array $inData): void
152
    {
153
        $access = $this->pageinfo !== [];
154
        $beUser = $this->getBackendUser();
155
        if ($this->id && $access || $beUser->isAdmin() && !$this->id) {
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: ($this->id && $access) |...sAdmin() && ! $this->id, Probably Intended Meaning: $this->id && ($access ||...Admin() && ! $this->id)
Loading history...
156
            if ($beUser->isAdmin() && !$this->id) {
157
                $this->pageinfo = ['title' => '[root-level]', 'uid' => 0, 'pid' => 0];
158
            }
159
            if ($inData['new_import']) {
160
                unset($inData['import_mode']);
161
            }
162
            $import = GeneralUtility::makeInstance(Import::class);
163
            $import->init();
164
            $import->update = $inData['do_update'];
165
            $import->import_mode = $inData['import_mode'];
166
            $import->enableLogging = $inData['enableLogging'];
167
            $import->global_ignore_pid = $inData['global_ignore_pid'];
168
            $import->force_all_UIDS = $inData['force_all_UIDS'];
169
            $import->showDiff = !$inData['notShowDiff'];
170
            $import->softrefInputValues = $inData['softrefInputValues'];
171
172
            // OUTPUT creation:
173
174
            // Make input selector:
175
            // must have trailing slash.
176
            $path = $this->getDefaultImportExportFolder();
177
            $exportFiles = $this->getExportFiles();
178
179
            $this->shortcutName .= ' (' . htmlspecialchars($this->pageinfo['title']) . ')';
180
181
            // Configuration
182
            $selectOptions = [''];
183
            foreach ($exportFiles as $file) {
184
                $selectOptions[$file->getCombinedIdentifier()] = $file->getPublicUrl();
185
            }
186
187
            $this->standaloneView->assign('import', $import);
188
            $this->standaloneView->assign('inData', $inData);
189
            $this->standaloneView->assign('fileSelectOptions', $selectOptions);
190
191
            if ($path) {
192
                $this->standaloneView->assign('importPath', sprintf($this->lang->getLL('importdata_fromPathS'), $path->getCombinedIdentifier()));
193
            } else {
194
                $this->standaloneView->assign('importPath', $this->lang->getLL('importdata_no_default_upload_folder'));
195
            }
196
            $this->standaloneView->assign('isAdmin', $beUser->isAdmin());
197
198
            // Upload file:
199
            $tempFolder = $this->getDefaultImportExportFolder();
200
            if ($tempFolder) {
201
                $this->standaloneView->assign('tempFolder', $tempFolder->getCombinedIdentifier());
202
                $this->standaloneView->assign('hasTempUploadFolder', true);
203
                if (GeneralUtility::_POST('_upload')) {
204
                    $this->standaloneView->assign('submitted', GeneralUtility::_POST('_upload'));
205
                    $this->standaloneView->assign('noFileUploaded', $this->fileProcessor->internalUploadMap[1]);
206
                    if ($this->uploadedFiles[0]) {
207
                        $this->standaloneView->assign('uploadedFile', $this->uploadedFiles[0]->getName());
208
                    }
209
                }
210
            }
211
212
            // Perform import or preview depending:
213
            if (isset($inData['file'])) {
214
                $inFile = $this->getFile($inData['file']);
215
                if ($inFile !== null && $inFile->exists()) {
216
                    $this->standaloneView->assign('metaDataInFileExists', true);
217
                    $importInhibitedMessages = [];
218
                    if ($import->loadFile($inFile->getForLocalProcessing(false), 1)) {
219
                        $importInhibitedMessages = $import->checkImportPrerequisites();
220
                        if ($inData['import_file']) {
221
                            if (empty($importInhibitedMessages)) {
222
                                $import->importData($this->id);
223
                                BackendUtility::setUpdateSignal('updatePageTree');
224
                            }
225
                        }
226
                        $import->display_import_pid_record = $this->pageinfo;
227
                        $this->standaloneView->assign('contentOverview', $import->displayContentOverview());
228
                    }
229
                    // Compile messages which are inhibiting a proper import and add them to output.
230
                    if (!empty($importInhibitedMessages)) {
231
                        $flashMessageQueue = GeneralUtility::makeInstance(FlashMessageService::class)->getMessageQueueByIdentifier('impexp.errors');
232
                        foreach ($importInhibitedMessages as $message) {
233
                            $flashMessageQueue->addMessage(GeneralUtility::makeInstance(
234
                                FlashMessage::class,
235
                                $message,
236
                                '',
237
                                FlashMessage::ERROR
238
                            ));
239
                        }
240
                    }
241
                }
242
            }
243
244
            $this->standaloneView->assign('errors', $import->errorLog);
245
        }
246
    }
247
248
    protected function getButtons(): void
249
    {
250
        parent::getButtons();
251
252
        $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
253
        if ($this->id && $this->pageinfo['uid'] ?? false || $this->getBackendUser()->isAdmin() && !$this->id) {
254
            // View
255
            $previewDataAttributes = PreviewUriBuilder::create((int)$this->pageinfo['uid'])
256
                ->withRootLine(BackendUtility::BEgetRootLine($this->pageinfo['uid']))
257
                ->buildDispatcherDataAttributes();
258
            $viewButton = $buttonBar->makeLinkButton()
259
                ->setTitle($this->lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.showPage'))
260
                ->setHref('#')
261
                ->setIcon($this->iconFactory->getIcon('actions-view-page', Icon::SIZE_SMALL))
262
                ->setDataAttributes($previewDataAttributes ?? []);
263
            $buttonBar->addButton($viewButton);
264
        }
265
    }
266
267
    /**
268
     * Check if a file has been uploaded
269
     *
270
     * @throws \TYPO3\CMS\Core\Resource\Exception
271
     */
272
    protected function checkUpload(): void
273
    {
274
        $file = GeneralUtility::_GP('file');
275
        // Initializing:
276
        $this->fileProcessor = GeneralUtility::makeInstance(ExtendedFileUtility::class);
277
        $this->fileProcessor->setActionPermissions();
278
        $conflictMode = empty(GeneralUtility::_GP('overwriteExistingFiles')) ? DuplicationBehavior::__default : DuplicationBehavior::REPLACE;
279
        $this->fileProcessor->setExistingFilesConflictMode(DuplicationBehavior::cast($conflictMode));
280
        $this->fileProcessor->start($file);
281
        $result = $this->fileProcessor->processData();
282
        if (!empty($result['upload'])) {
283
            foreach ($result['upload'] as $uploadedFiles) {
284
                $this->uploadedFiles += $uploadedFiles;
285
            }
286
        }
287
    }
288
289
    /**
290
     * Gets all export files.
291
     *
292
     * @return File[]
293
     * @throws \InvalidArgumentException
294
     */
295
    protected function getExportFiles(): array
296
    {
297
        $exportFiles = [];
298
299
        $folder = $this->getDefaultImportExportFolder();
300
        if ($folder !== null) {
301
302
            /** @var FileExtensionFilter $filter */
303
            $filter = GeneralUtility::makeInstance(FileExtensionFilter::class);
304
            $filter->setAllowedFileExtensions(['t3d', 'xml']);
305
            $folder->getStorage()->addFileAndFolderNameFilter([$filter, 'filterFileList']);
306
307
            $exportFiles = $folder->getFiles();
308
        }
309
310
        return $exportFiles;
311
    }
312
313
    /**
314
     * Gets a file by combined identifier.
315
     *
316
     * @param string $combinedIdentifier
317
     * @return File|null
318
     */
319
    protected function getFile(string $combinedIdentifier): ?File
320
    {
321
        try {
322
            $file = GeneralUtility::makeInstance(ResourceFactory::class)->getFileObjectFromCombinedIdentifier($combinedIdentifier);
323
        } catch (\Exception $exception) {
324
            $file = null;
325
        }
326
327
        return $file;
328
    }
329
330
    /**
331
     * @return BackendUserAuthentication
332
     */
333
    protected function getBackendUser(): BackendUserAuthentication
334
    {
335
        return $GLOBALS['BE_USER'];
336
    }
337
}
338