Edit File by line
/home/zeestwma/richards.../wp-conte.../plugins/elemento.../modules/interact...
File: validation.php
<?php
[0] Fix | Delete
[1] Fix | Delete
namespace Elementor\Modules\Interactions;
[2] Fix | Delete
[3] Fix | Delete
if ( ! defined( 'ABSPATH' ) ) {
[4] Fix | Delete
exit; // Exit if accessed directly.
[5] Fix | Delete
}
[6] Fix | Delete
[7] Fix | Delete
class Validation {
[8] Fix | Delete
private $elements_to_interactions_counter = [];
[9] Fix | Delete
private $max_number_of_interactions = 5;
[10] Fix | Delete
[11] Fix | Delete
private const VALID_TRIGGERS = [ 'load', 'scrollIn', 'scrollOut', 'scrollOn' ];
[12] Fix | Delete
private const VALID_EFFECTS = [ 'fade', 'slide', 'scale' ];
[13] Fix | Delete
private const VALID_TYPES = [ 'in', 'out' ];
[14] Fix | Delete
private const VALID_DIRECTIONS = [ '', 'left', 'right', 'top', 'bottom' ];
[15] Fix | Delete
[16] Fix | Delete
public function sanitize( $document ) {
[17] Fix | Delete
return $this->sanitize_document_data( $document );
[18] Fix | Delete
}
[19] Fix | Delete
[20] Fix | Delete
public function validate() {
[21] Fix | Delete
foreach ( $this->elements_to_interactions_counter as $element_id => $number_of_interactions ) {
[22] Fix | Delete
if ( $number_of_interactions > $this->max_number_of_interactions ) {
[23] Fix | Delete
throw new \Exception(
[24] Fix | Delete
sprintf(
[25] Fix | Delete
// translators: %1$s: element ID, %2$d: maximum number of interactions allowed.
[26] Fix | Delete
esc_html__( 'Element %1$s has more than %2$d interactions', 'elementor' ),
[27] Fix | Delete
esc_html( $element_id ),
[28] Fix | Delete
esc_html( $this->max_number_of_interactions )
[29] Fix | Delete
)
[30] Fix | Delete
);
[31] Fix | Delete
}
[32] Fix | Delete
}
[33] Fix | Delete
[34] Fix | Delete
return true;
[35] Fix | Delete
}
[36] Fix | Delete
[37] Fix | Delete
private function sanitize_document_data( $data ) {
[38] Fix | Delete
if ( isset( $data['elements'] ) && is_array( $data['elements'] ) ) {
[39] Fix | Delete
$data['elements'] = $this->sanitize_elements_interactions( $data['elements'] );
[40] Fix | Delete
}
[41] Fix | Delete
[42] Fix | Delete
return $data;
[43] Fix | Delete
}
[44] Fix | Delete
[45] Fix | Delete
private function sanitize_elements_interactions( $elements ) {
[46] Fix | Delete
if ( ! is_array( $elements ) ) {
[47] Fix | Delete
return $elements;
[48] Fix | Delete
}
[49] Fix | Delete
[50] Fix | Delete
foreach ( $elements as &$element ) {
[51] Fix | Delete
if ( isset( $element['interactions'] ) ) {
[52] Fix | Delete
$element['interactions'] = $this->sanitize_interactions( $element['interactions'], $element['id'] );
[53] Fix | Delete
}
[54] Fix | Delete
[55] Fix | Delete
if ( isset( $element['elements'] ) && is_array( $element['elements'] ) ) {
[56] Fix | Delete
$element['elements'] = $this->sanitize_elements_interactions( $element['elements'] );
[57] Fix | Delete
}
[58] Fix | Delete
}
[59] Fix | Delete
[60] Fix | Delete
return $elements;
[61] Fix | Delete
}
[62] Fix | Delete
[63] Fix | Delete
private function decode_interactions( $interactions ) {
[64] Fix | Delete
if ( is_array( $interactions ) ) {
[65] Fix | Delete
return isset( $interactions['items'] ) ? $interactions['items'] : [];
[66] Fix | Delete
}
[67] Fix | Delete
[68] Fix | Delete
if ( is_string( $interactions ) ) {
[69] Fix | Delete
$decoded = json_decode( $interactions, true );
[70] Fix | Delete
if ( json_last_error() === JSON_ERROR_NONE && is_array( $decoded ) ) {
[71] Fix | Delete
return isset( $decoded['items'] ) ? $decoded['items'] : [];
[72] Fix | Delete
}
[73] Fix | Delete
}
[74] Fix | Delete
[75] Fix | Delete
return [];
[76] Fix | Delete
}
[77] Fix | Delete
[78] Fix | Delete
private function increment_interactions_counter_for( $element_id ) {
[79] Fix | Delete
if ( ! array_key_exists( $element_id, $this->elements_to_interactions_counter ) ) {
[80] Fix | Delete
$this->elements_to_interactions_counter[ $element_id ] = 0;
[81] Fix | Delete
}
[82] Fix | Delete
[83] Fix | Delete
++$this->elements_to_interactions_counter[ $element_id ];
[84] Fix | Delete
[85] Fix | Delete
return $this;
[86] Fix | Delete
}
[87] Fix | Delete
[88] Fix | Delete
private function sanitize_interactions( $interactions, $element_id ) {
[89] Fix | Delete
$sanitized = [
[90] Fix | Delete
'items' => [],
[91] Fix | Delete
'version' => 1,
[92] Fix | Delete
];
[93] Fix | Delete
[94] Fix | Delete
$list_of_interactions = $this->decode_interactions( $interactions );
[95] Fix | Delete
[96] Fix | Delete
foreach ( $list_of_interactions as $interaction ) {
[97] Fix | Delete
if ( $this->is_valid_interaction_item( $interaction ) ) {
[98] Fix | Delete
$sanitized['items'][] = $interaction;
[99] Fix | Delete
$this->increment_interactions_counter_for( $element_id );
[100] Fix | Delete
}
[101] Fix | Delete
}
[102] Fix | Delete
[103] Fix | Delete
if ( empty( $sanitized['items'] ) ) {
[104] Fix | Delete
return [];
[105] Fix | Delete
}
[106] Fix | Delete
[107] Fix | Delete
return wp_json_encode( $sanitized );
[108] Fix | Delete
}
[109] Fix | Delete
[110] Fix | Delete
private function is_valid_interaction_item( $item ) {
[111] Fix | Delete
if ( ! is_array( $item ) ) {
[112] Fix | Delete
return false;
[113] Fix | Delete
}
[114] Fix | Delete
[115] Fix | Delete
// Validate PropType format: { $$type: 'interaction-item', value: { ... } }
[116] Fix | Delete
if ( ! isset( $item['$$type'] ) || 'interaction-item' !== $item['$$type'] ) {
[117] Fix | Delete
return false;
[118] Fix | Delete
}
[119] Fix | Delete
[120] Fix | Delete
if ( ! isset( $item['value'] ) || ! is_array( $item['value'] ) ) {
[121] Fix | Delete
return false;
[122] Fix | Delete
}
[123] Fix | Delete
[124] Fix | Delete
$value = $item['value'];
[125] Fix | Delete
[126] Fix | Delete
// Validate required fields exist
[127] Fix | Delete
if ( isset( $value['interaction_id'] ) && ! $this->is_valid_string_prop( $value, 'interaction_id' ) ) {
[128] Fix | Delete
return false;
[129] Fix | Delete
}
[130] Fix | Delete
[131] Fix | Delete
if ( ! $this->is_valid_string_prop( $value, 'trigger', self::VALID_TRIGGERS ) ) {
[132] Fix | Delete
return false;
[133] Fix | Delete
}
[134] Fix | Delete
[135] Fix | Delete
if ( ! $this->is_valid_animation_prop( $value ) ) {
[136] Fix | Delete
return false;
[137] Fix | Delete
}
[138] Fix | Delete
[139] Fix | Delete
return true;
[140] Fix | Delete
}
[141] Fix | Delete
[142] Fix | Delete
private function is_valid_string_prop( $data, $key, $allowed_values = null ) {
[143] Fix | Delete
if ( ! isset( $data[ $key ] ) || ! is_array( $data[ $key ] ) ) {
[144] Fix | Delete
return false;
[145] Fix | Delete
}
[146] Fix | Delete
[147] Fix | Delete
$prop = $data[ $key ];
[148] Fix | Delete
[149] Fix | Delete
if ( ! isset( $prop['$$type'] ) || 'string' !== $prop['$$type'] ) {
[150] Fix | Delete
return false;
[151] Fix | Delete
}
[152] Fix | Delete
[153] Fix | Delete
if ( ! isset( $prop['value'] ) || ! is_string( $prop['value'] ) ) {
[154] Fix | Delete
return false;
[155] Fix | Delete
}
[156] Fix | Delete
[157] Fix | Delete
if ( null !== $allowed_values && ! in_array( $prop['value'], $allowed_values, true ) ) {
[158] Fix | Delete
return false;
[159] Fix | Delete
}
[160] Fix | Delete
[161] Fix | Delete
return true;
[162] Fix | Delete
}
[163] Fix | Delete
[164] Fix | Delete
private function is_valid_boolean_prop( $data, $key ) {
[165] Fix | Delete
if ( ! isset( $data[ $key ] ) || ! is_array( $data[ $key ] ) ) {
[166] Fix | Delete
return false;
[167] Fix | Delete
}
[168] Fix | Delete
[169] Fix | Delete
$prop = $data[ $key ];
[170] Fix | Delete
[171] Fix | Delete
if ( ! isset( $prop['$$type'] ) || 'boolean' !== $prop['$$type'] ) {
[172] Fix | Delete
return false;
[173] Fix | Delete
}
[174] Fix | Delete
[175] Fix | Delete
if ( ! isset( $prop['value'] ) || ! is_bool( $prop['value'] ) ) {
[176] Fix | Delete
return false;
[177] Fix | Delete
}
[178] Fix | Delete
[179] Fix | Delete
return true;
[180] Fix | Delete
}
[181] Fix | Delete
[182] Fix | Delete
private function is_valid_number_prop( $data, $key ) {
[183] Fix | Delete
if ( ! isset( $data[ $key ] ) || ! is_array( $data[ $key ] ) ) {
[184] Fix | Delete
return false;
[185] Fix | Delete
}
[186] Fix | Delete
[187] Fix | Delete
$prop = $data[ $key ];
[188] Fix | Delete
[189] Fix | Delete
if ( ! isset( $prop['$$type'] ) || 'number' !== $prop['$$type'] ) {
[190] Fix | Delete
return false;
[191] Fix | Delete
}
[192] Fix | Delete
[193] Fix | Delete
if ( ! isset( $prop['value'] ) || ! is_numeric( $prop['value'] ) ) {
[194] Fix | Delete
return false;
[195] Fix | Delete
}
[196] Fix | Delete
[197] Fix | Delete
return true;
[198] Fix | Delete
}
[199] Fix | Delete
[200] Fix | Delete
private function is_valid_number_prop_in_range( $data, $key, $min = null, $max = null ) {
[201] Fix | Delete
if ( ! $this->is_valid_number_prop( $data, $key ) ) {
[202] Fix | Delete
return false;
[203] Fix | Delete
}
[204] Fix | Delete
[205] Fix | Delete
$value = (float) $data[ $key ]['value'];
[206] Fix | Delete
[207] Fix | Delete
if ( null !== $min && $value < $min ) {
[208] Fix | Delete
return false;
[209] Fix | Delete
}
[210] Fix | Delete
[211] Fix | Delete
if ( null !== $max && $value > $max ) {
[212] Fix | Delete
return false;
[213] Fix | Delete
}
[214] Fix | Delete
[215] Fix | Delete
return true;
[216] Fix | Delete
}
[217] Fix | Delete
[218] Fix | Delete
private function is_valid_config_prop( $data ) {
[219] Fix | Delete
if ( ! isset( $data['config'] ) || ! is_array( $data['config'] ) ) {
[220] Fix | Delete
return false;
[221] Fix | Delete
}
[222] Fix | Delete
[223] Fix | Delete
$config = $data['config'];
[224] Fix | Delete
[225] Fix | Delete
if ( ! isset( $config['$$type'] ) || 'config' !== $config['$$type'] ) {
[226] Fix | Delete
return false;
[227] Fix | Delete
}
[228] Fix | Delete
[229] Fix | Delete
if ( ! isset( $config['value'] ) || ! is_array( $config['value'] ) ) {
[230] Fix | Delete
return false;
[231] Fix | Delete
}
[232] Fix | Delete
[233] Fix | Delete
$config_value = $config['value'];
[234] Fix | Delete
[235] Fix | Delete
if ( isset( $config_value['replay'] ) && ! $this->is_valid_boolean_prop( $config_value, 'replay' ) ) {
[236] Fix | Delete
return false;
[237] Fix | Delete
}
[238] Fix | Delete
[239] Fix | Delete
if ( isset( $config_value['relativeTo'] ) && ! $this->is_valid_string_prop( $config_value, 'relativeTo' ) ) {
[240] Fix | Delete
return false;
[241] Fix | Delete
}
[242] Fix | Delete
[243] Fix | Delete
if ( isset( $config_value['offsetTop'] ) && ! $this->is_valid_number_prop_in_range( $config_value, 'offsetTop', 0, 100 ) ) {
[244] Fix | Delete
return false;
[245] Fix | Delete
}
[246] Fix | Delete
[247] Fix | Delete
if ( isset( $config_value['offsetBottom'] ) && ! $this->is_valid_number_prop_in_range( $config_value, 'offsetBottom', 0, 100 ) ) {
[248] Fix | Delete
return false;
[249] Fix | Delete
}
[250] Fix | Delete
[251] Fix | Delete
return true;
[252] Fix | Delete
}
[253] Fix | Delete
[254] Fix | Delete
private function is_valid_animation_prop( $data ) {
[255] Fix | Delete
if ( ! isset( $data['animation'] ) || ! is_array( $data['animation'] ) ) {
[256] Fix | Delete
return false;
[257] Fix | Delete
}
[258] Fix | Delete
[259] Fix | Delete
$animation = $data['animation'];
[260] Fix | Delete
[261] Fix | Delete
if ( ! isset( $animation['$$type'] ) || 'animation-preset-props' !== $animation['$$type'] ) {
[262] Fix | Delete
return false;
[263] Fix | Delete
}
[264] Fix | Delete
[265] Fix | Delete
if ( ! isset( $animation['value'] ) || ! is_array( $animation['value'] ) ) {
[266] Fix | Delete
return false;
[267] Fix | Delete
}
[268] Fix | Delete
[269] Fix | Delete
$animation_value = $animation['value'];
[270] Fix | Delete
[271] Fix | Delete
// Validate effect
[272] Fix | Delete
if ( ! $this->is_valid_string_prop( $animation_value, 'effect', self::VALID_EFFECTS ) ) {
[273] Fix | Delete
return false;
[274] Fix | Delete
}
[275] Fix | Delete
[276] Fix | Delete
// Validate type
[277] Fix | Delete
if ( ! $this->is_valid_string_prop( $animation_value, 'type', self::VALID_TYPES ) ) {
[278] Fix | Delete
return false;
[279] Fix | Delete
}
[280] Fix | Delete
[281] Fix | Delete
// Validate direction (can be empty string)
[282] Fix | Delete
if ( ! $this->is_valid_string_prop( $animation_value, 'direction', self::VALID_DIRECTIONS ) ) {
[283] Fix | Delete
return false;
[284] Fix | Delete
}
[285] Fix | Delete
[286] Fix | Delete
// Validate timing_config
[287] Fix | Delete
if ( ! $this->is_valid_timing_config( $animation_value ) ) {
[288] Fix | Delete
return false;
[289] Fix | Delete
}
[290] Fix | Delete
[291] Fix | Delete
if ( isset( $animation_value['config'] ) && ! $this->is_valid_config_prop( $animation_value ) ) {
[292] Fix | Delete
return false;
[293] Fix | Delete
}
[294] Fix | Delete
[295] Fix | Delete
return true;
[296] Fix | Delete
}
[297] Fix | Delete
[298] Fix | Delete
private function is_valid_timing_config( $data ) {
[299] Fix | Delete
if ( ! isset( $data['timing_config'] ) || ! is_array( $data['timing_config'] ) ) {
[300] Fix | Delete
return false;
[301] Fix | Delete
}
[302] Fix | Delete
[303] Fix | Delete
$timing = $data['timing_config'];
[304] Fix | Delete
[305] Fix | Delete
if ( ! isset( $timing['$$type'] ) || 'timing-config' !== $timing['$$type'] ) {
[306] Fix | Delete
return false;
[307] Fix | Delete
}
[308] Fix | Delete
[309] Fix | Delete
if ( ! isset( $timing['value'] ) || ! is_array( $timing['value'] ) ) {
[310] Fix | Delete
return false;
[311] Fix | Delete
}
[312] Fix | Delete
[313] Fix | Delete
$timing_value = $timing['value'];
[314] Fix | Delete
[315] Fix | Delete
// Validate duration
[316] Fix | Delete
if ( ! $this->is_valid_number_prop( $timing_value, 'duration' ) ) {
[317] Fix | Delete
return false;
[318] Fix | Delete
}
[319] Fix | Delete
[320] Fix | Delete
// Validate delay
[321] Fix | Delete
if ( ! $this->is_valid_number_prop( $timing_value, 'delay' ) ) {
[322] Fix | Delete
return false;
[323] Fix | Delete
}
[324] Fix | Delete
[325] Fix | Delete
return true;
[326] Fix | Delete
}
[327] Fix | Delete
}
[328] Fix | Delete
[329] Fix | Delete
It is recommended that you Edit text format, this type of Fix handles quite a lot in one request
Function