Файловый менеджер - Редактировать - /var/www/html/mediawiki-1.43.1/includes/libs/ParamValidator/ParamValidator.php
Ðазад
<?php namespace Wikimedia\ParamValidator; use DomainException; use InvalidArgumentException; use Wikimedia\Assert\Assert; use Wikimedia\Message\DataMessageValue; use Wikimedia\Message\MessageValue; use Wikimedia\Message\ParamType; use Wikimedia\Message\ScalarParam; use Wikimedia\ObjectFactory\ObjectFactory; /** * Service for formatting and validating API parameters * * A settings array is simply an array with keys being the relevant PARAM_* * constants from this class, TypeDef, and its subclasses. * * As a general overview of the architecture here: * - ParamValidator handles some general validation of the parameter, * then hands off to a TypeDef subclass to validate the specific representation * based on the parameter's type. * - TypeDef subclasses handle conversion between the string representation * submitted by the client and the output PHP data types, validating that the * strings are valid representations of the intended type as they do so. * - ValidationException is used to report fatal errors in the validation back * to the caller, since the return value represents the successful result of * the validation and might be any type or class. * - The Callbacks interface allows ParamValidator to reach out and fetch data * it needs to perform the validation. Currently that includes: * - Fetching the value of the parameter being validated (largely since a generic * caller cannot know whether it needs to fetch a string from $_GET/$_POST or * an array from $_FILES). * - Reporting of non-fatal warnings back to the caller. * - Fetching the "high limits" flag when necessary, to avoid the need for loading * the user unnecessarily. * * @since 1.34 * @unstable */ class ParamValidator { // region Constants for parameter settings arrays /** @name Constants for parameter settings arrays * These constants are keys in the settings array that define how the * parameters coming in from the request are to be interpreted. * * If a constant is associated with a failure code, the failure code * and data are described. ValidationExceptions are typically thrown, but * those indicated as "non-fatal" are instead passed to * Callbacks::recordCondition(). * * Additional constants may be defined by TypeDef subclasses, or by other * libraries for controlling things like auto-generated parameter documentation. * For purposes of namespacing the constants, the values of all constants * defined by this library begin with 'param-'. * * @{ */ /** * (mixed) Default value of the parameter. If omitted, null is the default. * * TypeDef::validate() will be informed when the default value was used by the presence of * 'is-default' in $options. */ public const PARAM_DEFAULT = 'param-default'; /** * (string|array) Type of the parameter. * Must be a registered type or an array of enumerated values (in which case the "enum" * type must be registered). If omitted, the default is the PHP type of the default value * (see PARAM_DEFAULT). */ public const PARAM_TYPE = 'param-type'; /** * (bool) Indicate that the parameter is required. * * Failure codes: * - 'missingparam': The parameter is omitted/empty (and no default was set). No data. */ public const PARAM_REQUIRED = 'param-required'; /** * (bool) Indicate that the parameter is multi-valued. * * A multi-valued parameter may be submitted in one of several formats. All * of the following result in a value of `[ 'a', 'b', 'c' ]`. * - "a|b|c", i.e. pipe-separated. * - "\x1Fa\x1Fb\x1Fc", i.e. separated by U+001F, with a signalling U+001F at the start. * - As a string[], e.g. from a query string like "foo[]=a&foo[]=b&foo[]=c". * * Each of the multiple values is passed individually to the TypeDef. * $options will contain a 'values-list' key holding the entire list. * * By default duplicates are removed from the resulting parameter list. Use * PARAM_ALLOW_DUPLICATES to override that behavior. * * Failure codes: * - 'toomanyvalues': More values were supplied than are allowed. See * PARAM_ISMULTI_LIMIT1, PARAM_ISMULTI_LIMIT2, and constructor option * 'ismultiLimits'. Data: * - 'limit': The limit currently in effect. * - 'lowlimit': The limit when high limits are not allowed. * - 'highlimit': The limit when high limits are allowed. * - 'unrecognizedvalues': Non-fatal. Invalid values were passed and * PARAM_IGNORE_UNRECOGNIZED_VALUES was set. Data: * - 'values': The unrecognized values. */ public const PARAM_ISMULTI = 'param-ismulti'; /** * (int) Maximum number of multi-valued parameter values allowed * * @see PARAM_ISMULTI */ public const PARAM_ISMULTI_LIMIT1 = 'param-ismulti-limit1'; /** * (int) Maximum number of multi-valued parameter values allowed for users * allowed high limits. * * @see PARAM_ISMULTI */ public const PARAM_ISMULTI_LIMIT2 = 'param-ismulti-limit2'; /** * (bool|string) Whether a magic "all values" value exists for multi-valued * enumerated types, and if so what that value is. * * When PARAM_TYPE has a defined set of values and PARAM_ISMULTI is true, * this allows for an asterisk ('*') to be passed in place of a pipe-separated list of * every possible value. If a string is set, it will be used in place of the asterisk. */ public const PARAM_ALL = 'param-all'; /** * (bool) Allow the same value to be set more than once when PARAM_ISMULTI is true? * * If not truthy, the set of values will be passed through * `array_values( array_unique() )`. The default is falsey. */ public const PARAM_ALLOW_DUPLICATES = 'param-allow-duplicates'; /** * (bool) Indicate that the parameter's value should not be logged. * * Failure codes: (non-fatal) * - 'param-sensitive': Always recorded when the parameter is used. */ public const PARAM_SENSITIVE = 'param-sensitive'; /** * (bool) Indicate that a deprecated parameter was used. * * Failure codes: (non-fatal) * - 'param-deprecated': Always recorded when the parameter is used. */ public const PARAM_DEPRECATED = 'param-deprecated'; /** * (bool) Whether to downgrade "badvalue" errors to non-fatal when validating multi-valued * parameters. * @see PARAM_ISMULTI */ public const PARAM_IGNORE_UNRECOGNIZED_VALUES = 'param-ignore-unrecognized-values'; /** @} */ // endregion -- end of Constants for parameter settings arrays /** * @see TypeDef::OPT_ENFORCE_JSON_TYPES */ public const OPT_ENFORCE_JSON_TYPES = TypeDef::OPT_ENFORCE_JSON_TYPES; /** Magic "all values" value when PARAM_ALL is true. */ public const ALL_DEFAULT_STRING = '*'; /** A list of standard type names and types that may be passed as `$typeDefs` to __construct(). */ public const STANDARD_TYPES = [ 'boolean' => [ 'class' => TypeDef\BooleanDef::class ], 'checkbox' => [ 'class' => TypeDef\PresenceBooleanDef::class ], 'integer' => [ 'class' => TypeDef\IntegerDef::class ], 'limit' => [ 'class' => TypeDef\LimitDef::class ], 'float' => [ 'class' => TypeDef\FloatDef::class ], 'double' => [ 'class' => TypeDef\FloatDef::class ], 'string' => [ 'class' => TypeDef\StringDef::class ], 'password' => [ 'class' => TypeDef\PasswordDef::class ], 'NULL' => [ 'class' => TypeDef\StringDef::class, 'args' => [ [ TypeDef\StringDef::OPT_ALLOW_EMPTY => true, ] ], ], 'timestamp' => [ 'class' => TypeDef\TimestampDef::class ], 'upload' => [ 'class' => TypeDef\UploadDef::class ], 'enum' => [ 'class' => TypeDef\EnumDef::class ], 'expiry' => [ 'class' => TypeDef\ExpiryDef::class ], ]; /** @var Callbacks */ private $callbacks; /** @var ObjectFactory */ private $objectFactory; /** @var (TypeDef|array)[] Map parameter type names to TypeDef objects or ObjectFactory specs */ private $typeDefs = []; /** @var int Default values for PARAM_ISMULTI_LIMIT1 */ private $ismultiLimit1; /** @var int Default values for PARAM_ISMULTI_LIMIT2 */ private $ismultiLimit2; /** * @param Callbacks $callbacks * @param ObjectFactory $objectFactory To turn specs into TypeDef objects * @param array $options Associative array of additional settings * - 'typeDefs': (array) As for addTypeDefs(). If omitted, self::STANDARD_TYPES will be used. * Pass an empty array if you want to start with no registered types. * - 'ismultiLimits': (int[]) Two ints, being the default values for PARAM_ISMULTI_LIMIT1 and * PARAM_ISMULTI_LIMIT2. If not given, defaults to `[ 50, 500 ]`. */ public function __construct( Callbacks $callbacks, ObjectFactory $objectFactory, array $options = [] ) { $this->callbacks = $callbacks; $this->objectFactory = $objectFactory; $this->addTypeDefs( $options['typeDefs'] ?? self::STANDARD_TYPES ); $this->ismultiLimit1 = $options['ismultiLimits'][0] ?? 50; $this->ismultiLimit2 = $options['ismultiLimits'][1] ?? 500; } /** * List known type names * @return string[] */ public function knownTypes() { return array_keys( $this->typeDefs ); } /** * Register multiple type handlers * * @see addTypeDef() * @param array $typeDefs Associative array mapping `$name` to `$typeDef`. */ public function addTypeDefs( array $typeDefs ) { foreach ( $typeDefs as $name => $def ) { $this->addTypeDef( $name, $def ); } } /** * Register a type handler * * To allow code to omit PARAM_TYPE in settings arrays to derive the type * from PARAM_DEFAULT, it is strongly recommended that the following types be * registered: "boolean", "integer", "double", "string", "NULL", and "enum". * * When using ObjectFactory specs, the following extra arguments are passed: * - The Callbacks object for this ParamValidator instance. * * @param string $name Type name * @param TypeDef|array $typeDef Type handler or ObjectFactory spec to create one. */ public function addTypeDef( $name, $typeDef ) { Assert::parameterType( [ TypeDef::class, 'array' ], $typeDef, '$typeDef' ); if ( isset( $this->typeDefs[$name] ) ) { throw new InvalidArgumentException( "Type '$name' is already registered" ); } $this->typeDefs[$name] = $typeDef; } /** * Register a type handler, overriding any existing handler * @see addTypeDef * @param string $name Type name * @param TypeDef|array|null $typeDef As for addTypeDef, or null to unregister a type. */ public function overrideTypeDef( $name, $typeDef ) { Assert::parameterType( [ TypeDef::class, 'array', 'null' ], $typeDef, '$typeDef' ); if ( $typeDef === null ) { unset( $this->typeDefs[$name] ); } else { $this->typeDefs[$name] = $typeDef; } } /** * Test if a type is registered * @param string $name Type name * @return bool */ public function hasTypeDef( $name ) { return isset( $this->typeDefs[$name] ); } /** * Get the TypeDef for a type * @param string|array $type Any array is considered equivalent to the string "enum". * @return TypeDef|null */ public function getTypeDef( $type ) { if ( is_array( $type ) ) { $type = 'enum'; } if ( !isset( $this->typeDefs[$type] ) ) { return null; } $def = $this->typeDefs[$type]; if ( !$def instanceof TypeDef ) { $def = $this->objectFactory->createObject( $def, [ 'extraArgs' => [ $this->callbacks ], 'assertClass' => TypeDef::class, ] ); $this->typeDefs[$type] = $def; } return $def; } /** * Logic shared by normalizeSettings() and checkSettings() * @param array|mixed $settings * @return array */ private function normalizeSettingsInternal( $settings ) { // Shorthand if ( !is_array( $settings ) ) { $settings = [ self::PARAM_DEFAULT => $settings, ]; } // When type is not given, determine it from the type of the PARAM_DEFAULT if ( !isset( $settings[self::PARAM_TYPE] ) ) { $settings[self::PARAM_TYPE] = gettype( $settings[self::PARAM_DEFAULT] ?? null ); } return $settings; } /** * Normalize a parameter settings array * @param array|mixed $settings Default value or an array of settings * using PARAM_* constants. * @return array */ public function normalizeSettings( $settings ) { $settings = $this->normalizeSettingsInternal( $settings ); $typeDef = $this->getTypeDef( $settings[self::PARAM_TYPE] ); if ( $typeDef ) { $settings = $typeDef->normalizeSettings( $settings ); } return $settings; } /** * Validate a parameter settings array * * This is intended for validation of parameter settings during unit or * integration testing, and should implement strict checks. * * The rest of the code should generally be more permissive. * * @param string $name Parameter name * @param array|mixed $settings Default value or an array of settings * using PARAM_* constants. * @param array $options Options array, passed through to the TypeDef and Callbacks. * @return array * - 'issues': (string[]) Errors detected in $settings, as English text. If the settings * are valid, this will be the empty array. * - 'allowedKeys': (string[]) ParamValidator keys that are allowed in `$settings`. * - 'messages': (MessageValue[]) Messages to be checked for existence. */ public function checkSettings( string $name, $settings, array $options ): array { $settings = $this->normalizeSettingsInternal( $settings ); $issues = []; $allowedKeys = [ self::PARAM_TYPE, self::PARAM_DEFAULT, self::PARAM_REQUIRED, self::PARAM_ISMULTI, self::PARAM_SENSITIVE, self::PARAM_DEPRECATED, self::PARAM_IGNORE_UNRECOGNIZED_VALUES, ]; $messages = []; $type = $settings[self::PARAM_TYPE]; $typeDef = null; if ( !is_string( $type ) && !is_array( $type ) ) { $issues[self::PARAM_TYPE] = 'PARAM_TYPE must be a string or array, got ' . gettype( $type ); } else { $typeDef = $this->getTypeDef( $settings[self::PARAM_TYPE] ); if ( !$typeDef ) { if ( is_array( $type ) ) { $type = 'enum'; } $issues[self::PARAM_TYPE] = "Unknown/unregistered PARAM_TYPE \"$type\""; } } if ( isset( $settings[self::PARAM_DEFAULT] ) ) { try { $this->validateValue( $name, $settings[self::PARAM_DEFAULT], $settings, [ 'is-default' => true ] + $options ); } catch ( ValidationException $ex ) { $issues[self::PARAM_DEFAULT] = 'Value for PARAM_DEFAULT does not validate (code ' . $ex->getFailureMessage()->getCode() . ')'; } } if ( !is_bool( $settings[self::PARAM_REQUIRED] ?? false ) ) { $issues[self::PARAM_REQUIRED] = 'PARAM_REQUIRED must be boolean, got ' . gettype( $settings[self::PARAM_REQUIRED] ); } if ( !is_bool( $settings[self::PARAM_ISMULTI] ?? false ) ) { $issues[self::PARAM_ISMULTI] = 'PARAM_ISMULTI must be boolean, got ' . gettype( $settings[self::PARAM_ISMULTI] ); } if ( !empty( $settings[self::PARAM_ISMULTI] ) ) { $allowedKeys = array_merge( $allowedKeys, [ self::PARAM_ISMULTI_LIMIT1, self::PARAM_ISMULTI_LIMIT2, self::PARAM_ALL, self::PARAM_ALLOW_DUPLICATES ] ); $limit1 = $settings[self::PARAM_ISMULTI_LIMIT1] ?? $this->ismultiLimit1; $limit2 = $settings[self::PARAM_ISMULTI_LIMIT2] ?? $this->ismultiLimit2; if ( !is_int( $limit1 ) ) { $issues[self::PARAM_ISMULTI_LIMIT1] = 'PARAM_ISMULTI_LIMIT1 must be an integer, got ' . gettype( $settings[self::PARAM_ISMULTI_LIMIT1] ); } elseif ( $limit1 <= 0 ) { $issues[self::PARAM_ISMULTI_LIMIT1] = "PARAM_ISMULTI_LIMIT1 must be greater than 0, got $limit1"; } if ( !is_int( $limit2 ) ) { $issues[self::PARAM_ISMULTI_LIMIT2] = 'PARAM_ISMULTI_LIMIT2 must be an integer, got ' . gettype( $settings[self::PARAM_ISMULTI_LIMIT2] ); } elseif ( $limit2 < $limit1 ) { $issues[self::PARAM_ISMULTI_LIMIT2] = 'PARAM_ISMULTI_LIMIT2 must be greater than or equal to PARAM_ISMULTI_LIMIT1, but ' . "$limit2 < $limit1"; } $all = $settings[self::PARAM_ALL] ?? false; if ( !is_string( $all ) && !is_bool( $all ) ) { $issues[self::PARAM_ALL] = 'PARAM_ALL must be a string or boolean, got ' . gettype( $all ); } elseif ( $all !== false && $typeDef ) { if ( $all === true ) { $all = self::ALL_DEFAULT_STRING; } $values = $typeDef->getEnumValues( $name, $settings, $options ); if ( !is_array( $values ) ) { $issues[self::PARAM_ALL] = 'PARAM_ALL cannot be used with non-enumerated types'; } elseif ( in_array( $all, $values, true ) ) { $issues[self::PARAM_ALL] = 'Value for PARAM_ALL conflicts with an enumerated value'; } } if ( !is_bool( $settings[self::PARAM_ALLOW_DUPLICATES] ?? false ) ) { $issues[self::PARAM_ALLOW_DUPLICATES] = 'PARAM_ALLOW_DUPLICATES must be boolean, got ' . gettype( $settings[self::PARAM_ALLOW_DUPLICATES] ); } } if ( !is_bool( $settings[self::PARAM_SENSITIVE] ?? false ) ) { $issues[self::PARAM_SENSITIVE] = 'PARAM_SENSITIVE must be boolean, got ' . gettype( $settings[self::PARAM_SENSITIVE] ); } if ( !is_bool( $settings[self::PARAM_DEPRECATED] ?? false ) ) { $issues[self::PARAM_DEPRECATED] = 'PARAM_DEPRECATED must be boolean, got ' . gettype( $settings[self::PARAM_DEPRECATED] ); } if ( !is_bool( $settings[self::PARAM_IGNORE_UNRECOGNIZED_VALUES] ?? false ) ) { $issues[self::PARAM_IGNORE_UNRECOGNIZED_VALUES] = 'PARAM_IGNORE_UNRECOGNIZED_VALUES must be ' . 'boolean, got ' . gettype( $settings[self::PARAM_IGNORE_UNRECOGNIZED_VALUES] ); } $ret = [ 'issues' => $issues, 'allowedKeys' => $allowedKeys, 'messages' => $messages ]; if ( $typeDef ) { $ret = $typeDef->checkSettings( $name, $settings, $options, $ret ); } return $ret; } /** * Fetch and validate a parameter value using a settings array * * @param string $name Parameter name * @param array|mixed $settings Default value or an array of settings * using PARAM_* constants. * @param array $options Options array, passed through to the TypeDef and Callbacks. * - An additional option, 'is-default', will be set when the value comes from PARAM_DEFAULT. * @return mixed Validated parameter value * @throws ValidationException if the value is invalid */ public function getValue( $name, $settings, array $options = [] ) { $settings = $this->normalizeSettings( $settings ); $typeDef = $this->getTypeDef( $settings[self::PARAM_TYPE] ); if ( !$typeDef ) { throw new DomainException( "Param $name's type is unknown - {$settings[self::PARAM_TYPE]}" ); } $value = $typeDef->getValue( $name, $settings, $options ); if ( $value !== null ) { if ( !empty( $settings[self::PARAM_SENSITIVE] ) ) { $strValue = $typeDef->stringifyValue( $name, $value, $settings, $options ); $this->callbacks->recordCondition( DataMessageValue::new( 'paramvalidator-param-sensitive', [], 'param-sensitive' ) ->plaintextParams( $name, $strValue ), $name, $value, $settings, $options ); } // Set a warning if a deprecated parameter has been passed if ( !empty( $settings[self::PARAM_DEPRECATED] ) ) { $strValue = $typeDef->stringifyValue( $name, $value, $settings, $options ); $this->callbacks->recordCondition( DataMessageValue::new( 'paramvalidator-param-deprecated', [], 'param-deprecated' ) ->plaintextParams( $name, $strValue ), $name, $value, $settings, $options ); } } elseif ( isset( $settings[self::PARAM_DEFAULT] ) ) { $value = $settings[self::PARAM_DEFAULT]; $options['is-default'] = true; } return $this->validateValue( $name, $value, $settings, $options ); } /** * Validate a parameter value using a settings array * * @param string $name Parameter name * @param null|mixed $value Parameter value * @param array|mixed $settings Default value or an array of settings * using PARAM_* constants. * @param array $options Options array, passed through to the TypeDef and Callbacks. * - An additional option, 'values-list', will be set when processing the * values of a multi-valued parameter. * @return mixed Validated parameter value(s) * @throws ValidationException if the value is invalid */ public function validateValue( $name, $value, $settings, array $options = [] ) { $settings = $this->normalizeSettings( $settings ); $typeDef = $this->getTypeDef( $settings[self::PARAM_TYPE] ); if ( !$typeDef ) { throw new DomainException( "Param $name's type is unknown - {$settings[self::PARAM_TYPE]}" ); } if ( $value === null ) { if ( !empty( $settings[self::PARAM_REQUIRED] ) ) { throw new ValidationException( DataMessageValue::new( 'paramvalidator-missingparam', [], 'missingparam' ) ->plaintextParams( $name ), $name, $value, $settings ); } return null; } // Non-multi if ( empty( $settings[self::PARAM_ISMULTI] ) ) { if ( is_string( $value ) && substr( $value, 0, 1 ) === "\x1f" ) { throw new ValidationException( DataMessageValue::new( 'paramvalidator-notmulti', [], 'badvalue' ) ->plaintextParams( $name, $value ), $name, $value, $settings ); } // T326764: If the type of the actual param value is different from // the type that is defined via getParamSettings(), throw an exception // because this is a type to value mismatch. if ( is_array( $value ) && !$typeDef->supportsArrays() ) { throw new ValidationException( DataMessageValue::new( 'paramvalidator-notmulti', [], 'badvalue' ) ->plaintextParams( $name, gettype( $value ) ), $name, $value, $settings ); } return $typeDef->validate( $name, $value, $settings, $options ); } // Split the multi-value and validate each parameter $limit1 = $settings[self::PARAM_ISMULTI_LIMIT1] ?? $this->ismultiLimit1; $limit2 = max( $limit1, $settings[self::PARAM_ISMULTI_LIMIT2] ?? $this->ismultiLimit2 ); if ( is_array( $value ) ) { $valuesList = $value; } elseif ( $options[ self::OPT_ENFORCE_JSON_TYPES ] ?? false ) { throw new ValidationException( DataMessageValue::new( 'paramvalidator-multivalue-must-be-array', [], 'multivalue-must-be-array' )->plaintextParams( $name ), $name, $value, $settings ); } else { $valuesList = self::explodeMultiValue( $value, $limit2 + 1 ); } // Handle PARAM_ALL $enumValues = $typeDef->getEnumValues( $name, $settings, $options ); if ( is_array( $enumValues ) && isset( $settings[self::PARAM_ALL] ) && count( $valuesList ) === 1 ) { $allValue = is_string( $settings[self::PARAM_ALL] ) ? $settings[self::PARAM_ALL] : self::ALL_DEFAULT_STRING; if ( $valuesList[0] === $allValue ) { return $enumValues; } } // Avoid checking useHighLimits() unless it's actually necessary $sizeLimit = ( $limit2 > $limit1 && count( $valuesList ) > $limit1 && $this->callbacks->useHighLimits( $options ) ) ? $limit2 : $limit1; if ( count( $valuesList ) > $sizeLimit ) { throw new ValidationException( DataMessageValue::new( 'paramvalidator-toomanyvalues', [], 'toomanyvalues', [ 'parameter' => $name, 'limit' => $sizeLimit, 'lowlimit' => $limit1, 'highlimit' => $limit2, ] )->plaintextParams( $name )->numParams( $sizeLimit ), $name, $valuesList, $settings ); } $options['values-list'] = $valuesList; $validValues = []; $invalidValues = []; foreach ( $valuesList as $v ) { try { $validValues[] = $typeDef->validate( $name, $v, $settings, $options ); } catch ( ValidationException $ex ) { if ( $ex->getFailureMessage()->getCode() !== 'badvalue' || empty( $settings[self::PARAM_IGNORE_UNRECOGNIZED_VALUES] ) ) { throw $ex; } $invalidValues[] = $v; } } if ( $invalidValues ) { if ( is_array( $value ) ) { $value = self::implodeMultiValue( $value ); } $this->callbacks->recordCondition( DataMessageValue::new( 'paramvalidator-unrecognizedvalues', [], 'unrecognizedvalues', [ 'values' => $invalidValues, ] ) ->plaintextParams( $name, $value ) ->commaListParams( array_map( static function ( $v ) { return new ScalarParam( ParamType::PLAINTEXT, $v ); }, $invalidValues ) ) ->numParams( count( $invalidValues ) ), $name, $value, $settings, $options ); } // Throw out duplicates if requested if ( empty( $settings[self::PARAM_ALLOW_DUPLICATES] ) ) { $validValues = array_values( array_unique( $validValues ) ); } return $validValues; } /** * Describe parameter settings in a machine-readable format. * * @param string $name Parameter name. * @param array|mixed $settings Default value or an array of settings * using PARAM_* constants. * @param array $options Options array. * @return array */ public function getParamInfo( $name, $settings, array $options ) { $settings = $this->normalizeSettings( $settings ); $typeDef = $this->getTypeDef( $settings[self::PARAM_TYPE] ); $info = []; $info['type'] = $settings[self::PARAM_TYPE]; $info['required'] = !empty( $settings[self::PARAM_REQUIRED] ); if ( !empty( $settings[self::PARAM_DEPRECATED] ) ) { $info['deprecated'] = true; } if ( !empty( $settings[self::PARAM_SENSITIVE] ) ) { $info['sensitive'] = true; } if ( isset( $settings[self::PARAM_DEFAULT] ) ) { $info['default'] = $settings[self::PARAM_DEFAULT]; } $info['multi'] = !empty( $settings[self::PARAM_ISMULTI] ); if ( $info['multi'] ) { $info['lowlimit'] = $settings[self::PARAM_ISMULTI_LIMIT1] ?? $this->ismultiLimit1; $info['highlimit'] = max( $info['lowlimit'], $settings[self::PARAM_ISMULTI_LIMIT2] ?? $this->ismultiLimit2 ); $info['limit'] = $info['highlimit'] > $info['lowlimit'] && $this->callbacks->useHighLimits( $options ) ? $info['highlimit'] : $info['lowlimit']; if ( !empty( $settings[self::PARAM_ALLOW_DUPLICATES] ) ) { $info['allowsduplicates'] = true; } $allSpecifier = $settings[self::PARAM_ALL] ?? false; if ( $allSpecifier !== false ) { if ( !is_string( $allSpecifier ) ) { $allSpecifier = self::ALL_DEFAULT_STRING; } $info['allspecifier'] = $allSpecifier; } } if ( $typeDef ) { $info = array_merge( $info, $typeDef->getParamInfo( $name, $settings, $options ) ); } // Filter out nulls (strictly) return array_filter( $info, static function ( $v ) { return $v !== null; } ); } /** * Describe parameter settings in human-readable format * * @param string $name Parameter name being described. * @param array|mixed $settings Default value or an array of settings * using PARAM_* constants. * @param array $options Options array. * @return MessageValue[] */ public function getHelpInfo( $name, $settings, array $options ) { $settings = $this->normalizeSettings( $settings ); $typeDef = $this->getTypeDef( $settings[self::PARAM_TYPE] ); // Define ordering. Some are overwritten below, some expected from the TypeDef $info = [ self::PARAM_DEPRECATED => null, self::PARAM_REQUIRED => null, self::PARAM_SENSITIVE => null, self::PARAM_TYPE => null, self::PARAM_ISMULTI => null, self::PARAM_ISMULTI_LIMIT1 => null, self::PARAM_ALL => null, self::PARAM_DEFAULT => null, ]; if ( !empty( $settings[self::PARAM_DEPRECATED] ) ) { $info[self::PARAM_DEPRECATED] = MessageValue::new( 'paramvalidator-help-deprecated' ); } if ( !empty( $settings[self::PARAM_REQUIRED] ) ) { $info[self::PARAM_REQUIRED] = MessageValue::new( 'paramvalidator-help-required' ); } if ( !empty( $settings[self::PARAM_ISMULTI] ) ) { $info[self::PARAM_ISMULTI] = MessageValue::new( 'paramvalidator-help-multi-separate' ); $lowcount = $settings[self::PARAM_ISMULTI_LIMIT1] ?? $this->ismultiLimit1; $highcount = max( $lowcount, $settings[self::PARAM_ISMULTI_LIMIT2] ?? $this->ismultiLimit2 ); $values = $typeDef ? $typeDef->getEnumValues( $name, $settings, $options ) : null; if ( // Only mention the limits if they're likely to matter. $values === null || count( $values ) > $lowcount || !empty( $settings[self::PARAM_ALLOW_DUPLICATES] ) ) { if ( $highcount > $lowcount ) { $info[self::PARAM_ISMULTI_LIMIT1] = MessageValue::new( 'paramvalidator-help-multi-max' ) ->numParams( $lowcount, $highcount ); } else { $info[self::PARAM_ISMULTI_LIMIT1] = MessageValue::new( 'paramvalidator-help-multi-max-simple' ) ->numParams( $lowcount ); } } $allSpecifier = $settings[self::PARAM_ALL] ?? false; if ( $allSpecifier !== false ) { if ( !is_string( $allSpecifier ) ) { $allSpecifier = self::ALL_DEFAULT_STRING; } $info[self::PARAM_ALL] = MessageValue::new( 'paramvalidator-help-multi-all' ) ->plaintextParams( $allSpecifier ); } } if ( isset( $settings[self::PARAM_DEFAULT] ) && $typeDef ) { $value = $typeDef->stringifyValue( $name, $settings[self::PARAM_DEFAULT], $settings, $options ); if ( $value === '' ) { $info[self::PARAM_DEFAULT] = MessageValue::new( 'paramvalidator-help-default-empty' ); } elseif ( $value !== null ) { $info[self::PARAM_DEFAULT] = MessageValue::new( 'paramvalidator-help-default' ) ->plaintextParams( $value ); } } if ( $typeDef ) { $info = array_merge( $info, $typeDef->getHelpInfo( $name, $settings, $options ) ); } // Put the default at the very end (the TypeDef may have added extra messages) $default = $info[self::PARAM_DEFAULT]; unset( $info[self::PARAM_DEFAULT] ); $info[self::PARAM_DEFAULT] = $default; // Filter out nulls return array_filter( $info ); } /** * Split a multi-valued parameter string, like explode() * * Note that, unlike explode(), this will return an empty array when given * an empty string. * * @param string $value * @param int $limit * @return string[] */ public static function explodeMultiValue( $value, $limit ) { if ( $value === '' || $value === "\x1f" ) { return []; } if ( substr( $value, 0, 1 ) === "\x1f" ) { $sep = "\x1f"; $value = substr( $value, 1 ); } else { $sep = '|'; } return explode( $sep, $value, $limit ); } /** * Implode an array as a multi-valued parameter string, like implode() * * @param array $value * @return string */ public static function implodeMultiValue( array $value ) { if ( $value === [ '' ] ) { // There's no value that actually returns a single empty string. // Best we can do is this that returns two, which will be deduplicated to one. return '|'; } foreach ( $value as $v ) { if ( strpos( $v, '|' ) !== false ) { return "\x1f" . implode( "\x1f", $value ); } } return implode( '|', $value ); } }
| ver. 1.1 | |
.
| PHP 8.4.18 | Ð“ÐµÐ½ÐµÑ€Ð°Ñ†Ð¸Ñ Ñтраницы: 0 |
proxy
|
phpinfo
|
ÐаÑтройка