PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / 3.8.2
Tutor LMS – eLearning and online course solution v3.8.2
3.9.14 3.9.13 3.9.12 3.9.11 trunk 1.0.0 1.0.0-alpha 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.2.0 1.2.1 1.2.11 1.2.12 1.2.13 1.2.20 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 1.7.7 1.7.8 1.7.9 1.8.0 1.8.1 1.8.10 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 1.8.9 1.9.0 1.9.1 1.9.10 1.9.11 1.9.12 1.9.13 1.9.14 1.9.15 1.9.16 1.9.2 1.9.3 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0.0 2.0.1 2.0.10 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 2.1.0 2.1.1 2.1.10 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.3.0 2.4.0 2.5.0 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 3.0.0 3.0.1 3.0.2 3.1.0 3.2.0 3.2.1 3.2.2 3.2.3 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.7.0 3.7.1 3.7.2 3.7.3 3.7.4 3.8.0 3.8.1 3.8.2 3.8.3 3.9.0 3.9.1 3.9.10 3.9.2 3.9.3 3.9.4 3.9.5 3.9.6 3.9.7 3.9.8 3.9.9
tutor / helpers / ValidationHelper.php
tutor / helpers Last commit date
DateTimeHelper.php 9 months ago HttpHelper.php 11 months ago PluginInstaller.php 1 year ago QueryHelper.php 9 months ago SessionHelper.php 3 years ago TemplateImportHelper.php 11 months ago ValidationHelper.php 10 months ago
ValidationHelper.php
387 lines
1 <?php
2 /**
3 * Form validation helper
4 *
5 * Provides static helper methods for form validation.
6 *
7 * @package Tutor\Helper
8 * @author Themeum<support@themeum.com>
9 * @link https://themeum.com
10 * @since 2.6.0
11 */
12
13 namespace Tutor\Helpers;
14
15 if ( ! defined( 'ABSPATH' ) ) {
16 return;
17 }
18
19 /**
20 * Validation class contains static methods
21 */
22 class ValidationHelper {
23
24 /**
25 * Store all validation errors.
26 *
27 * @since 3.7.2
28 *
29 * @var array
30 */
31 private static $errors = array();
32
33 /**
34 * Validate array elements
35 *
36 * @since 2.6.0
37 *
38 * @param array $validation_rules associative array for validation
39 * rules. For ex: [id => 'required|number', name => 'alpha_numeric|max:255'].
40 *
41 * @param array $data key value pair of data. Note array index should
42 * exactly match with validation_rules array index.
43 *
44 * @return object validation response
45 */
46 public static function validate( array $validation_rules, array $data ): object {
47 self::$errors = array();
48
49 foreach ( $validation_rules as $key => $validation_rule ) {
50 $rules = explode( '|', $validation_rule );
51
52 $required_rule_failed = false;
53
54 foreach ( $rules as $rule ) {
55 if ( $required_rule_failed ) {
56 break;
57 }
58
59 $nested_rules = explode( ':', $rule );
60
61 /**
62 * Optional input validation.
63 */
64 if ( isset( $nested_rules[0] ) && 'if_input' === $nested_rules[0] ) {
65 if ( ! self::has_key( $key, $data ) ) {
66 break;
67 }
68 }
69
70 foreach ( $nested_rules as $nested_rule ) {
71 switch ( $nested_rule ) {
72 case 'required':
73 if ( ! self::has_key( $key, $data ) || self::is_empty( $data[ $key ] ) ) {
74 /* translators: %s: field name */
75 self::add_error( $key, sprintf( __( '%s is required', 'tutor' ), self::humanize_key( $key ) ) );
76
77 $required_rule_failed = true;
78 }
79 break;
80 case 'numeric':
81 if ( ! self::is_numeric( $data[ $key ] ) ) {
82 /* translators: %s: field name */
83 self::add_error( $key, sprintf( __( '%s is not numeric', 'tutor' ), self::humanize_key( $key ) ) );
84 }
85 break;
86 /* Greater than (gt) */
87 case 'gt':
88 if ( $data[ $key ] < $nested_rules[1] ) {
89 /* translators: %1$s: field name, %2$d: value */
90 self::add_error( $key, sprintf( __( '%1$s need to be greater than %2$d', 'tutor' ), self::humanize_key( $key ), $nested_rules[1] ) );
91 }
92 break;
93 /* Less than (lt) */
94 case 'lt':
95 if ( $data[ $key ] > $nested_rules[1] ) {
96 /* translators: %1$s: field name, %2$d: value */
97 self::add_error( $key, sprintf( __( '%1$s need to be less than %2$d', 'tutor' ), self::humanize_key( $key ), $nested_rules[1] ) );
98 }
99 break;
100 case 'email':
101 if ( ! is_email( $data[ $key ] ) ) {
102 /* translators: %s: field name */
103 self::add_error( $key, sprintf( __( '%s is not valid email', 'tutor' ), self::humanize_key( $key ) ) );
104 }
105 break;
106 case 'min_length':
107 if ( strlen( $data[ $key ] ) < $nested_rules[1] ) {
108 /* translators: %1$s: field name, %2$d: value */
109 self::add_error( $key, sprintf( __( '%1$s minimum length is %2$d', 'tutor' ), self::humanize_key( $key ), $nested_rules[1] ) );
110 }
111 break;
112 case 'max_length':
113 if ( strlen( $data[ $key ] ) > $nested_rules[1] ) {
114 /* translators: %1$s: field name, %2$d: value */
115 self::add_error( $key, sprintf( __( '%1$s maximum length is %2$d', 'tutor' ), self::humanize_key( $key ), $nested_rules[1] ) );
116 }
117 break;
118 case 'mimes':
119 $extensions = explode( ',', $nested_rules[1] );
120 if ( ! self::in_array( $data[ $key ], $extensions ) ) {
121 /* translators: %s: field name */
122 self::add_error( $key, sprintf( __( '%s extension is not valid', 'tutor' ), self::humanize_key( $key ) ) );
123 }
124 break;
125 case 'match_string':
126 $strings = explode( ',', $nested_rules[1] );
127 if ( ! self::in_array( $data[ $key ], $strings ) ) {
128 /* translators: %s: field name */
129 self::add_error( $key, sprintf( __( '%s string is not valid', 'tutor' ), self::humanize_key( $key ) ) );
130 }
131 break;
132 case 'boolean':
133 if ( ! self::is_boolean( $data[ $key ] ) ) {
134 /* translators: %s: field name */
135 self::add_error( $key, sprintf( __( '%s is not boolean', 'tutor' ), self::humanize_key( $key ) ) );
136 }
137 break;
138 case 'is_array':
139 if ( ! self::is_array( $data[ $key ] ) ) {
140 /* translators: %s: field name */
141 self::add_error( $key, sprintf( __( '%s is not an array', 'tutor' ), self::humanize_key( $key ) ) );
142 }
143 break;
144 case 'date_format':
145 $format = explode( ':', $rule, 2 )[1];
146 if ( ! self::is_valid_date( $data[ $key ], $format ) ) {
147 /* translators: %s: field name */
148 self::add_error( $key, sprintf( __( '%s invalid date format', 'tutor' ), self::humanize_key( $key ) ) );
149 }
150 break;
151
152 case 'has_record':
153 list( $table, $column ) = explode( ',', $nested_rules[1], 2 );
154
155 $value = $data[ $key ];
156 $has_record = self::has_record( $table, $column, $value );
157 if ( ! $has_record ) {
158 /* translators: %s: field name */
159 self::add_error( $key, sprintf( __( '%s record not found', 'tutor' ), self::humanize_key( $key ) ) );
160 }
161 break;
162
163 case 'user_exists':
164 $user_id = (int) $data[ $key ];
165 $is_exists = self::is_user_exists( $user_id );
166 if ( ! $is_exists ) {
167 /* translators: %s: field name */
168 self::add_error( $key, sprintf( __( '%s user does not exist', 'tutor' ), self::humanize_key( $key ) ) );
169 }
170 break;
171 default:
172 // code...
173 break;
174 }
175 }
176 }
177 }
178
179 $response = array(
180 'success' => empty( self::$errors ),
181 'errors' => self::$errors,
182 );
183
184 return (object) $response;
185 }
186
187 /**
188 * Add validation error.
189 *
190 * @since 3.7.2
191 *
192 * @param string $key key.
193 * @param string $error error message.
194 *
195 * @return void
196 */
197 private static function add_error( $key, $error ) {
198 self::$errors[ $key ][] = $error;
199 }
200
201 /**
202 * Humanize key name.
203 * Example: course_id to Course ID, api_url to API URL
204 *
205 * @since 3.7.2
206 *
207 * @param string $key key to humanize.
208 *
209 * @return string
210 */
211 private static function humanize_key( $key ) {
212 $key = str_replace( '_', ' ', $key );
213 $key = ucwords( $key );
214
215 // All know word replace.
216 $key = preg_replace( '/\bId\b/i', 'ID', $key );
217 $key = preg_replace( '/\bUrl\b/i', 'URL', $key );
218 $key = preg_replace( '/\bApi\b/i', 'API', $key );
219 $key = preg_replace( '/\bIp\b/i', 'IP', $key );
220
221 return $key;
222 }
223
224 /**
225 * Check if value is numeric
226 *
227 * Rules: numeric
228 *
229 * @param mixed $value value to check.
230 *
231 * @return boolean
232 */
233 public static function is_numeric( $value ): bool {
234 return is_numeric( $value );
235 }
236
237 /**
238 * Check if value is empty
239 *
240 * Value will be considered empty if it is either null or empty string.
241 *
242 * Rules: required
243 *
244 * @param mixed $value value to check.
245 *
246 * @return boolean
247 */
248 public static function is_empty( $value ): bool {
249 return '' === $value || is_null( $value ) ? true : false;
250 }
251
252 /**
253 * Check if array has key
254 *
255 * @param string $key key to check.
256 * @param array $array_assoc array where to check.
257 *
258 * @return boolean
259 */
260 public static function has_key( string $key, array $array_assoc ): bool {
261 return isset( $array_assoc[ $key ] );
262 }
263
264 /**
265 * Check if element has in array
266 *
267 * Rules: match_string:{value1},{value2}",
268 *
269 * @param string $key key to check.
270 * @param array $array array where to check.
271 *
272 * @return boolean
273 */
274 public static function in_array( string $key, array $array ): bool {
275 return in_array( $key, $array );
276 }
277
278
279 /**
280 * The function checks if a given value is a boolean.
281 *
282 * Considered values: array( 1, 0, 'true', 'false', true, false ), any value
283 * except these will be not counted as boolean
284 *
285 * Rules: boolean
286 *
287 * @param mixed $value is the variable that will be checked if it is a boolean value or not.
288 *
289 * @return bool A boolean value is being returned, indicating whether the input value is a valid
290 * boolean or not.
291 */
292 public static function is_boolean( $value ): bool {
293 $allowed_booleans = array( 1, 0, '1', '0', 'true', 'false', true, false );
294 return in_array( $value, $allowed_booleans, true );
295 }
296
297 /**
298 * The function checks if a given value is an array.
299 *
300 * Usage: is_array:{value}
301 *
302 * @param mixed $value is the variable that will be checked if it is an array or not.
303 *
304 * @return bool A boolean value is being returned, indicating whether the input value is a valid
305 * boolean or not.
306 */
307 public static function is_array( $value ): bool {
308 return is_array( $value );
309 }
310
311 /**
312 * The function checks if a given date string is valid according to a specified format in PHP.
313 *
314 * Rules: date_format:Y-m-d
315 *
316 * @since 2.6.0
317 *
318 * @param string $date_string is a string representing a date in a specific format. For example,
319 * "2022-01-31" or "31/01/2022".
320 * @param string $format The format parameter is a string that specifies the expected format of the date
321 * string. It uses the same format as the PHP date() function, with placeholders for different parts of
322 * the date (e.g. "Y" for the year, "m" for the month, "d" for the day.
323 *
324 * @return bool A boolean value (true or false) is being returned, depending on whether the given date
325 * string is valid according to the specified format.
326 */
327 public static function is_valid_date( $date_string, $format ): bool {
328 $date_object = \DateTime::createFromFormat( $format, $date_string );
329 return $date_object && $date_object->format( $format ) === $date_string;
330 }
331
332 /**
333 * Check if user exists
334 *
335 * Rules: user_exists:{user_id}
336 *
337 * @param integer $user_id user id.
338 * @return boolean
339 */
340 public static function is_user_exists( int $user_id ): bool {
341 $user = get_user_by( 'id', $user_id );
342 return $user ? true : false;
343 }
344
345 /**
346 * Check a table has record.
347 *
348 * @since 2.7.0
349 *
350 * @param string $table table name with prefix or without.
351 * @param string $column table column name.
352 * @param mixed $value table column value.
353 *
354 * @return boolean
355 */
356 public static function has_record( $table, $column, $value ) {
357 global $wpdb;
358 $table_prefix = $wpdb->prefix;
359 if ( strpos( $table, $table_prefix ) !== 0 ) {
360 $table = $table_prefix . $table;
361 }
362
363 $record = QueryHelper::get_row( $table, array( $column => $value ), $column );
364 return $record ? true : false;
365 }
366
367 /**
368 * Validate term IDs before setting them.
369 *
370 * @since 3.6.0
371 *
372 * @param array $term_ids Term IDs to validate.
373 * @param string $taxonomy Taxonomy to check against.
374 *
375 * @return array Valid term IDs.
376 */
377 public static function validate_term_ids( $term_ids, $taxonomy ) {
378 return array_filter(
379 array_map( 'intval', $term_ids ),
380 function ( $term_id ) use ( $taxonomy ) {
381 $term = get_term( $term_id, $taxonomy );
382 return ! is_wp_error( $term ) && $term;
383 }
384 );
385 }
386 }
387