1<?php
2
3/*
4 * This file is part of the TYPO3 CMS project.
5 *
6 * It is free software; you can redistribute it and/or modify it under
7 * the terms of the GNU General Public License, either version 2
8 * of the License, or any later version.
9 *
10 * For the full copyright and license information, please read the
11 * LICENSE.txt file that was distributed with this source code.
12 *
13 * The TYPO3 project - inspiring people to share!
14 */
15
16namespace TYPO3\CMS\Impexp\Controller;
17
18use Psr\Http\Message\ResponseInterface;
19use Psr\Http\Message\ServerRequestInterface;
20use TYPO3\CMS\Backend\Routing\Exception\RouteNotFoundException;
21use TYPO3\CMS\Backend\Routing\UriBuilder;
22use TYPO3\CMS\Backend\Template\ModuleTemplate;
23use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
24use TYPO3\CMS\Core\Http\RedirectResponse;
25use TYPO3\CMS\Core\Imaging\Icon;
26use TYPO3\CMS\Core\Imaging\IconFactory;
27use TYPO3\CMS\Core\Localization\LanguageService;
28use TYPO3\CMS\Core\Resource\Exception;
29use TYPO3\CMS\Core\Resource\Folder;
30use TYPO3\CMS\Core\Type\Bitmask\Permission;
31use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
32use TYPO3\CMS\Core\Utility\GeneralUtility;
33use TYPO3\CMS\Fluid\View\StandaloneView;
34
35/**
36 * Main script class for the Import / Export facility.
37 *
38 * @todo: In TYPO3 v11 this class is about to become an abstract class
39 * @internal this is a TYPO3 Backend controller implementation and not part of TYPO3's Core API.
40 */
41class ImportExportController
42{
43    /**
44     * The integer value of the GET/POST var, 'id'. Used for submodules to the 'Web' module (page id)
45     *
46     * @var int
47     */
48    protected $id;
49
50    /**
51     * Array containing the current page.
52     *
53     * @var array
54     */
55    protected $pageinfo;
56
57    /**
58     * A WHERE clause for selection records from the pages table based on read-permissions of the current backend user.
59     *
60     * @var string
61     */
62    protected $perms_clause;
63
64    /**
65     * @var LanguageService
66     */
67    protected $lang;
68
69    /**
70     * @var IconFactory
71     */
72    protected $iconFactory;
73
74    /**
75     * The name of the module
76     *
77     * @var string
78     */
79    protected $moduleName = 'xMOD_tximpexp';
80
81    /**
82     * ModuleTemplate Container
83     *
84     * @var ModuleTemplate
85     */
86    protected $moduleTemplate;
87
88    /**
89     *  The name of the shortcut for this page
90     *
91     * @var string
92     */
93    protected $shortcutName;
94
95    /**
96     * @var StandaloneView
97     */
98    protected $standaloneView;
99
100    /**
101     * Return URL
102     *
103     * @var string
104     */
105    protected $returnUrl;
106
107    /**
108     * Constructor
109     */
110    public function __construct()
111    {
112        $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
113        $this->moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class);
114
115        $templatePath = ExtensionManagementUtility::extPath('impexp') . 'Resources/Private/';
116
117        $this->standaloneView = GeneralUtility::makeInstance(StandaloneView::class);
118        $this->standaloneView->setTemplateRootPaths([$templatePath . 'Templates/ImportExport/']);
119        $this->standaloneView->setLayoutRootPaths([$templatePath . 'Layouts/']);
120        $this->standaloneView->setPartialRootPaths([$templatePath . 'Partials/']);
121        $this->standaloneView->getRequest()->setControllerExtensionName('impexp');
122
123        $this->id = (int)GeneralUtility::_GP('id');
124        $this->perms_clause = $this->getBackendUser()->getPagePermsClause(Permission::PAGE_SHOW);
125        $this->returnUrl = GeneralUtility::sanitizeLocalUrl(GeneralUtility::_GP('returnUrl'));
126        $this->lang = $this->getLanguageService();
127    }
128
129    /**
130     * Injects the request object for the current request and gathers all data
131     *
132     * IMPORTING DATA:
133     *
134     * Incoming array has syntax:
135     * GETvar 'id' = import page id (must be readable)
136     *
137     * file = pointing to filename relative to public web path
138     *
139     * [all relation fields are clear, but not files]
140     * - page-tree is written first
141     * - then remaining pages (to the root of import)
142     * - 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)
143     * - then all internal relations are set and non-existing relations removed, relations to static tables preserved.
144     *
145     * EXPORTING DATA:
146     *
147     * Incoming array has syntax:
148     *
149     * file[] = file
150     * dir[] = dir
151     * list[] = table:pid
152     * record[] = table:uid
153     *
154     * pagetree[id] = (single id)
155     * pagetree[levels]=1,2,3, -1 = currently unpacked tree, -2 = only tables on page
156     * pagetree[tables][]=table/_ALL
157     *
158     * external_ref[tables][]=table/_ALL
159     *
160     * @param ServerRequestInterface $request
161     * @return ResponseInterface
162     * @throws RouteNotFoundException
163     */
164    public function mainAction(ServerRequestInterface $request): ResponseInterface
165    {
166        // @todo: This method will become abstract in TYPO3 v11.
167        trigger_error('Route identifier xMOD_tximpexp is deprecated and will be removed in TYPO3 v11. Consider using tx_impexp_export or tx_impexp_import instead.', E_USER_DEPRECATED);
168
169        $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
170        $inData = GeneralUtility::_GP('tx_impexp');
171        $routeName = 'tx_impexp_export';
172        if ($inData === null || $inData['action'] === 'import') {
173            $routeName = 'tx_impexp_import';
174        }
175        unset($inData['action']);
176        $target = (string)$uriBuilder->buildUriFromRoute($routeName, ['tx_impexp' => $inData]);
177        return new RedirectResponse($target, 308);
178    }
179
180    /**
181     * Create the panel of buttons for submitting the form or otherwise perform operations.
182     */
183    protected function getButtons(): void
184    {
185        $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
186        if ($this->getBackendUser()->mayMakeShortcut()) {
187            $shortcutButton = $buttonBar->makeShortcutButton()
188                ->setGetVariables(['tx_impexp'])
189                ->setDisplayName($this->shortcutName)
190                ->setModuleName($this->moduleName);
191            $buttonBar->addButton($shortcutButton);
192        }
193        // back button
194        if ($this->returnUrl) {
195            $backButton = $buttonBar->makeLinkButton()
196                ->setHref($this->returnUrl)
197                ->setTitle($this->lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.goBack'))
198                ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-view-go-back', Icon::SIZE_SMALL));
199            $buttonBar->addButton($backButton);
200        }
201    }
202
203    /**
204     * Returns a \TYPO3\CMS\Core\Resource\Folder object for saving export files
205     * to the server and is also used for uploading import files.
206     *
207     * @throws \InvalidArgumentException
208     * @return Folder|null
209     */
210    protected function getDefaultImportExportFolder(): ?Folder
211    {
212        $defaultImportExportFolder = null;
213
214        $defaultTemporaryFolder = $this->getBackendUser()->getDefaultUploadTemporaryFolder();
215        if ($defaultTemporaryFolder !== null) {
216            $importExportFolderName = 'importexport';
217            $createFolder = !$defaultTemporaryFolder->hasFolder($importExportFolderName);
218            if ($createFolder === true) {
219                try {
220                    $defaultImportExportFolder = $defaultTemporaryFolder->createFolder($importExportFolderName);
221                } catch (Exception $folderAccessException) {
222                }
223            } else {
224                $defaultImportExportFolder = $defaultTemporaryFolder->getSubfolder($importExportFolderName);
225            }
226        }
227
228        return $defaultImportExportFolder;
229    }
230
231    /**
232     * @return BackendUserAuthentication
233     */
234    protected function getBackendUser(): BackendUserAuthentication
235    {
236        return $GLOBALS['BE_USER'];
237    }
238
239    /**
240     * @return LanguageService
241     */
242    protected function getLanguageService(): LanguageService
243    {
244        return $GLOBALS['LANG'];
245    }
246}
247