GIF94;
| Path : /var/www/wordpress/wp-content/plugins/oxymade/includes/ |
| Current File : /var/www/wordpress/wp-content/plugins/oxymade/includes/class-oxymade-validator.php |
<?php
/**
* OxyMade Validator Class
*
* Handles validation and sanitization of all user inputs
*
* @package OxyMade
* @since 0.1.6
*/
namespace OxyMade\Includes;
class Validator {
/**
* Validate and sanitize color palette structure
*
* @param mixed $palette The palette data to validate
* @return array|false Sanitized palette or false on failure
*/
public static function validate_palette_structure($palette) {
if (!is_array($palette)) {
return false;
}
$valid_keys = array('primary', 'secondary', 'tertiary', 'accent', 'neutral');
$sanitized = array();
foreach ($palette as $key => $colors) {
$key = sanitize_key($key);
if (!in_array($key, $valid_keys, true)) {
continue;
}
if (!is_array($colors)) {
continue;
}
$sanitized[$key] = self::sanitize_color_group($colors);
}
return $sanitized;
}
/**
* Sanitize color group (shades within a color)
*
* @param array $colors Color shades array
* @return array Sanitized color shades
*/
private static function sanitize_color_group($colors) {
$sanitized = array();
$valid_shades = array('50', '100', '200', '300', '400', '500', '600', '700', '800', '900');
foreach ($colors as $shade => $color) {
$shade = sanitize_key($shade);
if (!in_array($shade, $valid_shades, true)) {
continue;
}
// Validate hex color
if (!self::is_valid_hex_color($color)) {
error_log("OxyMade: Invalid color value: {$color}");
continue;
}
$sanitized[$shade] = sanitize_hex_color($color);
}
return $sanitized;
}
/**
* Validate hex color format
*
* @param string $color Color value to validate
* @return bool True if valid hex color
*/
public static function is_valid_hex_color($color) {
return (bool) preg_match('/^#[0-9a-fA-F]{6}$/', $color);
}
/**
* Sanitize flat palette (key-value pairs)
*
* @param mixed $palette Flat palette data
* @return array Sanitized flat palette
*/
public static function sanitize_flat_palette($palette) {
if (!is_array($palette)) {
return array();
}
$sanitized = array();
foreach ($palette as $key => $value) {
$key = sanitize_key($key);
// Skip RGB values (they're valid but not hex format)
if (strpos($key, '-rgb') !== false) {
$sanitized[$key] = sanitize_text_field($value);
continue;
}
// Only validate hex colors
if (!self::is_valid_hex_color($value)) {
continue;
}
$sanitized[$key] = sanitize_hex_color($value);
}
return $sanitized;
}
/**
* Validate typography configuration
*
* @param mixed $config Typography configuration data
* @return array|false Sanitized config or false on failure
*/
public static function validate_typography_config($config) {
if (!is_array($config)) {
return false;
}
$sanitized = array();
// Validate font sizes
if (isset($config['base_font_size_mobile'])) {
$size = absint($config['base_font_size_mobile']);
$sanitized['base_font_size_mobile'] = max(12, min(24, $size));
}
if (isset($config['base_font_size_desktop'])) {
$size = absint($config['base_font_size_desktop']);
$sanitized['base_font_size_desktop'] = max(14, min(32, $size));
}
// Validate scale ratio
if (isset($config['scale_ratio'])) {
$ratio = floatval($config['scale_ratio']);
$sanitized['scale_ratio'] = max(1.1, min(2.0, $ratio));
}
// Validate font families
if (isset($config['font_family_primary'])) {
$sanitized['font_family_primary'] = sanitize_text_field($config['font_family_primary']);
}
if (isset($config['font_family_secondary'])) {
$sanitized['font_family_secondary'] = sanitize_text_field($config['font_family_secondary']);
}
// Validate font weights
$valid_weights = array('100', '200', '300', '400', '500', '600', '700', '800', '900');
if (isset($config['font_weight']) && in_array($config['font_weight'], $valid_weights, true)) {
$sanitized['font_weight'] = $config['font_weight'];
}
// Validate line heights
if (isset($config['line_height'])) {
$value = floatval($config['line_height']);
$sanitized['line_height'] = max(1.0, min(3.0, $value));
}
return $sanitized;
}
/**
* Validate and sanitize JSON data
*
* @param string $json_string JSON string to validate
* @param int $max_depth Maximum nesting depth
* @return mixed|false Decoded data or false on failure
*/
public static function validate_json($json_string, $max_depth = 10) {
if (!is_string($json_string)) {
return false;
}
// Decode with depth limit
$data = json_decode($json_string, true, $max_depth);
if (JSON_ERROR_NONE !== json_last_error()) {
error_log('OxyMade: JSON decode error: ' . json_last_error_msg());
return false;
}
return $data;
}
/**
* Validate array structure against schema
*
* @param array $data Data to validate
* @param array $schema Schema definition
* @return array|false Validated data or false on failure
*/
public static function validate_against_schema($data, $schema) {
if (!is_array($data) || !is_array($schema)) {
return false;
}
$validated = array();
foreach ($schema as $key => $rules) {
// Check if required
if (isset($rules['required']) && $rules['required'] && !isset($data[$key])) {
error_log("OxyMade: Missing required field: {$key}");
return false;
}
if (!isset($data[$key])) {
continue;
}
$value = $data[$key];
// Type validation
if (isset($rules['type'])) {
$valid = false;
switch ($rules['type']) {
case 'string':
if (is_string($value)) {
$value = sanitize_text_field($value);
$valid = true;
}
break;
case 'int':
if (is_numeric($value)) {
$value = absint($value);
$valid = true;
}
break;
case 'float':
if (is_numeric($value)) {
$value = floatval($value);
$valid = true;
}
break;
case 'bool':
$value = (bool) $value;
$valid = true;
break;
case 'array':
if (is_array($value)) {
$valid = true;
}
break;
case 'email':
if (is_email($value)) {
$value = sanitize_email($value);
$valid = true;
}
break;
case 'url':
if (filter_var($value, FILTER_VALIDATE_URL)) {
$value = esc_url_raw($value);
$valid = true;
}
break;
case 'color':
if (self::is_valid_hex_color($value)) {
$value = sanitize_hex_color($value);
$valid = true;
}
break;
}
if (!$valid) {
error_log("OxyMade: Invalid type for field {$key}: expected {$rules['type']}");
continue;
}
}
// Min/max validation for numeric values
if (isset($rules['min']) && is_numeric($value) && $value < $rules['min']) {
$value = $rules['min'];
}
if (isset($rules['max']) && is_numeric($value) && $value > $rules['max']) {
$value = $rules['max'];
}
// Enum validation
if (isset($rules['enum']) && is_array($rules['enum'])) {
if (!in_array($value, $rules['enum'], true)) {
error_log("OxyMade: Invalid value for field {$key}: not in allowed values");
continue;
}
}
$validated[$key] = $value;
}
return $validated;
}
/**
* Validate AJAX request data
*
* @param array $required_fields Required fields with validation rules
* @param array $data_source Data source (defaults to $_POST)
* @return bool|array True if valid, array of errors otherwise
*/
public static function validate_ajax_request($required_fields = array(), $data_source = null) {
if (null === $data_source) {
$data_source = $_POST;
}
$errors = array();
foreach ($required_fields as $field => $rules) {
if (!isset($data_source[$field])) {
$errors[] = sprintf(
\__('Missing required field: %s', 'oxymade'),
$field
);
continue;
}
$value = $data_source[$field];
// Type validation
if (isset($rules['type'])) {
switch ($rules['type']) {
case 'array':
if (!is_array($value)) {
$errors[] = sprintf(
\__('Field %s must be an array', 'oxymade'),
$field
);
}
break;
case 'string':
if (!is_string($value)) {
$errors[] = sprintf(
\__('Field %s must be a string', 'oxymade'),
$field
);
}
break;
case 'int':
if (!is_numeric($value)) {
$errors[] = sprintf(
\__('Field %s must be numeric', 'oxymade'),
$field
);
}
break;
}
}
// Length validation
if (isset($rules['max_length']) && is_string($value)) {
if (strlen($value) > $rules['max_length']) {
$errors[] = sprintf(
\__('Field %s exceeds maximum length of %d', 'oxymade'),
$field,
$rules['max_length']
);
}
}
}
return empty($errors) ? true : $errors;
}
}