PluginProbe ʕ •ᴥ•ʔ
Backup Migration / 1.3.0
Backup Migration v1.3.0
2.1.6 2.1.5.2 trunk 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.6.1 1.4.7 1.4.8 1.4.9 1.4.9.1 2.0.0 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.5.1
backup-backup / includes / cli / php_cli_finder.php
backup-backup / includes / cli Last commit date
php_cli_finder.php 2 years ago version_check.php 2 years ago
php_cli_finder.php
298 lines
1 <?php
2
3 // Namespace
4 namespace BMI\Plugin\PHPCLI;
5
6 // Use
7 use BMI\Plugin\Backup_Migration_Plugin as BMP;
8
9 // Exit on direct access
10 if (!defined('ABSPATH')) exit;
11
12 /**
13 * Scans for PHP CLI executable and makes sure exec is working
14 */
15 class Checker {
16
17 /**
18 * Points if the exec is disabled or not
19 */
20 public $ini_disabled = true;
21
22 /**
23 * __construct - Unused construct function
24 *
25 * @return {self}
26 */
27 function __construct() {}
28
29 /**
30 * findPHP - Scans the system to find executable PHP
31 *
32 * @return {bool/array} false on fail, array on success
33 * $final_executable = [
34 * 'version' => $php_cli_version,
35 * 'brand' => $php_brand,
36 * 'memory' => $php_cli_memory . '/' . $php_cli_memory_modified,
37 * 'max_exec' => $php_cli_max_exec . '/' . $php_cli_max_exec_modified,
38 * 'executable' => $executable_path_to_file
39 * ];
40 */
41 public function findPHP() {
42
43 // Return false if exec is disabled
44 if ($this->isExecEnabled() === false) return false;
45
46 // Check if user defined own PHP CLI
47 $user_defined = false;
48 if (defined('BMI_CLI_EXECUTABLE')) {
49 if (file_exists(BMI_CLI_EXECUTABLE)) {
50 $user_defined = true;
51 }
52 }
53
54 if ($user_defined === false) {
55
56 // Makes variable for system paths list
57 $system_paths = null;
58
59 // Exec command which displays all paths per line
60 @exec('(sed "s/:/\n/g" <<< $PATH) 2>&1', $system_paths);
61
62 // Concat output
63 $system_paths = implode("\n", $system_paths);
64
65 // Check if the output is not empty, if empty abort
66 if (empty($system_paths) || !$system_paths) return false;
67
68 // Make variable for executables that contains php keyword
69 $executables = ['php'];
70
71 // Make variable for "for" loop
72 $system_paths = explode("\n", $system_paths);
73
74 // Loop all paths and check for PHP executables
75 for ($i = 0; $i < sizeof($system_paths); ++$i) {
76
77 // Variable for scan output
78 $executables_scan = null;
79
80 // Trim the path just in case
81 $path = trim($system_paths[$i]);
82
83 // If path is empty ignore and continue
84 if (empty($path)) continue;
85
86 // Exec command which will display PHP (in name) executables
87 @exec('(for i in $(ls ' . $path . ' | grep "php"); do [ -x ' . $path . '/$i ] && echo ' . $path . '/$i || echo ""; done;) 2>&1', $executables_scan);
88
89 // Implode the output
90 $executables_scan = implode("\n", $executables_scan);
91
92 // Merge the array with other results
93 $executables = array_merge($executables, explode("\n", $executables_scan));
94
95 }
96
97 }
98
99 // Make variable for real PHP executables
100 $php_executables = [];
101
102 // If used defined own PHP CLI use it
103 if ($user_defined === true) $executables = [BMI_CLI_EXECUTABLE];
104
105 // Filter the array to exclude empty values and remove duplicates
106 $executables = array_filter(array_unique($executables));
107
108 // Make variable for final executable
109 $final_executable = false;
110
111 // Loop and test the executables
112 foreach ($executables as $exe) {
113
114 // If path+name does not contain php ignore and continue
115 if (strpos($exe, 'php') === false) continue;
116
117 // Make variable for CLI version in shell
118 $shell_version = null;
119
120 // Make variable for regex check
121 $output = null;
122
123 // Exec the command to check shell displayed version
124 @exec($exe . ' --version 2>&1', $shell_version);
125
126 // Implode the output
127 $shell_version = implode("\n", $shell_version);
128
129 // Test the output with regex to find PHP version and brand
130 preg_match('/PHP\ (.*)\ (.*)\ \(built: (.*)\)/i', $shell_version, $output);
131
132 // Check if the output is not empty and contains at least 4 results
133 if ($output && !empty($output) && !empty($output[1]) && sizeof($output) >= 4) {
134
135 // Remove additional characters from the version leave only numbers with dots
136 $php = preg_replace("/[^0-9.]/", "", $output[1]);
137
138 // Save the brand in the $brand variable
139 $brand = $output[2];
140
141 // Make variable for file version test
142 $file_version = null;
143
144 // Make variable for shell inline PHP version test
145 $inline_version = null;
146
147 // Exec the shell inline test for version
148 @exec($exe . ' -r "echo phpversion();" 2>&1', $inline_version);
149
150 // Implode the version
151 $inline_version = implode("\n", $inline_version);
152
153 // Check if the version match required minimum
154 if (version_compare($inline_version, '5.6', '>=')) {
155
156 // Path to CLI check file
157 $path_to_cli = BMI_INCLUDES . '/cli/version_check.php';
158
159 // Exec the file check if it can run files
160 @exec($exe . ' -f ' . $path_to_cli . ' 2>&1', $file_version);
161
162 // Check if the output is correct
163 if ($file_version && is_array($file_version) && !empty($file_version) && sizeof($file_version) >= 5) {
164
165 // The results from file saved to named variables
166 $php_cli_version = $file_version[0];
167 $php_cli_memory = $file_version[1];
168 $php_cli_max_exec = $file_version[2];
169 $php_cli_memory_modified = $file_version[3];
170 $php_cli_max_exec_modified = $file_version[4];
171
172 // Check if the version match the inline one (it's the same php.ini)
173 if (trim($php_cli_version) == trim($inline_version)) {
174
175 // If it match use this PHP CLI module
176 $final_executable = [
177 'brand' => $brand,
178 'version' => $php_cli_version,
179 'memory' => $php_cli_memory . '/' . $php_cli_memory_modified,
180 'max_exec' => $php_cli_max_exec . '/' . $php_cli_max_exec_modified,
181 'executable' => $exe
182 ];
183
184 break;
185
186 }
187
188 }
189
190 }
191
192 }
193
194 }
195
196 // Return the final result
197 return $final_executable;
198
199 }
200
201 /**
202 * isExecAvailable - Check if exec is not blocked by php.ini
203 *
204 * @return {bool} true on success / false on fail
205 */
206 public function isExecAvailable() {
207
208 // Get disabled functions
209 $disabled_functions = @ini_get('disable_functions');
210
211 // Turn disabled functions to array
212 $disabled_functions = explode(',', $disabled_functions);
213
214 // Check if everything is allowed
215 if (empty($disabled_functions)) {
216
217 // Check if function is callable and not disabled (PHP 8 check)
218 if (function_exists('shell_exec') && is_callable('shell_exec')) return true;
219 else return false;
220
221 }
222
223 // Few checks
224 if (!is_array($disabled_functions)) return false;
225 elseif (in_array('shell_exec', $disabled_functions)) return false;
226 elseif (in_array('exec', $disabled_functions)) return false;
227 elseif (in_array('system', $disabled_functions)) return false;
228 else {
229
230 // Check if function is callable and not disabled (PHP 8 check)
231 if (function_exists('shell_exec') && is_callable('shell_exec')) return true;
232 else return false;
233
234 }
235
236 }
237
238 /**
239 * isExecEnabled - Checks if exec function is not disabled or blocked
240 *
241 * @return {bool} true on success / false on fail
242 */
243 public function isExecEnabled() {
244
245 // Check if the function is not disabled in php.ini
246 if ($this->isExecAvailable()) {
247
248 // Mark as enabled in php_ini
249 $this->ini_disabled = false;
250
251 // Try to run simple shell
252 try {
253
254 // Output variable
255 $output = null;
256
257 // Execute the command
258 @exec('echo "It works!" 2>&1', $output);
259
260 // Implode the output just in case
261 if ($output) {
262 $output = implode("\n", $output);
263 } else return false;
264
265 // Check if the output is as expected
266 if ($output === 'It works!') return true;
267 else return false;
268
269 // Catch errors in older PHP
270 } catch (\Error $e) {
271
272 return false;
273
274 // Catch exceptions if any
275 } catch (\Exception $e) {
276
277 return false;
278
279 // Catch throwable exception if any
280 } catch (\Throwable $e) {
281
282 return false;
283
284 }
285
286 // If the function is blocked do not even try and return false
287 } else {
288
289 // Mark as disabled in php_ini
290 $this->ini_disabled = true;
291 return false;
292
293 }
294
295 }
296
297 }
298