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