* Steffen Kamper * All rights reserved * * This script is part of the TYPO3 project. The TYPO3 project is * free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * The GNU General Public License can be found at * http://www.gnu.org/copyleft/gpl.html. * * This script is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * This copyright notice MUST APPEAR in all copies of the script! ***************************************************************/ /** * class.tx_em_repository_utility.php * * Module: Extension manager - Central repository utility functions * * $Id: class.tx_em_repository_utility.php 2082 2010-03-21 17:19:42Z steffenk $ * * @author Marcus Krause * @author Steffen Kamper */ /** * Central utility class for repository handling. * * @author Marcus Krause * @author Steffen Kamper * * @since 2010-02-18 * @package TYPO3 * @subpackage EM */ class tx_em_Repository_Utility implements t3lib_Singleton { /** * ########################################## * Problem constants - to be used in bitmasks * ########################################## */ /** * Type of problem: extension file not existing in file system. * * @var integer */ const PROBLEM_EXTENSION_FILE_NOT_EXISTING = 1; /** * Type of problem: wrong hash indicates outdated extension file. * * @var integer */ const PROBLEM_EXTENSION_HASH_CHANGED = 2; /** * Type of problem: no version records in database. * * @var integer */ const PROBLEM_NO_VERSIONS_IN_DATABASE = 4; /** * Keeps instance of repository class. * * @var em_repository */ protected $repository = NULL; /** * Class constructor. * * @access public * @param object &$repository (optional) instance of {@link em_repository repository} class * @return void */ function __construct(&$repository = NULL) { if ($repository != NULL && is_object($repository) && $repository instanceof tx_em_Repository) { $this->setRepository($repository); } } /** * Method provides a wrapper for throwing an exception. * * @access protected * @see tx_em_ConnectionException * @param string $message the exception message to throw. * @param integer $code the exception code. * @return void */ protected function throwConnectionException($message = "", $code = 0) { throw new tx_em_ConnectionException(get_class($this) . ': ' . $message, $code); } /** * Method registers required repository instance to work with. * * Repository instance is passed by reference. * * @access public * @param em_repository &$repository instance of {@link em_repository repository} class * @return void * @see $repository */ public function setRepository(tx_em_Repository &$repository) { $this->repository = $repository; } /** * Method fetches extension list file from remote server. * * Delegates to {@link fetchFile()}. * * @access public * @return void * @see fetchFile() */ public function fetchExtListFile() { $this->fetchFile($this->getRemoteExtListFile(), $this->getLocalExtListFile()); } /** * Method fetches mirror list file from remote server. * * Delegates to {@link fetchFile()}. * * @access public * @return void * @see fetchFile() */ public function fetchMirrorListFile() { $this->fetchFile($this->getRemoteMirrorListFile(), $this->getLocalMirrorListFile()); } /** * Method fetches contents from remote server and * writes them into a file in the local file system. * * @access protected * @param string $remoteRessource remote ressource to read contents from * @param string $localRessource local ressource (absolute file path) to store retrieved contents to * @return void * @see t3lib_div::getURL(), t3lib_div::writeFile() * @throws tx_em_ConnectionException */ protected function fetchFile($remoteRessource, $localRessource) { if (is_string($remoteRessource) && is_string($localRessource) && !empty($remoteRessource) && !empty($localRessource)) { $fileContent = t3lib_div::getURL($remoteRessource, 0, array(TYPO3_user_agent)); if ($fileContent !== false) { t3lib_div::writeFile($localRessource, $fileContent) || $this->throwConnectionException(sprintf('Could not write to file %s.', htmlspecialchars($localRessource))); } else { $this->throwConnectionException(sprintf('Could not access remote ressource %s.', htmlspecialchars($remoteRessource))); } } } /** * Method returns location of local extension list file. * * @access public * @return string local location of file * @see getRemoteExtListFile() */ public function getLocalExtListFile() { $absFilePath = PATH_site . 'typo3temp/' . intval($this->repository->getId()) . '.extensions.xml.gz'; return $absFilePath; } /** * Method returns location of remote extension list file. * * @access public * @return string remote location of file * @see getLocalExtListFile() */ public function getRemoteExtListFile() { $mirror = $this->getMirrors(TRUE)->getMirror(); $filePath = 'http://' . $mirror['host'] . $mirror['path'] . 'extensions.xml.gz'; return $filePath; } /** * Method returns location of remote file containing * the extension checksum hash. * * @access public * @return string remote location of file */ public function getRemoteExtHashFile() { $mirror = $this->getMirrors(TRUE)->getMirror(); $filePath = 'http://' . $mirror['host'] . $mirror['path'] . 'extensions.md5'; return $filePath; } /** * Method returns location of local mirror list file. * * @access public * @return string local location of file * @see getRemoteMirrorListFile() */ public function getLocalMirrorListFile() { $absFilePath = PATH_site . 'typo3temp/' . intval($this->repository->getId()) . '.mirrors.xml.gz'; return $absFilePath; } /** * Method returns location of remote mirror list file. * * @access public * @return string remote location of file * @see getLocalMirrorListFile() */ public function getRemoteMirrorListFile() { $filePath = $this->repository->getMirrorListUrl(); return $filePath; } /** * Method returns available mirrors for registered repository. * * If there are no mirrors registered to the repository, * the method will retrieve them from file system or remote * server. * * @access public * @param boolean $forcedUpdateFromRemote if boolean true, mirror configuration will always retrieved from remote server * @return em_repository_mirrors instance of repository mirrors class */ public function getMirrors($forcedUpdateFromRemote = TRUE) { $assignedMirror = $this->repository->getMirrors(); if ($forcedUpdateFromRemote || is_null($assignedMirror) || !is_object($assignedMirror)) { if ($forcedUpdateFromRemote || !is_file($this->getLocalMirrorListFile())) { $this->fetchMirrorListFile(); } $objMirrorListImporter = t3lib_div::makeInstance('tx_em_Import_MirrorListImporter'); $this->repository->addMirrors($objMirrorListImporter->getMirrors($this->getLocalMirrorListFile())); } return $this->repository->getMirrors(); } /** * Method returns information if currently available * extension list might be outdated. * * @access public * @see em_repository_utility::PROBLEM_NO_VERSIONS_IN_DATABASE, * em_repository_utility::PROBLEM_EXTENSION_FILE_NOT_EXISTING, * em_repository_utility::PROBLEM_EXTENSION_HASH_CHANGED * @return integer integer "0" if everything is perfect, otherwise bitmask with occured problems * @see updateExtList() */ public function isExtListUpdateNecessary() { $updateNecessity = 0; if (tx_em_Database::getExtensionCountFromRepository($this->getRepositoryUID(TRUE)) <= 0) { $updateNecessity |= self::PROBLEM_NO_VERSIONS_IN_DATABASE; } if (!is_file($this->getLocalExtListFile())) { $updateNecessity |= self::PROBLEM_EXTENSION_FILE_NOT_EXISTING; } else { $remotemd5 = t3lib_div::getURL($this->getRemoteExtHashFile(), 0, array(TYPO3_user_agent)); if ($remotemd5 !== false) { $localmd5 = md5_file($this->getLocalExtListFile()); if ($remotemd5 !== $localmd5) { $updateNecessity |= self::PROBLEM_EXTENSION_HASH_CHANGED; } } else { $this->throwConnectionException('Could not retrieve extension hash file from remote server.'); } } return $updateNecessity; } /** * Method returns UID of the current repository. * * @access public * @param boolean $insertIfMissing creates repository record in DB if set to TRUE * @return integer */ public function getRepositoryUID($insertIfMissing = FALSE) { $uid = NULL; $repository = tx_em_Database::getRepositoryByUID($this->repository->getId()); if (empty($repository) && $insertIfMissing) { $uid = tx_em_Database::insertRepository($this->repository); } else { $uid = intval($repository[0]['uid']); } return $uid; } /** * Method updates TYPO3 database with up-to-date * extension version records. * * @access public * @param boolean $renderFlashMessage if method should return flashmessage or raw integer * @return mixed either sum of imported extensions or instance of t3lib_FlashMessage * @see isExtListUpdateNecessary() */ public function updateExtList($renderFlashMessage = FALSE) { if ($renderFlashMessage) { /* @var $flashMessage t3lib_FlashMessage */ $flashMessage = t3lib_div::makeInstance('t3lib_FlashMessage', ''); $flashMessage->setTitle($GLOBALS['LANG']->getLL('ext_import_list_unchanged')); $flashMessage->setMessage($GLOBALS['LANG']->getLL('ext_import_list_unchanged_header')); $flashMessage->setSeverity(t3lib_FlashMessage::INFO); } $sumRecords = 0; $updateNecessity = $this->isExtListUpdateNecessary(); if ($updateNecessity != 0) { // retrieval of file necessary $tmpBitmask = (self::PROBLEM_EXTENSION_FILE_NOT_EXISTING | self::PROBLEM_EXTENSION_HASH_CHANGED); if (($tmpBitmask & $updateNecessity) > 0) { $this->fetchExtListFile(); $updateNecessity &= ~$tmpBitmask; } // database table cleanup if (($updateNecessity & self::PROBLEM_NO_VERSIONS_IN_DATABASE)) { $updateNecessity &= ~self::PROBLEM_NO_VERSIONS_IN_DATABASE; } else { $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_extensions', 'repository=' . $this->getRepositoryUID()); } // no further problems - start of import process if ($updateNecessity === 0) { $objExtListImporter = t3lib_div::makeInstance('tx_em_Import_ExtensionListImporter'); $objExtListImporter->import($this->getLocalExtListFile(), $this->getRepositoryUID(TRUE)); $sumRecords = tx_em_Database::getExtensionCountFromRepository($this->getRepositoryUID()); if ($renderFlashMessage) { $flashMessage->setTitle($GLOBALS['LANG']->getLL('ext_import_extlist_updated_header')); $flashMessage->setMessage(sprintf($GLOBALS['LANG']->getLL('ext_import_extlist_updated'), tx_em_Database::getExtensionCountFromRepository())); $flashMessage->setSeverity(t3lib_FlashMessage::OK); } } } return $renderFlashMessage ? $flashMessage : $sumRecords; } } ?>