7be46e087f895ea97aa1e6df6ecf0abd963af0c5
[Packages/TYPO3.CMS.git] / typo3 / sysext / extensionmanager / Classes / Utility / Repository / Helper.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2010 Marcus Krause <marcus#exp2010@t3sec.info>
6 * Steffen Kamper <info@sk-typo3.de>
7 * All rights reserved
8 *
9 * This script is part of the TYPO3 project. The TYPO3 project is
10 * free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * The GNU General Public License can be found at
16 * http://www.gnu.org/copyleft/gpl.html.
17 *
18 * This script is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * This copyright notice MUST APPEAR in all copies of the script!
24 ***************************************************************/
25
26 /**
27 * Central utility class for repository handling.
28 *
29 * @author Marcus Krause <marcus#exp2010@t3sec.info>
30 * @author Steffen Kamper <info@sk-typo3.de>
31 *
32 * @package Extension Manager
33 * @subpackage Utility/Repository
34 */
35 class Tx_Extensionmanager_Utility_Repository_Helper implements t3lib_Singleton {
36
37 /**
38 * ##########################################
39 * Problem constants - to be used in bitmasks
40 * ##########################################
41 */
42 /**
43 * Type of problem: extension file not existing in file system.
44 *
45 * @var integer
46 */
47 const PROBLEM_EXTENSION_FILE_NOT_EXISTING = 1;
48
49 /**
50 * Type of problem: wrong hash indicates outdated extension file.
51 *
52 * @var integer
53 */
54 const PROBLEM_EXTENSION_HASH_CHANGED = 2;
55
56 /**
57 * Type of problem: no version records in database.
58 *
59 * @var integer
60 */
61 const PROBLEM_NO_VERSIONS_IN_DATABASE = 4;
62
63 /**
64 * Keeps instance of repository class.
65 *
66 * @var Tx_Extensionmanager_Domain_Model_Repository
67 */
68 protected $repository = NULL;
69
70 /**
71 * @var Tx_Extensionmanager_Domain_Repository_RepositoryRepository
72 */
73 protected $repositoryRepository;
74
75 /**
76 * @var Tx_Extensionmanager_Domain_Repository_ExtensionRepository
77 */
78 protected $extensionRepository;
79
80 /**
81 * Class constructor.
82 *
83 * @access public
84 */
85 public function __construct() {
86 /** @var $objectManager Tx_Extbase_Object_ObjectManager */
87 $this->objectManager = t3lib_div::makeInstance('Tx_Extbase_Object_ObjectManager');
88 $repositoryRepository = $this->objectManager->get('Tx_Extensionmanager_Domain_Repository_RepositoryRepository');
89 $this->extensionRepository = $this->objectManager->get('Tx_Extensionmanager_Domain_Repository_ExtensionRepository');
90 $repository = $repositoryRepository->findByUid(1);
91 $this->setRepository($repository);
92 }
93
94
95 /**
96 * Method registers required repository instance to work with.
97 *
98 * Repository instance is passed by reference.
99 *
100 * @access public
101 * @param Tx_Extensionmanager_Domain_Model_Repository $repository
102 * @return void
103 * @see $repository
104 */
105 public function setRepository(Tx_Extensionmanager_Domain_Model_Repository $repository) {
106 $this->repository = $repository;
107 }
108
109 /**
110 * Method fetches extension 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 fetchExtListFile() {
119 $this->fetchFile($this->getRemoteExtListFile(), $this->getLocalExtListFile());
120 }
121
122 /**
123 * Method fetches mirror list file from remote server.
124 *
125 * Delegates to {@link fetchFile()}.
126 *
127 * @access public
128 * @return void
129 * @see fetchFile()
130 */
131 public function fetchMirrorListFile() {
132 $this->fetchFile($this->getRemoteMirrorListFile(), $this->getLocalMirrorListFile());
133 }
134
135 /**
136 * Method fetches contents from remote server and
137 * writes them into a file in the local file system.
138 *
139 * @param string $remoteResource remote resource to read contents from
140 * @param string $localResource local resource (absolute file path) to store retrieved contents to
141 * @return void
142 * @see t3lib_div::getUrl(), t3lib_div::writeFile()
143 * @throws Tx_Extensionmanager_Exception_ExtensionManager
144 */
145 protected function fetchFile($remoteResource, $localResource) {
146 if (is_string($remoteResource) && is_string($localResource)
147 && !empty($remoteResource) && !empty($localResource)
148 ) {
149 $fileContent = t3lib_div::getUrl($remoteResource, 0, array(TYPO3_user_agent));
150 if ($fileContent !== FALSE) {
151 if (t3lib_div::writeFile($localResource, $fileContent) === FALSE) {
152 throw new Tx_Extensionmanager_Exception_ExtensionManager(
153 sprintf('Could not write to file %s.', htmlspecialchars($localResource)),
154 1342635378
155 );
156 }
157 } else {
158 throw new Tx_Extensionmanager_Exception_ExtensionManager(
159 sprintf('Could not access remote resource %s.', htmlspecialchars($remoteResource)),
160 1342635425
161 );
162 }
163 }
164 }
165
166 /**
167 * Method returns location of local extension list file.
168 *
169 * @access public
170 * @return string local location of file
171 * @see getRemoteExtListFile()
172 */
173 public function getLocalExtListFile() {
174 $absFilePath = PATH_site . 'typo3temp/' .
175 intval($this->repository->getUid()) .
176 '.extensions.xml.gz';
177 return $absFilePath;
178 }
179
180 /**
181 * Method returns location of remote extension list file.
182 *
183 * @access public
184 * @return string remote location of file
185 * @see getLocalExtListFile()
186 */
187 public function getRemoteExtListFile() {
188 $mirror = $this->getMirrors(TRUE)->getMirror();
189 $filePath = 'http://' . $mirror['host'] . $mirror['path'] .
190 'extensions.xml.gz';
191 return $filePath;
192 }
193
194 /**
195 * Method returns location of remote file containing
196 * the extension checksum hash.
197 *
198 * @access public
199 * @return string remote location of file
200 */
201 public function getRemoteExtHashFile() {
202 $mirror = $this->getMirrors(TRUE)->getMirror();
203 $filePath = 'http://' . $mirror['host'] . $mirror['path'] .
204 'extensions.md5';
205 return $filePath;
206 }
207
208 /**
209 * Method returns location of local mirror list file.
210 *
211 * @access public
212 * @return string local location of file
213 * @see getRemoteMirrorListFile()
214 */
215 public function getLocalMirrorListFile() {
216 $absFilePath = PATH_site . 'typo3temp/' .
217 intval($this->repository->getUid()) .
218 '.mirrors.xml.gz';
219 return $absFilePath;
220 }
221
222 /**
223 * Method returns location of remote mirror list file.
224 *
225 * @access public
226 * @return string remote location of file
227 * @see getLocalMirrorListFile()
228 */
229 public function getRemoteMirrorListFile() {
230 $filePath = $this->repository->getMirrorListUrl();
231 return $filePath;
232 }
233
234 /**
235 * Method returns available mirrors for registered repository.
236 *
237 * If there are no mirrors registered to the repository,
238 * the method will retrieve them from file system or remote
239 * server.
240 *
241 * @access public
242 * @param boolean $forcedUpdateFromRemote if boolean TRUE, mirror configuration will always retrieved from remote server
243 * @return Tx_Extensionmanager_Domain_Model_Mirrors instance of repository mirrors class
244 */
245 public function getMirrors($forcedUpdateFromRemote = TRUE) {
246 $assignedMirror = $this->repository->getMirrors();
247 if ($forcedUpdateFromRemote || is_null($assignedMirror) || !is_object($assignedMirror)) {
248 if ($forcedUpdateFromRemote || !is_file($this->getLocalMirrorListFile())) {
249 $this->fetchMirrorListFile();
250 }
251 /** @var $objMirrorListImporter Tx_Extensionmanager_Utility_Importer_MirrorList */
252 $objMirrorListImporter = t3lib_div::makeInstance('Tx_Extensionmanager_Utility_Importer_MirrorList');
253 $this->repository->addMirrors($objMirrorListImporter->getMirrors($this->getLocalMirrorListFile()));
254 }
255 return $this->repository->getMirrors();
256 }
257
258 /**
259 * Method returns information if currently available
260 * extension list might be outdated.
261 *
262 * @access public
263 * @see Tx_Extensionmanager_Utility_Repository_Helper::PROBLEM_NO_VERSIONS_IN_DATABASE,
264 * Tx_Extensionmanager_Utility_Repository_Helper::PROBLEM_EXTENSION_FILE_NOT_EXISTING,
265 * Tx_Extensionmanager_Utility_Repository_Helper::PROBLEM_EXTENSION_HASH_CHANGED
266 * @throws Tx_Extensionmanager_Exception_ExtensionManager
267 * @return integer "0" if everything is perfect, otherwise bitmask with problems
268 */
269 public function isExtListUpdateNecessary() {
270 $updateNecessity = 0;
271
272 if ($this->extensionRepository->countByRepository($this->repository->getUid()) <= 0) {
273 $updateNecessity |= self::PROBLEM_NO_VERSIONS_IN_DATABASE;
274 }
275
276 if (!is_file($this->getLocalExtListFile())) {
277 $updateNecessity |= self::PROBLEM_EXTENSION_FILE_NOT_EXISTING;
278 } else {
279 $remotemd5 = t3lib_div::getUrl($this->getRemoteExtHashFile(), 0, array(TYPO3_user_agent));
280
281 if ($remotemd5 !== FALSE) {
282 $localmd5 = md5_file($this->getLocalExtListFile());
283 if ($remotemd5 !== $localmd5) {
284 $updateNecessity |= self::PROBLEM_EXTENSION_HASH_CHANGED;
285 }
286 } else {
287 throw new Tx_Extensionmanager_Exception_ExtensionManager(
288 'Could not retrieve extension hash file from remote server.',
289 1342635016
290 );
291 }
292 }
293 return $updateNecessity;
294 }
295
296 /**
297 * Method updates TYPO3 database with up-to-date
298 * extension version records.
299 *
300 * @return boolean TRUE if the extension list was successfully update, FALSE if no update necessary
301 * @see isExtListUpdateNecessary()
302 */
303 public function updateExtList() {
304 $updated = FALSE;
305 $updateNecessity = $this->isExtListUpdateNecessary();
306
307 if ($updateNecessity !== 0) {
308 // retrieval of file necessary
309 $tmpBitmask = (self::PROBLEM_EXTENSION_FILE_NOT_EXISTING | self::PROBLEM_EXTENSION_HASH_CHANGED);
310 if (($tmpBitmask & $updateNecessity) > 0) {
311 $this->fetchExtListFile();
312 $updateNecessity &= ~$tmpBitmask;
313 }
314
315 // database table cleanup
316 if (($updateNecessity & self::PROBLEM_NO_VERSIONS_IN_DATABASE)) {
317 $updateNecessity &= ~self::PROBLEM_NO_VERSIONS_IN_DATABASE;
318 } else {
319 // using straight sql here as extbases "remove" runs into memory problems
320 $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_extensions', 'repository=' . $this->repository->getUid());
321 }
322
323 // no further problems - start of import process
324 if ($updateNecessity === 0) {
325 $uid = $this->repository->getUid();
326 /* @var $objExtListImporter Tx_Extensionmanager_Utility_Importer_ExtensionList */
327 $objExtListImporter = $this->objectManager->get('Tx_Extensionmanager_Utility_Importer_ExtensionList');
328 $objExtListImporter->import($this->getLocalExtListFile(), $uid);
329 $updated = TRUE;
330 }
331 }
332 return $updated;
333 }
334 }
335
336 ?>