Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
44.74% covered (danger)
44.74%
17 / 38
0.00% covered (danger)
0.00%
0 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
BaseWebsource
44.74% covered (danger)
44.74%
17 / 38
0.00% covered (danger)
0.00%
0 / 5
65.78
0.00% covered (danger)
0.00%
0 / 1
 spawn
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 getId
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getFileSystem
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 getFileStream
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
12
 getMimetype
80.95% covered (warning)
80.95%
17 / 21
0.00% covered (danger)
0.00%
0 / 1
10.69
1<?php
2
3/**
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; under version 2
7 * of the License (non-upgradable).
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17 *
18 * Copyright (c) 2013-2025 (original work) Open Assessment Technologies SA;
19 */
20
21namespace oat\tao\model\websource;
22
23use common_Exception;
24use common_exception_Error;
25use common_exception_NotFound;
26use GuzzleHttp\Psr7\Stream;
27use oat\oatbox\Configurable;
28use oat\oatbox\filesystem\FileSystem;
29use oat\oatbox\filesystem\FilesystemException;
30use oat\oatbox\filesystem\FileSystemService;
31use oat\oatbox\service\ServiceManager;
32use Psr\Http\Message\StreamInterface;
33use tao_helpers_File;
34use tao_models_classes_FileNotFoundException;
35
36/**
37 * @author Joel Bout, <joel@taotesting.com>
38 */
39abstract class BaseWebsource extends Configurable implements Websource
40{
41    public const OPTION_ID = 'id';
42    public const OPTION_FILESYSTEM_ID = 'fsUri';
43    private const ALLOWED_SVGZ_MIMETYPES = ['text/plain', 'image/svg', 'application/x-gzip'];
44
45    /**
46     * Filesystem that is being made available
47     */
48    protected $fileSystem = null;
49
50    /**
51     * Identifier of the Access Provider
52     *
53     * @var string
54     */
55    private $id;
56
57    /**
58     * Used to instantiate new AccessProviders
59     * @param $fileSystemId
60     * @param array $customConfig
61     * @return BaseWebsource
62     * @throws common_Exception
63     */
64    protected static function spawn($fileSystemId, $customConfig = [])
65    {
66        $customConfig[self::OPTION_FILESYSTEM_ID] = $fileSystemId;
67        $customConfig[self::OPTION_ID] = uniqid();
68        $webSource = new static($customConfig);
69        WebsourceManager::singleton()->addWebsource($webSource);
70
71        return $webSource;
72    }
73
74    /**
75     * Return the identifer of the AccessProvider
76     *
77     * @return string
78     */
79    public function getId()
80    {
81        return $this->getOption(self::OPTION_ID);
82    }
83
84    /**
85     * @return null|FileSystem
86     * @throws common_exception_Error
87     * @throws common_exception_NotFound
88     */
89    public function getFileSystem()
90    {
91        if ($this->fileSystem === null) {
92            /** @var FileSystemService $fsService */
93            $fsService = ServiceManager::getServiceManager()->get(FileSystemService::SERVICE_ID);
94            $this->fileSystem = $fsService->getFileSystem($this->getOption(self::OPTION_FILESYSTEM_ID));
95        }
96        return $this->fileSystem;
97    }
98
99    /**
100     * @param $filePath
101     * @return StreamInterface
102     * @throws common_exception_Error
103     * @throws common_exception_NotFound
104     * @throws tao_models_classes_FileNotFoundException
105     */
106    public function getFileStream($filePath)
107    {
108        if ($filePath === '') {
109            throw new tao_models_classes_FileNotFoundException("Empty file path");
110        }
111        $fs = $this->getFileSystem();
112        try {
113            $resource = $fs->readStream($filePath);
114        } catch (FilesystemException $e) {
115            throw new tao_models_classes_FileNotFoundException($filePath);
116        }
117        return new Stream($resource, ['size' => $fs->fileSize($filePath)]);
118    }
119
120    /**
121     * Get a file's mime-type.
122     * @param string $filePath The path to the file.
123     * @return string|false The file mime-type or false on failure.
124     * @throws common_exception_Error
125     * @throws common_exception_NotFound
126     * @throws FilesystemException
127     */
128    public function getMimetype($filePath)
129    {
130        $mimeType = $this->getFileSystem()->mimeType($filePath);
131
132        $pathParts = pathinfo($filePath);
133        if (!isset($pathParts['extension'])) {
134            return $mimeType;
135        }
136
137        switch ($pathParts['extension']) {
138            case 'js':
139                if (str_starts_with($mimeType, 'text/')) {
140                    return 'text/javascript';
141                }
142                break;
143            case 'css':
144                // for css files mime type can be 'text/plain' due to bug in finfo
145                // (see more: https://bugs.php.net/bug.php?id=53035)
146                if (str_starts_with($mimeType, 'text/')) {
147                    return 'text/css';
148                }
149                break;
150            case 'svg':
151            case 'svgz':
152                // when there are more than one image in svg file - finfo recognizes it as `image/svg`, while it
153                // should be `image/svg+xml` or at least `text/plain` for a previous hack to work
154                if (in_array($mimeType, self::ALLOWED_SVGZ_MIMETYPES, true)) {
155                    return tao_helpers_File::MIME_SVG;
156                }
157                break;
158            case 'mp3':
159                return 'audio/mpeg';
160        }
161
162        return $mimeType;
163    }
164}