MirrorService.php 6.5 KB
Newer Older
1
<?php
2 3
namespace T3o\TerFe2\Service;

4 5
/*
 * This file is part of the TYPO3 CMS project.
6
 *
7 8 9
 * It is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License, either version 2
 * of the License, or any later version.
10
 *
11 12
 * For the full copyright and license information, please read the
 * LICENSE.txt file that was distributed with this source code.
13
 *
14 15
 * The TYPO3 project - inspiring people to share!
 */
16 17 18 19

/**
 * Service to handle mirrors
 */
20
class MirrorService implements \TYPO3\CMS\Core\SingletonInterface
21 22 23
{

    /**
24
     * @var int
25 26 27 28 29 30 31 32 33
     */
    protected $maxAttempts = 2;

    /**
     * @var string
     */
    protected $protocol = 'http';

    /**
34
     * @var int
35 36 37 38 39 40 41 42
     */
    protected $repositoryId = 1;

    /**
     * @var string
     */
    protected $mirrorUrl;

Thomas Löffler's avatar
Thomas Löffler committed
43 44 45 46 47 48 49 50 51 52 53 54 55
    /**
     * @var \TYPO3\CMS\Extensionmanager\Domain\Repository\RepositoryRepository
     */
    protected $repositoryRepository;

    /**
     * @param \TYPO3\CMS\Extensionmanager\Domain\Repository\RepositoryRepository $repositoryRepository
     */
    public function injectRepositoryRepository(\TYPO3\CMS\Extensionmanager\Domain\Repository\RepositoryRepository $repositoryRepository)
    {
        $this->repositoryRepository = $repositoryRepository;
    }

56 57 58
    /**
     * Setter for maxAttempts
     *
59
     * @param int $maxAttempts Maximal count of attemts to connect
60 61 62 63 64 65 66 67 68
     */
    public function setMaxAttempts($maxAttempts)
    {
        $this->maxAttempts = (int)$maxAttempts;
    }

    /**
     * Getter for maxAttempts
     *
69
     * @return int Maximal count of attemts to connect
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
     */
    public function getMaxAttempts()
    {
        return (int)$this->maxAttempts;
    }

    /**
     * Setter for protocol
     *
     * @param string $protocol Url protocol
     */
    public function setProtocol($protocol)
    {
        $this->protocol = $protocol;
    }

    /**
     * Getter for protocol
     *
     * @return string Url protocol
     */
    public function getProtocol()
    {
        return $this->protocol;
    }

    /**
     * Setter for repositoryId
     *
99
     * @param int $repositoryId Repository id
100 101 102 103 104 105 106 107 108
     */
    public function setRepositoryId($repositoryId)
    {
        $this->repositoryId = (int)$repositoryId;
    }

    /**
     * Getter for repositoryId
     *
109
     * @return int Repository id
110 111 112 113 114 115 116 117 118
     */
    public function getRepositoryId()
    {
        return (int)$this->repositoryId;
    }

    /**
     * Returns mirror url from local extension manager
     *
119
     * @param bool $refresh Generate new mirror url
120
     * @return string Mirror url
121
     * @throws \Exception
122
     */
Markus Sommer's avatar
Markus Sommer committed
123
    public function getMirror($refresh = false)
124 125 126 127 128 129
    {
        if (!$refresh && !empty($this->mirrorUrl)) {
            return $this->mirrorUrl;
        }

        // Get extension manager settings
130
        $emSettings = [
131 132 133 134
            'rep_url' => '',
            'extMirrors' => '',
            'selectedRepository' => $this->getRepositoryId(),
            'selectedMirror' => 0,
135
        ];
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
        if (!empty($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['em'])) {
            $extConf = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['em']);
            $emSettings = array_merge($emSettings, $extConf);
        }

        if (!empty($emSettings['rep_url'])) {
            // Force manually added url
            $mirrorUrl = $emSettings['rep_url'];
        } else {
            // Set selected repository to "1" if no mirrors found
            $mirrors = unserialize($emSettings['extMirrors']);
            if (!is_array($mirrors)) {
                if ($emSettings['selectedRepository'] < 1) {
                    $emSettings['selectedRepository'] = 1;
                }
            }

            // Get mirrors from repository object
Thomas Löffler's avatar
Thomas Löffler committed
154
            $repository = $this->repositoryRepository->findByUid($emSettings['selectedRepository']);
155
            if ($repository->getMirrorListUrl()) {
Thomas Löffler's avatar
Thomas Löffler committed
156 157 158 159
                $repositoryUtility = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
                    \TYPO3\CMS\Extensionmanager\Utility\Importer\MirrorListUtility::class
                );
                $mirrors = $repositoryUtility->getMirrors($repository->getMirrorListUrl())->getMirrors();
160 161
                unset($repositoryUtility);
                if (!is_array($mirrors)) {
162
                    throw new \Exception('No mirrors found');
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
                }
            }

            // Build url
            $protocol = $this->getProtocol();
            $selectedMirror = (!empty($emSettings['selectedMirror']) ? $emSettings['selectedMirror'] : array_rand($mirrors));
            $mirrorUrl = rtrim($protocol, ':/') . '://' . $mirrors[$selectedMirror]['host'] . $mirrors[$selectedMirror]['path'];
        }

        return $this->mirrorUrl = rtrim($mirrorUrl, '/ ') . '/';
    }

    /**
     * Generate the url to a file on mirror server
     *
     * @param string $filename File name to check
     * @return string Url to file on mirror server
180
     * @throws \Exception
181 182 183 184
     */
    public function getUrlToFile($filename)
    {
        if (empty($filename)) {
185
            throw new \Exception('No filename given to generate url');
186 187 188 189 190 191 192 193
        }

        // Get first mirror url
        $mirrorUrl = $this->getMirror();

        // Check mirrors if file exits
        $attempts = 1;
        $maxAttempts = $this->getMaxAttempts();
194
        while (!\T3o\TerFe2\Utility\FileUtility::fileExists($mirrorUrl . $filename)) {
195 196
            $attempts++;
            if ($attempts > $maxAttempts) {
197
                // throw new \Exception('File "' . $filename . '" could not be found on ' . $maxAttempts . ' mirrors, break');
198 199 200
                // break;
                return '';
            }
Markus Sommer's avatar
Markus Sommer committed
201
            $mirrorUrl = $this->getMirror(true);
202 203 204 205 206 207 208 209 210 211
        }

        return $mirrorUrl . $filename;
    }

    /**
     * Fetch a file from mirror server
     *
     * @param string $filename File name to fetch
     * @return string File content
212
     * @throws \Exception
213 214 215 216 217
     */
    public function getFile($filename)
    {
        $url = $this->getUrlToFile($filename);

218 219
        if (\T3o\TerFe2\Utility\FileUtility::isLocalUrl($url)) {
            $url = \T3o\TerFe2\Utility\FileUtility::getAbsolutePathFromUrl($url);
220
            $content = \TYPO3\CMS\Core\Utility\GeneralUtility::getURL($url);
221
        } else {
222
            $content = \TYPO3\CMS\Core\Utility\GeneralUtility::getURL($url, 0, [TYPO3_user_agent]);
223 224 225
        }

        if (empty($content)) {
226
            throw new \Exception('Could not fetch file "' . $filename . '" from mirror server');
227 228 229 230 231
        }

        return (string)$content;
    }
}