Edit File by line
/home/zeestwma/ajeebong.../wp-conte.../plugins/code-sni.../php
File: class-validator.php
<?php
[0] Fix | Delete
[1] Fix | Delete
namespace Code_Snippets;
[2] Fix | Delete
[3] Fix | Delete
/**
[4] Fix | Delete
* Validates code prior to execution.
[5] Fix | Delete
*
[6] Fix | Delete
* @package Code_Snippets
[7] Fix | Delete
*/
[8] Fix | Delete
class Validator {
[9] Fix | Delete
[10] Fix | Delete
/**
[11] Fix | Delete
* Code to validate.
[12] Fix | Delete
*
[13] Fix | Delete
* @var string
[14] Fix | Delete
*/
[15] Fix | Delete
private string $code;
[16] Fix | Delete
[17] Fix | Delete
/**
[18] Fix | Delete
* List of tokens.
[19] Fix | Delete
*
[20] Fix | Delete
* @var array<string>
[21] Fix | Delete
*/
[22] Fix | Delete
private array $tokens;
[23] Fix | Delete
[24] Fix | Delete
/**
[25] Fix | Delete
* The index of the token currently being examined.
[26] Fix | Delete
*
[27] Fix | Delete
* @var integer
[28] Fix | Delete
*/
[29] Fix | Delete
private int $current;
[30] Fix | Delete
[31] Fix | Delete
/**
[32] Fix | Delete
* The total number of tokens.
[33] Fix | Delete
*
[34] Fix | Delete
* @var integer
[35] Fix | Delete
*/
[36] Fix | Delete
private int $length;
[37] Fix | Delete
[38] Fix | Delete
/**
[39] Fix | Delete
* Array to keep track of the various function, class and interface identifiers which have been defined.
[40] Fix | Delete
*
[41] Fix | Delete
* @var array<string, string[]>
[42] Fix | Delete
*/
[43] Fix | Delete
private array $defined_identifiers = [];
[44] Fix | Delete
[45] Fix | Delete
/**
[46] Fix | Delete
* Exclude certain tokens from being checked.
[47] Fix | Delete
*
[48] Fix | Delete
* @var array<string, string[]>
[49] Fix | Delete
*/
[50] Fix | Delete
private array $exceptions = [];
[51] Fix | Delete
[52] Fix | Delete
/**
[53] Fix | Delete
* Class constructor.
[54] Fix | Delete
*
[55] Fix | Delete
* @param string $code Snippet code for parsing.
[56] Fix | Delete
*/
[57] Fix | Delete
public function __construct( string $code ) {
[58] Fix | Delete
$this->code = $code;
[59] Fix | Delete
$this->tokens = token_get_all( "<?php\n" . $this->code );
[60] Fix | Delete
$this->length = count( $this->tokens );
[61] Fix | Delete
$this->current = 0;
[62] Fix | Delete
}
[63] Fix | Delete
[64] Fix | Delete
/**
[65] Fix | Delete
* Determine whether the parser has reached the end of the list of tokens.
[66] Fix | Delete
*
[67] Fix | Delete
* @return bool
[68] Fix | Delete
*/
[69] Fix | Delete
private function end(): bool {
[70] Fix | Delete
return $this->current === $this->length;
[71] Fix | Delete
}
[72] Fix | Delete
[73] Fix | Delete
/**
[74] Fix | Delete
* Retrieve the next token without moving the pointer
[75] Fix | Delete
*
[76] Fix | Delete
* @return string|array<string|int>|null The current token if the list has not been expended, null otherwise.
[77] Fix | Delete
*/
[78] Fix | Delete
private function peek() {
[79] Fix | Delete
return $this->end() ? null : $this->tokens[ $this->current ];
[80] Fix | Delete
}
[81] Fix | Delete
[82] Fix | Delete
/**
[83] Fix | Delete
* Move the pointer to the next token, if there is one.
[84] Fix | Delete
*
[85] Fix | Delete
* If the first argument is provided, only move the pointer if the tokens match.
[86] Fix | Delete
*/
[87] Fix | Delete
private function next() {
[88] Fix | Delete
if ( ! $this->end() ) {
[89] Fix | Delete
++$this->current;
[90] Fix | Delete
}
[91] Fix | Delete
}
[92] Fix | Delete
[93] Fix | Delete
/**
[94] Fix | Delete
* Check whether a particular identifier has been used previously.
[95] Fix | Delete
*
[96] Fix | Delete
* @param string $type Which type of identifier this is. Supports T_FUNCTION, T_CLASS and T_INTERFACE.
[97] Fix | Delete
* @param string $identifier The name of the identifier itself.
[98] Fix | Delete
*
[99] Fix | Delete
* @return bool true if the identifier is not unique.
[100] Fix | Delete
*/
[101] Fix | Delete
private function check_duplicate_identifier( string $type, string $identifier ): bool {
[102] Fix | Delete
[103] Fix | Delete
if ( ! isset( $this->defined_identifiers[ $type ] ) ) {
[104] Fix | Delete
switch ( $type ) {
[105] Fix | Delete
case T_FUNCTION:
[106] Fix | Delete
$defined_functions = get_defined_functions();
[107] Fix | Delete
$this->defined_identifiers[ T_FUNCTION ] = array_merge( $defined_functions['internal'], $defined_functions['user'] );
[108] Fix | Delete
break;
[109] Fix | Delete
[110] Fix | Delete
case T_CLASS:
[111] Fix | Delete
$this->defined_identifiers[ T_CLASS ] = get_declared_classes();
[112] Fix | Delete
break;
[113] Fix | Delete
[114] Fix | Delete
case T_INTERFACE:
[115] Fix | Delete
$this->defined_identifiers[ T_INTERFACE ] = get_declared_interfaces();
[116] Fix | Delete
break;
[117] Fix | Delete
[118] Fix | Delete
default:
[119] Fix | Delete
return false;
[120] Fix | Delete
}
[121] Fix | Delete
}
[122] Fix | Delete
[123] Fix | Delete
$duplicate = in_array( $identifier, $this->defined_identifiers[ $type ], true );
[124] Fix | Delete
array_unshift( $this->defined_identifiers[ $type ], $identifier );
[125] Fix | Delete
[126] Fix | Delete
return $duplicate && ! ( isset( $this->exceptions[ $type ] ) && in_array( $identifier, $this->exceptions[ $type ], true ) );
[127] Fix | Delete
}
[128] Fix | Delete
[129] Fix | Delete
/**
[130] Fix | Delete
* Validate the given PHP code and return the result.
[131] Fix | Delete
*
[132] Fix | Delete
* @return array<string, mixed>|false Array containing message if an error was encountered, false if validation was successful.
[133] Fix | Delete
*/
[134] Fix | Delete
public function validate() {
[135] Fix | Delete
[136] Fix | Delete
while ( ! $this->end() ) {
[137] Fix | Delete
$token = $this->peek();
[138] Fix | Delete
$this->next();
[139] Fix | Delete
[140] Fix | Delete
if ( ! is_array( $token ) ) {
[141] Fix | Delete
continue;
[142] Fix | Delete
}
[143] Fix | Delete
[144] Fix | Delete
// If this is a function or class exists check, then allow this function or class to be defined.
[145] Fix | Delete
if ( T_STRING === $token[0] && ( 'function_exists' === $token[1] || 'class_exists' === $token[1] ) ) {
[146] Fix | Delete
$type = 'function_exists' === $token[1] ? T_FUNCTION : T_CLASS;
[147] Fix | Delete
[148] Fix | Delete
// Eat tokens until we find the function or class name.
[149] Fix | Delete
while ( ! $this->end() && T_CONSTANT_ENCAPSED_STRING !== $token[0] ) {
[150] Fix | Delete
$token = $this->peek();
[151] Fix | Delete
$this->next();
[152] Fix | Delete
}
[153] Fix | Delete
[154] Fix | Delete
// Add the identifier to the list of exceptions.
[155] Fix | Delete
$this->exceptions[ $type ] = $this->exceptions[ $type ] ?? [];
[156] Fix | Delete
$this->exceptions[ $type ][] = trim( $token[1], '\'"' );
[157] Fix | Delete
continue;
[158] Fix | Delete
}
[159] Fix | Delete
[160] Fix | Delete
// If we have a double colon, followed by a class, then consume it before the next section.
[161] Fix | Delete
if ( T_DOUBLE_COLON === $token[0] ) {
[162] Fix | Delete
$token = $this->peek();
[163] Fix | Delete
$this->next();
[164] Fix | Delete
[165] Fix | Delete
if ( T_CLASS === $token[0] ) {
[166] Fix | Delete
$this->next();
[167] Fix | Delete
$token = $this->peek();
[168] Fix | Delete
}
[169] Fix | Delete
}
[170] Fix | Delete
[171] Fix | Delete
// Only look for class and function declaration tokens.
[172] Fix | Delete
if ( T_CLASS !== $token[0] && T_FUNCTION !== $token[0] ) {
[173] Fix | Delete
continue;
[174] Fix | Delete
}
[175] Fix | Delete
[176] Fix | Delete
/**
[177] Fix | Delete
* Ensure the type of $token is inferred correctly.
[178] Fix | Delete
*
[179] Fix | Delete
* @var string|array<string|int> $token
[180] Fix | Delete
*/
[181] Fix | Delete
$structure_type = $token[0];
[182] Fix | Delete
[183] Fix | Delete
// Continue eating tokens until we find the name of the class or function.
[184] Fix | Delete
while ( ! $this->end() && T_STRING !== $token[0] &&
[185] Fix | Delete
( T_FUNCTION !== $structure_type || '(' !== $token ) && ( T_CLASS !== $structure_type || '{' !== $token ) ) {
[186] Fix | Delete
$token = $this->peek();
[187] Fix | Delete
$this->next();
[188] Fix | Delete
}
[189] Fix | Delete
[190] Fix | Delete
// If we've eaten all the tokens without discovering a name, then there must be a syntax error, so return appropriately.
[191] Fix | Delete
if ( $this->end() ) {
[192] Fix | Delete
return array(
[193] Fix | Delete
'message' => __( 'Parse error: syntax error, unexpected end of snippet.', 'code-snippets' ),
[194] Fix | Delete
'line' => $token[2],
[195] Fix | Delete
);
[196] Fix | Delete
}
[197] Fix | Delete
[198] Fix | Delete
// If the function or class is anonymous, with no name, then no need to check.
[199] Fix | Delete
if ( ! ( T_FUNCTION === $structure_type && '(' === $token ) && ! ( T_CLASS === $structure_type && '{' === $token ) ) {
[200] Fix | Delete
[201] Fix | Delete
// Check whether the name has already been defined.
[202] Fix | Delete
if ( $this->check_duplicate_identifier( $structure_type, $token[1] ) ) {
[203] Fix | Delete
switch ( $structure_type ) {
[204] Fix | Delete
case T_FUNCTION:
[205] Fix | Delete
/* translators: %s: PHP function name */
[206] Fix | Delete
$message = __( 'Cannot redeclare function %s.', 'code-snippets' );
[207] Fix | Delete
break;
[208] Fix | Delete
case T_CLASS:
[209] Fix | Delete
/* translators: %s: PHP class name */
[210] Fix | Delete
$message = __( 'Cannot redeclare class %s.', 'code-snippets' );
[211] Fix | Delete
break;
[212] Fix | Delete
case T_INTERFACE:
[213] Fix | Delete
/* translators: %s: PHP interface name */
[214] Fix | Delete
$message = __( 'Cannot redeclare interface %s.', 'code-snippets' );
[215] Fix | Delete
break;
[216] Fix | Delete
default:
[217] Fix | Delete
/* translators: %s: PHP identifier name*/
[218] Fix | Delete
$message = __( 'Cannot redeclare %s.', 'code-snippets' );
[219] Fix | Delete
}
[220] Fix | Delete
[221] Fix | Delete
return array(
[222] Fix | Delete
'message' => sprintf( $message, $token[1] ),
[223] Fix | Delete
'line' => $token[2],
[224] Fix | Delete
);
[225] Fix | Delete
}
[226] Fix | Delete
}
[227] Fix | Delete
[228] Fix | Delete
// If we have entered into a class, eat tokens until we find the closing brace.
[229] Fix | Delete
if ( T_CLASS !== $structure_type ) {
[230] Fix | Delete
continue;
[231] Fix | Delete
}
[232] Fix | Delete
[233] Fix | Delete
// Find the opening brace for the class.
[234] Fix | Delete
while ( ! $this->end() && '{' !== $token ) {
[235] Fix | Delete
$token = $this->peek();
[236] Fix | Delete
$this->next();
[237] Fix | Delete
}
[238] Fix | Delete
[239] Fix | Delete
// Continue traversing the class tokens until we have found the class closing brace.
[240] Fix | Delete
$depth = 1;
[241] Fix | Delete
while ( ! $this->end() && $depth > 0 ) {
[242] Fix | Delete
$token = $this->peek();
[243] Fix | Delete
[244] Fix | Delete
if ( '{' === $token ) {
[245] Fix | Delete
++$depth;
[246] Fix | Delete
} elseif ( '}' === $token ) {
[247] Fix | Delete
--$depth;
[248] Fix | Delete
}
[249] Fix | Delete
[250] Fix | Delete
$this->next();
[251] Fix | Delete
}
[252] Fix | Delete
[253] Fix | Delete
// If we did not make it out of the class, then there's a problem.
[254] Fix | Delete
if ( $depth > 0 ) {
[255] Fix | Delete
return array(
[256] Fix | Delete
'message' => __( 'Parse error: syntax error, unexpected end of snippet.', 'code-snippets' ),
[257] Fix | Delete
'line' => $token[2],
[258] Fix | Delete
);
[259] Fix | Delete
}
[260] Fix | Delete
}
[261] Fix | Delete
[262] Fix | Delete
return false;
[263] Fix | Delete
}
[264] Fix | Delete
}
[265] Fix | Delete
[266] Fix | Delete
It is recommended that you Edit text format, this type of Fix handles quite a lot in one request
Function