2 /***************************************************************
5 * (c) 2010 Marcus Krause <marcus#exp2010@t3sec.info>
6 * Steffen Kamper <info@sk-typo3.de>
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.
15 * The GNU General Public License can be found at
16 * http://www.gnu.org/copyleft/gpl.html.
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.
23 * This copyright notice MUST APPEAR in all copies of the script!
24 ***************************************************************/
27 * Central utility class for repository handling.
29 * @author Marcus Krause <marcus#exp2010@t3sec.info>
30 * @author Steffen Kamper <info@sk-typo3.de>
32 * @package Extension Manager
33 * @subpackage Utility/Repository
35 class Tx_Extensionmanager_Utility_Repository_Helper
implements t3lib_Singleton
{
38 * ##########################################
39 * Problem constants - to be used in bitmasks
40 * ##########################################
43 * Type of problem: extension file not existing in file system.
47 const PROBLEM_EXTENSION_FILE_NOT_EXISTING
= 1;
50 * Type of problem: wrong hash indicates outdated extension file.
54 const PROBLEM_EXTENSION_HASH_CHANGED
= 2;
57 * Type of problem: no version records in database.
61 const PROBLEM_NO_VERSIONS_IN_DATABASE
= 4;
64 * Keeps instance of repository class.
66 * @var Tx_Extensionmanager_Domain_Model_Repository
68 protected $repository = NULL;
71 * @var Tx_Extensionmanager_Domain_Repository_RepositoryRepository
73 protected $repositoryRepository;
76 * @var Tx_Extensionmanager_Domain_Repository_ExtensionRepository
78 protected $extensionRepository;
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);
96 * Method registers required repository instance to work with.
98 * Repository instance is passed by reference.
101 * @param Tx_Extensionmanager_Domain_Model_Repository $repository
105 public function setRepository(Tx_Extensionmanager_Domain_Model_Repository
$repository) {
106 $this->repository
= $repository;
110 * Method fetches extension list file from remote server.
112 * Delegates to {@link fetchFile()}.
118 public function fetchExtListFile() {
119 $this->fetchFile($this->getRemoteExtListFile(), $this->getLocalExtListFile());
123 * Method fetches mirror list file from remote server.
125 * Delegates to {@link fetchFile()}.
131 public function fetchMirrorListFile() {
132 $this->fetchFile($this->getRemoteMirrorListFile(), $this->getLocalMirrorListFile());
136 * Method fetches contents from remote server and
137 * writes them into a file in the local file system.
139 * @param string $remoteResource remote resource to read contents from
140 * @param string $localResource local resource (absolute file path) to store retrieved contents to
142 * @see t3lib_div::getUrl(), t3lib_div::writeFile()
143 * @throws Tx_Extensionmanager_Exception_ExtensionManager
145 protected function fetchFile($remoteResource, $localResource) {
146 if (is_string($remoteResource) && is_string($localResource)
147 && !empty($remoteResource) && !empty($localResource)
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)),
158 throw new Tx_Extensionmanager_Exception_ExtensionManager(
159 sprintf('Could not access remote resource %s.', htmlspecialchars($remoteResource)),
167 * Method returns location of local extension list file.
170 * @return string local location of file
171 * @see getRemoteExtListFile()
173 public function getLocalExtListFile() {
174 $absFilePath = PATH_site
. 'typo3temp/' .
175 intval($this->repository
->getUid()) .
176 '.extensions.xml.gz';
181 * Method returns location of remote extension list file.
184 * @return string remote location of file
185 * @see getLocalExtListFile()
187 public function getRemoteExtListFile() {
188 $mirror = $this->getMirrors(TRUE)->getMirror();
189 $filePath = 'http://' . $mirror['host'] . $mirror['path'] .
195 * Method returns location of remote file containing
196 * the extension checksum hash.
199 * @return string remote location of file
201 public function getRemoteExtHashFile() {
202 $mirror = $this->getMirrors(TRUE)->getMirror();
203 $filePath = 'http://' . $mirror['host'] . $mirror['path'] .
209 * Method returns location of local mirror list file.
212 * @return string local location of file
213 * @see getRemoteMirrorListFile()
215 public function getLocalMirrorListFile() {
216 $absFilePath = PATH_site
. 'typo3temp/' .
217 intval($this->repository
->getUid()) .
223 * Method returns location of remote mirror list file.
226 * @return string remote location of file
227 * @see getLocalMirrorListFile()
229 public function getRemoteMirrorListFile() {
230 $filePath = $this->repository
->getMirrorListUrl();
235 * Method returns available mirrors for registered repository.
237 * If there are no mirrors registered to the repository,
238 * the method will retrieve them from file system or remote
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
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();
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()));
255 return $this->repository
->getMirrors();
259 * Method returns information if currently available
260 * extension list might be outdated.
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
269 public function isExtListUpdateNecessary() {
270 $updateNecessity = 0;
272 if ($this->extensionRepository
->countByRepository($this->repository
->getUid()) <= 0) {
273 $updateNecessity |
= self
::PROBLEM_NO_VERSIONS_IN_DATABASE
;
276 if (!is_file($this->getLocalExtListFile())) {
277 $updateNecessity |
= self
::PROBLEM_EXTENSION_FILE_NOT_EXISTING
;
279 $remotemd5 = t3lib_div
::getUrl($this->getRemoteExtHashFile(), 0, array(TYPO3_user_agent
));
281 if ($remotemd5 !== FALSE) {
282 $localmd5 = md5_file($this->getLocalExtListFile());
283 if ($remotemd5 !== $localmd5) {
284 $updateNecessity |
= self
::PROBLEM_EXTENSION_HASH_CHANGED
;
287 throw new Tx_Extensionmanager_Exception_ExtensionManager(
288 'Could not retrieve extension hash file from remote server.',
293 return $updateNecessity;
297 * Method updates TYPO3 database with up-to-date
298 * extension version records.
300 * @return boolean TRUE if the extension list was successfully update, FALSE if no update necessary
301 * @see isExtListUpdateNecessary()
303 public function updateExtList() {
305 $updateNecessity = $this->isExtListUpdateNecessary();
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;
315 // database table cleanup
316 if (($updateNecessity & self
::PROBLEM_NO_VERSIONS_IN_DATABASE
)) {
317 $updateNecessity &= ~self
::PROBLEM_NO_VERSIONS_IN_DATABASE
;
319 // using straight sql here as extbases "remove" runs into memory problems
320 $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_extensions', 'repository=' . $this->repository
->getUid());
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);