Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 64
0.00% covered (danger)
0.00%
0 / 14
CRAP
0.00% covered (danger)
0.00%
0 / 1
UnregisteredLocalFile
0.00% covered (danger)
0.00%
0 / 63
0.00% covered (danger)
0.00%
0 / 14
930
0.00% covered (danger)
0.00%
0 / 1
 newFromPath
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 newFromTitle
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 __construct
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
56
 cachePageDimensions
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
30
 getWidth
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 getHeight
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 getMimeType
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
12
 getBitDepth
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 getMetadata
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 getMetadataArray
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 getSizeAndMetadata
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 getURL
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 getSize
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 setLocalReference
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * @license GPL-2.0-or-later
4 * @file
5 */
6
7namespace MediaWiki\FileRepo\File;
8
9use BadMethodCallException;
10use MediaHandler;
11use MediaWiki\FileRepo\FileRepo;
12use MediaWiki\MediaWikiServices;
13use MediaWiki\Title\Title;
14use Wikimedia\FileBackend\FSFile\FSFile;
15
16/**
17 * File without associated database record.
18 *
19 * Represents a standalone local file, or a file in a local repository
20 * with no database, for example a FileRepo repository.
21 *
22 * Read-only.
23 *
24 * @todo Currently it doesn't really work in the repository role, there are
25 * lots of functions missing. It is used by the WebStore extension in the
26 * standalone role.
27 *
28 * @ingroup FileAbstraction
29 */
30class UnregisteredLocalFile extends File {
31    /** @var Title */
32    protected $title;
33
34    /** @var string */
35    protected $path;
36
37    /** @var string|false|null */
38    protected $mime;
39
40    /** @var array[]|bool[] Dimension data */
41    protected $pageDims;
42
43    /** @var array|null */
44    protected $sizeAndMetadata;
45
46    /** @var MediaHandler */
47    public $handler;
48
49    /**
50     * @param string $path Storage path
51     * @param string $mime
52     */
53    public static function newFromPath( $path, $mime ): static {
54        return new static( false, false, $path, $mime );
55    }
56
57    /**
58     * @param Title $title
59     * @param FileRepo $repo
60     */
61    public static function newFromTitle( $title, $repo ): static {
62        return new static( $title, $repo, false, false );
63    }
64
65    /**
66     * Create an UnregisteredLocalFile based on a path or a (title,repo) pair.
67     * A FileRepo object is not required here, unlike most other File classes.
68     *
69     * @param Title|false $title
70     * @param FileRepo|false $repo
71     * @param string|false $path
72     * @param string|false $mime
73     */
74    public function __construct( $title = false, $repo = false, $path = false, $mime = false ) {
75        if ( !( $title && $repo ) && !$path ) {
76            throw new BadMethodCallException( __METHOD__ .
77                ': not enough parameters, must specify title and repo, or a full path' );
78        }
79        if ( $title instanceof Title ) {
80            $this->title = File::normalizeTitle( $title, 'exception' );
81            $this->name = $repo->getNameFromTitle( $title );
82        } else {
83            $this->name = basename( $path );
84            $this->title = File::normalizeTitle( $this->name, 'exception' );
85        }
86        $this->repo = $repo;
87        if ( $path ) {
88            $this->path = $path;
89        } else {
90            $this->assertRepoDefined();
91            $this->path = $repo->getRootDirectory() . '/' .
92                $repo->getHashPath( $this->name ) . $this->name;
93        }
94        if ( $mime ) {
95            $this->mime = $mime;
96        }
97        $this->pageDims = [];
98    }
99
100    /**
101     * @param int $page
102     * @return array|false
103     */
104    private function cachePageDimensions( $page = 1 ) {
105        $page = (int)$page;
106        if ( $page < 1 ) {
107            $page = 1;
108        }
109
110        if ( !isset( $this->pageDims[$page] ) ) {
111            if ( !$this->getHandler() ) {
112                return false;
113            }
114            if ( $this->getHandler()->isMultiPage( $this ) ) {
115                $this->pageDims[$page] = $this->handler->getPageDimensions( $this, $page );
116            } else {
117                $info = $this->getSizeAndMetadata();
118                return [
119                    'width' => $info['width'],
120                    'height' => $info['height']
121                ];
122            }
123        }
124
125        return $this->pageDims[$page];
126    }
127
128    /**
129     * @param int $page
130     * @return int
131     */
132    public function getWidth( $page = 1 ) {
133        $dim = $this->cachePageDimensions( $page );
134
135        return $dim['width'] ?? 0;
136    }
137
138    /**
139     * @param int $page
140     * @return int
141     */
142    public function getHeight( $page = 1 ) {
143        $dim = $this->cachePageDimensions( $page );
144
145        return $dim['height'] ?? 0;
146    }
147
148    /**
149     * @return string|false
150     */
151    public function getMimeType() {
152        if ( $this->mime === null ) {
153            $refPath = $this->getLocalRefPath();
154            if ( $refPath !== false ) {
155                $magic = MediaWikiServices::getInstance()->getMimeAnalyzer();
156                $this->mime = $magic->guessMimeType( $refPath );
157            } else {
158                $this->mime = false;
159            }
160        }
161
162        return $this->mime;
163    }
164
165    /**
166     * @return int
167     */
168    public function getBitDepth() {
169        $info = $this->getSizeAndMetadata();
170        return $info['bits'] ?? 0;
171    }
172
173    /**
174     * @return string|false
175     */
176    public function getMetadata() {
177        $info = $this->getSizeAndMetadata();
178        return $info['metadata'] ? serialize( $info['metadata'] ) : false;
179    }
180
181    public function getMetadataArray(): array {
182        $info = $this->getSizeAndMetadata();
183        return $info['metadata'];
184    }
185
186    private function getSizeAndMetadata(): array {
187        if ( $this->sizeAndMetadata === null ) {
188            if ( !$this->getHandler() ) {
189                $this->sizeAndMetadata = [ 'width' => 0, 'height' => 0, 'metadata' => [] ];
190            } else {
191                $this->sizeAndMetadata = $this->getHandler()->getSizeAndMetadataWithFallback(
192                    $this, $this->getLocalRefPath() );
193            }
194        }
195
196        return $this->sizeAndMetadata;
197    }
198
199    /**
200     * @return string|false
201     */
202    public function getURL() {
203        if ( $this->repo ) {
204            return $this->repo->getZoneUrl( 'public' ) . '/' .
205                $this->repo->getHashPath( $this->name ) . rawurlencode( $this->name );
206        } else {
207            return false;
208        }
209    }
210
211    /**
212     * @return false|int
213     */
214    public function getSize() {
215        $this->assertRepoDefined();
216
217        return $this->repo->getFileSize( $this->path );
218    }
219
220    /**
221     * Optimize getLocalRefPath() by using an existing local reference.
222     * The file at the path of $fsFile should not be deleted (or at least
223     * not until the end of the request). This is mostly a performance hack.
224     *
225     * @param FSFile $fsFile
226     * @return void
227     */
228    public function setLocalReference( FSFile $fsFile ) {
229        $this->fsFile = $fsFile;
230    }
231}
232
233/** @deprecated class alias since 1.44 */
234class_alias( UnregisteredLocalFile::class, 'UnregisteredLocalFile' );