[TASK] Use fully qualified name resolution in PHP 5.5
[Packages/TYPO3.CMS.git] / typo3 / sysext / extensionmanager / Classes / Utility / Repository / Helper.php
1 <?php
2 namespace TYPO3\CMS\Extensionmanager\Utility\Repository;
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 * Central utility class for repository handling.
18 *
19 * @author Marcus Krause <marcus#exp2010@t3sec.info>
20 * @author Steffen Kamper <info@sk-typo3.de>
21 */
22 class Helper implements \TYPO3\CMS\Core\SingletonInterface {
23
24 /**
25 * ##########################################
26 * Problem constants - to be used in bitmasks
27 * ##########################################
28 */
29 /**
30 * Type of problem: extension file not existing in file system.
31 *
32 * @var int
33 */
34 const PROBLEM_EXTENSION_FILE_NOT_EXISTING = 1;
35 /**
36 * Type of problem: wrong hash indicates outdated extension file.
37 *
38 * @var int
39 */
40 const PROBLEM_EXTENSION_HASH_CHANGED = 2;
41 /**
42 * Type of problem: no version records in database.
43 *
44 * @var int
45 */
46 const PROBLEM_NO_VERSIONS_IN_DATABASE = 4;
47 /**
48 * Keeps instance of repository class.
49 *
50 * @var \TYPO3\CMS\Extensionmanager\Domain\Model\Repository
51 */
52 protected $repository = NULL;
53
54 /**
55 * @var \TYPO3\CMS\Extensionmanager\Domain\Repository\RepositoryRepository
56 */
57 protected $repositoryRepository;
58
59 /**
60 * @var \TYPO3\CMS\Extensionmanager\Domain\Repository\ExtensionRepository
61 */
62 protected $extensionRepository;
63
64 /**
65 * Class constructor.
66 *
67 * @access public
68 */
69 public function __construct() {
70 /** @var $objectManager \TYPO3\CMS\Extbase\Object\ObjectManager */
71 $this->objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Object\ObjectManager::class);
72 /** @var \TYPO3\CMS\Extensionmanager\Domain\Repository\RepositoryRepository $repositoryRepository */
73 $repositoryRepository = $this->objectManager->get(\TYPO3\CMS\Extensionmanager\Domain\Repository\RepositoryRepository::class);
74 $this->extensionRepository = $this->objectManager->get(\TYPO3\CMS\Extensionmanager\Domain\Repository\ExtensionRepository::class);
75 /** @var \TYPO3\CMS\Extensionmanager\Domain\Model\Repository $repository */
76 $repository = $repositoryRepository->findByUid(1);
77 if (is_object($repository)) {
78 $this->setRepository($repository);
79 }
80 }
81
82 /**
83 * Method registers required repository instance to work with.
84 *
85 * Repository instance is passed by reference.
86 *
87 * @access public
88 * @param \TYPO3\CMS\Extensionmanager\Domain\Model\Repository $repository
89 * @return void
90 * @see $repository
91 */
92 public function setRepository(\TYPO3\CMS\Extensionmanager\Domain\Model\Repository $repository) {
93 $this->repository = $repository;
94 }
95
96 /**
97 * Method fetches extension list file from remote server.
98 *
99 * Delegates to {@link fetchFile()}.
100 *
101 * @access public
102 * @return void
103 * @see fetchFile()
104 */
105 public function fetchExtListFile() {
106 $this->fetchFile($this->getRemoteExtListFile(), $this->getLocalExtListFile());
107 }
108
109 /**
110 * Method fetches mirror list file from remote server.
111 *
112 * Delegates to {@link fetchFile()}.
113 *
114 * @access public
115 * @return void
116 * @see fetchFile()
117 */
118 public function fetchMirrorListFile() {
119 $this->fetchFile($this->getRemoteMirrorListFile(), $this->getLocalMirrorListFile());
120 }
121
122 /**
123 * Method fetches contents from remote server and
124 * writes them into a file in the local file system.
125 *
126 * @param string $remoteResource remote resource to read contents from
127 * @param string $localResource local resource (absolute file path) to store retrieved contents to
128 * @return void
129 * @see \TYPO3\CMS\Core\Utility\GeneralUtility::getUrl(), \TYPO3\CMS\Core\Utility\GeneralUtility::writeFile()
130 * @throws \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException
131 */
132 protected function fetchFile($remoteResource, $localResource) {
133 if (is_string($remoteResource) && is_string($localResource) && !empty($remoteResource) && !empty($localResource)) {
134 $fileContent = \TYPO3\CMS\Core\Utility\GeneralUtility::getUrl($remoteResource, 0, array(TYPO3_user_agent));
135 if ($fileContent !== FALSE) {
136 if (\TYPO3\CMS\Core\Utility\GeneralUtility::writeFile($localResource, $fileContent) === FALSE) {
137 throw new \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException(sprintf('Could not write to file %s.', htmlspecialchars($localResource)), 1342635378);
138 }
139 } else {
140 throw new \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException(sprintf('Could not access remote resource %s.', htmlspecialchars($remoteResource)), 1342635425);
141 }
142 }
143 }
144
145 /**
146 * Method returns location of local extension list file.
147 *
148 * @access public
149 * @return string local location of file
150 * @see getRemoteExtListFile()
151 */
152 public function getLocalExtListFile() {
153 $absFilePath = PATH_site . 'typo3temp/' . (int)$this->repository->getUid() . '.extensions.xml.gz';
154 return $absFilePath;
155 }
156
157 /**
158 * Method returns location of remote extension list file.
159 *
160 * @access public
161 * @return string remote location of file
162 * @see getLocalExtListFile()
163 */
164 public function getRemoteExtListFile() {
165 $mirror = $this->getMirrors(TRUE)->getMirror();
166 $filePath = 'http://' . $mirror['host'] . $mirror['path'] . 'extensions.xml.gz';
167 return $filePath;
168 }
169
170 /**
171 * Method returns location of remote file containing
172 * the extension checksum hash.
173 *
174 * @access public
175 * @return string remote location of file
176 */
177 public function getRemoteExtHashFile() {
178 $mirror = $this->getMirrors(TRUE)->getMirror();
179 $filePath = 'http://' . $mirror['host'] . $mirror['path'] . 'extensions.md5';
180 return $filePath;
181 }
182
183 /**
184 * Method returns location of local mirror list file.
185 *
186 * @access public
187 * @return string local location of file
188 * @see getRemoteMirrorListFile()
189 */
190 public function getLocalMirrorListFile() {
191 $absFilePath = PATH_site . 'typo3temp/' . (int)$this->repository->getUid() . '.mirrors.xml.gz';
192 return $absFilePath;
193 }
194
195 /**
196 * Method returns location of remote mirror list file.
197 *
198 * @access public
199 * @return string remote location of file
200 * @see getLocalMirrorListFile()
201 */
202 public function getRemoteMirrorListFile() {
203 $filePath = $this->repository->getMirrorListUrl();
204 return $filePath;
205 }
206
207 /**
208 * Method returns available mirrors for registered repository.
209 *
210 * If there are no mirrors registered to the repository,
211 * the method will retrieve them from file system or remote
212 * server.
213 *
214 * @access public
215 * @param bool $forcedUpdateFromRemote if boolean TRUE, mirror configuration will always retrieved from remote server
216 * @return \TYPO3\CMS\Extensionmanager\Domain\Model\Mirrors instance of repository mirrors class
217 */
218 public function getMirrors($forcedUpdateFromRemote = TRUE) {
219 $assignedMirror = $this->repository->getMirrors();
220 if ($forcedUpdateFromRemote || is_null($assignedMirror) || !is_object($assignedMirror)) {
221 if ($forcedUpdateFromRemote || !is_file($this->getLocalMirrorListFile())) {
222 $this->fetchMirrorListFile();
223 }
224 /** @var $objMirrorListImporter \TYPO3\CMS\Extensionmanager\Utility\Importer\MirrorListUtility */
225 $objMirrorListImporter = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extensionmanager\Utility\Importer\MirrorListUtility::class);
226 $this->repository->addMirrors($objMirrorListImporter->getMirrors($this->getLocalMirrorListFile()));
227 }
228 return $this->repository->getMirrors();
229 }
230
231 /**
232 * Method returns information if currently available
233 * extension list might be outdated.
234 *
235 * @access public
236 * @see Tx_Extensionmanager_Utility_Repository_Helper::PROBLEM_NO_VERSIONS_IN_DATABASE,
237 * @throws \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException
238 * @return int "0" if everything is perfect, otherwise bitmask with problems
239 */
240 public function isExtListUpdateNecessary() {
241 $updateNecessity = 0;
242 if ($this->extensionRepository->countByRepository($this->repository->getUid()) <= 0) {
243 $updateNecessity |= self::PROBLEM_NO_VERSIONS_IN_DATABASE;
244 }
245 if (!is_file($this->getLocalExtListFile())) {
246 $updateNecessity |= self::PROBLEM_EXTENSION_FILE_NOT_EXISTING;
247 } else {
248 $remotemd5 = \TYPO3\CMS\Core\Utility\GeneralUtility::getUrl($this->getRemoteExtHashFile(), 0, array(TYPO3_user_agent));
249 if ($remotemd5 !== FALSE) {
250 $localmd5 = md5_file($this->getLocalExtListFile());
251 if ($remotemd5 !== $localmd5) {
252 $updateNecessity |= self::PROBLEM_EXTENSION_HASH_CHANGED;
253 }
254 } else {
255 throw new \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException('Could not retrieve extension hash file from remote server.', 1342635016);
256 }
257 }
258 return $updateNecessity;
259 }
260
261 /**
262 * Method updates TYPO3 database with up-to-date
263 * extension version records.
264 *
265 * @return bool TRUE if the extension list was successfully update, FALSE if no update necessary
266 * @see isExtListUpdateNecessary()
267 */
268 public function updateExtList() {
269 $updated = FALSE;
270 $updateNecessity = $this->isExtListUpdateNecessary();
271 if ($updateNecessity !== 0) {
272 // retrieval of file necessary
273 $tmpBitmask = self::PROBLEM_EXTENSION_FILE_NOT_EXISTING | self::PROBLEM_EXTENSION_HASH_CHANGED;
274 if (($tmpBitmask & $updateNecessity) > 0) {
275 $this->fetchExtListFile();
276 $updateNecessity &= ~$tmpBitmask;
277 }
278 // database table cleanup
279 if ($updateNecessity & self::PROBLEM_NO_VERSIONS_IN_DATABASE) {
280 $updateNecessity &= ~self::PROBLEM_NO_VERSIONS_IN_DATABASE;
281 } else {
282 // Use straight query as extbase "remove" is too slow here
283 // This truncates the whole table. It would be more correct to remove only rows of a specific
284 // repository, but multiple repository handling is not implemented, and truncate is quicker.
285 $this->getDatabaseConnection()->exec_TRUNCATEquery('tx_extensionmanager_domain_model_extension');
286 }
287 // no further problems - start of import process
288 if ($updateNecessity === 0) {
289 $uid = $this->repository->getUid();
290 /* @var $objExtListImporter \TYPO3\CMS\Extensionmanager\Utility\Importer\ExtensionListUtility */
291 $objExtListImporter = $this->objectManager->get(\TYPO3\CMS\Extensionmanager\Utility\Importer\ExtensionListUtility::class);
292 $objExtListImporter->import($this->getLocalExtListFile(), $uid);
293 $updated = TRUE;
294 }
295 }
296 return $updated;
297 }
298
299 /**
300 * Get database connection
301 *
302 * @return \TYPO3\CMS\Core\Database\DatabaseConnection
303 */
304 protected function getDatabaseConnection() {
305 return $GLOBALS['TYPO3_DB'];
306 }
307
308 }