556301b89823af004fd883d27ae1097cf85afafa
[lhc/web/wiklou.git] / includes / libs / ParamValidator / TypeDef / IntegerDef.php
1 <?php
2
3 namespace Wikimedia\ParamValidator\TypeDef;
4
5 use Wikimedia\ParamValidator\TypeDef;
6 use Wikimedia\ParamValidator\ValidationException;
7
8 /**
9 * Type definition for integer types
10 *
11 * A valid representation consists of an optional sign (`+` or `-`) followed by
12 * one or more decimal digits.
13 *
14 * The result from validate() is a PHP integer.
15 *
16 * * ValidationException codes:
17 * - 'badinteger': The value was invalid or could not be represented as a PHP
18 * integer. No data.
19 *
20 * Additional codes may be generated when using certain PARAM constants. See
21 * the constants' documentation for details.
22 *
23 * @since 1.34
24 */
25 class IntegerDef extends TypeDef {
26
27 /**
28 * (bool) Whether to enforce the specified range.
29 *
30 * If set and truthy, ValidationExceptions from PARAM_MIN, PARAM_MAX, and
31 * PARAM_MAX2 are non-fatal.
32 */
33 const PARAM_IGNORE_RANGE = 'param-ignore-range';
34
35 /**
36 * (int) Minimum allowed value.
37 *
38 * ValidationException codes:
39 * - 'belowminimum': The value was below the allowed minimum. Data:
40 * - 'min': Allowed minimum, or empty string if there is none.
41 * - 'max': Allowed (normal) maximum, or empty string if there is none.
42 * - 'max2': Allowed (high limits) maximum, or empty string if there is none.
43 */
44 const PARAM_MIN = 'param-min';
45
46 /**
47 * (int) Maximum allowed value (normal limits)
48 *
49 * ValidationException codes:
50 * - 'abovemaximum': The value was above the allowed maximum. Data:
51 * - 'min': Allowed minimum, or empty string if there is none.
52 * - 'max': Allowed (normal) maximum, or empty string if there is none.
53 * - 'max2': Allowed (high limits) maximum, or empty string if there is none.
54 */
55 const PARAM_MAX = 'param-max';
56
57 /**
58 * (int) Maximum allowed value (high limits)
59 *
60 * If not specified, PARAM_MAX will be enforced for all users. Ignored if
61 * PARAM_MAX is not set.
62 *
63 * ValidationException codes:
64 * - 'abovehighmaximum': The value was above the allowed maximum. Data:
65 * - 'min': Allowed minimum, or empty string if there is none.
66 * - 'max': Allowed (normal) maximum, or empty string if there is none.
67 * - 'max2': Allowed (high limits) maximum, or empty string if there is none.
68 */
69 const PARAM_MAX2 = 'param-max2';
70
71 public function validate( $name, $value, array $settings, array $options ) {
72 if ( !preg_match( '/^[+-]?\d+$/D', $value ) ) {
73 throw new ValidationException( $name, $value, $settings, 'badinteger', [] );
74 }
75 $ret = intval( $value, 10 );
76
77 // intval() returns min/max on overflow, so check that
78 if ( $ret === PHP_INT_MAX || $ret === PHP_INT_MIN ) {
79 $tmp = ( $ret < 0 ? '-' : '' ) . ltrim( $value, '-0' );
80 if ( $tmp !== (string)$ret ) {
81 throw new ValidationException( $name, $value, $settings, 'badinteger', [] );
82 }
83 }
84
85 $min = $settings[self::PARAM_MIN] ?? null;
86 $max = $settings[self::PARAM_MAX] ?? null;
87 $max2 = $settings[self::PARAM_MAX2] ?? null;
88 $err = null;
89
90 if ( $min !== null && $ret < $min ) {
91 $err = 'belowminimum';
92 $ret = $min;
93 } elseif ( $max !== null && $ret > $max ) {
94 if ( $max2 !== null && $this->callbacks->useHighLimits( $options ) ) {
95 if ( $ret > $max2 ) {
96 $err = 'abovehighmaximum';
97 $ret = $max2;
98 }
99 } else {
100 $err = 'abovemaximum';
101 $ret = $max;
102 }
103 }
104 if ( $err !== null ) {
105 $ex = new ValidationException( $name, $value, $settings, $err, [
106 'min' => $min === null ? '' : $min,
107 'max' => $max === null ? '' : $max,
108 'max2' => $max2 === null ? '' : $max2,
109 ] );
110 if ( empty( $settings[self::PARAM_IGNORE_RANGE] ) ) {
111 throw $ex;
112 }
113 $this->callbacks->recordCondition( $ex, $options );
114 }
115
116 return $ret;
117 }
118
119 public function normalizeSettings( array $settings ) {
120 if ( !isset( $settings[self::PARAM_MAX] ) ) {
121 unset( $settings[self::PARAM_MAX2] );
122 }
123
124 if ( isset( $settings[self::PARAM_MAX2] ) && isset( $settings[self::PARAM_MAX] ) &&
125 $settings[self::PARAM_MAX2] < $settings[self::PARAM_MAX]
126 ) {
127 $settings[self::PARAM_MAX2] = $settings[self::PARAM_MAX];
128 }
129
130 return parent::normalizeSettings( $settings );
131 }
132
133 public function describeSettings( $name, array $settings, array $options ) {
134 $info = parent::describeSettings( $name, $settings, $options );
135
136 $min = $settings[self::PARAM_MIN] ?? '';
137 $max = $settings[self::PARAM_MAX] ?? '';
138 $max2 = $settings[self::PARAM_MAX2] ?? '';
139 if ( $max === '' || $max2 !== '' && $max2 <= $max ) {
140 $max2 = '';
141 }
142
143 if ( empty( $options['compact'] ) ) {
144 if ( $min !== '' ) {
145 $info['min'] = $min;
146 }
147 if ( $max !== '' ) {
148 $info['max'] = $max;
149 }
150 if ( $max2 !== '' ) {
151 $info['max2'] = $max2;
152 }
153 } else {
154 $key = '';
155 if ( $min !== '' ) {
156 $key = 'min';
157 }
158 if ( $max2 !== '' ) {
159 $key .= 'max2';
160 } elseif ( $max !== '' ) {
161 $key .= 'max';
162 }
163 if ( $key !== '' ) {
164 $info[$key] = [ 'min' => $min, 'max' => $max, 'max2' => $max2 ];
165 }
166 }
167
168 return $info;
169 }
170
171 }