PluginProbe
Remote Website Management by Watchful / trunk
Remote Website Management by Watchful vtrunk
v2.0.17 v2.0.16 v2.0.15 v2.0.14 v2.0.13 v2.0.12 v2.0.11 trunk v1.2.11 v1.2.12 v1.2.13 v1.2.14 v1.2.17 v1.2.19 v1.2.20 v1.2.9 v1.3.0 v1.3.1 v1.3.2 v1.4.1 v1.4.10 v1.4.11 v1.4.12 v1.4.2 v1.4.3 All 72 releases
watchful / lib / Controller / Core.php

Core.php in Remote Website Management by Watchful trunk, at lib/Controller/Core.php

361 lines 9.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Controller for upgrading WP core.
4 *
5 * @version 2016-12-20 11:41 UTC+01
6 * @package Watchful WP Client
7 * @author Watchful
8 * @authorUrl https://watchful.net
9 * @copyright Copyright (c) 2020 watchful.net
10 * @license GNU/GPL
11 */
12
13 namespace Watchful\Controller;
14
15 /**
16 * WP REST API Menu routes
17 *
18 * @package WP_API_Menus
19 */
20
21 use Core_Upgrader;
22 use stdClass;
23 use Watchful\Exception;
24 use Watchful\Helpers\Authentification;
25 use Watchful\Helpers\BackupPluginHelper;
26 use Watchful\Skins\SkinCoreUpgrader;
27 use WP_REST_Server;
28 use Watchful\Helpers\PhpFilesystem;
29
30 if (!defined('ABSPATH')) {
31 exit; // Exit if accessed directly.
32 }
33
34 /**
35 * WP Core upgrade class.
36 */
37 class Core implements BaseControllerInterface
38 {
39 /**
40 * Current WordPress version.
41 *
42 * @var string
43 */
44 private static $wp_version;
45
46 /**
47 * Store the WordPress core version that is currently defined.
48 * This is useful to do it the earliest possible in the execution because
49 * some poorly written plugins or themes may accidentally (or intentionally) change it.
50 */
51 public static function remember_wp_version()
52 {
53 static::$wp_version = (string)get_bloginfo('version');
54 }
55
56 /**
57 * Register watchful routes for WP API v2.
58 *
59 * @since 1.2.0
60 */
61 public function register_routes()
62 {
63 register_rest_route(
64 'watchful/v1',
65 '/core/update',
66 array(
67 array(
68 'methods' => WP_REST_Server::CREATABLE,
69 'callback' => array($this, 'update_core'),
70 'permission_callback' => array('Watchful\Routes', 'authentification'),
71 'args' => Authentification::get_arguments(),
72 ),
73 )
74 );
75 }
76
77 /**
78 * Update WP core.
79 *
80 * @return boolean
81 *
82 * @throws Exception If the response is a WP_Error object.
83 */
84 public function update_core()
85 {
86 $core = new Core();
87 $response = $core->upgrade_core();
88
89 if (is_wp_error($response)) {
90 // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped -- ExceptionHandler serialises this as JSON, not HTML.
91 throw new Exception($response->get_error_code(), 500, $response->get_error_data());
92 }
93
94 return $response;
95 }
96
97 /**
98 * Upgrade WP core.
99 *
100 * @return boolean
101 *
102 * @throws Exception If file mods are not allowed.
103 */
104 private function upgrade_core()
105 {
106 if (defined('DISALLOW_FILE_MODS') && DISALLOW_FILE_MODS) {
107 throw new Exception('file modification is disabled (DISALLOW_FILE_MODS)', 403);
108 }
109
110 include_once ABSPATH.'wp-admin/includes/admin.php';
111 include_once ABSPATH.'wp-admin/includes/upgrade.php';
112 include_once ABSPATH.WPINC.'/update.php';
113 require_once ABSPATH.'wp-admin/includes/class-wp-upgrader.php';
114
115 // Check for filesystem access.
116 if (false === $this->check_filesystem_access()) {
117 throw new Exception('filesystem not writable', 403);
118 }
119
120 // Force refresh.
121 wp_version_check();
122
123 $updates = get_core_updates();
124
125 if (is_wp_error($updates) || !$updates) {
126 throw new Exception('core is already up to date', 400);
127 }
128
129 $update = reset($updates);
130
131 if (!$update) {
132 throw new Exception('core is already up to date', 400);
133 }
134
135 $skin = new SkinCoreUpgrader();
136
137 $upgrader = new Core_Upgrader($skin);
138 $result = $upgrader->upgrade($update);
139
140 if (is_wp_error($result)) {
141 return $result;
142 }
143
144 global $wp_current_db_version, $wp_db_version;
145
146 // We have to include version.php so $wp_db_version
147 // will take the version of the updated version of WordPress.
148 require_once ABSPATH.WPINC.'/version.php';
149
150 wp_upgrade();
151
152 return true;
153 }
154
155 /**
156 * Check file system access.
157 *
158 * @return boolean
159 */
160 private function check_filesystem_access()
161 {
162 ob_start();
163 $success = request_filesystem_credentials('');
164 ob_end_clean();
165
166 return (bool)$success;
167 }
168
169 /**
170 * Create and return a standard status class.
171 */
172 public function get_status()
173 {
174 $status = new stdClass();
175
176 $settings = get_option('watchfulSettings');
177 $maintenance = isset($settings['watchful_maintenance']) ? $settings['watchful_maintenance'] : false;
178
179 $status->access = true;
180 $status->maintenance = $maintenance;
181 $status->can_update = true;
182
183 return $status;
184 }
185
186 /**
187 * Get latest versions of WP, php, server, and MySQL.
188 *
189 * @return object
190 */
191 public function get_versions()
192 {
193 $version = new stdClass();
194
195 $version->j_version = static::get_wp_version();
196 $version->jUpd_version = $this->get_latest_update(
197 ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName
198 $version->php_version = phpversion();
199 $version->server_version = $this->get_server_version();
200 $version->mysql_version = $this->get_db_version();
201
202 return $version;
203 }
204
205 /**
206 * Get the WordPress core version. If it was previously stored using
207 * remember_wp_version(), the stored version will be returned. If it wasn't, the
208 * version will retrieved using get_bloginfo().
209 *
210 * @return string
211 */
212 public static function get_wp_version()
213 {
214 if (static::$wp_version) {
215 return static::$wp_version;
216 }
217
218 return (string)get_bloginfo('version');
219 }
220
221 /**
222 * Get the latest WP update.
223 *
224 * @return string
225 */
226 private function get_latest_update()
227 {
228 require_once ABSPATH.'/wp-admin/includes/update.php';
229
230 if (function_exists('get_core_updates')) {
231 $core_update_response = get_core_updates();
232 if (!empty($core_update_response)) {
233 return $core_update_response[0]->version;
234 }
235 }
236
237 return get_bloginfo('version');
238 }
239
240 /**
241 * Get the server version.
242 *
243 * @return string
244 */
245 private function get_server_version()
246 {
247 if (isset($_SERVER['SERVER_SOFTWARE'])) {
248 return sanitize_text_field(wp_unslash($_SERVER['SERVER_SOFTWARE']));
249 }
250 if ((getenv('SERVER_SOFTWARE'))) {
251 return getenv('SERVER_SOFTWARE');
252 }
253
254 return 'NOT_FOUND';
255 }
256
257 /**
258 * Get the DB version.
259 *
260 * @return string
261 */
262 private function get_db_version()
263 {
264 global $wpdb;
265
266 return preg_replace('/[^0-9.].*/', '', $wpdb->get_var('SELECT VERSION()'));
267 }
268
269 /**
270 * Get data for some important system files
271 *
272 * @return array
273 */
274 public function get_files_properties()
275 {
276 $files_properties = array();
277
278 $files = $this->get_files_to_check();
279
280 foreach ($files as $file) {
281 $checksum = 'NOT_FOUND';
282 $fstat['size'] = 'NOT_FOUND';
283 $fstat['mtime'] = 'NOT_FOUND';
284
285 // If the file exists.
286 if (file_exists($file)) {
287 $fp = PhpFilesystem::fopen($file, 'r');
288 $fstat = fstat($fp);
289 PhpFilesystem::fclose($fp);
290 $checksum = md5_file($file);
291 }
292
293 // Special handling of wp-config.php file, which may be placed one level above for increased security
294 if ($checksum === 'NOT_FOUND' && $file === ABSPATH.'/wp-config.php') {
295 $file = ABSPATH.'/../wp-config.php';
296 if (file_exists($file)) {
297 $fp = PhpFilesystem::fopen($file, 'r');
298 $fstat = fstat($fp);
299 PhpFilesystem::fclose($fp);
300 $checksum = md5_file($file);
301 }
302 }
303
304 $file = array(
305 'rootpath' => $file,
306 'size' => $fstat['size'],
307 'modificationtime' => $fstat['mtime'],
308 'checksum' => $checksum,
309 );
310 $files_properties[] = $file;
311 }
312
313 return $files_properties;
314 }
315
316 /**
317 * Get an array containing full path of files to check
318 *
319 * @return array
320 */
321 private function get_files_to_check()
322 {
323 // Files to check.
324 $files = array(
325 ABSPATH.'/index.php',
326 ABSPATH.'/wp-config.php',
327 ABSPATH.'/.htaccess',
328 ABSPATH.'/wp-admin/index.php',
329 );
330
331 foreach (search_theme_directories() as $theme_dir => $theme_data) {
332 $theme_full_path = $theme_data['theme_root']."/".$theme_dir;
333 array_push($files, $theme_full_path.'/index.php');
334 array_push($files, $theme_full_path.'/footer.php');
335 array_push($files, $theme_full_path.'/functions.php');
336 array_push($files, $theme_full_path.'/header.php');
337 array_push($files, $theme_full_path.'/style.css');
338 }
339
340 return $files;
341 }
342
343 /**
344 * Get the latest backup date.
345 * @param array $site_backups_data
346 * @return string The date of the latest backup or an empty string if not set
347 */
348 public function get_latest_backup_info($site_backups_data = array())
349 {
350 if (empty($site_backups_data)) {
351 return '';
352 }
353
354 $date = (new BackupPluginHelper())
355 ->get_last_backup_date($site_backups_data);
356
357 return $date ? $date->format('Y-m-d H:i:s') : '';
358 }
359
360 }
361