Cleanup: Updated copyright comments
[Packages/TYPO3.CMS.git] / typo3 / sysext / em / classes / repository / class.tx_em_repository_utility.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2010-2011 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 * class.tx_em_repository_utility.php
27 *
28 * Module: Extension manager - Central repository utility functions
29 *
30 * $Id: class.tx_em_repository_utility.php 2082 2010-03-21 17:19:42Z steffenk $
31 *
32 * @author Marcus Krause <marcus#exp2010@t3sec.info>
33 * @author Steffen Kamper <info@sk-typo3.de>
34 */
35
36
37 /**
38 * Central utility class for repository handling.
39 *
40 * @author Marcus Krause <marcus#exp2010@t3sec.info>
41 * @author Steffen Kamper <info@sk-typo3.de>
42 *
43 * @since 2010-02-18
44 * @package TYPO3
45 * @subpackage EM
46 */
47 class tx_em_Repository_Utility implements t3lib_Singleton {
48
49
50 /**
51 * ##########################################
52 * Problem constants - to be used in bitmasks
53 * ##########################################
54 */
55 /**
56 * Type of problem: extension file not existing in file system.
57 *
58 * @var integer
59 */
60 const PROBLEM_EXTENSION_FILE_NOT_EXISTING = 1;
61
62 /**
63 * Type of problem: wrong hash indicates outdated extension file.
64 *
65 * @var integer
66 */
67 const PROBLEM_EXTENSION_HASH_CHANGED = 2;
68
69 /**
70 * Type of problem: no version records in database.
71 *
72 * @var integer
73 */
74 const PROBLEM_NO_VERSIONS_IN_DATABASE = 4;
75
76
77 /**
78 * Keeps instance of repository class.
79 *
80 * @var em_repository
81 */
82 protected $repository = NULL;
83
84
85 /**
86 * Class constructor.
87 *
88 * @access public
89 * @param object &$repository (optional) instance of {@link em_repository repository} class
90 * @return void
91 */
92 function __construct(&$repository = NULL) {
93 if ($repository !== NULL && is_object($repository)
94 && $repository instanceof tx_em_Repository) {
95 $this->setRepository($repository);
96 }
97 }
98
99 /**
100 * Method provides a wrapper for throwing an exception.
101 *
102 * @access protected
103 * @see tx_em_ConnectionException
104 * @param string $message the exception message to throw.
105 * @param integer $code the exception code.
106 * @return void
107 */
108 protected function throwConnectionException($message = "", $code = 0) {
109 throw new tx_em_ConnectionException(get_class($this) . ': ' . $message, $code);
110 }
111
112 /**
113 * Method registers required repository instance to work with.
114 *
115 * Repository instance is passed by reference.
116 *
117 * @access public
118 * @param em_repository &$repository instance of {@link em_repository repository} class
119 * @return void
120 * @see $repository
121 */
122 public function setRepository(tx_em_Repository &$repository) {
123 $this->repository = $repository;
124 }
125
126 /**
127 * Method fetches extension list file from remote server.
128 *
129 * Delegates to {@link fetchFile()}.
130 *
131 * @access public
132 * @return void
133 * @see fetchFile()
134 */
135 public function fetchExtListFile() {
136 $this->fetchFile($this->getRemoteExtListFile(), $this->getLocalExtListFile());
137 }
138
139 /**
140 * Method fetches mirror list file from remote server.
141 *
142 * Delegates to {@link fetchFile()}.
143 *
144 * @access public
145 * @return void
146 * @see fetchFile()
147 */
148 public function fetchMirrorListFile() {
149 $this->fetchFile($this->getRemoteMirrorListFile(), $this->getLocalMirrorListFile());
150 }
151
152 /**
153 * Method fetches contents from remote server and
154 * writes them into a file in the local file system.
155 *
156 * @access protected
157 * @param string $remoteRessource remote ressource to read contents from
158 * @param string $localRessource local ressource (absolute file path) to store retrieved contents to
159 * @return void
160 * @see t3lib_div::getURL(), t3lib_div::writeFile()
161 * @throws tx_em_ConnectionException
162 */
163 protected function fetchFile($remoteRessource, $localRessource) {
164 if (is_string($remoteRessource) && is_string($localRessource)
165 && !empty($remoteRessource) && !empty($localRessource)) {
166 $fileContent = t3lib_div::getURL($remoteRessource, 0, array(TYPO3_user_agent));
167 if ($fileContent !== false) {
168 t3lib_div::writeFile($localRessource, $fileContent) || $this->throwConnectionException(sprintf('Could not write to file %s.', htmlspecialchars($localRessource)));
169 } else {
170 $this->throwConnectionException(sprintf('Could not access remote ressource %s.', htmlspecialchars($remoteRessource)));
171 }
172 }
173 }
174
175 /**
176 * Method returns location of local extension list file.
177 *
178 * @access public
179 * @return string local location of file
180 * @see getRemoteExtListFile()
181 */
182 public function getLocalExtListFile() {
183 $absFilePath = PATH_site . 'typo3temp/'
184 . intval($this->repository->getId())
185 . '.extensions.xml.gz';
186 return $absFilePath;
187 }
188
189 /**
190 * Method returns location of remote extension list file.
191 *
192 * @access public
193 * @return string remote location of file
194 * @see getLocalExtListFile()
195 */
196 public function getRemoteExtListFile() {
197 $mirror = $this->getMirrors(TRUE)->getMirror();
198 $filePath = 'http://' . $mirror['host'] . $mirror['path']
199 . 'extensions.xml.gz';
200 return $filePath;
201 }
202
203 /**
204 * Method returns location of remote file containing
205 * the extension checksum hash.
206 *
207 * @access public
208 * @return string remote location of file
209 */
210 public function getRemoteExtHashFile() {
211 $mirror = $this->getMirrors(TRUE)->getMirror();
212 $filePath = 'http://' . $mirror['host'] . $mirror['path']
213 . 'extensions.md5';
214 return $filePath;
215 }
216
217 /**
218 * Method returns location of local mirror list file.
219 *
220 * @access public
221 * @return string local location of file
222 * @see getRemoteMirrorListFile()
223 */
224 public function getLocalMirrorListFile() {
225 $absFilePath = PATH_site . 'typo3temp/'
226 . intval($this->repository->getId())
227 . '.mirrors.xml.gz';
228 return $absFilePath;
229 }
230
231 /**
232 * Method returns location of remote mirror list file.
233 *
234 * @access public
235 * @return string remote location of file
236 * @see getLocalMirrorListFile()
237 */
238 public function getRemoteMirrorListFile() {
239 $filePath = $this->repository->getMirrorListUrl();
240 return $filePath;
241 }
242
243 /**
244 * Method returns available mirrors for registered repository.
245 *
246 * If there are no mirrors registered to the repository,
247 * the method will retrieve them from file system or remote
248 * server.
249 *
250 * @access public
251 * @param boolean $forcedUpdateFromRemote if boolean true, mirror configuration will always retrieved from remote server
252 * @return em_repository_mirrors instance of repository mirrors class
253 */
254 public function getMirrors($forcedUpdateFromRemote = TRUE) {
255 $assignedMirror = $this->repository->getMirrors();
256 if ($forcedUpdateFromRemote || is_null($assignedMirror) || !is_object($assignedMirror)) {
257 if ($forcedUpdateFromRemote || !is_file($this->getLocalMirrorListFile())) {
258 $this->fetchMirrorListFile();
259 }
260 $objMirrorListImporter = t3lib_div::makeInstance('tx_em_Import_MirrorListImporter');
261 $this->repository->addMirrors($objMirrorListImporter->getMirrors($this->getLocalMirrorListFile()));
262 }
263 return $this->repository->getMirrors();
264 }
265
266 /**
267 * Method returns information if currently available
268 * extension list might be outdated.
269 *
270 * @access public
271 * @see em_repository_utility::PROBLEM_NO_VERSIONS_IN_DATABASE,
272 * em_repository_utility::PROBLEM_EXTENSION_FILE_NOT_EXISTING,
273 * em_repository_utility::PROBLEM_EXTENSION_HASH_CHANGED
274 * @return integer integer "0" if everything is perfect, otherwise bitmask with occured problems
275 * @see updateExtList()
276 */
277 public function isExtListUpdateNecessary() {
278 $updateNecessity = 0;
279
280 if (tx_em_Database::getExtensionCountFromRepository($this->getRepositoryUID(TRUE)) <= 0) {
281 $updateNecessity |= self::PROBLEM_NO_VERSIONS_IN_DATABASE;
282 }
283
284 if (!is_file($this->getLocalExtListFile())) {
285 $updateNecessity |= self::PROBLEM_EXTENSION_FILE_NOT_EXISTING;
286 } else {
287 $remotemd5 = t3lib_div::getURL($this->getRemoteExtHashFile(), 0, array(TYPO3_user_agent));
288
289 if ($remotemd5 !== false) {
290 $localmd5 = md5_file($this->getLocalExtListFile());
291 if ($remotemd5 !== $localmd5) {
292 $updateNecessity |= self::PROBLEM_EXTENSION_HASH_CHANGED;
293 }
294 } else {
295 $this->throwConnectionException('Could not retrieve extension hash file from remote server.');
296 }
297 }
298 return $updateNecessity;
299 }
300
301 /**
302 * Method returns UID of the current repository.
303 *
304 * @access public
305 * @param boolean $insertIfMissing creates repository record in DB if set to TRUE
306 * @return integer
307 */
308 public function getRepositoryUID($insertIfMissing = FALSE) {
309 $uid = $this->repository->getId();
310 $repository = tx_em_Database::getRepositoryByUID($uid);
311 if (empty($repository) && $insertIfMissing) {
312 $uid = tx_em_Database::insertRepository($this->repository);
313 } else {
314 $uid = intval($repository['uid']);
315 }
316
317 return $uid;
318 }
319
320 /**
321 * Method updates TYPO3 database with up-to-date
322 * extension version records.
323 *
324 * @access public
325 * @param boolean $renderFlashMessage if method should return flashmessage or raw integer
326 * @return mixed either sum of imported extensions or instance of t3lib_FlashMessage
327 * @see isExtListUpdateNecessary()
328 */
329 public function updateExtList($renderFlashMessage = FALSE) {
330
331 if ($renderFlashMessage) {
332 /* @var $flashMessage t3lib_FlashMessage */
333 $flashMessage = t3lib_div::makeInstance('t3lib_FlashMessage',
334 $GLOBALS['LANG']->getLL('ext_import_list_unchanged_header'),
335 $GLOBALS['LANG']->getLL('ext_import_list_unchanged'),
336 t3lib_FlashMessage::INFO
337 );
338 }
339 $sumRecords = 0;
340
341 $updateNecessity = $this->isExtListUpdateNecessary();
342
343 if ($updateNecessity !== 0) {
344 // retrieval of file necessary
345 $tmpBitmask = (self::PROBLEM_EXTENSION_FILE_NOT_EXISTING | self::PROBLEM_EXTENSION_HASH_CHANGED);
346 if (($tmpBitmask & $updateNecessity) > 0) {
347 $this->fetchExtListFile();
348 $updateNecessity &= ~$tmpBitmask;
349 }
350
351 // database table cleanup
352 if (($updateNecessity & self::PROBLEM_NO_VERSIONS_IN_DATABASE)) {
353 $updateNecessity &= ~self::PROBLEM_NO_VERSIONS_IN_DATABASE;
354 } else {
355 $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_extensions', 'repository=' . $this->getRepositoryUID());
356 }
357
358 // no further problems - start of import process
359 if ($updateNecessity === 0) {
360 $uid = $this->getRepositoryUID(TRUE);
361 /* @var $objExtListImporter tx_em_Import_ExtensionListImporter */
362 $objExtListImporter = t3lib_div::makeInstance('tx_em_Import_ExtensionListImporter');
363 $objExtListImporter->import($this->getLocalExtListFile(), $uid);
364 $sumRecords = tx_em_Database::getExtensionCountFromRepository($uid);
365 if ($renderFlashMessage) {
366 $flashMessage->setTitle($GLOBALS['LANG']->getLL('ext_import_extlist_updated_header'));
367 $flashMessage->setMessage(sprintf($GLOBALS['LANG']->getLL('ext_import_extlist_updated'), tx_em_Database::getExtensionCountFromRepository()));
368 $flashMessage->setSeverity(t3lib_FlashMessage::OK);
369 }
370 }
371 }
372 return $renderFlashMessage ? $flashMessage : $sumRecords;
373 }
374 }
375
376 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['typo3/sysext/em/classes/repository/class.tx_em_repository_utility.php'])) {
377 include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['typo3/sysext/em/classes/repository/class.tx_em_repository_utility.php']);
378 }
379
380 ?>