PluginProbe ʕ •ᴥ•ʔ
Advanced File Manager – Ultimate File Manager for WordPress And Document Library Solution / trunk
Advanced File Manager – Ultimate File Manager for WordPress And Document Library Solution vtrunk
trunk 4.1.5 4.1.6 5.0 5.2.13 5.2.14 5.3.0 5.3.1 5.3.2 5.3.3 5.3.4 5.3.5 5.3.6 5.4.0 5.4.1 5.4.10 5.4.11 5.4.12 5.4.2 5.4.3 5.4.4 5.4.5 5.4.6 5.4.7 5.4.8
file-manager-advanced / application / class_fma_debug_validator.php
file-manager-advanced / application Last commit date
assets 3 months ago library 3 weeks ago logs 10 months ago pages 3 months ago post-smtp-notice 3 weeks ago rest-api 10 months ago svg-sanitizer 10 months ago class_fma_admin_menus.php 3 weeks ago class_fma_blocks.php 4 months ago class_fma_connector.php 3 weeks ago class_fma_debug_validator.php 8 months ago class_fma_elfinder_connector.php 3 weeks ago class_fma_lang.php 2 years ago class_fma_local_filesystem.php 3 months ago class_fma_main.php 3 weeks ago class_fma_pure_php_validator.php 8 months ago class_fma_shortcode.php 7 months ago fma-elfinder-helpers.php 3 weeks ago
class_fma_debug_validator.php
289 lines
1 <?php
2 /**
3 * FMA Debug Validator
4 *
5 * Robust PHP syntax validation using exec-with-fallback library
6 * for better compatibility across different hosting environments
7 *
8 * @package Advanced File Manager
9 * @since 1.0.0
10 */
11
12 defined( 'ABSPATH' ) || exit;
13
14 // Load Pure PHP validator (no exec functions required)
15 if ( file_exists( plugin_dir_path( __FILE__ ) . 'class_fma_pure_php_validator.php' ) ) {
16 require_once plugin_dir_path( __FILE__ ) . 'class_fma_pure_php_validator.php';
17 }
18
19 if ( ! class_exists( 'FMA_Debug_Validator' ) ) :
20
21 /**
22 * Class FMA_Debug_Validator
23 *
24 * @since 1.0.0
25 */
26 class FMA_Debug_Validator {
27
28 /**
29 * Instance of this class
30 *
31 * @since 1.0.0
32 * @var FMA_Debug_Validator
33 */
34 private static $instance = null;
35
36 /**
37 * PHP executable path
38 *
39 * @since 1.0.0
40 * @var string
41 */
42 private $php_path = 'php';
43
44 /**
45 * Constructor
46 *
47 * @since 1.0.0
48 */
49 private function __construct() {
50 }
51
52 /**
53 * Get instance
54 *
55 * @since 1.0.0
56 * @return FMA_Debug_Validator
57 */
58 public static function get_instance() {
59 if ( null === self::$instance ) {
60 self::$instance = new self();
61 }
62 return self::$instance;
63 }
64
65 /**
66 * Validate PHP syntax
67 *
68 * @since 1.0.0
69 * @param string $php_code PHP code to validate
70 * @return array Validation result with success status and errors
71 */
72 public function validate_syntax( $php_code ) {
73 // Use Pure PHP Validator (no exec functions required)
74 if ( class_exists( 'FMA_Pure_PHP_Validator' ) ) {
75 $pure_validator = FMA_Pure_PHP_Validator::get_instance();
76 return $pure_validator->validate_syntax( $php_code );
77 }
78
79 // Fallback to original method
80 $result = array(
81 'valid' => false,
82 'errors' => array(),
83 'message' => '',
84 'php_version' => '',
85 'execution_time' => 0
86 );
87
88 $start_time = microtime( true );
89
90 try {
91 // Create temporary file
92 $temp_file = $this->create_temp_file( $php_code );
93 if ( ! $temp_file ) {
94 $result['errors'][] = 'Unable to create temporary file for validation';
95 $result['message'] = 'PHP syntax errors found';
96 return $result;
97 }
98
99 // Run PHP syntax check
100 $output = array();
101 $return_code = 0;
102 $command = $this->php_path . ' -l "' . $temp_file . '" 2>&1';
103
104 // Use exec-with-fallback if available
105 if ( class_exists( 'ExecWithFallback\\ExecWithFallback' ) ) {
106 $exec_result = \ExecWithFallback\ExecWithFallback::exec( $command, $output, $return_code );
107 } else {
108 // Fallback to regular exec
109 $exec_result = exec( $command, $output, $return_code );
110 }
111
112 // Get PHP version
113 $version_output = array();
114 if ( class_exists( 'ExecWithFallback\\ExecWithFallback' ) ) {
115 \ExecWithFallback\ExecWithFallback::exec( $this->php_path . ' -v', $version_output );
116 } else {
117 exec( $this->php_path . ' -v', $version_output );
118 }
119 $result['php_version'] = ! empty( $version_output ) ? $version_output[0] : 'PHP ' . PHP_VERSION;
120
121 // Parse results
122 if ( $return_code === 0 ) {
123 $result['valid'] = true;
124 $result['message'] = 'PHP syntax is valid';
125 $result['errors'] = array();
126 } else {
127 $result['valid'] = false;
128 $result['message'] = 'PHP syntax errors found';
129 $result['errors'] = $this->parse_syntax_errors( $output );
130 }
131
132 // Clean up
133 $this->cleanup_temp_file( $temp_file );
134
135 } catch ( Exception $e ) {
136 $result['errors'][] = 'Validation failed: ' . $e->getMessage();
137 $result['message'] = 'PHP syntax errors found';
138 }
139
140 $result['execution_time'] = round( ( microtime( true ) - $start_time ) * 1000, 2 );
141
142 return $result;
143 }
144
145 /**
146 * Create temporary file with PHP code
147 *
148 * @since 1.0.0
149 * @param string $php_code PHP code
150 * @return string|false Temporary file path or false on failure
151 */
152 private function create_temp_file( $php_code ) {
153 // Ensure code has proper PHP tags
154 if ( strpos( $php_code, '<?php' ) === false && strpos( $php_code, '<?=' ) === false ) {
155 $php_code = '<?php' . "\n" . $php_code;
156 }
157
158 $temp_file = tempnam( sys_get_temp_dir(), 'fma_php_validation_' );
159 if ( $temp_file === false ) {
160 return false;
161 }
162
163 $result = file_put_contents( $temp_file, $php_code );
164 if ( $result === false ) {
165 unlink( $temp_file );
166 return false;
167 }
168
169 return $temp_file;
170 }
171
172 /**
173 * Clean up temporary file
174 *
175 * @since 1.0.0
176 * @param string $temp_file Temporary file path
177 */
178 private function cleanup_temp_file( $temp_file ) {
179 if ( file_exists( $temp_file ) ) {
180 unlink( $temp_file );
181 }
182 }
183
184 /**
185 * Parse syntax errors from PHP output
186 *
187 * @since 1.0.0
188 * @param array $output PHP command output
189 * @return array Parsed errors
190 */
191 private function parse_syntax_errors( $output ) {
192 $errors = array();
193 $output_text = implode( "\n", $output );
194
195 // Parse PHP syntax errors
196 if ( preg_match( '/Parse error:\s*(.+?)\s+in\s+(.+?)\s+on\s+line\s+(\d+)/i', $output_text, $matches ) ) {
197 $errors[] = array(
198 'type' => 'parse_error',
199 'message' => trim( $matches[1] ),
200 'file' => basename( $matches[2] ),
201 'line' => intval( $matches[3] ),
202 'severity' => 'error'
203 );
204 }
205
206 // Parse fatal errors
207 if ( preg_match( '/Fatal error:\s*(.+?)\s+in\s+(.+?)\s+on\s+line\s+(\d+)/i', $output_text, $matches ) ) {
208 $errors[] = array(
209 'type' => 'fatal_error',
210 'message' => trim( $matches[1] ),
211 'file' => basename( $matches[2] ),
212 'line' => intval( $matches[3] ),
213 'severity' => 'error'
214 );
215 }
216
217 // Parse warnings
218 if ( preg_match( '/Warning:\s*(.+?)\s+in\s+(.+?)\s+on\s+line\s+(\d+)/i', $output_text, $matches ) ) {
219 $errors[] = array(
220 'type' => 'warning',
221 'message' => trim( $matches[1] ),
222 'file' => basename( $matches[2] ),
223 'line' => intval( $matches[3] ),
224 'severity' => 'warning'
225 );
226 }
227
228 // If no specific errors found, add generic error
229 if ( empty( $errors ) && ! empty( $output_text ) ) {
230 $errors[] = array(
231 'type' => 'unknown',
232 'message' => trim( $output_text ),
233 'file' => 'unknown',
234 'line' => 0,
235 'severity' => 'error'
236 );
237 }
238
239 return $errors;
240 }
241
242 /**
243 * Get PHP configuration info
244 *
245 * @since 1.0.0
246 * @return array PHP configuration
247 */
248 public function get_php_info() {
249 $info = array(
250 'php_path' => $this->php_path,
251 'php_version' => PHP_VERSION,
252 'php_binary' => PHP_BINARY,
253 'exec_functions' => array(),
254 'disabled_functions' => array(),
255 'exec_with_fallback_available' => class_exists( 'ExecWithFallback\\ExecWithFallback' )
256 );
257
258 // Check available exec functions
259 $exec_functions = array( 'exec', 'system', 'shell_exec', 'passthru', 'proc_open', 'popen' );
260 foreach ( $exec_functions as $func ) {
261 $info['exec_functions'][ $func ] = function_exists( $func ) && ! in_array( $func, explode( ',', ini_get( 'disable_functions' ) ) );
262 }
263
264 // Get disabled functions
265 $disabled = ini_get( 'disable_functions' );
266 $info['disabled_functions'] = ! empty( $disabled ) ? explode( ',', $disabled ) : array();
267
268 return $info;
269 }
270
271 /**
272 * Test if validation is available
273 *
274 * @since 1.0.0
275 * @return bool
276 */
277 public function is_available() {
278 try {
279 $test_code = '<?php echo "test";';
280 $result = $this->validate_syntax( $test_code );
281 return $result['success'];
282 } catch ( Exception $e ) {
283 return false;
284 }
285 }
286 }
287
288 endif;
289