PluginProbe
Tutor LMS – eLearning and online course solution / 3.9.2
Tutor LMS – eLearning and online course solution v3.9.2
4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 4.0.2 4.0.1 4.0.0 3.9.15 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 All 191 releases
tutor / helpers / ValidationHelper.php

ValidationHelper.php in Tutor LMS – eLearning and online course solution 3.9.2, at helpers/ValidationHelper.php

387 lines 10.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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