24 use MediaWiki\HookContainer\ProtectedHookAccessorTrait;
31 use Wikimedia\AtEase\AtEase;
50 use ProtectedHookAccessorTrait;
125 self::EMPTY_FILE =>
'empty-file',
126 self::FILE_TOO_LARGE =>
'file-too-large',
127 self::FILETYPE_MISSING =>
'filetype-missing',
128 self::FILETYPE_BADTYPE =>
'filetype-banned',
129 self::MIN_LENGTH_PARTNAME =>
'filename-tooshort',
130 self::ILLEGAL_FILENAME =>
'illegal-filename',
131 self::OVERWRITE_EXISTING_FILE =>
'overwrite',
132 self::VERIFICATION_ERROR =>
'verification-error',
133 self::HOOK_ABORTED =>
'hookaborted',
134 self::WINDOWS_NONASCII_FILENAME =>
'windows-nonascii-filename',
135 self::FILENAME_TOO_LONG =>
'filename-toolong',
137 return $code_to_status[$error] ??
'unknown-error';
147 $enableUploads = MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::EnableUploads );
149 return $enableUploads &&
wfIniGetBool(
'file_uploads' );
161 foreach ( [
'upload',
'edit' ] as $permission ) {
162 if ( !$performer->
isAllowed( $permission ) ) {
177 return $user->pingLimiter(
'upload' );
191 $type =
$type ?: $request->getVal(
'wpSourceType',
'File' );
205 if ( $className ===
null ) {
206 $className =
'UploadFrom' .
$type;
207 wfDebug( __METHOD__ .
": class name: $className" );
208 if ( !in_array(
$type, self::$uploadHandlers ) ) {
214 if ( !$className::isEnabled() ) {
219 if ( !$className::isValidRequest( $request ) ) {
224 $handler =
new $className;
226 $handler->initializeFromRequest( $request );
265 $this->mDesiredDestName = $name;
267 throw new MWException( __METHOD__ .
" given storage path `$tempPath`." );
271 $this->mRemoveTempFile = $removeTempFile;
286 $this->mTempPath = $tempPath;
287 $this->mFileSize = $fileSize ?:
null;
288 if ( strlen( $this->mTempPath ) && file_exists( $this->mTempPath ) ) {
289 $this->tempFileObj =
new TempFSFile( $this->mTempPath );
291 $this->mFileSize = filesize( $this->mTempPath );
294 $this->tempFileObj =
null;
312 return empty( $this->mFileSize );
337 $repo = MediaWikiServices::getInstance()->getRepoGroup()->getLocalRepo();
342 $tmpFile = $repo->getLocalCopy( $srcPath );
344 $tmpFile->bind( $this );
346 $path = $tmpFile ? $tmpFile->getPath() :
false;
383 if ( $this->mFileSize > $maxSize ) {
396 if ( $verification !==
true ) {
399 'details' => $verification
407 if ( $result !==
true ) {
422 if ( $nt ===
null ) {
424 if ( $this->mTitleError == self::ILLEGAL_FILENAME ) {
427 if ( $this->mTitleError == self::FILETYPE_BADTYPE ) {
429 if ( count( $this->mBlackListedExtensions ) ) {
451 $verifyMimeType = MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::VerifyMimeType );
452 $verifyMimeTypeIE = MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::VerifyMimeTypeIE );
453 if ( $verifyMimeType ) {
454 wfDebug(
"mime: <$mime> extension: <{$this->mFinalExtension}>" );
455 $mimeTypeExclusions = MediaWikiServices::getInstance()->getMainConfig()
456 ->get( MainConfigNames::MimeTypeExclusions );
457 if ( self::checkFileExtension(
$mime, $mimeTypeExclusions ) ) {
458 return [
'filetype-badmime',
$mime ];
461 if ( $verifyMimeTypeIE ) {
462 # Check what Internet Explorer would detect
463 $fp = fopen( $this->mTempPath,
'rb' );
465 $chunk = fread( $fp, 256 );
468 $magic = MediaWikiServices::getInstance()->getMimeAnalyzer();
469 $extMime = $magic->getMimeTypeFromExtensionOrNull( (
string)$this->mFinalExtension ) ??
'';
470 $ieTypes = $magic->getIEMimeTypes( $this->mTempPath, $chunk, $extMime );
471 foreach ( $ieTypes as $ieType ) {
472 if ( self::checkFileExtension( $ieType, $mimeTypeExclusions ) ) {
473 return [
'filetype-bad-ie-mime', $ieType ];
489 $config = MediaWikiServices::getInstance()->getMainConfig();
490 $verifyMimeType = $config->get( MainConfigNames::VerifyMimeType );
491 $disableUploadScriptChecks = $config->get( MainConfigNames::DisableUploadScriptChecks );
493 if ( $status !==
true ) {
497 $mwProps =
new MWFileProps( MediaWikiServices::getInstance()->getMimeAnalyzer() );
498 $this->mFileProps = $mwProps->getPropsFromPath( $this->mTempPath, $this->mFinalExtension );
499 $mime = $this->mFileProps[
'mime'];
501 if ( $verifyMimeType ) {
502 # XXX: Missing extension will be caught by validateName() via getTitle()
503 if ( (
string)$this->mFinalExtension !==
'' &&
510 # check for htmlish code and javascript
511 if ( !$disableUploadScriptChecks ) {
512 if ( $this->mFinalExtension ==
'svg' ||
$mime ==
'image/svg+xml' ) {
514 if ( $svgStatus !==
false ) {
522 $handlerStatus = $handler->verifyUpload( $this->mTempPath );
523 if ( !$handlerStatus->isOK() ) {
524 $errors = $handlerStatus->getErrorsArray();
526 return reset( $errors );
531 $this->getHookRunner()->onUploadVerifyFile( $this,
$mime, $error );
532 if ( $error !==
true ) {
533 if ( !is_array( $error ) ) {
539 wfDebug( __METHOD__ .
": all clear; passing." );
553 $config = MediaWikiServices::getInstance()->getMainConfig();
554 $disableUploadScriptChecks = $config->get( MainConfigNames::DisableUploadScriptChecks );
555 # getTitle() sets some internal parameters like $this->mFinalExtension
558 $mwProps =
new MWFileProps( MediaWikiServices::getInstance()->getMimeAnalyzer() );
559 $this->mFileProps = $mwProps->getPropsFromPath( $this->mTempPath, $this->mFinalExtension );
561 # check MIME type, if desired
562 $mime = $this->mFileProps[
'file-mime'];
564 if ( $status !==
true ) {
568 # check for htmlish code and javascript
569 if ( !$disableUploadScriptChecks ) {
570 if ( self::detectScript( $this->mTempPath,
$mime, $this->mFinalExtension ) ) {
571 return [
'uploadscripted' ];
573 if ( $this->mFinalExtension ==
'svg' ||
$mime ==
'image/svg+xml' ) {
575 if ( $svgStatus !==
false ) {
581 # Scan the uploaded file for viruses
584 return [
'uploadvirus', $virus ];
596 $names = [ $entry[
'name'] ];
603 $nullPos = strpos( $entry[
'name'],
"\000" );
604 if ( $nullPos !==
false ) {
605 $names[] = substr( $entry[
'name'], 0, $nullPos );
610 if ( preg_grep(
'!\.class/?$!', $names ) ) {
611 $this->mJavaDetected =
true;
645 if ( $nt ===
null ) {
649 $status = PermissionStatus::newEmpty();
652 if ( !$status->isGood() ) {
653 return $status->toLegacyErrorArray();
657 if ( $overwriteError !==
true ) {
658 return [ $overwriteError ];
674 if ( $user ===
null ) {
682 $localFile->load( File::READ_LATEST );
683 $filename = $localFile->getName();
686 $badFileName = $this->
checkBadFileName( $filename, $this->mDesiredDestName );
687 if ( $badFileName !==
null ) {
688 $warnings[
'badfilename'] = $badFileName;
692 if ( $unwantedFileExtensionDetails !==
null ) {
693 $warnings[
'filetype-unwanted-type'] = $unwantedFileExtensionDetails;
696 $fileSizeWarnings = $this->
checkFileSize( $this->mFileSize );
697 if ( $fileSizeWarnings ) {
698 $warnings = array_merge( $warnings, $fileSizeWarnings );
702 if ( $localFileExistsWarnings ) {
703 $warnings = array_merge( $warnings, $localFileExistsWarnings );
707 $warnings[
'was-deleted'] = $filename;
712 $ignoreLocalDupes = isset( $warnings[
'exists'] );
715 $warnings[
'duplicate'] = $dupes;
719 if ( $archivedDupes !==
null ) {
720 $warnings[
'duplicate-archive'] = $archivedDupes;
738 array_walk_recursive( $warnings,
static function ( &$param, $key ) {
739 if ( $param instanceof
File ) {
741 'fileName' => $param->getName(),
742 'timestamp' => $param->getTimestamp()
744 } elseif ( is_object( $param ) ) {
745 throw new InvalidArgumentException(
746 'UploadBase::makeWarningsSerializable: ' .
747 'Unexpected object of class ' . get_class( $param ) );
763 $comparableName = str_replace(
' ',
'_', $desiredFileName );
766 if ( $desiredFileName != $filename && $comparableName != $filename ) {
783 $checkFileExtensions = MediaWikiServices::getInstance()->getMainConfig()
784 ->get( MainConfigNames::CheckFileExtensions );
785 $fileExtensions = MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::FileExtensions );
786 if ( $checkFileExtensions ) {
787 $extensions = array_unique( $fileExtensions );
791 $wgLang->commaList( $extensions ),
806 $uploadSizeWarning = MediaWikiServices::getInstance()->getMainConfig()
807 ->get( MainConfigNames::UploadSizeWarning );
811 if ( $uploadSizeWarning && ( $fileSize > $uploadSizeWarning ) ) {
812 $warnings[
'large-file'] = [
818 if ( $fileSize == 0 ) {
819 $warnings[
'empty-file'] =
true;
835 if ( $exists !==
false ) {
836 $warnings[
'exists'] = $exists;
839 if ( $hash !==
false && $hash === $localFile->
getSha1() ) {
840 $warnings[
'no-change'] = $localFile;
845 foreach ( $history as $oldFile ) {
846 if ( $hash === $oldFile->getSha1() ) {
847 $warnings[
'duplicate-version'][] = $oldFile;
866 if ( $hash ===
false ) {
869 $dupes = MediaWikiServices::getInstance()->getRepoGroup()->findBySha1( $hash );
871 foreach ( $dupes as $key => $dupe ) {
875 $title->equals( $dupe->getTitle() )
877 unset( $dupes[$key] );
892 if ( $hash ===
false ) {
896 if ( $archivedFile->getID() > 0 ) {
898 return $archivedFile->getName();
925 $comment, $pageText, $watch, $user, $tags = [], ?
string $watchlistExpiry =
null
932 $this->getHookRunner()->onUploadVerifyUpload( $this, $user, $props, $comment, $pageText, $error );
934 if ( !is_array( $error ) ) {
951 if ( $status->isGood() ) {
953 MediaWikiServices::getInstance()->getWatchlistManager()->addWatchIgnoringRights(
959 $this->getHookRunner()->onUploadComplete( $this );
983 if ( $this->mTitle !==
false ) {
986 if ( !is_string( $this->mDesiredDestName ) ) {
988 $this->mTitle =
null;
997 $this->mFilteredName =
$title->getDBkey();
1002 # oi_archive_name is max 255 bytes, which include a timestamp and an
1003 # exclamation mark, so restrict file name to 240 bytes.
1004 if ( strlen( $this->mFilteredName ) > 240 ) {
1006 $this->mTitle =
null;
1019 if ( $nt ===
null ) {
1021 $this->mTitle =
null;
1025 $this->mFilteredName = $nt->
getDBkey();
1033 if (
$ext !== [] ) {
1034 $this->mFinalExtension = trim( end(
$ext ) );
1036 $this->mFinalExtension =
'';
1041 if ( $this->mTempPath !==
null ) {
1042 $magic = MediaWikiServices::getInstance()->getMimeAnalyzer();
1043 $mime = $magic->guessMimeType( $this->mTempPath );
1044 if (
$mime !==
'unknown/unknown' ) {
1045 # Get a space separated list of extensions
1046 $mimeExt = $magic->getExtensionFromMimeTypeOrNull(
$mime );
1047 if ( $mimeExt !==
null ) {
1048 # Set the extension to the canonical extension
1049 $this->mFinalExtension = $mimeExt;
1051 # Fix up the other variables
1052 $this->mFilteredName .=
".{$this->mFinalExtension}";
1061 $config = MediaWikiServices::getInstance()->getMainConfig();
1062 $checkFileExtensions = $config->get( MainConfigNames::CheckFileExtensions );
1063 $strictFileExtensions = $config->get( MainConfigNames::StrictFileExtensions );
1064 $fileExtensions = $config->get( MainConfigNames::FileExtensions );
1065 $prohibitedFileExtensions = $config->get( MainConfigNames::ProhibitedFileExtensions );
1069 if ( $this->mFinalExtension ==
'' ) {
1071 $this->mTitle =
null;
1074 } elseif ( $blackListedExtensions ||
1075 ( $checkFileExtensions && $strictFileExtensions &&
1078 $this->mBlackListedExtensions = $blackListedExtensions;
1080 $this->mTitle =
null;
1086 if ( !preg_match(
'/^[\x0-\x7f]*$/', $nt->getText() )
1087 && !MediaWikiServices::getInstance()->getRepoGroup()
1088 ->getLocalRepo()->backendSupportsUnicodePaths()
1091 $this->mTitle =
null;
1096 # If there was more than one "extension", reassemble the base
1097 # filename to prevent bogus complaints about length
1098 if ( count(
$ext ) > 1 ) {
1099 $iterations = count(
$ext ) - 1;
1100 for ( $i = 0; $i < $iterations; $i++ ) {
1101 $partname .=
'.' .
$ext[$i];
1105 if ( strlen( $partname ) < 1 ) {
1107 $this->mTitle =
null;
1112 $this->mTitle = $nt;
1124 if ( $this->mLocalFile ===
null ) {
1126 $this->mLocalFile = $nt ===
null
1128 : MediaWikiServices::getInstance()->getRepoGroup()->getLocalRepo()->newFile( $nt );
1154 if ( !$isPartial ) {
1164 return Status::newFatal(
'uploadstash-exception', get_class( $e ), $e->getMessage() );
1175 $this->getHookRunner()->onUploadStashFile( $this, $user, $props, $error );
1176 if ( $error && !is_array( $error ) ) {
1177 $error = [ $error ];
1190 $stash = MediaWikiServices::getInstance()->getRepoGroup()
1191 ->getLocalRepo()->getUploadStash( $user );
1193 $this->mStashFile =
$file;
1203 if ( $this->mRemoveTempFile && $this->tempFileObj ) {
1205 wfDebug( __METHOD__ .
": Marked temporary file '{$this->mTempPath}' for removal" );
1206 $this->tempFileObj->autocollect();
1224 $bits = explode(
'.', $filename );
1225 $basename = array_shift( $bits );
1227 return [ $basename, $bits ];
1239 return in_array( strtolower(
$ext ), $list );
1251 return array_intersect( array_map(
'strtolower',
$ext ), $list );
1262 $magic = MediaWikiServices::getInstance()->getMimeAnalyzer();
1265 if ( !$magic->isRecognizableExtension( $extension ) ) {
1266 wfDebug( __METHOD__ .
": passing file with unknown detected mime type; " .
1267 "unrecognized extension '$extension', can't verify" );
1271 wfDebug( __METHOD__ .
": rejecting file with unknown detected mime type; " .
1272 "recognized extension '$extension', so probably invalid file" );
1278 $match = $magic->isMatchingExtension( $extension,
$mime );
1280 if ( $match ===
null ) {
1281 if ( $magic->getMimeTypesFromExtension( $extension ) !== [] ) {
1282 wfDebug( __METHOD__ .
": No extension known for $mime, but we know a mime for $extension" );
1286 wfDebug( __METHOD__ .
": no file extension known for mime type $mime, passing file" );
1290 } elseif ( $match ) {
1291 wfDebug( __METHOD__ .
": mime type $mime matches extension $extension, passing file" );
1297 .
": mime type $mime mismatches file extension $extension, rejecting file" );
1315 # ugly hack: for text files, always look at the entire file.
1316 # For binary field, just check the first K.
1318 $isText = strpos(
$mime,
'text/' ) === 0;
1320 $chunk = file_get_contents(
$file );
1322 $fp = fopen(
$file,
'rb' );
1326 $chunk = fread( $fp, 1024 );
1330 $chunk = strtolower( $chunk );
1336 # decode from UTF-16 if needed (could be used for obfuscation).
1337 if ( substr( $chunk, 0, 2 ) ==
"\xfe\xff" ) {
1339 } elseif ( substr( $chunk, 0, 2 ) ==
"\xff\xfe" ) {
1345 if ( $enc !==
null ) {
1346 $chunk = iconv( $enc,
"ASCII//IGNORE", $chunk );
1349 $chunk = trim( $chunk );
1352 wfDebug( __METHOD__ .
": checking for embedded scripts and HTML stuff" );
1354 # check for HTML doctype
1355 if ( preg_match(
"/<!DOCTYPE *X?HTML/i", $chunk ) ) {
1361 if ( $extension ==
'svg' || strpos(
$mime,
'image/svg' ) === 0 ) {
1362 if ( self::checkXMLEncodingMissmatch(
$file ) ) {
1376 '<html', # also in safari
1377 '<script', # also in safari
1380 foreach ( $tags as $tag ) {
1381 if ( strpos( $chunk, $tag ) !==
false ) {
1382 wfDebug( __METHOD__ .
": found something that may make it be mistaken for html: $tag" );
1392 # resolve entity-refs to look at attributes. may be harsh on big files... cache result?
1395 # look for script-types
1396 if ( preg_match(
'!type\s*=\s*[\'"]?\s*(?:\w*/)?(?:ecma|java)!sim', $chunk ) ) {
1397 wfDebug( __METHOD__ .
": found script types" );
1402 # look for html-style script-urls
1403 if ( preg_match(
'!(?:href|src|data)\s*=\s*[\'"]?\s*(?:ecma|java)script:!sim', $chunk ) ) {
1404 wfDebug( __METHOD__ .
": found html-style script urls" );
1409 # look for css-style script-urls
1410 if ( preg_match(
'!url\s*\(\s*[\'"]?\s*(?:ecma|java)script:!sim', $chunk ) ) {
1411 wfDebug( __METHOD__ .
": found css-style script urls" );
1416 wfDebug( __METHOD__ .
": no scripts found" );
1429 $svgMetadataCutoff = MediaWikiServices::getInstance()->getMainConfig()
1430 ->get( MainConfigNames::SVGMetadataCutoff );
1431 $contents = file_get_contents(
$file,
false,
null, 0, $svgMetadataCutoff );
1432 $encodingRegex =
'!encoding[ \t\n\r]*=[ \t\n\r]*[\'"](.*?)[\'"]!si';
1434 if ( preg_match(
"!<\?xml\b(.*?)\?>!si", $contents,
$matches ) ) {
1435 if ( preg_match( $encodingRegex,
$matches[1], $encMatch )
1436 && !in_array( strtoupper( $encMatch[1] ), self::$safeXmlEncodings )
1438 wfDebug( __METHOD__ .
": Found unsafe XML encoding '{$encMatch[1]}'" );
1442 } elseif ( preg_match(
"!<\?xml\b!si", $contents ) ) {
1445 wfDebug( __METHOD__ .
": Unmatched XML declaration start" );
1448 } elseif ( substr( $contents, 0, 4 ) ==
"\x4C\x6F\xA7\x94" ) {
1450 wfDebug( __METHOD__ .
": EBCDIC Encoded XML" );
1457 $attemptEncodings = [
'UTF-16',
'UTF-16BE',
'UTF-32',
'UTF-32BE' ];
1458 foreach ( $attemptEncodings as $encoding ) {
1459 AtEase::suppressWarnings();
1460 $str = iconv( $encoding,
'UTF-8', $contents );
1461 AtEase::restoreWarnings();
1462 if ( $str !=
'' && preg_match(
"!<\?xml\b(.*?)\?>!si", $str,
$matches ) ) {
1463 if ( preg_match( $encodingRegex,
$matches[1], $encMatch )
1464 && !in_array( strtoupper( $encMatch[1] ), self::$safeXmlEncodings )
1466 wfDebug( __METHOD__ .
": Found unsafe XML encoding '{$encMatch[1]}'" );
1470 } elseif ( $str !=
'' && preg_match(
"!<\?xml\b!si", $str ) ) {
1473 wfDebug( __METHOD__ .
": Unmatched XML declaration start" );
1488 $this->mSVGNSError =
false;
1491 [ $this,
'checkSvgScriptCallback' ],
1494 'processing_instruction_handler' => [ __CLASS__,
'checkSvgPICallback' ],
1495 'external_dtd_handler' => [ __CLASS__,
'checkSvgExternalDTD' ],
1498 if ( $check->wellFormed !==
true ) {
1501 return $partial ? false : [
'uploadinvalidxml' ];
1502 } elseif ( $check->filterMatch ) {
1503 if ( $this->mSVGNSError ) {
1507 return $check->filterMatchType;
1521 if ( preg_match(
'/xml-stylesheet/i', $target ) ) {
1522 return [
'upload-scripted-pi-callback' ];
1543 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd',
1544 'http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd',
1545 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-basic.dtd',
1546 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-tiny.dtd',
1548 'http://www.w3.org/TR/2001/PR-SVG-20010719/DTD/svg10.dtd',
1550 if (
$type !==
'PUBLIC'
1551 || !in_array( $systemId, $allowedDTDs )
1552 || strpos( $publicId,
"-//W3C//" ) !== 0
1554 return [
'upload-scripted-dtd' ];
1571 static $validNamespaces = [
1574 'http://creativecommons.org/ns#',
1575 'http://inkscape.sourceforge.net/dtd/sodipodi-0.dtd',
1576 'http://ns.adobe.com/adobeillustrator/10.0/',
1577 'http://ns.adobe.com/adobesvgviewerextensions/3.0/',
1578 'http://ns.adobe.com/extensibility/1.0/',
1579 'http://ns.adobe.com/flows/1.0/',
1580 'http://ns.adobe.com/illustrator/1.0/',
1581 'http://ns.adobe.com/imagereplacement/1.0/',
1582 'http://ns.adobe.com/pdf/1.3/',
1583 'http://ns.adobe.com/photoshop/1.0/',
1584 'http://ns.adobe.com/saveforweb/1.0/',
1585 'http://ns.adobe.com/variables/1.0/',
1586 'http://ns.adobe.com/xap/1.0/',
1587 'http://ns.adobe.com/xap/1.0/g/',
1588 'http://ns.adobe.com/xap/1.0/g/img/',
1589 'http://ns.adobe.com/xap/1.0/mm/',
1590 'http://ns.adobe.com/xap/1.0/rights/',
1591 'http://ns.adobe.com/xap/1.0/stype/dimensions#',
1592 'http://ns.adobe.com/xap/1.0/stype/font#',
1593 'http://ns.adobe.com/xap/1.0/stype/manifestitem#',
1594 'http://ns.adobe.com/xap/1.0/stype/resourceevent#',
1595 'http://ns.adobe.com/xap/1.0/stype/resourceref#',
1596 'http://ns.adobe.com/xap/1.0/t/pg/',
1597 'http://purl.org/dc/elements/1.1/',
1598 'http://purl.org/dc/elements/1.1',
1599 'http://schemas.microsoft.com/visio/2003/svgextensions/',
1600 'http://sodipodi.sourceforge.net/dtd/sodipodi-0.dtd',
1601 'http://taptrix.com/inkpad/svg_extensions',
1602 'http://web.resource.org/cc/',
1603 'http://www.freesoftware.fsf.org/bkchem/cdml',
1604 'http://www.inkscape.org/namespaces/inkscape',
1605 'http://www.opengis.net/gml',
1606 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
1607 'http://www.w3.org/2000/svg',
1608 'http://www.w3.org/tr/rec-rdf-syntax/',
1609 'http://www.w3.org/2000/01/rdf-schema#',
1614 $isBuggyInkscape = preg_match(
'/^&(#38;)*ns_[a-z_]+;$/', $namespace );
1616 if ( !( $isBuggyInkscape || in_array( $namespace, $validNamespaces ) ) ) {
1617 wfDebug( __METHOD__ .
": Non-svg namespace '$namespace' in uploaded file." );
1619 $this->mSVGNSError = $namespace;
1627 if ( $strippedElement ==
'script' ) {
1628 wfDebug( __METHOD__ .
": Found script element '$element' in uploaded file." );
1630 return [
'uploaded-script-svg', $strippedElement ];
1633 # e.g., <svg xmlns="http://www.w3.org/2000/svg">
1634 # <handler xmlns:ev="http://www.w3.org/2001/xml-events" ev:event="load">alert(1)</handler> </svg>
1635 if ( $strippedElement ==
'handler' ) {
1636 wfDebug( __METHOD__ .
": Found scriptable element '$element' in uploaded file." );
1638 return [
'uploaded-script-svg', $strippedElement ];
1641 # SVG reported in Feb '12 that used xml:stylesheet to generate javascript block
1642 if ( $strippedElement ==
'stylesheet' ) {
1643 wfDebug( __METHOD__ .
": Found scriptable element '$element' in uploaded file." );
1645 return [
'uploaded-script-svg', $strippedElement ];
1648 # Block iframes, in case they pass the namespace check
1649 if ( $strippedElement ==
'iframe' ) {
1650 wfDebug( __METHOD__ .
": iframe in uploaded file." );
1652 return [
'uploaded-script-svg', $strippedElement ];
1656 if ( $strippedElement ==
'style'
1659 wfDebug( __METHOD__ .
": hostile css in style element." );
1660 return [
'uploaded-hostile-svg' ];
1663 foreach ( $attribs as $attrib => $value ) {
1665 $value = strtolower( $value );
1667 if ( substr( $stripped, 0, 2 ) ==
'on' ) {
1669 .
": Found event-handler attribute '$attrib'='$value' in uploaded file." );
1671 return [
'uploaded-event-handler-on-svg', $attrib, $value ];
1674 # Do not allow relative links, or unsafe url schemas.
1675 # For <a> tags, only data:, http: and https: and same-document
1676 # fragment links are allowed. For all other tags, only data:
1677 # and fragment are allowed.
1678 if ( $stripped ==
'href'
1680 && strpos( $value,
'data:' ) !== 0
1681 && strpos( $value,
'#' ) !== 0
1683 if ( !( $strippedElement ===
'a'
1684 && preg_match(
'!^https?://!i', $value ) )
1686 wfDebug( __METHOD__ .
": Found href attribute <$strippedElement "
1687 .
"'$attrib'='$value' in uploaded file." );
1689 return [
'uploaded-href-attribute-svg', $strippedElement, $attrib, $value ];
1693 # only allow data: targets that should be safe. This prevents vectors like,
1694 # image/svg, text/xml, application/xml, and text/html, which can contain scripts
1695 if ( $stripped ==
'href' && strncasecmp(
'data:', $value, 5 ) === 0 ) {
1698 $parameters =
'(?>;[a-zA-Z0-9\!#$&\'*+.^_`{|}~-]+=(?>[a-zA-Z0-9\!#$&\'*+.^_`{|}~-]+|"(?>[\0-\x0c\x0e-\x21\x23-\x5b\x5d-\x7f]+|\\\\[\0-\x7f])*"))*(?:;base64)?';
1700 if ( !preg_match(
"!^data:\s*image/(gif|jpeg|jpg|png)$parameters,!i", $value ) ) {
1701 wfDebug( __METHOD__ .
": Found href to unwhitelisted data: uri "
1702 .
"\"<$strippedElement '$attrib'='$value'...\" in uploaded file." );
1703 return [
'uploaded-href-unsafe-target-svg', $strippedElement, $attrib, $value ];
1707 # Change href with animate from (http:
1708 if ( $stripped ===
'attributename'
1709 && $strippedElement ===
'animate'
1712 wfDebug( __METHOD__ .
": Found animate that might be changing href using from "
1713 .
"\"<$strippedElement '$attrib'='$value'...\" in uploaded file." );
1715 return [
'uploaded-animate-svg', $strippedElement, $attrib, $value ];
1718 # use set/animate to add event-handler attribute to parent
1719 if ( ( $strippedElement ==
'set' || $strippedElement ==
'animate' )
1720 && $stripped ==
'attributename'
1721 && substr( $value, 0, 2 ) ==
'on'
1723 wfDebug( __METHOD__ .
": Found svg setting event-handler attribute with "
1724 .
"\"<$strippedElement $stripped='$value'...\" in uploaded file." );
1726 return [
'uploaded-setting-event-handler-svg', $strippedElement, $stripped, $value ];
1729 # use set to add href attribute to parent element
1730 if ( $strippedElement ==
'set'
1731 && $stripped ==
'attributename'
1732 && strpos( $value,
'href' ) !==
false
1734 wfDebug( __METHOD__ .
": Found svg setting href attribute '$value' in uploaded file." );
1736 return [
'uploaded-setting-href-svg' ];
1739 # use set to add a remote / data / script target to an element
1740 if ( $strippedElement ==
'set'
1741 && $stripped ==
'to'
1742 && preg_match(
'!(http|https|data|script):!sim', $value )
1744 wfDebug( __METHOD__ .
": Found svg setting attribute to '$value' in uploaded file." );
1746 return [
'uploaded-wrong-setting-svg', $value ];
1749 # use handler attribute with remote / data / script
1750 if ( $stripped ==
'handler' && preg_match(
'!(http|https|data|script):!sim', $value ) ) {
1751 wfDebug( __METHOD__ .
": Found svg setting handler with remote/data/script "
1752 .
"'$attrib'='$value' in uploaded file." );
1754 return [
'uploaded-setting-handler-svg', $attrib, $value ];
1757 # use CSS styles to bring in remote code
1758 if ( $stripped ==
'style'
1761 wfDebug( __METHOD__ .
": Found svg setting a style with "
1762 .
"remote url '$attrib'='$value' in uploaded file." );
1763 return [
'uploaded-remote-url-svg', $attrib, $value ];
1766 # Several attributes can include css, css character escaping isn't allowed
1767 $cssAttrs = [
'font',
'clip-path',
'fill',
'filter',
'marker',
1768 'marker-end',
'marker-mid',
'marker-start',
'mask',
'stroke' ];
1769 if ( in_array( $stripped, $cssAttrs )
1770 && self::checkCssFragment( $value )
1772 wfDebug( __METHOD__ .
": Found svg setting a style with "
1773 .
"remote url '$attrib'='$value' in uploaded file." );
1774 return [
'uploaded-remote-url-svg', $attrib, $value ];
1777 # image filters can pull in url, which could be svg that executes scripts
1778 # Only allow url( "#foo" ). Do not allow url( http:
1779 if ( $strippedElement ==
'image'
1780 && $stripped ==
'filter'
1781 && preg_match(
'!url\s*\(\s*["\']?[^#]!sim', $value )
1783 wfDebug( __METHOD__ .
": Found image filter with url: "
1784 .
"\"<$strippedElement $stripped='$value'...\" in uploaded file." );
1786 return [
'uploaded-image-filter-svg', $strippedElement, $stripped, $value ];
1800 # Forbid external stylesheets, for both reliability and to protect viewer's privacy
1801 if ( stripos( $value,
'@import' ) !==
false ) {
1805 # We allow @font-face to embed fonts with data: urls, so we snip the string
1806 # 'url' out so this case won't match when we check for urls below
1807 $pattern =
'!(@font-face\s*{[^}]*src:)url(\("data:;base64,)!im';
1808 $value = preg_replace( $pattern,
'$1$2', $value );
1810 # Check for remote and executable CSS. Unlike in Sanitizer::checkCss, the CSS
1811 # properties filter and accelerator don't seem to be useful for xss in SVG files.
1812 # Expression and -o-link don't seem to work either, but filtering them here in case.
1813 # Additionally, we catch remote urls like url("http:..., url('http:..., url(http:...,
1814 # but not local ones such as url("#..., url('#..., url(#....
1815 if ( preg_match(
'!expression
1817 | -o-link-source\s*:
1818 | -o-replace\s*:!imx', $value ) ) {
1822 if ( preg_match_all(
1823 "!(\s*(url|image|image-set)\s*\(\s*[\"']?\s*[^#]+.*?\))!sim",
1828 # TODO: redo this in one regex. Until then, url("#whatever") matches the first
1829 foreach (
$matches[1] as $match ) {
1830 if ( !preg_match(
"!\s*(url|image|image-set)\s*\(\s*(#|'#|\"#)!im", $match ) ) {
1836 if ( preg_match(
'/[\000-\010\013\016-\037\177]/', $value ) ) {
1850 $parts = explode(
':', strtolower( $element ) );
1851 $name = array_pop( $parts );
1852 $ns = implode(
':', $parts );
1854 return [ $ns, $name ];
1863 $parts = explode(
':', strtolower( $name ) );
1865 return array_pop( $parts );
1880 $mainConfig = MediaWikiServices::getInstance()->getMainConfig();
1881 $antivirus = $mainConfig->get( MainConfigNames::Antivirus );
1882 $antivirusSetup = $mainConfig->get( MainConfigNames::AntivirusSetup );
1883 $antivirusRequired = $mainConfig->get( MainConfigNames::AntivirusRequired );
1884 if ( !$antivirus ) {
1885 wfDebug( __METHOD__ .
": virus scanner disabled" );
1890 if ( !$antivirusSetup[$antivirus] ) {
1891 wfDebug( __METHOD__ .
": unknown virus scanner: {$antivirus}" );
1892 $wgOut->wrapWikiMsg(
"<div class=\"error\">\n$1\n</div>",
1893 [
'virus-badscanner', $antivirus ] );
1895 return wfMessage(
'virus-unknownscanner' )->text() .
" {$antivirus}";
1898 # look up scanner configuration
1899 $command = $antivirusSetup[$antivirus][
'command'];
1900 $exitCodeMap = $antivirusSetup[$antivirus][
'codemap'];
1901 $msgPattern = $antivirusSetup[$antivirus][
'messagepattern'] ??
null;
1903 if ( strpos(
$command,
"%f" ) ===
false ) {
1904 # simple pattern: append file to scan
1907 # complex pattern: replace "%f" with file to scan
1911 wfDebug( __METHOD__ .
": running virus scan: $command " );
1913 # execute virus scanner
1916 # NOTE: there's a 50 line workaround to make stderr redirection work on windows, too.
1917 # that does not seem to be worth the pain.
1918 # Ask me (Duesentrieb) about it if it's ever needed.
1921 # map exit code to AV_xxx constants.
1922 $mappedCode = $exitCode;
1923 if ( $exitCodeMap ) {
1924 if ( isset( $exitCodeMap[$exitCode] ) ) {
1925 $mappedCode = $exitCodeMap[$exitCode];
1926 } elseif ( isset( $exitCodeMap[
"*"] ) ) {
1927 $mappedCode = $exitCodeMap[
"*"];
1935 # scan failed (code was mapped to false by $exitCodeMap)
1936 wfDebug( __METHOD__ .
": failed to scan $file (code $exitCode)." );
1938 $output = $antivirusRequired
1939 ?
wfMessage(
'virus-scanfailed', [ $exitCode ] )->text()
1942 # scan failed because filetype is unknown (probably immune)
1943 wfDebug( __METHOD__ .
": unsupported file type $file (code $exitCode)." );
1947 wfDebug( __METHOD__ .
": file passed virus scan." );
1950 $output = trim( $output );
1953 $output =
true; #
if there
's no output, return true
1954 } elseif ( $msgPattern ) {
1956 if ( preg_match( $msgPattern, $output, $groups ) && $groups[1] ) {
1957 $output = $groups[1];
1961 wfDebug( __METHOD__ . ": FOUND VIRUS! scanner feedback: $output" );
1975 private function checkOverwrite( Authority $performer ) {
1976 // First check whether the local file can be overwritten
1977 $file = $this->getLocalFile();
1978 $file->load( File::READ_LATEST );
1979 if ( $file->exists() ) {
1980 if ( !self::userCanReUpload( $performer, $file ) ) {
1981 return [ 'fileexists-forbidden
', $file->getName() ];
1987 $services = MediaWikiServices::getInstance();
1989 /* Check shared conflicts: if the local file does not exist, but
1990 * RepoGroup::findFile finds a file, it exists in a shared repository.
1992 $file = $services->getRepoGroup()->findFile( $this->getTitle(), [ 'latest
' => true ] );
1993 if ( $file && !$performer->isAllowed( 'reupload-shared
' )
1995 return [ 'fileexists-shared-forbidden
', $file->getName() ];
2008 public static function userCanReUpload( Authority $performer, File $img ) {
2009 if ( $performer->isAllowed( 'reupload
' ) ) {
2010 return true; // non-conditional
2011 } elseif ( !$performer->isAllowed( 'reupload-own
' ) ) {
2015 if ( !( $img instanceof LocalFile ) ) {
2019 return $performer->getUser()->equals( $img->getUploader( File::RAW ) );
2033 public static function getExistsWarning( $file ) {
2034 if ( $file->exists() ) {
2035 return [ 'warning
' => 'exists
', 'file
' => $file ];
2038 if ( $file->getTitle()->getArticleID() ) {
2039 return [ 'warning
' => 'page-exists
', 'file
' => $file ];
2042 if ( !strpos( $file->getName(), '.
' ) ) {
2043 $partname = $file->getName();
2046 $n = strrpos( $file->getName(), '.
' );
2047 $extension = substr( $file->getName(), $n + 1 );
2048 $partname = substr( $file->getName(), 0, $n );
2050 $normalizedExtension = File::normalizeExtension( $extension );
2051 $localRepo = MediaWikiServices::getInstance()->getRepoGroup()->getLocalRepo();
2053 if ( $normalizedExtension != $extension ) {
2054 // We're not
using the normalized form of the extension.
2060 $file_lc = $localRepo->newFile( $nt_lc );
2062 if ( $file_lc->exists() ) {
2064 'warning' =>
'exists-normalized',
2066 'normalizedFile' => $file_lc
2072 $similarFiles = $localRepo->findFilesByPrefix(
"{$partname}.", 1 );
2073 if ( count( $similarFiles ) ) {
2075 'warning' =>
'exists-normalized',
2077 'normalizedFile' => $similarFiles[0],
2081 if ( self::isThumbName(
$file->getName() ) ) {
2082 # Check for filenames like 50px- or 180px-, these are mostly thumbnails
2084 substr( $partname, strpos( $partname,
'-' ) + 1 ) .
'.' . $extension,
2087 $file_thb = $localRepo->newFile( $nt_thb );
2088 if ( $file_thb->exists() ) {
2090 'warning' =>
'thumb',
2092 'thumbFile' => $file_thb
2097 'warning' =>
'thumb-name',
2099 'thumbFile' => $file_thb
2104 foreach ( self::getFilenamePrefixBlacklist() as $prefix ) {
2105 if ( substr( $partname, 0, strlen( $prefix ) ) == $prefix ) {
2107 'warning' =>
'bad-prefix',
2123 $n = strrpos( $filename,
'.' );
2124 $partname = $n ? substr( $filename, 0, $n ) : $filename;
2127 substr( $partname, 3, 3 ) ==
'px-' ||
2128 substr( $partname, 2, 3 ) ==
'px-'
2130 preg_match(
"/[0-9]{2}/", substr( $partname, 0, 2 ) );
2140 $message =
wfMessage(
'filename-prefix-blacklist' )->inContentLanguage();
2141 if ( !$message->isDisabled() ) {
2142 $lines = explode(
"\n", $message->plain() );
2145 $comment = substr( trim(
$line ), 0, 1 );
2146 if ( $comment ==
'#' || $comment ==
'' ) {
2150 $comment = strpos(
$line,
'#' );
2151 if ( $comment > 0 ) {
2154 $list[] = trim(
$line );
2193 $code = $error[
'status'];
2194 unset( $code[
'status'] );
2207 $maxUploadSize = MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::MaxUploadSize );
2209 if ( is_array( $maxUploadSize ) ) {
2210 if ( $forType !==
null && isset( $maxUploadSize[$forType] ) ) {
2211 return $maxUploadSize[$forType];
2213 return $maxUploadSize[
'*'];
2216 return intval( $maxUploadSize );
2229 ini_get(
'upload_max_filesize' ),
2233 ini_get(
'post_max_size' ),
2236 return min( $phpMaxFileSize, $phpMaxPostSize );
2254 return $store->get( $key );
2273 if ( $value ===
false ) {
2274 $store->delete( $key );
2276 $store->set( $key, $value, $store::TTL_DAY );
2298 return MediaWikiServices::getInstance()->getMainObjectStash();
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
wfIniGetBool( $setting)
Safety wrapper around ini_get() for boolean settings.
wfShellExecWithStderr( $cmd, &$retval=null, $environ=[], $limits=[])
Execute a shell command, returning both stdout and stderr.
wfStripIllegalFilenameChars( $name)
Replace all invalid characters with '-'.
wfShorthandToInteger( $string='', $default=-1)
Converts shorthand byte notation to integer form.
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
if(!defined( 'MW_NO_SESSION') &&! $wgCommandLineMode) $wgOut
if(!defined( 'MW_NO_SESSION') &&! $wgCommandLineMode) $wgLang
static getPropertyNames( $filter=[])
Returns all possible parameters to iiprop.
static getInfo( $file, $prop, $result, $thumbParams=null, $opts=false)
Get result information for an image revision.
static getPropertyNames( $filter=null)
Returns all possible parameters to siiprop.
Deleted file in the 'filearchive' table.
Class representing a cache/ephemeral data store.
makeKey( $collection,... $components)
Make a cache key for the global keyspace and given components.
static getSha1Base36FromPath( $path)
Get a SHA-1 hash of a file in the local filesystem, in base-36 lower case encoding,...
static isStoragePath( $path)
Check if a given path is a "mwstore://" path.
static isVirtualUrl( $url)
Determine if a string is an mwrepo:// URL.
Implements some public methods and some protected utility functions which are required by multiple ch...
wasDeleted()
Was this file ever deleted from the wiki?
static runner()
Get a HookRunner instance for calling hooks using the new interfaces.
Local file in the wiki's own database.
exists()
canRender inherited
getHistory( $limit=null, $start=null, $end=null, $inc=true)
purgeDescription inherited
MimeMagic helper wrapper.
A class containing constants representing the names of configuration variables.
static getMain()
Get the RequestContext object associated with the main request.
static decodeCharReferences( $text)
Decode any character references, numeric or named entities, in the text and return a UTF-8 string.
static normalizeCss( $value)
Normalize CSS into a format we can easily search for hostile input.
static newFatal( $message,... $parameters)
Factory function for fatal errors.
static newGood( $value=null)
Factory function for good results.
This class is used to hold the location and do limited manipulation of files stored temporarily (this...
static capitalize( $text, $ns=NS_MAIN)
Capitalize a text string for a title if it belongs to a namespace that capitalizes.
getDBkey()
Get the main part with underscores.
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
static makeTitleSafe( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
UploadBase and subclasses are the backend of MediaWiki's file uploads.
static string[] $uploadHandlers
Upload handlers.
getSourceType()
Returns the upload type.
static makeWarningsSerializable( $warnings)
Convert the warnings array returned by checkWarnings() to something that can be serialized.
static setSessionStatus(UserIdentity $user, $statusKey, $value)
Set the current status of a chunked upload (used for polling)
UploadStashFile null $mStashFile
static verifyExtension( $mime, $extension)
Checks if the MIME type of the uploaded file matches the file extension.
postProcessUpload()
Perform extra steps after a successful upload.
checkSvgScriptCallback( $element, $attribs, $data=null)
verifyPermissions(Authority $performer)
Alias for verifyTitlePermissions.
checkLocalFileExists(LocalFile $localFile, $hash)
getLocalFile()
Return the local file and initializes if necessary.
stripXmlNamespace( $name)
string null $mFilteredName
checkBadFileName( $filename, $desiredFileName)
Check whether the resulting filename is different from the desired one, but ignore things like ucfirs...
static createFromRequest(&$request, $type=null)
Create a form of UploadBase depending on wpSourceType and initializes it.
runUploadStashFileHook(User $user)
zipEntryCallback( $entry)
Callback for ZipDirectoryReader to detect Java class files.
static checkSvgPICallback( $target, $data)
Callback to filter SVG Processing Instructions.
static isValidRequest( $request)
Check whether a request if valid for this handler.
convertVerifyErrorToStatus( $error)
string null $mFinalExtension
verifyPartialFile()
A verification routine suitable for partial files.
static detectScript( $file, $mime, $extension)
Heuristic for detecting files that could contain JavaScript instructions or things that may look like...
verifyFile()
Verifies that it's ok to include the uploaded file.
static isEnabled()
Returns true if uploads are enabled.
static isThumbName( $filename)
Helper function that checks whether the filename looks like a thumbnail.
static getUploadSessionStore()
getVerificationErrorCode( $error)
performUpload( $comment, $pageText, $watch, $user, $tags=[], ?string $watchlistExpiry=null)
Really perform the upload.
string null $mDesiredDestName
static checkCssFragment( $value)
Check a block of CSS or CSS fragment for anything that looks like it is bringing in remote code.
verifyTitlePermissions(Authority $performer)
Check whether the user can edit, upload and create the image.
static getFilenamePrefixBlacklist()
Get a list of blacklisted filename prefixes from [[MediaWiki:Filename-prefix-blacklist]].
const OVERWRITE_EXISTING_FILE
setTempFile( $tempPath, $fileSize=null)
static getSessionStatus(UserIdentity $user, $statusKey)
Get the current status of a chunked upload (used for polling)
static checkXMLEncodingMissmatch( $file)
Check a whitelist of xml encodings that are known not to be interpreted differently by the server's x...
doStashFile(User $user=null)
Implementation for stashFile() and tryStashFile().
string[] $mBlackListedExtensions
static isAllowed(Authority $performer)
Returns true if the user can use this upload module or else a string identifying the missing permissi...
const WINDOWS_NONASCII_FILENAME
cleanupTempFile()
If we've modified the upload file we need to manually remove it on exit to clean up.
validateName()
Verify that the name is valid and, if necessary, that we can overwrite.
checkFileSize( $fileSize)
isEmptyFile()
Return true if the file is empty.
static checkFileExtension( $ext, $list)
Perform case-insensitive match against a list of file extensions.
tryStashFile(User $user, $isPartial=false)
Like stashFile(), but respects extensions' wishes to prevent the stashing.
checkAgainstArchiveDupes( $hash, Authority $performer)
getTitle()
Returns the title of the file to be uploaded.
initializePathInfo( $name, $tempPath, $fileSize, $removeTempFile=false)
static getMaxUploadSize( $forType=null)
Get MediaWiki's maximum uploaded file size for given type of upload, based on $wgMaxUploadSize.
bool null $mRemoveTempFile
static checkSvgExternalDTD( $type, $publicId, $systemId)
Verify that DTD urls referenced are only the standard dtds.
getTempFileSha1Base36()
Get the base 36 SHA1 of the file.
static splitXmlNamespace( $element)
Divide the element name passed by the xml parser to the callback into URI and prefix.
getImageInfo( $result)
Gets image info about the file just uploaded.
detectScriptInSvg( $filename, $partial)
static splitExtensions( $filename)
Split a file into a base name and all dot-delimited 'extensions' on the end.
fetchFile()
Fetch the file.
checkWarnings( $user=null)
Check for non fatal problems with the file.
static getUploadSessionKey(BagOStuff $store, UserIdentity $user, $statusKey)
static isThrottled( $user)
Returns true if the user has surpassed the upload rate limit, false otherwise.
checkLocalFileWasDeleted(LocalFile $localFile)
getFileSize()
Return the file size.
verifyUpload()
Verify whether the upload is sensible.
checkOverwrite(Authority $performer)
Check if there's an overwrite conflict and, if so, if restrictions forbid this user from performing t...
const MIN_LENGTH_PARTNAME
static checkFileExtensionList( $ext, $list)
Perform case-insensitive match against a list of file extensions.
static detectVirus( $file)
Generic wrapper function for a virus scanner program.
checkUnwantedFileExtensions( $fileExtension)
string null $mTempPath
Local file system path to the file to upload (or a local copy)
TempFSFile null $tempFileObj
Wrapper to handle deleting the temp file.
LocalFile null $mLocalFile
static getExistsWarning( $file)
Helper function that does various existence checks for a file.
static getMaxPhpUploadSize()
Get the PHP maximum uploaded file size, based on ini settings.
verifyMimeType( $mime)
Verify the MIME type.
initializeFromRequest(&$request)
Initialize from a WebRequest.
string false $mSVGNSError
checkAgainstExistingDupes( $hash, $ignoreLocalDupes)
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.
if(!is_readable( $file)) $ext
if(!file_exists( $CREDITS)) $lines