PluginProbe
ZIP AI – AI Website Builder & AI Agent (Beta) / trunk
ZIP AI – AI Website Builder & AI Agent (Beta) vtrunk
0.0.10 0.0.9 trunk 0.0.4 0.0.5 0.0.6 0.0.7 0.0.8
zip-ai / inc / core / validator.php

validator.php in ZIP AI – AI Website Builder & AI Agent (Beta) trunk, at inc/core/validator.php

91 lines 2.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Validator - Centralized schema-based validation and sanitation
4 *
5 * @package zip-ai
6 */
7
8 namespace ZipAI\MCP\Classes\Core;
9
10 // Exit if accessed directly.
11 if ( ! defined( 'ABSPATH' ) ) {
12 exit;
13 }
14
15 /**
16 * Class Validator
17 */
18 class Validator {
19
20 /**
21 * Validate and sanitize input against a JSON schema.
22 *
23 * @param array<string,mixed> $schema The JSON schema to validate against.
24 * @param array<string,mixed> $input The raw input data.
25 * @return array<string,mixed>|\WP_Error Validated and sanitized data on success, WP_Error on failure.
26 */
27 public static function validate( $schema, $input ) {
28 $valid_data = array();
29 $properties = isset( $schema['properties'] ) && is_array( $schema['properties'] ) ? $schema['properties'] : array();
30 $required = isset( $schema['required'] ) && is_array( $schema['required'] ) ? $schema['required'] : array();
31
32 // Check for missing required fields.
33 foreach ( $required as $field ) {
34 $field = Utils::to_str( $field );
35 if ( ! isset( $input[ $field ] ) ) {
36 return new \WP_Error(
37 'missing_required_field',
38 sprintf( 'Missing required field: %s', $field )
39 );
40 }
41 }
42
43 // Validate and sanitize each property.
44 foreach ( $properties as $field => $config ) {
45 $field = (string) $field;
46 $config = is_array( $config ) ? $config : array();
47 $value = isset( $input[ $field ] ) ? $input[ $field ] : ( isset( $config['default'] ) ? $config['default'] : null );
48
49 if ( null === $value ) {
50 continue;
51 }
52
53 $type = isset( $config['type'] ) ? $config['type'] : 'string';
54
55 switch ( $type ) {
56 case 'integer':
57 $value = Utils::to_int( $value );
58 if ( isset( $config['minimum'] ) && $value < Utils::to_int( $config['minimum'] ) ) {
59 return new \WP_Error( 'invalid_range', sprintf( '%s is below minimum %d', $field, Utils::to_int( $config['minimum'] ) ) );
60 }
61 if ( isset( $config['maximum'] ) && $value > Utils::to_int( $config['maximum'] ) ) {
62 return new \WP_Error( 'invalid_range', sprintf( '%s is above maximum %d', $field, Utils::to_int( $config['maximum'] ) ) );
63 }
64 break;
65
66 case 'boolean':
67 $value = filter_var( $value, FILTER_VALIDATE_BOOLEAN );
68 break;
69
70 case 'string':
71 if ( isset( $config['enum'] ) && is_array( $config['enum'] ) && ! in_array( $value, $config['enum'], true ) ) {
72 return new \WP_Error( 'invalid_enum', sprintf( 'Invalid value for %s. Expected one of: %s', $field, implode( ', ', array_map( array( Utils::class, 'to_str' ), $config['enum'] ) ) ) );
73 }
74 // Default string sanitation if not explicitly handled by the tool.
75 // Note: Tools can still do their own more specific sanitation.
76 break;
77
78 case 'array':
79 if ( ! is_array( $value ) ) {
80 return new \WP_Error( 'invalid_type', sprintf( '%s must be an array', $field ) );
81 }
82 break;
83 }
84
85 $valid_data[ $field ] = $value;
86 }
87
88 return $valid_data;
89 }
90 }
91