wikimedia /
mediawiki
This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | /** |
||
| 3 | * Handler for SVG images. |
||
| 4 | * |
||
| 5 | * This program is free software; you can redistribute it and/or modify |
||
| 6 | * it under the terms of the GNU General Public License as published by |
||
| 7 | * the Free Software Foundation; either version 2 of the License, or |
||
| 8 | * (at your option) any later version. |
||
| 9 | * |
||
| 10 | * This program is distributed in the hope that it will be useful, |
||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
| 13 | * GNU General Public License for more details. |
||
| 14 | * |
||
| 15 | * You should have received a copy of the GNU General Public License along |
||
| 16 | * with this program; if not, write to the Free Software Foundation, Inc., |
||
| 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
||
| 18 | * http://www.gnu.org/copyleft/gpl.html |
||
| 19 | * |
||
| 20 | * @file |
||
| 21 | * @ingroup Media |
||
| 22 | */ |
||
| 23 | use Wikimedia\ScopedCallback; |
||
|
0 ignored issues
–
show
|
|||
| 24 | |||
| 25 | /** |
||
| 26 | * Handler for SVG images. |
||
| 27 | * |
||
| 28 | * @ingroup Media |
||
| 29 | */ |
||
| 30 | class SvgHandler extends ImageHandler { |
||
| 31 | const SVG_METADATA_VERSION = 2; |
||
| 32 | |||
| 33 | /** @var array A list of metadata tags that can be converted |
||
| 34 | * to the commonly used exif tags. This allows messages |
||
| 35 | * to be reused, and consistent tag names for {{#formatmetadata:..}} |
||
| 36 | */ |
||
| 37 | private static $metaConversion = [ |
||
| 38 | 'originalwidth' => 'ImageWidth', |
||
| 39 | 'originalheight' => 'ImageLength', |
||
| 40 | 'description' => 'ImageDescription', |
||
| 41 | 'title' => 'ObjectName', |
||
| 42 | ]; |
||
| 43 | |||
| 44 | function isEnabled() { |
||
| 45 | global $wgSVGConverters, $wgSVGConverter; |
||
| 46 | if ( !isset( $wgSVGConverters[$wgSVGConverter] ) ) { |
||
| 47 | wfDebug( "\$wgSVGConverter is invalid, disabling SVG rendering.\n" ); |
||
| 48 | |||
| 49 | return false; |
||
| 50 | } else { |
||
| 51 | return true; |
||
| 52 | } |
||
| 53 | } |
||
| 54 | |||
| 55 | public function mustRender( $file ) { |
||
| 56 | return true; |
||
| 57 | } |
||
| 58 | |||
| 59 | function isVectorized( $file ) { |
||
| 60 | return true; |
||
| 61 | } |
||
| 62 | |||
| 63 | /** |
||
| 64 | * @param File $file |
||
| 65 | * @return bool |
||
| 66 | */ |
||
| 67 | function isAnimatedImage( $file ) { |
||
| 68 | # @todo Detect animated SVGs |
||
| 69 | $metadata = $file->getMetadata(); |
||
| 70 | if ( $metadata ) { |
||
| 71 | $metadata = $this->unpackMetadata( $metadata ); |
||
| 72 | if ( isset( $metadata['animated'] ) ) { |
||
| 73 | return $metadata['animated']; |
||
| 74 | } |
||
| 75 | } |
||
| 76 | |||
| 77 | return false; |
||
| 78 | } |
||
| 79 | |||
| 80 | /** |
||
| 81 | * Which languages (systemLanguage attribute) is supported. |
||
| 82 | * |
||
| 83 | * @note This list is not guaranteed to be exhaustive. |
||
| 84 | * To avoid OOM errors, we only look at first bit of a file. |
||
| 85 | * Thus all languages on this list are present in the file, |
||
| 86 | * but its possible for the file to have a language not on |
||
| 87 | * this list. |
||
| 88 | * |
||
| 89 | * @param File $file |
||
| 90 | * @return array Array of language codes, or empty if no language switching supported. |
||
| 91 | */ |
||
| 92 | public function getAvailableLanguages( File $file ) { |
||
| 93 | $metadata = $file->getMetadata(); |
||
| 94 | $langList = []; |
||
| 95 | if ( $metadata ) { |
||
| 96 | $metadata = $this->unpackMetadata( $metadata ); |
||
| 97 | if ( isset( $metadata['translations'] ) ) { |
||
| 98 | foreach ( $metadata['translations'] as $lang => $langType ) { |
||
| 99 | if ( $langType === SVGReader::LANG_FULL_MATCH ) { |
||
| 100 | $langList[] = $lang; |
||
| 101 | } |
||
| 102 | } |
||
| 103 | } |
||
| 104 | } |
||
| 105 | return $langList; |
||
| 106 | } |
||
| 107 | |||
| 108 | /** |
||
| 109 | * What language to render file in if none selected. |
||
| 110 | * |
||
| 111 | * @param File $file |
||
| 112 | * @return string Language code. |
||
| 113 | */ |
||
| 114 | public function getDefaultRenderLanguage( File $file ) { |
||
| 115 | return 'en'; |
||
| 116 | } |
||
| 117 | |||
| 118 | /** |
||
| 119 | * We do not support making animated svg thumbnails |
||
| 120 | * @param File $file |
||
| 121 | * @return bool |
||
| 122 | */ |
||
| 123 | function canAnimateThumbnail( $file ) { |
||
| 124 | return false; |
||
| 125 | } |
||
| 126 | |||
| 127 | /** |
||
| 128 | * @param File $image |
||
| 129 | * @param array $params |
||
| 130 | * @return bool |
||
| 131 | */ |
||
| 132 | function normaliseParams( $image, &$params ) { |
||
| 133 | global $wgSVGMaxSize; |
||
| 134 | if ( !parent::normaliseParams( $image, $params ) ) { |
||
| 135 | return false; |
||
| 136 | } |
||
| 137 | # Don't make an image bigger than wgMaxSVGSize on the smaller side |
||
| 138 | if ( $params['physicalWidth'] <= $params['physicalHeight'] ) { |
||
| 139 | View Code Duplication | if ( $params['physicalWidth'] > $wgSVGMaxSize ) { |
|
| 140 | $srcWidth = $image->getWidth( $params['page'] ); |
||
| 141 | $srcHeight = $image->getHeight( $params['page'] ); |
||
| 142 | $params['physicalWidth'] = $wgSVGMaxSize; |
||
| 143 | $params['physicalHeight'] = File::scaleHeight( $srcWidth, $srcHeight, $wgSVGMaxSize ); |
||
|
0 ignored issues
–
show
It seems like
$srcWidth defined by $image->getWidth($params['page']) on line 140 can also be of type boolean; however, File::scaleHeight() does only seem to accept integer, maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. Loading history...
It seems like
$srcHeight defined by $image->getHeight($params['page']) on line 141 can also be of type boolean; however, File::scaleHeight() does only seem to accept integer, maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. Loading history...
|
|||
| 144 | } |
||
| 145 | View Code Duplication | } else { |
|
| 146 | if ( $params['physicalHeight'] > $wgSVGMaxSize ) { |
||
| 147 | $srcWidth = $image->getWidth( $params['page'] ); |
||
| 148 | $srcHeight = $image->getHeight( $params['page'] ); |
||
| 149 | $params['physicalWidth'] = File::scaleHeight( $srcHeight, $srcWidth, $wgSVGMaxSize ); |
||
|
0 ignored issues
–
show
It seems like
$srcHeight defined by $image->getHeight($params['page']) on line 148 can also be of type boolean; however, File::scaleHeight() does only seem to accept integer, maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. Loading history...
It seems like
$srcWidth defined by $image->getWidth($params['page']) on line 147 can also be of type boolean; however, File::scaleHeight() does only seem to accept integer, maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. Loading history...
|
|||
| 150 | $params['physicalHeight'] = $wgSVGMaxSize; |
||
| 151 | } |
||
| 152 | } |
||
| 153 | |||
| 154 | return true; |
||
| 155 | } |
||
| 156 | |||
| 157 | /** |
||
| 158 | * @param File $image |
||
| 159 | * @param string $dstPath |
||
| 160 | * @param string $dstUrl |
||
| 161 | * @param array $params |
||
| 162 | * @param int $flags |
||
| 163 | * @return bool|MediaTransformError|ThumbnailImage|TransformParameterError |
||
| 164 | */ |
||
| 165 | function doTransform( $image, $dstPath, $dstUrl, $params, $flags = 0 ) { |
||
| 166 | if ( !$this->normaliseParams( $image, $params ) ) { |
||
| 167 | return new TransformParameterError( $params ); |
||
| 168 | } |
||
| 169 | $clientWidth = $params['width']; |
||
| 170 | $clientHeight = $params['height']; |
||
| 171 | $physicalWidth = $params['physicalWidth']; |
||
| 172 | $physicalHeight = $params['physicalHeight']; |
||
| 173 | $lang = isset( $params['lang'] ) ? $params['lang'] : $this->getDefaultRenderLanguage( $image ); |
||
| 174 | |||
| 175 | if ( $flags & self::TRANSFORM_LATER ) { |
||
| 176 | return new ThumbnailImage( $image, $dstUrl, $dstPath, $params ); |
||
| 177 | } |
||
| 178 | |||
| 179 | $metadata = $this->unpackMetadata( $image->getMetadata() ); |
||
| 180 | if ( isset( $metadata['error'] ) ) { // sanity check |
||
| 181 | $err = wfMessage( 'svg-long-error', $metadata['error']['message'] )->text(); |
||
| 182 | |||
| 183 | return new MediaTransformError( 'thumbnail_error', $clientWidth, $clientHeight, $err ); |
||
| 184 | } |
||
| 185 | |||
| 186 | View Code Duplication | if ( !wfMkdirParents( dirname( $dstPath ), null, __METHOD__ ) ) { |
|
| 187 | return new MediaTransformError( 'thumbnail_error', $clientWidth, $clientHeight, |
||
| 188 | wfMessage( 'thumbnail_dest_directory' )->text() ); |
||
| 189 | } |
||
| 190 | |||
| 191 | $srcPath = $image->getLocalRefPath(); |
||
| 192 | View Code Duplication | if ( $srcPath === false ) { // Failed to get local copy |
|
| 193 | wfDebugLog( 'thumbnail', |
||
| 194 | sprintf( 'Thumbnail failed on %s: could not get local copy of "%s"', |
||
| 195 | wfHostname(), $image->getName() ) ); |
||
| 196 | |||
| 197 | return new MediaTransformError( 'thumbnail_error', |
||
| 198 | $params['width'], $params['height'], |
||
| 199 | wfMessage( 'filemissing' )->text() |
||
| 200 | ); |
||
| 201 | } |
||
| 202 | |||
| 203 | // Make a temp dir with a symlink to the local copy in it. |
||
| 204 | // This plays well with rsvg-convert policy for external entities. |
||
| 205 | // https://git.gnome.org/browse/librsvg/commit/?id=f01aded72c38f0e18bc7ff67dee800e380251c8e |
||
| 206 | $tmpDir = wfTempDir() . '/svg_' . wfRandomString( 24 ); |
||
| 207 | $lnPath = "$tmpDir/" . basename( $srcPath ); |
||
| 208 | $ok = mkdir( $tmpDir, 0771 ) && symlink( $srcPath, $lnPath ); |
||
| 209 | /** @noinspection PhpUnusedLocalVariableInspection */ |
||
| 210 | $cleaner = new ScopedCallback( function () use ( $tmpDir, $lnPath ) { |
||
|
0 ignored issues
–
show
$cleaner is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the Loading history...
|
|||
| 211 | MediaWiki\suppressWarnings(); |
||
| 212 | unlink( $lnPath ); |
||
| 213 | rmdir( $tmpDir ); |
||
| 214 | MediaWiki\restoreWarnings(); |
||
| 215 | } ); |
||
| 216 | View Code Duplication | if ( !$ok ) { |
|
| 217 | wfDebugLog( 'thumbnail', |
||
| 218 | sprintf( 'Thumbnail failed on %s: could not link %s to %s', |
||
| 219 | wfHostname(), $lnPath, $srcPath ) ); |
||
| 220 | return new MediaTransformError( 'thumbnail_error', |
||
| 221 | $params['width'], $params['height'], |
||
| 222 | wfMessage( 'thumbnail-temp-create' )->text() |
||
| 223 | ); |
||
| 224 | } |
||
| 225 | |||
| 226 | $status = $this->rasterize( $lnPath, $dstPath, $physicalWidth, $physicalHeight, $lang ); |
||
| 227 | if ( $status === true ) { |
||
| 228 | return new ThumbnailImage( $image, $dstUrl, $dstPath, $params ); |
||
| 229 | } else { |
||
| 230 | return $status; // MediaTransformError |
||
| 231 | } |
||
| 232 | } |
||
| 233 | |||
| 234 | /** |
||
| 235 | * Transform an SVG file to PNG |
||
| 236 | * This function can be called outside of thumbnail contexts |
||
| 237 | * @param string $srcPath |
||
| 238 | * @param string $dstPath |
||
| 239 | * @param string $width |
||
| 240 | * @param string $height |
||
| 241 | * @param bool|string $lang Language code of the language to render the SVG in |
||
| 242 | * @throws MWException |
||
| 243 | * @return bool|MediaTransformError |
||
| 244 | */ |
||
| 245 | public function rasterize( $srcPath, $dstPath, $width, $height, $lang = false ) { |
||
| 246 | global $wgSVGConverters, $wgSVGConverter, $wgSVGConverterPath; |
||
| 247 | $err = false; |
||
| 248 | $retval = ''; |
||
| 249 | if ( isset( $wgSVGConverters[$wgSVGConverter] ) ) { |
||
| 250 | if ( is_array( $wgSVGConverters[$wgSVGConverter] ) ) { |
||
| 251 | // This is a PHP callable |
||
| 252 | $func = $wgSVGConverters[$wgSVGConverter][0]; |
||
| 253 | $args = array_merge( [ $srcPath, $dstPath, $width, $height, $lang ], |
||
| 254 | array_slice( $wgSVGConverters[$wgSVGConverter], 1 ) ); |
||
| 255 | if ( !is_callable( $func ) ) { |
||
| 256 | throw new MWException( "$func is not callable" ); |
||
| 257 | } |
||
| 258 | $err = call_user_func_array( $func, $args ); |
||
| 259 | $retval = (bool)$err; |
||
| 260 | } else { |
||
| 261 | // External command |
||
| 262 | $cmd = str_replace( |
||
| 263 | [ '$path/', '$width', '$height', '$input', '$output' ], |
||
| 264 | [ $wgSVGConverterPath ? wfEscapeShellArg( "$wgSVGConverterPath/" ) : "", |
||
| 265 | intval( $width ), |
||
| 266 | intval( $height ), |
||
| 267 | wfEscapeShellArg( $srcPath ), |
||
| 268 | wfEscapeShellArg( $dstPath ) ], |
||
| 269 | $wgSVGConverters[$wgSVGConverter] |
||
| 270 | ); |
||
| 271 | |||
| 272 | $env = []; |
||
| 273 | if ( $lang !== false ) { |
||
| 274 | $env['LANG'] = $lang; |
||
| 275 | } |
||
| 276 | |||
| 277 | wfDebug( __METHOD__ . ": $cmd\n" ); |
||
| 278 | $err = wfShellExecWithStderr( $cmd, $retval, $env ); |
||
| 279 | } |
||
| 280 | } |
||
| 281 | $removed = $this->removeBadFile( $dstPath, $retval ); |
||
| 282 | if ( $retval != 0 || $removed ) { |
||
| 283 | $this->logErrorForExternalProcess( $retval, $err, $cmd ); |
||
|
0 ignored issues
–
show
The variable
$cmd does not seem to be defined for all execution paths leading up to this point.
If you define a variable conditionally, it can happen that it is not defined for all execution paths. Let’s take a look at an example: function myFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
// $x is potentially undefined here.
echo $x;
}
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined. Available Fixes
Loading history...
|
|||
| 284 | return new MediaTransformError( 'thumbnail_error', $width, $height, $err ); |
||
| 285 | } |
||
| 286 | |||
| 287 | return true; |
||
| 288 | } |
||
| 289 | |||
| 290 | public static function rasterizeImagickExt( $srcPath, $dstPath, $width, $height ) { |
||
| 291 | $im = new Imagick( $srcPath ); |
||
| 292 | $im->setImageFormat( 'png' ); |
||
| 293 | $im->setBackgroundColor( 'transparent' ); |
||
| 294 | $im->setImageDepth( 8 ); |
||
| 295 | |||
| 296 | if ( !$im->thumbnailImage( intval( $width ), intval( $height ), /* fit */ false ) ) { |
||
| 297 | return 'Could not resize image'; |
||
| 298 | } |
||
| 299 | if ( !$im->writeImage( $dstPath ) ) { |
||
| 300 | return "Could not write to $dstPath"; |
||
| 301 | } |
||
| 302 | } |
||
| 303 | |||
| 304 | /** |
||
| 305 | * @param File|FSFile $file |
||
| 306 | * @param string $path Unused |
||
| 307 | * @param bool|array $metadata |
||
| 308 | * @return array |
||
| 309 | */ |
||
| 310 | function getImageSize( $file, $path, $metadata = false ) { |
||
| 311 | if ( $metadata === false && $file instanceof File ) { |
||
| 312 | $metadata = $file->getMetadata(); |
||
| 313 | } |
||
| 314 | $metadata = $this->unpackMetadata( $metadata ); |
||
| 315 | |||
| 316 | if ( isset( $metadata['width'] ) && isset( $metadata['height'] ) ) { |
||
| 317 | return [ $metadata['width'], $metadata['height'], 'SVG', |
||
| 318 | "width=\"{$metadata['width']}\" height=\"{$metadata['height']}\"" ]; |
||
| 319 | } else { // error |
||
| 320 | return [ 0, 0, 'SVG', "width=\"0\" height=\"0\"" ]; |
||
| 321 | } |
||
| 322 | } |
||
| 323 | |||
| 324 | function getThumbType( $ext, $mime, $params = null ) { |
||
| 325 | return [ 'png', 'image/png' ]; |
||
| 326 | } |
||
| 327 | |||
| 328 | /** |
||
| 329 | * Subtitle for the image. Different from the base |
||
| 330 | * class so it can be denoted that SVG's have |
||
| 331 | * a "nominal" resolution, and not a fixed one, |
||
| 332 | * as well as so animation can be denoted. |
||
| 333 | * |
||
| 334 | * @param File $file |
||
| 335 | * @return string |
||
| 336 | */ |
||
| 337 | function getLongDesc( $file ) { |
||
| 338 | global $wgLang; |
||
| 339 | |||
| 340 | $metadata = $this->unpackMetadata( $file->getMetadata() ); |
||
| 341 | if ( isset( $metadata['error'] ) ) { |
||
| 342 | return wfMessage( 'svg-long-error', $metadata['error']['message'] )->text(); |
||
| 343 | } |
||
| 344 | |||
| 345 | $size = $wgLang->formatSize( $file->getSize() ); |
||
| 346 | |||
| 347 | if ( $this->isAnimatedImage( $file ) ) { |
||
| 348 | $msg = wfMessage( 'svg-long-desc-animated' ); |
||
| 349 | } else { |
||
| 350 | $msg = wfMessage( 'svg-long-desc' ); |
||
| 351 | } |
||
| 352 | |||
| 353 | $msg->numParams( $file->getWidth(), $file->getHeight() )->params( $size ); |
||
| 354 | |||
| 355 | return $msg->parse(); |
||
| 356 | } |
||
| 357 | |||
| 358 | /** |
||
| 359 | * @param File|FSFile $file |
||
| 360 | * @param string $filename |
||
| 361 | * @return string Serialised metadata |
||
| 362 | */ |
||
| 363 | function getMetadata( $file, $filename ) { |
||
| 364 | $metadata = [ 'version' => self::SVG_METADATA_VERSION ]; |
||
| 365 | try { |
||
| 366 | $metadata += SVGMetadataExtractor::getMetadata( $filename ); |
||
| 367 | } catch ( Exception $e ) { // @todo SVG specific exceptions |
||
| 368 | // File not found, broken, etc. |
||
| 369 | $metadata['error'] = [ |
||
| 370 | 'message' => $e->getMessage(), |
||
| 371 | 'code' => $e->getCode() |
||
| 372 | ]; |
||
| 373 | wfDebug( __METHOD__ . ': ' . $e->getMessage() . "\n" ); |
||
| 374 | } |
||
| 375 | |||
| 376 | return serialize( $metadata ); |
||
| 377 | } |
||
| 378 | |||
| 379 | View Code Duplication | function unpackMetadata( $metadata ) { |
|
| 380 | MediaWiki\suppressWarnings(); |
||
| 381 | $unser = unserialize( $metadata ); |
||
| 382 | MediaWiki\restoreWarnings(); |
||
| 383 | if ( isset( $unser['version'] ) && $unser['version'] == self::SVG_METADATA_VERSION ) { |
||
| 384 | return $unser; |
||
| 385 | } else { |
||
| 386 | return false; |
||
| 387 | } |
||
| 388 | } |
||
| 389 | |||
| 390 | function getMetadataType( $image ) { |
||
| 391 | return 'parsed-svg'; |
||
| 392 | } |
||
| 393 | |||
| 394 | function isMetadataValid( $image, $metadata ) { |
||
| 395 | $meta = $this->unpackMetadata( $metadata ); |
||
| 396 | if ( $meta === false ) { |
||
| 397 | return self::METADATA_BAD; |
||
| 398 | } |
||
| 399 | if ( !isset( $meta['originalWidth'] ) ) { |
||
| 400 | // Old but compatible |
||
| 401 | return self::METADATA_COMPATIBLE; |
||
| 402 | } |
||
| 403 | |||
| 404 | return self::METADATA_GOOD; |
||
| 405 | } |
||
| 406 | |||
| 407 | protected function visibleMetadataFields() { |
||
| 408 | $fields = [ 'objectname', 'imagedescription' ]; |
||
| 409 | |||
| 410 | return $fields; |
||
| 411 | } |
||
| 412 | |||
| 413 | /** |
||
| 414 | * @param File $file |
||
| 415 | * @param bool|IContextSource $context Context to use (optional) |
||
| 416 | * @return array|bool |
||
| 417 | */ |
||
| 418 | function formatMetadata( $file, $context = false ) { |
||
| 419 | $result = [ |
||
| 420 | 'visible' => [], |
||
| 421 | 'collapsed' => [] |
||
| 422 | ]; |
||
| 423 | $metadata = $file->getMetadata(); |
||
| 424 | if ( !$metadata ) { |
||
| 425 | return false; |
||
| 426 | } |
||
| 427 | $metadata = $this->unpackMetadata( $metadata ); |
||
| 428 | if ( !$metadata || isset( $metadata['error'] ) ) { |
||
| 429 | return false; |
||
| 430 | } |
||
| 431 | |||
| 432 | /* @todo Add a formatter |
||
| 433 | $format = new FormatSVG( $metadata ); |
||
| 434 | $formatted = $format->getFormattedData(); |
||
| 435 | */ |
||
| 436 | |||
| 437 | // Sort fields into visible and collapsed |
||
| 438 | $visibleFields = $this->visibleMetadataFields(); |
||
| 439 | |||
| 440 | $showMeta = false; |
||
| 441 | foreach ( $metadata as $name => $value ) { |
||
| 442 | $tag = strtolower( $name ); |
||
| 443 | if ( isset( self::$metaConversion[$tag] ) ) { |
||
| 444 | $tag = strtolower( self::$metaConversion[$tag] ); |
||
| 445 | } else { |
||
| 446 | // Do not output other metadata not in list |
||
| 447 | continue; |
||
| 448 | } |
||
| 449 | $showMeta = true; |
||
| 450 | self::addMeta( $result, |
||
| 451 | in_array( $tag, $visibleFields ) ? 'visible' : 'collapsed', |
||
| 452 | 'exif', |
||
| 453 | $tag, |
||
| 454 | $value |
||
| 455 | ); |
||
| 456 | } |
||
| 457 | |||
| 458 | return $showMeta ? $result : false; |
||
| 459 | } |
||
| 460 | |||
| 461 | /** |
||
| 462 | * @param string $name Parameter name |
||
| 463 | * @param mixed $value Parameter value |
||
| 464 | * @return bool Validity |
||
| 465 | */ |
||
| 466 | public function validateParam( $name, $value ) { |
||
| 467 | if ( in_array( $name, [ 'width', 'height' ] ) ) { |
||
| 468 | // Reject negative heights, widths |
||
| 469 | return ( $value > 0 ); |
||
| 470 | } elseif ( $name == 'lang' ) { |
||
| 471 | // Validate $code |
||
| 472 | if ( $value === '' || !Language::isValidBuiltInCode( $value ) ) { |
||
| 473 | wfDebug( "Invalid user language code\n" ); |
||
| 474 | |||
| 475 | return false; |
||
| 476 | } |
||
| 477 | |||
| 478 | return true; |
||
| 479 | } |
||
| 480 | |||
| 481 | // Only lang, width and height are acceptable keys |
||
| 482 | return false; |
||
| 483 | } |
||
| 484 | |||
| 485 | /** |
||
| 486 | * @param array $params Name=>value pairs of parameters |
||
| 487 | * @return string Filename to use |
||
| 488 | */ |
||
| 489 | public function makeParamString( $params ) { |
||
| 490 | $lang = ''; |
||
| 491 | if ( isset( $params['lang'] ) && $params['lang'] !== 'en' ) { |
||
| 492 | $params['lang'] = strtolower( $params['lang'] ); |
||
| 493 | $lang = "lang{$params['lang']}-"; |
||
| 494 | } |
||
| 495 | if ( !isset( $params['width'] ) ) { |
||
| 496 | return false; |
||
| 497 | } |
||
| 498 | |||
| 499 | return "$lang{$params['width']}px"; |
||
| 500 | } |
||
| 501 | |||
| 502 | public function parseParamString( $str ) { |
||
| 503 | $m = false; |
||
| 504 | if ( preg_match( '/^lang([a-z]+(?:-[a-z]+)*)-(\d+)px$/', $str, $m ) ) { |
||
| 505 | return [ 'width' => array_pop( $m ), 'lang' => $m[1] ]; |
||
| 506 | } elseif ( preg_match( '/^(\d+)px$/', $str, $m ) ) { |
||
| 507 | return [ 'width' => $m[1], 'lang' => 'en' ]; |
||
| 508 | } else { |
||
| 509 | return false; |
||
| 510 | } |
||
| 511 | } |
||
| 512 | |||
| 513 | public function getParamMap() { |
||
| 514 | return [ 'img_lang' => 'lang', 'img_width' => 'width' ]; |
||
| 515 | } |
||
| 516 | |||
| 517 | /** |
||
| 518 | * @param array $params |
||
| 519 | * @return array |
||
| 520 | */ |
||
| 521 | function getScriptParams( $params ) { |
||
| 522 | $scriptParams = [ 'width' => $params['width'] ]; |
||
| 523 | if ( isset( $params['lang'] ) ) { |
||
| 524 | $scriptParams['lang'] = $params['lang']; |
||
| 525 | } |
||
| 526 | |||
| 527 | return $scriptParams; |
||
| 528 | } |
||
| 529 | |||
| 530 | public function getCommonMetaArray( File $file ) { |
||
| 531 | $metadata = $file->getMetadata(); |
||
| 532 | if ( !$metadata ) { |
||
| 533 | return []; |
||
| 534 | } |
||
| 535 | $metadata = $this->unpackMetadata( $metadata ); |
||
| 536 | if ( !$metadata || isset( $metadata['error'] ) ) { |
||
| 537 | return []; |
||
| 538 | } |
||
| 539 | $stdMetadata = []; |
||
| 540 | foreach ( $metadata as $name => $value ) { |
||
| 541 | $tag = strtolower( $name ); |
||
| 542 | if ( $tag === 'originalwidth' || $tag === 'originalheight' ) { |
||
| 543 | // Skip these. In the exif metadata stuff, it is assumed these |
||
| 544 | // are measured in px, which is not the case here. |
||
| 545 | continue; |
||
| 546 | } |
||
| 547 | if ( isset( self::$metaConversion[$tag] ) ) { |
||
| 548 | $tag = self::$metaConversion[$tag]; |
||
| 549 | $stdMetadata[$tag] = $value; |
||
| 550 | } |
||
| 551 | } |
||
| 552 | |||
| 553 | return $stdMetadata; |
||
| 554 | } |
||
| 555 | } |
||
| 556 |
Let’s assume that you have a directory layout like this:
. |-- OtherDir | |-- Bar.php | `-- Foo.php `-- SomeDir `-- Foo.phpand let’s assume the following content of
Bar.php:If both files
OtherDir/Foo.phpandSomeDir/Foo.phpare loaded in the same runtime, you will see a PHP error such as the following:PHP Fatal error: Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.phpHowever, as
OtherDir/Foo.phpdoes not necessarily have to be loaded and the error is only triggered if it is loaded beforeOtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias: