ParamValidator: Flag as unstable for 1.34
[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 * @unstable
25 */
26 class IntegerDef extends TypeDef {
27
28 /**
29 * (bool) Whether to enforce the specified range.
30 *
31 * If set and truthy, ValidationExceptions from PARAM_MIN, PARAM_MAX, and
32 * PARAM_MAX2 are non-fatal.
33 */
34 const PARAM_IGNORE_RANGE = 'param-ignore-range';
35
36 /**
37 * (int) Minimum allowed value.
38 *
39 * ValidationException codes:
40 * - 'belowminimum': The value was below the allowed minimum. Data:
41 * - 'min': Allowed minimum, or empty string if there is none.
42 * - 'max': Allowed (normal) maximum, or empty string if there is none.
43 * - 'max2': Allowed (high limits) maximum, or empty string if there is none.
44 */
45 const PARAM_MIN = 'param-min';
46
47 /**
48 * (int) Maximum allowed value (normal limits)
49 *
50 * ValidationException codes:
51 * - 'abovemaximum': The value was above the allowed maximum. Data:
52 * - 'min': Allowed minimum, or empty string if there is none.
53 * - 'max': Allowed (normal) maximum, or empty string if there is none.
54 * - 'max2': Allowed (high limits) maximum, or empty string if there is none.
55 */
56 const PARAM_MAX = 'param-max';
57
58 /**
59 * (int) Maximum allowed value (high limits)
60 *
61 * If not specified, PARAM_MAX will be enforced for all users. Ignored if
62 * PARAM_MAX is not set.
63 *
64 * ValidationException codes:
65 * - 'abovehighmaximum': The value was above the allowed maximum. Data:
66 * - 'min': Allowed minimum, or empty string if there is none.
67 * - 'max': Allowed (normal) maximum, or empty string if there is none.
68 * - 'max2': Allowed (high limits) maximum, or empty string if there is none.
69 */
70 const PARAM_MAX2 = 'param-max2';
71
72 public function validate( $name, $value, array $settings, array $options ) {
73 if ( !preg_match( '/^[+-]?\d+$/D', $value ) ) {
74 throw new ValidationException( $name, $value, $settings, 'badinteger', [] );
75 }
76 $ret = intval( $value, 10 );
77
78 // intval() returns min/max on overflow, so check that
79 if ( $ret === PHP_INT_MAX || $ret === PHP_INT_MIN ) {
80 $tmp = ( $ret < 0 ? '-' : '' ) . ltrim( $value, '-0' );
81 if ( $tmp !== (string)$ret ) {
82 throw new ValidationException( $name, $value, $settings, 'badinteger', [] );
83 }
84 }
85
86 $min = $settings[self::PARAM_MIN] ?? null;
87 $max = $settings[self::PARAM_MAX] ?? null;
88 $max2 = $settings[self::PARAM_MAX2] ?? null;
89 $err = null;
90
91 if ( $min !== null && $ret < $min ) {
92 $err = 'belowminimum';
93 $ret = $min;
94 } elseif ( $max !== null && $ret > $max ) {
95 if ( $max2 !== null && $this->callbacks->useHighLimits( $options ) ) {
96 if ( $ret > $max2 ) {
97 $err = 'abovehighmaximum';
98 $ret = $max2;
99 }
100 } else {
101 $err = 'abovemaximum';
102 $ret = $max;
103 }
104 }
105 if ( $err !== null ) {
106 $ex = new ValidationException( $name, $value, $settings, $err, [
107 'min' => $min === null ? '' : $min,
108 'max' => $max === null ? '' : $max,
109 'max2' => $max2 === null ? '' : $max2,
110 ] );
111 if ( empty( $settings[self::PARAM_IGNORE_RANGE] ) ) {
112 throw $ex;
113 }
114 $this->callbacks->recordCondition( $ex, $options );
115 }
116
117 return $ret;
118 }
119
120 public function normalizeSettings( array $settings ) {
121 if ( !isset( $settings[self::PARAM_MAX] ) ) {
122 unset( $settings[self::PARAM_MAX2] );
123 }
124
125 if ( isset( $settings[self::PARAM_MAX2] ) && isset( $settings[self::PARAM_MAX] ) &&
126 $settings[self::PARAM_MAX2] < $settings[self::PARAM_MAX]
127 ) {
128 $settings[self::PARAM_MAX2] = $settings[self::PARAM_MAX];
129 }
130
131 return parent::normalizeSettings( $settings );
132 }
133
134 public function describeSettings( $name, array $settings, array $options ) {
135 $info = parent::describeSettings( $name, $settings, $options );
136
137 $min = $settings[self::PARAM_MIN] ?? '';
138 $max = $settings[self::PARAM_MAX] ?? '';
139 $max2 = $settings[self::PARAM_MAX2] ?? '';
140 if ( $max === '' || $max2 !== '' && $max2 <= $max ) {
141 $max2 = '';
142 }
143
144 if ( empty( $options['compact'] ) ) {
145 if ( $min !== '' ) {
146 $info['min'] = $min;
147 }
148 if ( $max !== '' ) {
149 $info['max'] = $max;
150 }
151 if ( $max2 !== '' ) {
152 $info['max2'] = $max2;
153 }
154 } else {
155 $key = '';
156 if ( $min !== '' ) {
157 $key = 'min';
158 }
159 if ( $max2 !== '' ) {
160 $key .= 'max2';
161 } elseif ( $max !== '' ) {
162 $key .= 'max';
163 }
164 if ( $key !== '' ) {
165 $info[$key] = [ 'min' => $min, 'max' => $max, 'max2' => $max2 ];
166 }
167 }
168
169 return $info;
170 }
171
172 }