PluginProbe
Woody Code Snippets – Insert PHP, CSS, JS, and Header/Footer Scripts / 2.7.8
Woody Code Snippets – Insert PHP, CSS, JS, and Header/Footer Scripts v2.7.8
2.7.9 2.7.8 2.7.7 2.7.6 2.7.5 2.7.4 trunk 1.3 2.0.4 2.0.6 2.1.91 2.2.4 2.2.7 2.2.9 2.3.1 2.3.10 2.4.10 2.4.2 2.4.4 2.4.5 2.4.6 2.4.7 2.4.8 2.4.9 2.6.0 All 30 releases
← All changes | includes/class.code-validator.php +103 -0 2.7.7 → 2.7.8 View file →
@@ -15,8 +15,111 @@
15 15 */
16 16 class WINP_Code_Validator {
17 17
18 18 /**
19 + * Validate executable snippet code by evaluating it once.
20 + *
21 + * Runs the redeclaration preflight and then evaluates the code with output
22 + * discarded, reporting syntax errors, warnings and uncaught errors. The code
23 + * is executed in the current request, exactly as the snippet editor does.
24 + *
25 + * @param string $snippet_code Unslashed snippet code.
26 + * @param string $snippet_type Snippet type.
27 + * @return array{valid:bool,message:string} Validation result.
28 + */
29 + public static function validate_code( $snippet_code, $snippet_type ) {
30 + if ( empty( $snippet_code ) ) {
31 + return [
32 + 'valid' => true,
33 + 'message' => '',
34 + ];
35 + }
36 +
37 + $redeclaration = self::find_function_redeclaration( $snippet_code, $snippet_type );
38 + if ( null !== $redeclaration ) {
39 + return [
40 + 'valid' => false,
41 + // translators: %1$d is the line number, %2$s is the fully qualified function name.
42 + 'message' => sprintf( __( 'Line %1$d: Cannot redeclare function %2$s(). Rename the function or guard its declaration with function_exists().', 'insert-php' ), $redeclaration['line'], $redeclaration['name'] ),
43 + ];
44 + }
45 +
46 + $validation_errors = [];
47 +
48 + // Set custom error handler to catch warnings and notices.
49 + set_error_handler( // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_set_error_handler
50 + function ( $errno, $errstr, $errfile, $errline ) use ( &$validation_errors ) {
51 + // Extract line number from eval'd code if present.
52 + if ( strpos( $errfile, "eval()'d code" ) !== false ) {
53 + // translators: %1$d is the line number, %2$s is the error message.
54 + $validation_errors[] = sprintf( __( 'Line %1$d: %2$s', 'insert-php' ), $errline, $errstr );
55 + } else {
56 + $validation_errors[] = $errstr;
57 + }
58 + return true; // Don't execute PHP internal error handler.
59 + }
60 + );
61 +
62 + ob_start();
63 +
64 + try {
65 + $result = WINP_SNIPPET_TYPE_UNIVERSAL === $snippet_type
66 + ? eval( '?> ' . $snippet_code . ' <?php ' )
67 + : eval( $snippet_code );
68 + } catch ( ParseError $e ) {
69 + ob_end_clean();
70 + restore_error_handler();
71 +
72 + return [
73 + 'valid' => false,
74 + // translators: %1$d is the line number, %2$s is the error message.
75 + 'message' => sprintf( __( 'Syntax error on line %1$d: %2$s', 'insert-php' ), $e->getLine(), $e->getMessage() ),
76 + ];
77 + } catch ( Throwable $e ) {
78 + ob_end_clean();
79 + restore_error_handler();
80 +
81 + // For fatal errors in eval'd code, report the actual line number.
82 + if ( strpos( $e->getFile(), "eval()'d code" ) !== false ) {
83 + return [
84 + 'valid' => false,
85 + // translators: %1$d is the line number, %2$s is the error message.
86 + 'message' => sprintf( __( 'Error on line %1$d: %2$s', 'insert-php' ), $e->getLine(), $e->getMessage() ),
87 + ];
88 + }
89 +
90 + return [
91 + 'valid' => false,
92 + // translators: %s is the error message.
93 + 'message' => sprintf( __( 'Error: %s', 'insert-php' ), $e->getMessage() ),
94 + ];
95 + }
96 +
97 + // Discard any output (echo/print statements are normal for snippets).
98 + ob_end_clean();
99 + restore_error_handler();
100 +
101 + if ( ! empty( $validation_errors ) ) {
102 + return [
103 + 'valid' => false,
104 + 'message' => implode( '<br>', $validation_errors ),
105 + ];
106 + }
107 +
108 + if ( false === $result ) {
109 + return [
110 + 'valid' => false,
111 + 'message' => __( 'The code contains syntax errors. Please review and fix them before saving.', 'insert-php' ),
112 + ];
113 + }
114 +
115 + return [
116 + 'valid' => true,
117 + 'message' => '',
118 + ];
119 + }
120 +
121 + /**
19 122 * Find a top-level function declaration that would be redeclared by eval().
20 123 *
21 124 * PHP terminates the request when eval() declares an already-loaded function,
22 125 * so this conflict has to be detected before evaluating the snippet.