build: Upgrade mediawiki/mediawiki-phan-config from 0.13.0 to 0.14.0 manually

* Switch out raw Exceptions, mostly for InvalidArgumentExceptions.
  * Fake exceptions triggered to give Monolog a backtrace are for
    some reason "traditionally" RuntimeExceptions, instead, so we
    continue to use that pattern in remaining locations.
* Just entirely give up on PostgresResultWrapper's resource vs. object mess.
* Drop now-unneeded false positive hits.

Change-Id: Id183ab60994cd9c6dc80401d4ce4de0ddf2b3da0
This commit is contained in:
James D. Forrester 2024-02-08 18:12:50 -05:00 committed by Bartosz Dziewoński
parent 01271d2357
commit 102a4f8a35
51 changed files with 166 additions and 148 deletions

View file

@ -125,6 +125,7 @@ For notes on 1.41.x and older releases, see HISTORY.
* Updated doctrine/dbal from 3.4.2 to 3.7.2.
* Updated doctrine/sql-formatter from 1.1.1 to 1.1.3.
* Updated grunt-banana-checker from 0.11.0 to 0.11.1.
* Updated mediawiki/mediawiki-phan-config from 0.13.0 to 0.14.0.
* Updated psy/psysh from ^0.11.1 to ^0.12.0.
* Updated seld/jsonlint from 1.8.3 to 1.10.1.
* Updated wikimedia/testing-access-wrapper from 2.0.0 to 3.0.0.

View file

@ -94,7 +94,7 @@
"hamcrest/hamcrest-php": "^2.0",
"johnkary/phpunit-speedtrap": "^4.0",
"mediawiki/mediawiki-codesniffer": "42.0.0",
"mediawiki/mediawiki-phan-config": "0.13.0",
"mediawiki/mediawiki-phan-config": "0.14.0",
"nikic/php-parser": "^4.10.2",
"php-parallel-lint/php-console-highlighter": "1.0.0",
"php-parallel-lint/php-parallel-lint": "1.3.2",

View file

@ -1950,13 +1950,11 @@ function wfMemoryLimit( $newLimit ) {
if ( $newLimit == -1 ) {
wfDebug( "Removing PHP's memory limit" );
AtEase::suppressWarnings();
// @phan-suppress-next-line PhanTypeMismatchArgumentInternal Scalar okay with php8.1
ini_set( 'memory_limit', $newLimit );
AtEase::restoreWarnings();
} elseif ( $newLimit > $oldLimit ) {
wfDebug( "Raising PHP's memory limit to $newLimit bytes" );
AtEase::suppressWarnings();
// @phan-suppress-next-line PhanTypeMismatchArgumentInternal Scalar okay with php8.1
ini_set( 'memory_limit', $newLimit );
AtEase::restoreWarnings();
}

View file

@ -403,6 +403,7 @@ class HookContainer implements SalvageableService {
* @return bool Whether the hook has a handler registered to it
*/
public function isRegistered( string $hook ): bool {
// @phan-suppress-next-line MediaWikiNoEmptyIfDefined
return !empty( $this->getHandlers( $hook ) );
}

View file

@ -928,7 +928,6 @@ class OutputPage extends ContextSource {
# Not modified
# Give a 304 Not Modified response code and disable body output
wfDebug( __METHOD__ . ": NOT MODIFIED, $info", 'private' );
// @phan-suppress-next-line PhanTypeMismatchArgumentInternal Scalar okay with php8.1
ini_set( 'zlib.output_compression', 0 );
$this->getRequest()->response()->statusHeader( 304 );
$this->sendCacheControl();

View file

@ -3,6 +3,7 @@
namespace MediaWiki\Request;
use MediaWiki\Http\Telemetry;
use RuntimeException;
/**
* @since 1.29
@ -77,7 +78,7 @@ class HeaderCallback {
}
// Save a backtrace for logging in case it turns out that headers were sent prematurely
self::$headersSentException = new \Exception( 'Headers already sent from this point' );
self::$headersSentException = new RuntimeException( 'Headers already sent from this point' );
}
/**
@ -94,7 +95,7 @@ class HeaderCallback {
$logger = \MediaWiki\Logger\LoggerFactory::getInstance( 'headers-sent' );
$logger->error( 'Warning: headers were already sent from the location below', [
'exception' => self::$headersSentException,
'detection-trace' => new \Exception( 'Detected here' ),
'detection-trace' => new RuntimeException( 'Detected here' ),
] );
}
}

View file

@ -21,7 +21,7 @@
namespace MediaWiki\ResourceLoader;
use Composer\Spdx\SpdxLicenses;
use Exception;
use LogicException;
use MediaWiki\MainConfigNames;
use MediaWiki\MediaWikiServices;
use PharData;
@ -117,7 +117,7 @@ class ForeignResourceManager {
* @param string $action
* @param string $module
* @return bool
* @throws Exception
* @throws LogicException
*/
public function run( $action, $module ) {
$actions = [ 'update', 'verify', 'make-sri' ];
@ -157,7 +157,7 @@ class ForeignResourceManager {
// depending on action.
if ( !isset( $info['type'] ) ) {
throw new Exception( "Module '$moduleName' must have a 'type' key." );
throw new LogicException( "Module '$moduleName' must have a 'type' key." );
}
$this->validateLicense( $moduleName, $info );
@ -177,7 +177,7 @@ class ForeignResourceManager {
$this->verbose( "... preparing {$this->tmpParentDir}\n" );
wfRecursiveRemoveDir( $this->tmpParentDir );
if ( !wfMkdirParents( $this->tmpParentDir ) ) {
throw new Exception( "Unable to create {$this->tmpParentDir}" );
throw new LogicException( "Unable to create {$this->tmpParentDir}" );
}
switch ( $info['type'] ) {
@ -192,14 +192,14 @@ class ForeignResourceManager {
$this->handleTypeMultiFile( $moduleName, $destDir, $info );
break;
default:
throw new Exception( "Unknown type '{$info['type']}' for '$moduleName'" );
throw new LogicException( "Unknown type '{$info['type']}' for '$moduleName'" );
}
if ( $this->action === 'update' ) {
foreach ( $info['transforms'] ?? [] as $file => $transforms ) {
$fullFilePath = "$destDir/$file";
if ( !file_exists( $fullFilePath ) ) {
throw new Exception( "$moduleName: invalid transform target $file" );
throw new LogicException( "$moduleName: invalid transform target $file" );
}
if ( !is_array( $transforms ) || !array_is_list( $transforms ) ) {
$transforms = [ $transforms ];
@ -209,7 +209,7 @@ class ForeignResourceManager {
// not super efficient but these files aren't expected to be large
file_put_contents( $fullFilePath, "/*@nomin*/\n" . file_get_contents( $fullFilePath ) );
} else {
throw new Exception( "$moduleName: invalid transform $transform" );
throw new LogicException( "$moduleName: invalid transform $transform" );
}
}
}
@ -297,10 +297,10 @@ class ForeignResourceManager {
$req = MediaWikiServices::getInstance()->getHttpRequestFactory()
->create( $src, [ 'method' => 'GET', 'followRedirects' => false ], __METHOD__ );
if ( !$req->execute()->isOK() ) {
throw new Exception( "Failed to download resource at {$src}" );
throw new LogicException( "Failed to download resource at {$src}" );
}
if ( $req->getStatus() !== 200 ) {
throw new Exception( "Unexpected HTTP {$req->getStatus()} response from {$src}" );
throw new LogicException( "Unexpected HTTP {$req->getStatus()} response from {$src}" );
}
$data = $req->getContent();
$algo = $integrity === null ? $this->defaultAlgo : explode( '-', $integrity )[0];
@ -313,7 +313,7 @@ class ForeignResourceManager {
$this->output( "Integrity for {$src}\n\tintegrity: {$actualIntegrity}\n" );
} else {
$expectedIntegrity = $integrity ?? 'null';
throw new Exception( "Integrity check failed for {$src}\n" .
throw new LogicException( "Integrity check failed for {$src}\n" .
"\tExpected: {$expectedIntegrity}\n" .
"\tActual: {$actualIntegrity}"
);
@ -328,7 +328,7 @@ class ForeignResourceManager {
*/
private function handleTypeFile( $moduleName, $destDir, array $info ) {
if ( !isset( $info['src'] ) ) {
throw new Exception( "Module '$moduleName' must have a 'src' key." );
throw new LogicException( "Module '$moduleName' must have a 'src' key." );
}
$data = $this->fetch( $info['src'], $info['integrity'] ?? null, $moduleName );
$dest = $info['dest'] ?? basename( $info['src'] );
@ -349,11 +349,11 @@ class ForeignResourceManager {
*/
private function handleTypeMultiFile( $moduleName, $destDir, array $info ) {
if ( !isset( $info['files'] ) ) {
throw new Exception( "Module '$moduleName' must have a 'files' key." );
throw new LogicException( "Module '$moduleName' must have a 'files' key." );
}
foreach ( $info['files'] as $dest => $file ) {
if ( !isset( $file['src'] ) ) {
throw new Exception( "Module '$moduleName' file '$dest' must have a 'src' key." );
throw new LogicException( "Module '$moduleName' file '$dest' must have a 'src' key." );
}
$data = $this->fetch( $file['src'], $file['integrity'] ?? null, $moduleName );
$path = "$destDir/$dest";
@ -375,7 +375,7 @@ class ForeignResourceManager {
private function handleTypeTar( $moduleName, $destDir, array $info, string $fileType ) {
$info += [ 'src' => null, 'integrity' => null, 'dest' => null ];
if ( $info['src'] === null ) {
throw new Exception( "Module '$moduleName' must have a 'src' key." );
throw new LogicException( "Module '$moduleName' must have a 'src' key." );
}
// Download the resource to a temporary file and open it
$data = $this->fetch( $info['src'], $info['integrity'], $moduleName );
@ -397,7 +397,7 @@ class ForeignResourceManager {
// Use glob() to expand wildcards and check existence
$fromPaths = glob( "{$tmpDir}/{$fromSubPath}", GLOB_BRACE );
if ( !$fromPaths ) {
throw new Exception( "Path '$fromSubPath' of '$moduleName' not found." );
throw new LogicException( "Path '$fromSubPath' of '$moduleName' not found." );
}
foreach ( $fromPaths as $fromPath ) {
$toCopy[$fromPath] = $toSubPath === null
@ -429,7 +429,7 @@ class ForeignResourceManager {
$this->verbose( "... moving $from to $to\n" );
wfMkdirParents( dirname( $to ) );
if ( !rename( $from, $to ) ) {
throw new Exception( "Could not move $from to $to." );
throw new LogicException( "Could not move $from to $to." );
}
}
}
@ -484,7 +484,9 @@ class ForeignResourceManager {
*/
private function validateLicense( $moduleName, $info ) {
if ( !isset( $info['license'] ) || !is_string( $info['license'] ) ) {
throw new Exception( "Module '$moduleName' needs a valid SPDX license; no license is currently present" );
throw new LogicException(
"Module '$moduleName' needs a valid SPDX license; no license is currently present"
);
}
$licenses = new SpdxLicenses();
if ( !$licenses->validate( $info['license'] ) ) {

View file

@ -20,7 +20,7 @@
namespace MediaWiki\ResourceLoader;
use Exception;
use LogicException;
/**
* Loads the module definition from JSON files in the format that OOUI uses, converting it to the
@ -65,7 +65,7 @@ class OOUIImageModule extends ImageModule {
if ( !isset( $definition[$key] ) ) {
$definition[$key] = $value;
} elseif ( $definition[$key] !== $value ) {
throw new Exception(
throw new LogicException(
"Mismatched OOUI theme images definition: " .
"key '$key' of theme '$theme' for module '$module' " .
"does not match other themes"

View file

@ -30,6 +30,7 @@ use HttpStatus;
use InvalidArgumentException;
use Less_Environment;
use Less_Parser;
use LogicException;
use MediaWiki\CommentStore\CommentStore;
use MediaWiki\Config\Config;
use MediaWiki\Deferred\DeferredUpdates;
@ -1797,12 +1798,12 @@ MESSAGE;
*
* @param array $configuration List of configuration values keyed by variable name
* @return string JavaScript code
* @throws Exception
* @throws LogicException
*/
public static function makeConfigSetScript( array $configuration ) {
$json = self::encodeJsonForScript( $configuration );
if ( $json === false ) {
$e = new Exception(
$e = new LogicException(
'JSON serialization of config data failed. ' .
'This usually means the config data is not valid UTF-8.'
);

View file

@ -24,7 +24,7 @@ namespace MediaWiki\ResourceLoader;
use DOMDocument;
use DOMElement;
use DOMNode;
use Exception;
use InvalidArgumentException;
use Wikimedia\RemexHtml\DOM\DOMBuilder;
use Wikimedia\RemexHtml\HTMLData;
use Wikimedia\RemexHtml\Serializer\HtmlFormatter;
@ -59,7 +59,7 @@ class VueComponentParser {
* @param string $html HTML with <script>, <template> and <style> tags at the top level
* @param array $options Associative array of options
* @return array
* @throws Exception If the input is invalid
* @throws InvalidArgumentException If the input is invalid
*/
public function parse( string $html, array $options = [] ): array {
$dom = $this->parseHTML( $html );
@ -69,14 +69,14 @@ class VueComponentParser {
// Find the <script>, <template> and <style> tags. They can appear in any order, but they
// must be at the top level, and there can only be one of each.
if ( !$head ) {
throw new Exception( 'Parsed DOM did not contain a <head> tag' );
throw new InvalidArgumentException( 'Parsed DOM did not contain a <head> tag' );
}
$nodes = $this->findUniqueTags( $head, [ 'script', 'template', 'style' ] );
// Throw an error if we didn't find a <script> or <template> tag. <style> is optional.
foreach ( [ 'script', 'template' ] as $requiredTag ) {
if ( !isset( $nodes[ $requiredTag ] ) ) {
throw new Exception( "No <$requiredTag> tag found" );
throw new InvalidArgumentException( "No <$requiredTag> tag found" );
}
}
@ -125,7 +125,7 @@ class VueComponentParser {
$tagName = strtolower( $node->nodeName );
if ( in_array( $tagName, $tagNames ) ) {
if ( isset( $nodes[ $tagName ] ) ) {
throw new Exception( "More than one <$tagName> tag found" );
throw new InvalidArgumentException( "More than one <$tagName> tag found" );
}
$nodes[ $tagName ] = $node;
}
@ -137,18 +137,18 @@ class VueComponentParser {
* Verify that a given node only has a given set of attributes, and no others.
* @param DOMNode $node Node to check
* @param array $allowedAttributes Attributes the node is allowed to have
* @throws Exception If the node has an attribute it's not allowed to have
* @throws InvalidArgumentException If the node has an attribute it's not allowed to have
*/
private function validateAttributes( DOMNode $node, array $allowedAttributes ): void {
if ( $allowedAttributes ) {
foreach ( $node->attributes as $attr ) {
if ( !in_array( $attr->name, $allowedAttributes ) ) {
throw new Exception( "<{$node->nodeName}> may not have the " .
throw new InvalidArgumentException( "<{$node->nodeName}> may not have the " .
"{$attr->name} attribute" );
}
}
} elseif ( $node->attributes->length > 0 ) {
throw new Exception( "<{$node->nodeName}> may not have any attributes" );
throw new InvalidArgumentException( "<{$node->nodeName}> may not have any attributes" );
}
}
@ -156,14 +156,14 @@ class VueComponentParser {
* Get the contents and language of the <style> tag. The language can be 'css' or 'less'.
* @param DOMElement $styleNode The <style> tag.
* @return array [ 'style' => string, 'lang' => string ]
* @throws Exception If an invalid language is used, or if the 'scoped' attribute is set.
* @throws InvalidArgumentException If an invalid language is used, or if the 'scoped' attribute is set.
*/
private function getStyleAndLang( DOMElement $styleNode ): array {
$style = trim( $styleNode->nodeValue ?? '' );
$styleLang = $styleNode->hasAttribute( 'lang' ) ?
$styleNode->getAttribute( 'lang' ) : 'css';
if ( $styleLang !== 'css' && $styleLang !== 'less' ) {
throw new Exception( "<style lang=\"$styleLang\"> is invalid," .
throw new InvalidArgumentException( "<style lang=\"$styleLang\"> is invalid," .
" lang must be \"css\" or \"less\"" );
}
return [
@ -287,7 +287,7 @@ class VueComponentParser {
if ( $name === $this->nodeName ) {
if ( $this->nodeDepth === 0 && $this->seenTag ) {
// This is the second opening tag, not nested in the first one
throw new Exception( "More than one <{$this->nodeName}> tag found" );
throw new InvalidArgumentException( "More than one <{$this->nodeName}> tag found" );
}
$this->nodeDepth++;
$this->seenTag = true;

View file

@ -4,6 +4,7 @@ namespace MediaWiki\Rest;
use MediaWiki\Rest\HeaderParser\HttpDate;
use MediaWiki\Rest\HeaderParser\IfNoneMatch;
use RuntimeException;
use Wikimedia\Timestamp\ConvertibleTimestamp;
class ConditionalHeaderUtil {
@ -59,7 +60,7 @@ class ConditionalHeaderUtil {
if ( $this->eTag !== null ) {
$resourceTag = $parser->parseETag( $this->eTag );
if ( !$resourceTag ) {
throw new \Exception( 'Invalid ETag returned by handler: `' .
throw new RuntimeException( 'Invalid ETag returned by handler: `' .
$parser->getLastError() . '`' );
}
} else {

View file

@ -68,7 +68,6 @@ class YamlFormat implements SettingsFormat {
}
private function parseWithPhp( string $data ): array {
// @phan-suppress-next-line PhanTypeMismatchArgumentInternal Scalar okay with php8.1
$previousValue = ini_set( 'yaml.decode_php', false );
try {
$ndocs = 0;

View file

@ -1735,7 +1735,6 @@ class ApiMain extends ApiBase {
// Avoid outputting the compressed representation of a zero-length body
AtEase::suppressWarnings();
// @phan-suppress-next-line PhanTypeMismatchArgumentInternal Scalar okay with php8.1
ini_set( 'zlib.output_compression', 0 );
AtEase::restoreWarnings();
wfResetOutputBuffers( false );

View file

@ -25,7 +25,6 @@
namespace MediaWiki\Context;
use BadMethodCallException;
use Exception;
use InvalidArgumentException;
use Language;
use LogicException;
@ -46,6 +45,7 @@ use MediaWiki\Title\Title;
use MediaWiki\User\User;
use Message;
use MessageSpecifier;
use RuntimeException;
use Skin;
use Timing;
use Wikimedia\Assert\Assert;
@ -214,7 +214,7 @@ class RequestContext implements IContextSource, MutableContext {
$logger = LoggerFactory::getInstance( 'GlobalTitleFail' );
$logger->info(
__METHOD__ . ' called with no title set.',
[ 'exception' => new Exception ]
[ 'exception' => new RuntimeException ]
);
}

View file

@ -1631,7 +1631,7 @@ class DifferenceEngine extends ContextSource {
// called a DifferenceEngineSlotDiffRenderer that wraps the same DifferenceEngine class).
// This will happen when a content model has no custom slot diff renderer, it does have
// a custom difference engine, but that does not override this method.
throw new Exception( get_class( $this ) . ': could not maintain backwards compatibility. '
throw new LogicException( get_class( $this ) . ': could not maintain backwards compatibility. '
. 'Please use a SlotDiffRenderer.' );
}
return $slotDiffRenderer->getDiff( $old, $new ) . $this->getDebugString();
@ -1643,7 +1643,7 @@ class DifferenceEngine extends ContextSource {
* @param string $otext Old text, must be already segmented
* @param string $ntext New text, must be already segmented
*
* @throws Exception If content handling for text content is configured in a way
* @throws LogicException If content handling for text content is configured in a way
* that makes maintaining B/C hard.
* @return bool|string
*
@ -1656,7 +1656,7 @@ class DifferenceEngine extends ContextSource {
if ( !( $slotDiffRenderer instanceof TextSlotDiffRenderer ) ) {
// Someone used the GetSlotDiffRenderer hook to replace the renderer.
// This is too unlikely to happen to bother handling properly.
throw new Exception( 'The slot diff renderer for text content should be a '
throw new LogicException( 'The slot diff renderer for text content should be a '
. 'TextSlotDiffRenderer subclass' );
}
return $slotDiffRenderer->getTextDiff( $otext, $ntext ) . $this->getDebugString();

View file

@ -47,11 +47,11 @@ class LockManagerGroup {
foreach ( $lockManagerConfigs as $config ) {
$config['domain'] = $this->domain;
if ( !isset( $config['name'] ) ) {
throw new Exception( "Cannot register a lock manager with no name." );
throw new InvalidArgumentException( "Cannot register a lock manager with no name." );
}
$name = $config['name'];
if ( !isset( $config['class'] ) ) {
throw new Exception( "Cannot register lock manager `{$name}` with no class." );
throw new InvalidArgumentException( "Cannot register lock manager `{$name}` with no class." );
}
$class = $config['class'];
unset( $config['class'] ); // lock manager won't need this
@ -72,7 +72,7 @@ class LockManagerGroup {
*/
public function get( $name ) {
if ( !isset( $this->managers[$name] ) ) {
throw new Exception( "No lock manager defined with the name `$name`." );
throw new InvalidArgumentException( "No lock manager defined with the name `$name`." );
}
// Lazy-load the actual lock manager instance
if ( !isset( $this->managers[$name]['instance'] ) ) {
@ -96,7 +96,7 @@ class LockManagerGroup {
*/
public function config( $name ) {
if ( !isset( $this->managers[$name] ) ) {
throw new Exception( "No lock manager defined with the name `$name`." );
throw new InvalidArgumentException( "No lock manager defined with the name `$name`." );
}
$class = $this->managers[$name]['class'];

View file

@ -211,8 +211,7 @@ class HTMLMultiSelectField extends HTMLFormField implements HTMLNestedFilterable
}
if ( $this->mOptionsLabelsNotFromMessage ) {
foreach ( $options as &$option ) {
// @phan-suppress-next-line SecurityCheck-XSS Labels are raw when not from message
$option['label'] = new OOUI\HtmlSnippet( $option['label'] );
$option['label'] = new \OOUI\HtmlSnippet( $option['label'] );
}
}
unset( $option );

View file

@ -110,7 +110,7 @@ class HTMLTextAreaField extends HTMLFormField {
$classes = [];
if ( isset( $this->mParams['cols'] ) ) {
throw new Exception( "OOUIHTMLForm does not support the 'cols' parameter for textareas" );
throw new InvalidArgumentException( "OOUIHTMLForm does not support the 'cols' parameter for textareas" );
}
$attribs = $this->getTooltipAndAccessKeyOOUI();

View file

@ -262,7 +262,7 @@ abstract class MWHttpRequest implements LoggerAwareInterface {
protected function setReverseProxy( string $proxy ) {
$parsedProxy = wfParseUrl( $proxy );
if ( $parsedProxy === false ) {
throw new Exception( "Invalid reverseProxy configured: $proxy" );
throw new InvalidArgumentException( "Invalid reverseProxy configured: $proxy" );
}
// Set the current host in the Host header
$this->setHeader( 'Host', $this->parsedUrl['host'] );

View file

@ -101,11 +101,12 @@ class MwHttpRequestToResponseInterfaceAdapter implements ResponseInterface {
}
private function validateHasResponse( MWHttpRequest $mwHttpRequest ): void {
/**
/*
* MWHttpRequest objects contain request information, but also contain response information after calling
* `execute`. The best way of determining whether a MWHttpRequest contains response information is to check
* whether its headers list is empty.
*/
// @phan-suppress-next-line MediaWikiNoEmptyIfDefined
if ( empty( $mwHttpRequest->getResponseHeaders() ) ) {
throw new LogicException( 'Trying to get response information from a request that was not yet executed' );
}

View file

@ -693,14 +693,12 @@ abstract class DatabaseInstaller {
wfMessage( 'config-db-install-account' )->text()
) .
"<span class=\"cdx-card__text__description\">" .
// @phan-suppress-next-line SecurityCheck-DoubleEscaped taint cannot track the helpbox from the rest
$this->getTextBox(
'_InstallUser',
'config-db-username',
[ 'dir' => 'ltr' ],
$this->parent->getHelpBox( 'config-db-install-username' )
) .
// @phan-suppress-next-line SecurityCheck-DoubleEscaped taint cannot track the helpbox from the rest
$this->getPasswordBox(
'_InstallPassword',
'config-db-password',

View file

@ -27,7 +27,6 @@ use AddRFCandPMIDInterwiki;
use AutoLoader;
use CleanupEmptyCategories;
use DeleteDefaultMessages;
use Exception;
use ExtensionRegistry;
use FakeMaintenance;
use FixDefaultJsonContentPages;
@ -184,7 +183,7 @@ abstract class DatabaseUpdater {
return $this->autoExtensionHookContainer;
}
if ( defined( 'MW_EXTENSIONS_LOADED' ) ) {
throw new Exception( __METHOD__ .
throw new LogicException( __METHOD__ .
' apparently called from installer but no hook container was injected' );
}
if ( !defined( 'MEDIAWIKI_INSTALL' ) ) {

View file

@ -37,6 +37,7 @@ use GuzzleHttp\Psr7\Header;
use IntlChar;
use InvalidArgumentException;
use Language;
use LogicException;
use MediaWiki\Config\Config;
use MediaWiki\Config\GlobalVarConfig;
use MediaWiki\Config\HashConfig;
@ -57,6 +58,7 @@ use MediaWiki\User\User;
use MWCryptRand;
use Parser;
use ParserOptions;
use RuntimeException;
use Wikimedia\AtEase\AtEase;
use Wikimedia\Services\ServiceDisabledException;
use WikitextContent;
@ -700,7 +702,7 @@ abstract class Installer {
}
if ( !str_ends_with( $lsFile, '.php' ) ) {
throw new Exception(
throw new RuntimeException(
'The installer cannot yet handle non-php settings files: ' . $lsFile . '. ' .
'Use `php maintenance/run.php update` to update an existing installation.'
);
@ -1348,7 +1350,7 @@ abstract class Installer {
*/
protected function getExtensionInfo( $type, $parentRelPath, $name ) {
if ( $this->getVar( 'IP' ) === null ) {
throw new Exception( 'Cannot find extensions since the IP variable is not yet set' );
throw new RuntimeException( 'Cannot find extensions since the IP variable is not yet set' );
}
if ( $type !== 'extension' && $type !== 'skin' ) {
throw new InvalidArgumentException( "Invalid extension type" );
@ -1637,7 +1639,7 @@ abstract class Installer {
*/
public function getAutoExtensionHookContainer() {
if ( !$this->autoExtensionHookContainer ) {
throw new \Exception( __METHOD__ .
throw new LogicException( __METHOD__ .
': includeExtensions() has not been called' );
}
return $this->autoExtensionHookContainer;

View file

@ -36,7 +36,7 @@ class RecentChangesUpdateJob extends Job {
parent::__construct( 'recentChangesUpdate', $title, $params );
if ( !isset( $params['type'] ) ) {
throw new Exception( "Missing 'type' parameter." );
throw new InvalidArgumentException( "Missing 'type' parameter." );
}
$this->executionFlags |= self::JOB_NO_EXPLICIT_TRX_ROUND;

View file

@ -1388,7 +1388,7 @@ class Message implements MessageSpecifier, Serializable {
LoggerFactory::getInstance( 'Bug58676' )->warning(
'Invalid parameter for message "{msgkey}": {param}',
[
'exception' => new Exception,
'exception' => new RuntimeException,
'msgkey' => $this->getKey(),
'param' => htmlspecialchars( serialize( $param ) ),
]
@ -1542,7 +1542,7 @@ class Message implements MessageSpecifier, Serializable {
. htmlspecialchars( $listType )
. ' (params are ' . htmlspecialchars( serialize( $params ) ) . ')';
trigger_error( $warning, E_USER_WARNING );
$e = new Exception;
$e = new InvalidArgumentException;
wfDebugLog( 'Bug58676', $warning . "\n" . $e->getTraceAsString() );
return [ 'before', '[INVALID]' ];
}

View file

@ -1500,7 +1500,7 @@ class MessageCache implements LoggerAwareInterface {
$logger = LoggerFactory::getInstance( 'GlobalTitleFail' );
$logger->info(
__METHOD__ . ' called with no title set.',
[ 'exception' => new Exception ]
[ 'exception' => new RuntimeException ]
);
$page = $wgTitle;
}

View file

@ -136,7 +136,6 @@ class HTTPFileStreamer {
if ( isset( $optHeaders['if-modified-since'] ) ) {
$modsince = preg_replace( '/;.*$/', '', $optHeaders['if-modified-since'] );
if ( $mtimeCT->getTimestamp( TS_UNIX ) <= strtotime( $modsince ) ) {
// @phan-suppress-next-line PhanTypeMismatchArgumentInternal Scalar okay with php8.1
ini_set( 'zlib.output_compression', 0 );
$headerFunc( 304 );
return true; // ok

View file

@ -121,7 +121,7 @@ class MultiHttpClient implements LoggerAwareInterface {
if ( isset( $options['caBundlePath'] ) ) {
$this->caBundlePath = $options['caBundlePath'];
if ( !file_exists( $this->caBundlePath ) ) {
throw new Exception( "Cannot find CA bundle: " . $this->caBundlePath );
throw new InvalidArgumentException( "Cannot find CA bundle: " . $this->caBundlePath );
}
}
static $opts = [
@ -395,7 +395,7 @@ class MultiHttpClient implements LoggerAwareInterface {
) {
curl_setopt( $ch, CURLOPT_UPLOAD, true );
} else {
throw new Exception( "Missing 'Content-Length' or 'Transfer-Encoding' header." );
throw new InvalidArgumentException( "Missing 'Content-Length' or 'Transfer-Encoding' header." );
}
} elseif ( $req['body'] !== '' ) {
$fp = fopen( "php://temp", "wb+" );
@ -418,7 +418,7 @@ class MultiHttpClient implements LoggerAwareInterface {
} else {
// phpcs:ignore MediaWiki.Usage.ForbiddenFunctions.is_resource
if ( is_resource( $req['body'] ) || $req['body'] !== '' ) {
throw new Exception( "HTTP body specified for a non PUT/POST request." );
throw new InvalidArgumentException( "HTTP body specified for a non PUT/POST request." );
}
$req['headers']['content-length'] = 0;
}
@ -430,7 +430,7 @@ class MultiHttpClient implements LoggerAwareInterface {
$headers = [];
foreach ( $req['headers'] as $name => $value ) {
if ( strpos( $name, ':' ) !== false ) {
throw new Exception( "Header name must not contain colon-space." );
throw new InvalidArgumentException( "Header name must not contain colon-space." );
}
$headers[] = $name . ': ' . trim( $value );
}
@ -669,9 +669,9 @@ class MultiHttpClient implements LoggerAwareInterface {
unset( $req[1] );
}
if ( !isset( $req['method'] ) ) {
throw new Exception( "Request has no 'method' field set." );
throw new InvalidArgumentException( "Request has no 'method' field set." );
} elseif ( !isset( $req['url'] ) ) {
throw new Exception( "Request has no 'url' field set." );
throw new InvalidArgumentException( "Request has no 'url' field set." );
}
if ( $this->localProxy !== false && $this->isLocalURL( $req['url'] ) ) {
$this->useReverseProxy( $req, $this->localProxy );
@ -710,11 +710,11 @@ class MultiHttpClient implements LoggerAwareInterface {
private function useReverseProxy( array &$req, $proxy ) {
$parsedProxy = wfParseUrl( $proxy );
if ( $parsedProxy === false ) {
throw new Exception( "Invalid reverseProxy configured: $proxy" );
throw new InvalidArgumentException( "Invalid reverseProxy configured: $proxy" );
}
$parsedUrl = wfParseUrl( $req['url'] );
if ( $parsedUrl === false ) {
throw new Exception( "Invalid url specified: {$req['url']}" );
throw new InvalidArgumentException( "Invalid url specified: {$req['url']}" );
}
// Set the current host in the Host header
$req['headers']['Host'] = $parsedUrl['host'];

View file

@ -106,7 +106,7 @@ abstract class MemcachedBagOStuff extends MediumSpecificBagOStuff {
*/
public function validateKeyEncoding( $key ) {
if ( preg_match( '/[^\x21-\x7e]+/', $key ) ) {
throw new Exception( "Key contains invalid characters: $key" );
throw new InvalidArgumentException( "Key contains invalid characters: $key" );
}
return $key;

View file

@ -17,6 +17,10 @@
*
* @file
*/
// Suppress UnusedPluginSuppression because Phan on PHP 7.4 and PHP 8.1 need different suppressions
// @phan-file-suppress UnusedPluginSuppression,UnusedPluginFileSuppression
namespace Wikimedia\Rdbms;
use RuntimeException;
@ -202,10 +206,13 @@ class DatabasePostgres extends Database {
// Newer PHP versions use PgSql\Result instead of resource variables
// https://www.php.net/manual/en/function.pg-get-result.php
$pgRes = pg_get_result( $conn );
// Phan on PHP 7.4 and PHP 8.1 need different suppressions
// @phan-suppress-next-line PhanTypeMismatchProperty,PhanTypeMismatchPropertyProbablyReal
$this->lastResultHandle = $pgRes;
$res = pg_result_error( $pgRes ) ? false : $pgRes;
return new QueryStatus(
// @phan-suppress-next-line PhanTypeMismatchArgument
is_bool( $res ) ? $res : new PostgresResultWrapper( $this, $conn, $res ),
$pgRes ? pg_affected_rows( $pgRes ) : 0,
$this->lastError(),
@ -230,6 +237,7 @@ class DatabasePostgres extends Database {
];
foreach ( $diags as $d ) {
$this->logger->debug( sprintf( "PgSQL ERROR(%d): %s",
// @phan-suppress-next-line PhanTypeMismatchArgumentInternal
$d, pg_result_error_field( $this->lastResultHandle, $d ) ) );
}
}
@ -247,6 +255,7 @@ class DatabasePostgres extends Database {
public function lastError() {
if ( $this->conn ) {
if ( $this->lastResultHandle ) {
// @phan-suppress-next-line PhanTypeMismatchArgumentInternal
return pg_result_error( $this->lastResultHandle );
} else {
return pg_last_error() ?: $this->lastConnectError;
@ -258,6 +267,7 @@ class DatabasePostgres extends Database {
public function lastErrno() {
if ( $this->lastResultHandle ) {
// @phan-suppress-next-line PhanTypeMismatchArgumentInternal
$lastErrno = pg_result_error_field( $this->lastResultHandle, PGSQL_DIAG_SQLSTATE );
if ( $lastErrno !== false ) {
return $lastErrno;

View file

@ -2,6 +2,9 @@
namespace Wikimedia\Rdbms;
// Phan insists these are resources until we drop PHP 7.4
/* @phan-file-suppress PhanTypeMismatchArgumentInternal */
class PostgresResultWrapper extends ResultWrapper {
/** @var DatabasePostgres */
private $db;

View file

@ -67,33 +67,33 @@ class GIFMetadataExtractor {
$comment = [];
if ( !$filename ) {
throw new Exception( 'No file name specified' );
throw new InvalidArgumentException( 'No file name specified' );
}
if ( !file_exists( $filename ) || is_dir( $filename ) ) {
throw new Exception( "File $filename does not exist" );
throw new InvalidArgumentException( "File $filename does not exist" );
}
$fh = fopen( $filename, 'rb' );
if ( !$fh ) {
throw new Exception( "Unable to open file $filename" );
throw new InvalidArgumentException( "Unable to open file $filename" );
}
// Check for the GIF header
$buf = fread( $fh, 6 );
if ( !( $buf === 'GIF87a' || $buf === 'GIF89a' ) ) {
throw new Exception( "Not a valid GIF file; header: $buf" );
throw new InvalidArgumentException( "Not a valid GIF file; header: $buf" );
}
// Read width and height.
$buf = fread( $fh, 2 );
if ( strlen( $buf ) < 2 ) {
throw new Exception( "Not a valid GIF file; Unable to read width." );
throw new InvalidArgumentException( "Not a valid GIF file; Unable to read width." );
}
$width = unpack( 'v', $buf )[1];
$buf = fread( $fh, 2 );
if ( strlen( $buf ) < 2 ) {
throw new Exception( "Not a valid GIF file; Unable to read height." );
throw new InvalidArgumentException( "Not a valid GIF file; Unable to read height." );
}
$height = unpack( 'v', $buf )[1];
@ -135,7 +135,9 @@ class GIFMetadataExtractor {
} elseif ( $buf === self::$gifExtensionSep ) {
$buf = fread( $fh, 1 );
if ( strlen( $buf ) < 1 ) {
throw new Exception( "Not a valid GIF file; Unable to read graphics control extension." );
throw new InvalidArgumentException(
"Not a valid GIF file; Unable to read graphics control extension."
);
}
$extension_code = unpack( 'C', $buf )[1];
@ -150,7 +152,7 @@ class GIFMetadataExtractor {
$buf = fread( $fh, 2 ); // Delay, in hundredths of seconds.
if ( strlen( $buf ) < 2 ) {
throw new Exception( "Not a valid GIF file; Unable to read delay" );
throw new InvalidArgumentException( "Not a valid GIF file; Unable to read delay" );
}
$delay = unpack( 'v', $buf )[1];
$duration += $delay * 0.01;
@ -160,17 +162,17 @@ class GIFMetadataExtractor {
$term = fread( $fh, 1 ); // Should be a terminator
if ( strlen( $term ) < 1 ) {
throw new Exception( "Not a valid GIF file; Unable to read terminator byte" );
throw new InvalidArgumentException( "Not a valid GIF file; Unable to read terminator byte" );
}
$term = unpack( 'C', $term )[1];
if ( $term != 0 ) {
throw new Exception( "Malformed Graphics Control Extension block" );
throw new InvalidArgumentException( "Malformed Graphics Control Extension block" );
}
} elseif ( $extension_code === 0xFE ) {
// Comment block(s).
$data = self::readBlock( $fh );
if ( $data === "" ) {
throw new Exception( 'Read error, zero-length comment block' );
throw new InvalidArgumentException( 'Read error, zero-length comment block' );
}
// The standard says this should be ASCII, however its unclear if
@ -201,7 +203,7 @@ class GIFMetadataExtractor {
// or XMP (or theoretically any other type of extension block)
$blockLength = fread( $fh, 1 );
if ( strlen( $blockLength ) < 1 ) {
throw new Exception( "Not a valid GIF file; Unable to read block length" );
throw new InvalidArgumentException( "Not a valid GIF file; Unable to read block length" );
}
$blockLength = unpack( 'C', $blockLength )[1];
$data = fread( $fh, $blockLength );
@ -218,13 +220,13 @@ class GIFMetadataExtractor {
$data = fread( $fh, 2 ); // Block length and introduction, should be 03 01
if ( $data !== "\x03\x01" ) {
throw new Exception( "Expected \x03\x01, got $data" );
throw new InvalidArgumentException( "Expected \x03\x01, got $data" );
}
// Unsigned little-endian integer, loop count or zero for "forever"
$loopData = fread( $fh, 2 );
if ( strlen( $loopData ) < 2 ) {
throw new Exception( "Not a valid GIF file; Unable to read loop count" );
throw new InvalidArgumentException( "Not a valid GIF file; Unable to read loop count" );
}
$loopCount = unpack( 'v', $loopData )[1];
@ -244,7 +246,7 @@ class GIFMetadataExtractor {
if ( substr( $xmp, -257, 3 ) !== "\x01\xFF\xFE"
|| substr( $xmp, -4 ) !== "\x03\x02\x01\x00"
) {
throw new Exception( "XMP does not have magic trailer!" );
throw new InvalidArgumentException( "XMP does not have magic trailer!" );
}
// strip out trailer.
@ -261,10 +263,10 @@ class GIFMetadataExtractor {
break;
} else {
if ( strlen( $buf ) < 1 ) {
throw new Exception( "Not a valid GIF file; Unable to read unknown byte." );
throw new InvalidArgumentException( "Not a valid GIF file; Unable to read unknown byte." );
}
$byte = unpack( 'C', $buf )[1];
throw new Exception( "At position: " . ftell( $fh ) . ", Unknown byte " . $byte );
throw new InvalidArgumentException( "At position: " . ftell( $fh ) . ", Unknown byte " . $byte );
}
}
@ -300,7 +302,7 @@ class GIFMetadataExtractor {
*/
private static function decodeBPP( $data ) {
if ( strlen( $data ) < 1 ) {
throw new Exception( "Not a valid GIF file; Unable to read bits per channel." );
throw new InvalidArgumentException( "Not a valid GIF file; Unable to read bits per channel." );
}
$buf = unpack( 'C', $data )[1];
$bpp = ( $buf & 7 ) + 1;
@ -319,7 +321,7 @@ class GIFMetadataExtractor {
while ( !feof( $fh ) ) {
$buf = fread( $fh, 1 );
if ( strlen( $buf ) < 1 ) {
throw new Exception( "Not a valid GIF file; Unable to read block length." );
throw new InvalidArgumentException( "Not a valid GIF file; Unable to read block length." );
}
$block_len = unpack( 'C', $buf )[1];
if ( $block_len == 0 ) {
@ -352,10 +354,10 @@ class GIFMetadataExtractor {
while ( $subLength !== "\0" ) {
$blocks++;
if ( $blocks > self::MAX_SUBBLOCKS ) {
throw new Exception( "MAX_SUBBLOCKS exceeded (over $blocks sub-blocks)" );
throw new InvalidArgumentException( "MAX_SUBBLOCKS exceeded (over $blocks sub-blocks)" );
}
if ( feof( $fh ) ) {
throw new Exception( "Read error: Unexpected EOF." );
throw new InvalidArgumentException( "Read error: Unexpected EOF." );
}
if ( $includeLengths ) {
$data .= $subLength;

View file

@ -270,12 +270,14 @@ class JpegHandler extends ExifBitmapHandler {
// Make a regex out of the source data to match it to an array of color
// spaces in a case-insensitive way
$colorSpaceRegex = '/' . preg_quote( $data[0], '/' ) . '/i';
// @phan-suppress-next-line MediaWikiNoEmptyIfDefined
if ( empty( preg_grep( $colorSpaceRegex, $colorSpaces ) ) ) {
// We can't establish that this file matches the color space, don't process it
return false;
}
$profileRegex = '/' . preg_quote( $data[1], '/' ) . '/i';
// @phan-suppress-next-line MediaWikiNoEmptyIfDefined
if ( empty( preg_grep( $profileRegex, $oldProfileStrings ) ) ) {
// We can't establish that this file has the expected ICC profile, don't process it
return false;

View file

@ -86,23 +86,23 @@ class PNGMetadataExtractor {
$colorType = 'unknown';
if ( !$filename ) {
throw new Exception( __METHOD__ . ": No file name specified" );
throw new InvalidArgumentException( __METHOD__ . ": No file name specified" );
}
if ( !file_exists( $filename ) || is_dir( $filename ) ) {
throw new Exception( __METHOD__ . ": File $filename does not exist" );
throw new InvalidArgumentException( __METHOD__ . ": File $filename does not exist" );
}
$fh = fopen( $filename, 'rb' );
if ( !$fh ) {
throw new Exception( __METHOD__ . ": Unable to open file $filename" );
throw new InvalidArgumentException( __METHOD__ . ": Unable to open file $filename" );
}
// Check for the PNG header
$buf = self::read( $fh, 8 );
if ( $buf !== self::$pngSig ) {
throw new Exception( __METHOD__ . ": Not a valid PNG file; header: $buf" );
throw new InvalidArgumentException( __METHOD__ . ": Not a valid PNG file; header: $buf" );
}
// Read chunks
@ -114,7 +114,7 @@ class PNGMetadataExtractor {
wfDebug( __METHOD__ . ': Chunk size of ' . $chunk_size .
' too big, skipping. Max size is: ' . self::MAX_CHUNK_SIZE );
if ( fseek( $fh, 4 + $chunk_size + self::$crcSize, SEEK_CUR ) !== 0 ) {
throw new Exception( __METHOD__ . ': seek error' );
throw new InvalidArgumentException( __METHOD__ . ': seek error' );
}
continue;
}
@ -414,10 +414,10 @@ class PNGMetadataExtractor {
$result = fread( $fh, $size );
if ( $result === false ) {
throw new Exception( __METHOD__ . ': read error' );
throw new InvalidArgumentException( __METHOD__ . ': read error' );
}
if ( strlen( $result ) < $size ) {
throw new Exception( __METHOD__ . ': unexpected end of file' );
throw new InvalidArgumentException( __METHOD__ . ': unexpected end of file' );
}
return $result;
}

View file

@ -6314,7 +6314,7 @@ class Parser {
// Save the backtrace when locking, so that if some code tries locking again,
// we can print the lock owner's backtrace for easier debugging
$e = new Exception;
$e = new RuntimeException;
$this->mInParse = $e->getTraceAsString();
$recursiveCheck = new ScopedCallback( function () {

View file

@ -167,7 +167,7 @@ class ParsoidOutputAccess {
try {
if ( $uncacheable ) {
$options = $options | ParserOutputAccess::OPT_NO_UPDATE_CACHE;
$options |= ParserOutputAccess::OPT_NO_UPDATE_CACHE;
}
// Since we know we are generating Parsoid output, explicitly
// call ParserOptions::setUseParsoid. This ensures that when

View file

@ -952,6 +952,7 @@ class DefaultPreferencesFactory implements PreferencesFactory {
$validSkinNames = $this->getValidSkinNames( $user, $context );
if ( $validSkinNames ) {
$defaultPreferences['skin'] = [
// @phan-suppress-next-line SecurityCheck-XSS False +ve, label is escaped in generateSkinOptions()
'type' => 'radio',
'options' => $this->generateSkinOptions( $user, $context, $validSkinNames ),
'section' => 'rendering/skin',

View file

@ -77,11 +77,11 @@ class ProfilerXhprof extends Profiler {
xhprof_enable( $flags, $options );
} elseif ( function_exists( 'tideways_xhprof_enable' ) ) {
if ( isset( $params['exclude'] ) ) {
throw new Exception( 'The exclude option is not supported in tideways_xhprof' );
throw new RuntimeException( 'The exclude option is not supported in tideways_xhprof' );
}
tideways_xhprof_enable( $flags );
} else {
throw new Exception( 'Neither xhprof nor tideways_xhprof is installed' );
throw new RuntimeException( 'Neither xhprof nor tideways_xhprof is installed' );
}
}
@ -98,7 +98,7 @@ class ProfilerXhprof extends Profiler {
} elseif ( function_exists( 'tideways_xhprof_disable' ) ) {
$data = tideways_xhprof_disable();
} else {
throw new Exception( 'Neither xhprof nor tideways_xhprof is installed' );
throw new RuntimeException( 'Neither xhprof nor tideways_xhprof is installed' );
}
$this->xhprofData = new XhprofData( $data, $this->params );
}

View file

@ -769,7 +769,9 @@ class ExtensionProcessor implements Processor {
if ( isset( $this->credits[$name] ) ) {
$firstPath = $this->credits[$name]['path'];
$secondPath = $credits['path'];
throw new Exception( "It was attempted to load $name twice, from $firstPath and $secondPath." );
throw new InvalidArgumentException(
"It was attempted to load $name twice, from $firstPath and $secondPath."
);
}
$this->credits[$name] = $credits;
@ -780,7 +782,7 @@ class ExtensionProcessor implements Processor {
protected function extractForeignResourcesDir( array $info, string $name, string $dir ): void {
if ( array_key_exists( 'ForeignResourcesDir', $info ) ) {
if ( !is_string( $info['ForeignResourcesDir'] ) ) {
throw new Exception( "Incorrect ForeignResourcesDir type, must be a string (in $name)" );
throw new InvalidArgumentException( "Incorrect ForeignResourcesDir type, must be a string (in $name)" );
}
$this->attributes['ForeignResourcesDir'][$name] = "{$dir}/{$info['ForeignResourcesDir']}";
}

View file

@ -410,7 +410,7 @@ class ExtensionRegistry {
*
* @param int[] $queue keys are filenames, values are ignored
* @return array extracted info
* @throws Exception
* @throws InvalidArgumentException
* @throws ExtensionDependencyError
*/
public function readFromQueue( array $queue ) {
@ -421,16 +421,16 @@ class ExtensionRegistry {
foreach ( $queue as $path => $mtime ) {
$json = file_get_contents( $path );
if ( $json === false ) {
throw new Exception( "Unable to read $path, does it exist?" );
throw new InvalidArgumentException( "Unable to read $path, does it exist?" );
}
$info = json_decode( $json, /* $assoc = */ true );
if ( !is_array( $info ) ) {
throw new Exception( "$path is not a valid JSON file." );
throw new InvalidArgumentException( "$path is not a valid JSON file." );
}
$version = $info['manifest_version'];
if ( $version < self::OLDEST_MANIFEST_VERSION || $version > self::MANIFEST_VERSION ) {
throw new Exception( "$path: unsupported manifest_version: {$version}" );
throw new InvalidArgumentException( "$path: unsupported manifest_version: {$version}" );
}
// get all requirements/dependencies for this extension
@ -647,7 +647,7 @@ class ExtensionRegistry {
}
// @codeCoverageIgnoreEnd
if ( isset( $this->testAttributes[$name] ) ) {
throw new Exception( "The attribute '$name' has already been overridden" );
throw new InvalidArgumentException( "The attribute '$name' has already been overridden" );
}
$this->testAttributes[$name] = $value;
return new ScopedCallback( function () use ( $name ) {

View file

@ -134,9 +134,7 @@ class PHPSessionHandler implements SessionHandlerInterface {
AtEase::suppressWarnings();
// Tell PHP not to mess with cookies itself
// @phan-suppress-next-line PhanTypeMismatchArgumentInternal Scalar okay with php8.1
ini_set( 'session.use_cookies', 0 );
// @phan-suppress-next-line PhanTypeMismatchArgumentInternal Scalar okay with php8.1
ini_set( 'session.use_trans_sid', 0 );
// T124510: Disable automatic PHP session related cache headers.

View file

@ -23,12 +23,15 @@
namespace MediaWiki\Session;
use BadMethodCallException;
use LogicException;
use MediaWiki\MainConfigNames;
use MediaWiki\MediaWikiServices;
use MediaWiki\Request\WebRequest;
use MediaWiki\User\User;
use MWRestrictions;
use Psr\Log\LoggerInterface;
use RuntimeException;
/**
* Manages data for an authenticated session
@ -472,7 +475,7 @@ class Session implements \Countable, \Iterator, \ArrayAccess {
return self::$encryptionAlgorithm;
}
throw new \BadMethodCallException(
throw new BadMethodCallException(
'Encryption is not available. You really should install the PHP OpenSSL extension. ' .
'But if you really can\'t and you\'re willing ' .
'to accept insecure storage of sensitive session data, set ' .
@ -510,12 +513,12 @@ class Session implements \Countable, \Iterator, \ArrayAccess {
}
break;
case 'insecure':
$ex = new \Exception( 'No encryption is available, storing data as plain text' );
$ex = new RuntimeException( 'No encryption is available, storing data as plain text' );
$this->logger->warning( $ex->getMessage(), [ 'exception' => $ex ] );
$ciphertext = $serialized;
break;
default:
throw new \LogicException( 'invalid algorithm' );
throw new LogicException( 'invalid algorithm' );
}
// Seal
@ -547,7 +550,7 @@ class Session implements \Countable, \Iterator, \ArrayAccess {
// Unseal and check
$pieces = explode( '.', $encrypted, 4 );
if ( count( $pieces ) !== 3 ) {
$ex = new \Exception( 'Invalid sealed-secret format' );
$ex = new RuntimeException( 'Invalid sealed-secret format' );
$this->logger->warning( $ex->getMessage(), [ 'exception' => $ex ] );
return $default;
}
@ -555,7 +558,7 @@ class Session implements \Countable, \Iterator, \ArrayAccess {
[ $encKey, $hmacKey ] = $this->getSecretKeys();
$integCalc = hash_hmac( 'sha256', $iv . '.' . $ciphertext, $hmacKey, true );
if ( !hash_equals( $integCalc, base64_decode( $hmac ) ) ) {
$ex = new \Exception( 'Sealed secret has been tampered with, aborting.' );
$ex = new RuntimeException( 'Sealed secret has been tampered with, aborting.' );
$this->logger->warning( $ex->getMessage(), [ 'exception' => $ex ] );
return $default;
}
@ -567,13 +570,13 @@ class Session implements \Countable, \Iterator, \ArrayAccess {
$serialized = openssl_decrypt( base64_decode( $ciphertext ), $algorithm[1], $encKey,
OPENSSL_RAW_DATA, base64_decode( $iv ) );
if ( $serialized === false ) {
$ex = new \Exception( 'Decyption failed: ' . openssl_error_string() );
$ex = new RuntimeException( 'Decyption failed: ' . openssl_error_string() );
$this->logger->debug( $ex->getMessage(), [ 'exception' => $ex ] );
return $default;
}
break;
case 'insecure':
$ex = new \Exception(
$ex = new RuntimeException(
'No encryption is available, retrieving data that was stored as plain text'
);
$this->logger->warning( $ex->getMessage(), [ 'exception' => $ex ] );
@ -674,7 +677,7 @@ class Session implements \Countable, \Iterator, \ArrayAccess {
public function &offsetGet( $offset ) {
$data = &$this->backend->getData();
if ( !array_key_exists( $offset, $data ) ) {
$ex = new \Exception( "Undefined index (auto-adds to session with a null value): $offset" );
$ex = new LogicException( "Undefined index (auto-adds to session with a null value): $offset" );
$this->logger->debug( $ex->getMessage(), [ 'exception' => $ex ] );
}
return $data[$offset];

View file

@ -2,6 +2,7 @@
namespace MediaWiki\Tidy;
use InvalidArgumentException;
use Wikimedia\RemexHtml\HTMLData;
use Wikimedia\RemexHtml\Serializer\Serializer;
use Wikimedia\RemexHtml\Serializer\SerializerNode;
@ -382,7 +383,7 @@ class RemexCompatMunger implements TreeHandler {
while ( $node !== $cloneEnd ) {
$nextParent = $serializer->getParentNode( $node );
if ( $nextParent === $root ) {
throw new \Exception( 'Did not find end of clone range' );
throw new InvalidArgumentException( 'Did not find end of clone range' );
}
$nodes[] = $node;
if ( $node->snData->nonblankNodeCount === 0 ) {

View file

@ -2,7 +2,7 @@
namespace MediaWiki\Tidy;
use Exception;
use InvalidArgumentException;
use Wikimedia\RemexHtml\Serializer\SerializerNode;
use Wikimedia\RemexHtml\TreeBuilder\Element;
@ -78,7 +78,7 @@ class RemexMungerData {
public function __set( $name, $value ) {
// @phan-suppress-previous-line PhanPluginNeverReturnMethod
throw new Exception( "Cannot set property \"$name\"" );
throw new InvalidArgumentException( "Cannot set property \"$name\"" );
}
/**

View file

@ -25,7 +25,6 @@ namespace MediaWiki\User;
use AllowDynamicProperties;
use ArrayIterator;
use DBAccessObjectUtils;
use Exception;
use IDBAccessObject;
use InvalidArgumentException;
use MailAddress;
@ -364,7 +363,7 @@ class User implements Authority, UserIdentity, UserEmailContact {
if ( !$wgFullyInitialised && $this->mFrom === 'session' ) {
LoggerFactory::getInstance( 'session' )
->warning( 'User::loadFromSession called before the end of Setup.php', [
'exception' => new Exception(
'exception' => new RuntimeException(
'User::loadFromSession called before the end of Setup.php'
),
] );

View file

@ -141,15 +141,15 @@ class AutoloadGenerator {
*
* @param string $fqcn FQCN to force the location of
* @param string $inputPath Full path to the file containing the class
* @throws Exception
* @throws InvalidArgumentException
*/
public function forceClassPath( $fqcn, $inputPath ) {
$path = self::normalizePathSeparator( realpath( $inputPath ) );
if ( !$path ) {
throw new \Exception( "Invalid path: $inputPath" );
throw new InvalidArgumentException( "Invalid path: $inputPath" );
}
if ( !str_starts_with( $path, $this->basepath ) ) {
throw new \Exception( "Path is not within basepath: $inputPath" );
throw new InvalidArgumentException( "Path is not within basepath: $inputPath" );
}
$shortpath = substr( $path, strlen( $this->basepath ) );
$this->overrides[$fqcn] = $shortpath;
@ -157,7 +157,7 @@ class AutoloadGenerator {
/**
* @param string $inputPath Path to a php file to find classes within
* @throws Exception
* @throws InvalidArgumentException
*/
public function readFile( $inputPath ) {
// NOTE: do NOT expand $inputPath using realpath(). It is perfectly
@ -166,7 +166,7 @@ class AutoloadGenerator {
$inputPath = self::normalizePathSeparator( $inputPath );
$len = strlen( $this->basepath );
if ( !str_starts_with( $inputPath, $this->basepath ) ) {
throw new \Exception( "Path is not within basepath: $inputPath" );
throw new InvalidArgumentException( "Path is not within basepath: $inputPath" );
}
if ( $this->shouldExclude( $inputPath ) ) {
return;

View file

@ -3,7 +3,6 @@
namespace MediaWiki\Utils;
use BadMethodCallException;
use Exception;
use InvalidArgumentException;
use MediaWiki\MainConfigSchema;
use MWDebug;
@ -166,7 +165,7 @@ class UrlUtils {
// user to override the port number (T67184)
if ( $defaultProto === PROTO_HTTPS && $this->httpsPort != 443 ) {
if ( isset( $bits['port'] ) ) {
throw new Exception(
throw new InvalidArgumentException(
'A protocol-relative server may not contain a port number' );
}
$url = "$defaultProtoWithoutSlashes$serverUrl:{$this->httpsPort}$url";

View file

@ -1147,6 +1147,7 @@ class WatchedItemStore implements WatchedItemStoreInterface, StatsdAwareInterfac
}, $wlIds );
// Insert into watchlist_expiry, updating the expiry for duplicate rows.
// @phan-suppress-next-line SecurityCheck-SQLInjection
$dbw->newInsertQueryBuilder()
->insertInto( 'watchlist_expiry' )
->rows( $weRows )

View file

@ -139,13 +139,11 @@ class TestSetup {
$wgUsePigLatinVariant = true;
// xdebug's default of 100 is too low for MediaWiki
// @phan-suppress-next-line PhanTypeMismatchArgumentInternal
ini_set( 'xdebug.max_nesting_level', 1000 );
// Make sure that serialize_precision is set to its default value
// so floating-point numbers within serialized or JSON-encoded data
// will match the expected string representations (T116683).
// @phan-suppress-next-line PhanTypeMismatchArgumentInternal
ini_set( 'serialize_precision', -1 );
}

View file

@ -68,7 +68,6 @@ class ParserFuzzTest extends Maintenance {
'config' => [],
], [], '' );
// @phan-suppress-next-line PhanTypeMismatchArgumentInternal
ini_set( 'memory_limit', $this->memoryLimit * 1048576 * 2 );
$numTotal = 0;

View file

@ -66,7 +66,7 @@ class TaintCheckAnnotationsTest {
$db->selectRowCount( $_GET['a'], '' ); // @phan-suppress-current-line SecurityCheck-SQLInjection
$db->selectRowCount( '', $_GET['a'] ); // @phan-suppress-current-line SecurityCheck-SQLInjection
$db->selectRowCount( '', '', [ $_GET['a'] ] ); // @phan-suppress-current-line SecurityCheck-SQLInjection
echo $db->selectRowCount( 'safe', 'safe' ); // @phan-suppress-current-line SecurityCheck-XSS
echo $db->selectRowCount( 'safe', 'safe' ); // Safe
$db->selectRow( $_GET['a'], '', [] ); // @phan-suppress-current-line SecurityCheck-SQLInjection
$db->selectRow( '', $_GET['a'], [] ); // @phan-suppress-current-line SecurityCheck-SQLInjection
@ -262,7 +262,7 @@ class TaintCheckAnnotationsTest {
$db->selectRowCount( $_GET['a'], '' ); // @phan-suppress-current-line SecurityCheck-SQLInjection
$db->selectRowCount( '', $_GET['a'] ); // @phan-suppress-current-line SecurityCheck-SQLInjection
$db->selectRowCount( '', '', [ $_GET['a'] ] ); // @phan-suppress-current-line SecurityCheck-SQLInjection
echo $db->selectRowCount( 'safe', 'safe' ); // @phan-suppress-current-line SecurityCheck-XSS
echo $db->selectRowCount( 'safe', 'safe' ); // Safe
$db->selectRow( $_GET['a'], '', [] ); // @phan-suppress-current-line SecurityCheck-SQLInjection
$db->selectRow( '', $_GET['a'], [] ); // @phan-suppress-current-line SecurityCheck-SQLInjection
@ -352,15 +352,15 @@ class TaintCheckAnnotationsTest {
$iqb->insert( $_GET['a'] );// @phan-suppress-current-line SecurityCheck-SQLInjection
$iqb->insertInto( $_GET['a'] );// @phan-suppress-current-line SecurityCheck-SQLInjection
$iqb->row( $_GET['a'] );// TODO: Unsafe
$iqb->row( $_GET['a'] );// @phan-suppress-current-line SecurityCheck-SQLInjection
$iqb->row( [ 'bar' => $_GET['a'] ] );// Safe
$iqb->row( [ $_GET['a'] => 'foo' ] );// TODO: Unsafe
$iqb->row( [ $_GET['a'] => 'foo' ] );// @phan-suppress-current-line SecurityCheck-SQLInjection
$iqb->rows( $_GET['a'] );// TODO: Unsafe
$iqb->rows( [ $_GET['a'] ] );// TODO: Unsafe
$iqb->rows( $_GET['a'] );// @phan-suppress-current-line SecurityCheck-SQLInjection
$iqb->rows( [ $_GET['a'] ] );// @phan-suppress-current-line SecurityCheck-SQLInjection
$iqb->rows( [ $_GET['a'] => [] ] );// Safe
$iqb->rows( [ $_GET['a'] => [ 'foo' => $_GET['a'] ] ] );// Safe
$iqb->rows( [ $_GET['a'] => [ $_GET['a'] => 'foo' ] ] );// TODO: Unsafe
$iqb->rows( [ $_GET['a'] => [ $_GET['a'] => 'foo' ] ] );// @phan-suppress-current-line SecurityCheck-SQLInjection
$iqb->set( $_GET['a'] );// @phan-suppress-current-line SecurityCheck-SQLInjection
$iqb->set( [ $_GET['a'] ] );// @phan-suppress-current-line SecurityCheck-SQLInjection