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