Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
89.04% covered (warning)
89.04%
65 / 73
0.00% covered (danger)
0.00%
0 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
MediaFileTrait
89.04% covered (warning)
89.04%
65 / 73
0.00% covered (danger)
0.00%
0 / 3
20.53
0.00% covered (danger)
0.00%
0 / 1
 getFileInfo
89.13% covered (warning)
89.13%
41 / 46
0.00% covered (danger)
0.00%
0 / 1
10.13
 getTransformInfo
94.44% covered (success)
94.44%
17 / 18
0.00% covered (danger)
0.00%
0 / 1
7.01
 getImageLimitsFromOption
77.78% covered (warning)
77.78%
7 / 9
0.00% covered (danger)
0.00%
0 / 1
3.10
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\MainConfigNames;
22use MediaWiki\MediaWikiServices;
23use MediaWiki\Permissions\Authority;
24use MediaWiki\User\UserIdentity;
25
26/**
27 * Trait for functionality related to media files
28 *
29 * @internal
30 * @ingroup FileRepo
31 */
32trait MediaFileTrait {
33    /**
34     * @param File $file
35     * @param Authority $performer for permissions check
36     * @param array $transforms array of transforms to include in the response
37     * @return array response data
38     */
39    private function getFileInfo( $file, Authority $performer, $transforms ) {
40        $urlUtils = MediaWikiServices::getInstance()->getUrlUtils();
41        // If there is a problem with the file, there is very little info we can reliably
42        // return (T228286, T239213), but we do what we can (T201205).
43        $responseFile = [
44            'title' => $file->getTitle()->getText(),
45            'file_description_url' => $urlUtils->expand( $file->getDescriptionUrl(), PROTO_RELATIVE ),
46            'latest' => null,
47            'preferred' => null,
48            'original' => null,
49        ];
50
51        foreach ( $transforms as $transformType => $_ ) {
52            $responseFile[$transformType] = null;
53        }
54
55        if ( $file->exists() ) {
56            $uploader = $file->getUploader( File::FOR_THIS_USER, $performer );
57            if ( $uploader ) {
58                $fileUser = [
59                    'id' => $uploader->getId(),
60                    'name' => $uploader->getName(),
61                ];
62            } else {
63                $fileUser = [
64                    'id' => null,
65                    'name' => null,
66                ];
67            }
68            $responseFile['latest'] = [
69                'timestamp' => wfTimestamp( TS_ISO_8601, $file->getTimestamp() ),
70                'user' => $fileUser,
71            ];
72
73            // If the file doesn't and shouldn't have a duration, return null instead of 0.
74            // Testing for 0 first, then checking mediatype, makes gifs behave as desired for
75            // both still and animated cases.
76            $duration = $file->getLength();
77            $mediaTypesWithDurations = [ MEDIATYPE_AUDIO, MEDIATYPE_VIDEO, MEDIATYPE_MULTIMEDIA ];
78            if ( $duration == 0 && !in_array( $file->getMediaType(), $mediaTypesWithDurations ) ) {
79                $duration = null;
80            }
81
82            if ( $file->allowInlineDisplay() ) {
83                foreach ( $transforms as $transformType => $transform ) {
84                    $responseFile[$transformType] = $this->getTransformInfo(
85                        $file,
86                        // @phan-suppress-next-line PhanTypeMismatchArgumentNullable False positive
87                        $duration,
88                        $transform['maxWidth'],
89                        $transform['maxHeight']
90                    );
91                }
92            }
93
94            $responseFile['original'] = [
95                'mediatype' => $file->getMediaType(),
96                'size' => $file->getSize(),
97                'width' => $file->getWidth() ?: null,
98                'height' => $file->getHeight() ?: null,
99                'duration' => $duration,
100                'url' => $urlUtils->expand( $file->getUrl(), PROTO_RELATIVE ),
101            ];
102        }
103
104        return $responseFile;
105    }
106
107    /**
108     * @param File $file
109     * @param int|null $duration File duration (if any)
110     * @param int $maxWidth Max width to display at
111     * @param int $maxHeight Max height to display at
112     * @return array|null Transform info ready to include in response, or null if unavailable
113     */
114    private function getTransformInfo( $file, $duration, $maxWidth, $maxHeight ) {
115        $transformInfo = null;
116
117        [ $width, $height ] = $file->getDisplayWidthHeight( $maxWidth, $maxHeight );
118        $transform = $file->transform( [ 'width' => $width, 'height' => $height ] );
119        if ( $transform && !$transform->isError() ) {
120            // $file->getSize() returns original size. Only include if dimensions match.
121            $size = null;
122            if ( $file->getWidth() == $transform->getWidth() &&
123                $file->getHeight() == $transform->getHeight()
124            ) {
125                $size = $file->getSize();
126            }
127
128            $transformInfo = [
129                'mediatype' => $transform->getFile()->getMediaType(),
130                'size' => $size,
131                'width' => $transform->getWidth() ?: null,
132                'height' => $transform->getHeight() ?: null,
133                'duration' => $duration,
134                'url' => MediaWikiServices::getInstance()->getUrlUtils()
135                    ->expand( $transform->getUrl(), PROTO_RELATIVE ),
136            ];
137        }
138
139        return $transformInfo;
140    }
141
142    /**
143     * Returns the corresponding $wgImageLimits entry for the selected user option
144     *
145     * @param UserIdentity $user
146     * @param string $optionName Name of a option to check, typically imagesize or thumbsize
147     * @return int[]
148     * @since 1.35
149     */
150    public static function getImageLimitsFromOption( UserIdentity $user, string $optionName ) {
151        $imageLimits = MediaWikiServices::getInstance()->getMainConfig()
152            ->get( MainConfigNames::ImageLimits );
153        $optionsLookup = MediaWikiServices::getInstance()->getUserOptionsLookup();
154        $option = $optionsLookup->getIntOption( $user, $optionName );
155        if ( !isset( $imageLimits[$option] ) ) {
156            $option = $optionsLookup->getDefaultOption( $optionName, $user );
157        }
158
159        // The user offset might still be incorrect, specially if
160        // $wgImageLimits got changed (see T10858).
161        if ( !isset( $imageLimits[$option] ) ) {
162            // Default to the first offset in $wgImageLimits
163            $option = 0;
164        }
165
166        // if nothing is set, fallback to a hardcoded default
167        return $imageLimits[$option] ?? [ 800, 600 ];
168    }
169}