PluginProbe ʕ •ᴥ•ʔ
JetBackup – Backup, Restore & Migrate / 3.1.14.17
JetBackup – Backup, Restore & Migrate v3.1.14.17
3.1.23.6 3.1.23.5 3.1.23.3 3.1.22.4 3.1.22.3 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.8.1 1.4.9 1.5.0 1.5.1 1.5.1.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.6.0 1.6.10 1.6.11 1.6.12 1.6.13 1.6.15 1.6.5.1 1.6.8.8 1.6.9 1.6.9.1 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7.5 2.0.8.7 2.0.9.11 2.0.9.14 2.0.9.15 2.0.9.6 2.0.9.7 2.0.9.9 3.1.10.7 3.1.11.1 3.1.12.3 3.1.13.4 3.1.14.17 3.1.15.4 3.1.16.1 3.1.17.5 3.1.18.10 3.1.18.8 3.1.18.9 3.1.19.8 3.1.20.3 3.1.21.3 3.1.7.9 3.1.9.2 trunk 1.1.90 1.1.91 1.2.0 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2
backup / src / JetBackup / Wordpress / Helper.php
backup / src / JetBackup / Wordpress Last commit date
.htaccess 9 months ago Blog.php 9 months ago Helper.php 9 months ago Init.php 9 months ago Installer.php 9 months ago MySQL.php 9 months ago UI.php 9 months ago Update.php 9 months ago Wordpress.php 9 months ago index.html 9 months ago web.config 9 months ago
Helper.php
325 lines
1 <?php
2
3 namespace JetBackup\Wordpress;
4
5 use Exception;
6 use JetBackup\Alert\Alert;
7 use JetBackup\Entities\Util;
8 use JetBackup\Exception\IOException;
9 use JetBackup\Factory;
10 use JetBackup\JetBackup;
11 use WP_User;
12
13 if (!defined( '__JETBACKUP__')) die('Direct access is not allowed');
14
15 class Helper {
16
17 private string $_homedir='';
18
19 private const SUPPORT_USER_TTL = 30 * 24 * 60 * 60; // 30 days in seconds
20
21 const MYSQL_AUTH_PATTERNS = [
22 'db_name' => "/define\s*\(\s*['\"]DB_NAME['\"]\s*,\s*['\"]((?:\\\\.|[^'\"])+)['\"]\s*\)\s*;/",
23 'db_user' => "/define\s*\(\s*['\"]DB_USER['\"]\s*,\s*['\"]((?:\\\\.|[^'\"])+)['\"]\s*\)\s*;/",
24 'db_password' => "/define\s*\(\s*['\"]DB_PASSWORD['\"]\s*,\s*['\"]((?:\\\\.|[^'\"])+)['\"]\s*\)\s*;/",
25 'db_host' => "/define\s*\(\s*['\"]DB_HOST['\"]\s*,\s*['\"]((?:\\\\.|[^'\"])+)['\"]\s*\)\s*;/",
26 'table_prefix' => "/^\s*\\\$table_prefix\s*=\s*['\"]((?:\\\\.|[^'\"])+)['\"]\s*;/",
27 ];
28
29 public static function isMainSite(): bool {
30 return (function_exists('is_main_site') && is_main_site());
31 }
32
33 public static function getMainSiteId(): int {
34 $main_site_id = 1;
35 if (function_exists('get_main_site_id')) return get_main_site_id();
36 if (function_exists('get_site_option')) $main_site_id = (int) get_site_option('main_site_id');
37 if ($main_site_id > 0) return $main_site_id;
38 return $main_site_id;
39 }
40
41 public static function isMultisite(): bool {
42 if (function_exists('is_multisite') && is_multisite()) return true;
43 if (defined( 'MULTISITE')) return MULTISITE;
44 if (defined( 'SUBDOMAIN_INSTALL') || defined( 'VHOST') || defined( 'SUNRISE')) return true;
45 return false;
46 }
47
48 public static function isNetworkAdminUser(): bool {
49 return function_exists('current_user_can') && current_user_can('manage_network') &&
50 function_exists('is_super_admin') && is_super_admin();
51 }
52
53 /**
54 * @throws Exception
55 */
56 public static function getWordpressUser($username) : ?array {
57
58 if(!function_exists('get_user_by')) throw new Exception("Function get_user_by() not defined");
59 if(!function_exists('wp_set_password')) throw new Exception("Function wp_set_password() not defined");
60
61 $user = get_user_by('login', $username);
62 if(!$user) return null;
63
64
65 $password = Util::generatePassword();
66 wp_set_password($password, $user->ID);
67
68 return [
69 'username' => $user->user_login,
70 'email' => $user->user_email,
71 'password' => $password,
72 'wordpress_admin_url' => Wordpress::getAdminURL(),
73
74 ];
75
76 }
77
78 /**
79 * @throws Exception
80 */
81 public static function clearSupportUser() : void {
82
83 $config = Factory::getConfig();
84 if(!$username = $config->getSupportUsername()) return;
85 if(!$user = get_user_by('login', $username)) return;
86 $user_created_date = $user->data->user_registered ?? null;
87 if(!$user_created_date) return;
88 if(!$user_created_timestamp = strtotime($user_created_date)) return;
89
90 if ((time() - $user_created_timestamp) > self::SUPPORT_USER_TTL) {
91
92 if (self::isMultisite()) {
93 if (!function_exists('wpmu_delete_user')) require_once WP_ROOT . JetBackup::SEP . 'wp-admin' . JetBackup::SEP . 'includes' . JetBackup::SEP . 'ms.php';
94 revoke_super_admin($user->ID); // super admin user is protected by wp_delete user, so we need to revoke first
95 wpmu_delete_user($user->ID);
96 } else {
97 if (!function_exists('wp_delete_user')) require_once WP_ROOT . JetBackup::SEP . 'wp-admin' . JetBackup::SEP . 'includes' . JetBackup::SEP . 'user.php';
98 wp_delete_user($user->ID);
99 }
100 $config->setSupportUsername('');
101 $config->save();
102 Alert::add('System Cleanup', "Temporary support user '{$user->data->user_login}' created 30 days ago removed", Alert::LEVEL_INFORMATION);
103 }
104
105 }
106
107 /**
108 * @throws IOException
109 * @throws Exception
110 */
111 public static function createSupportUser() : array {
112
113 $config = Factory::getConfig();
114 $username = $config->getSupportUsername();
115 if ($username && $output = self::getWordpressUser($username)) return $output;
116
117 if(!function_exists('wp_create_user')) throw new Exception("Function wp_create_user() not defined");
118 if(!function_exists('grant_super_admin')) throw new Exception("Function grant_super_admin() not defined");
119
120 // Generate new user details
121 $email = "support+" . Util::generateRandomString(5) . "@jetbackup.com";
122 $password = Util::generatePassword();
123 $username = "jetbackup_" . Util::generateRandomString(5);
124
125 // Create new user
126 $user_id = wp_create_user($username, $password, $email);
127 if (is_wp_error($user_id)) throw new Exception($user_id->get_error_message());
128
129 $user = new WP_User($user_id);
130 $user->set_role('administrator');
131 if (self::isMultisite()) grant_super_admin($user_id); // Grant network admin privileges
132
133 $config->setSupportUsername($username);
134 $config->save();
135
136 return [
137 'username' => $user->user_login,
138 'email' => $email,
139 'password' => $password,
140 'wordpress_admin_url' => Wordpress::getAdminURL(),
141 ];
142
143 }
144
145 public static function isAdminUser(): bool {
146 return function_exists('current_user_can') && current_user_can('manage_options') &&
147 function_exists('is_super_admin') && is_super_admin();
148 }
149
150 /**
151 * Returns true/false if I am in the network admin GUI interface (not if I am network admin USER)
152 * @return bool
153 */
154 public static function isNetworkAdminInterface(): bool {
155 if (function_exists('is_network_admin') && is_network_admin()) return true;
156 if (isset($GLOBALS['current_screen'])) return $GLOBALS['current_screen']->in_admin( 'network' );
157 elseif (defined('WP_NETWORK_ADMIN')) return WP_NETWORK_ADMIN;
158 return false;
159 }
160
161 /**
162 * @param bool $public
163 * Example output: /home/user/public_html/
164 * public flag: public_html (no ending /)
165 * @return string
166 */
167 public function getWordPressHomedir( bool $public = false):string {
168 if(!$this->_homedir) {
169 $homedir = function_exists('get_home_path') ? get_home_path() : WP_ROOT;
170 $this->_homedir = rtrim($homedir, JetBackup::SEP) . JetBackup::SEP;
171 }
172 if ($public) return basename($this->_homedir);
173 return $this->_homedir;
174 }
175
176 /**
177 * @return string
178 * Returns public restore file location
179 * Example -
180 * Alternate path enabled: /home/user/public_html/wp-content/plugins/backup/public/cron
181 * Alternate path disabled: /home/user/public_html
182 */
183 public function getRestoreFileLocation() : string {
184 if (Factory::getSettingsRestore()->isRestoreAlternatePathEnabled()) return rtrim(JetBackup::CRON_PATH, JetBackup::SEP);
185 return rtrim($this->getWordPressHomedir(), JetBackup::SEP);
186 }
187
188 /**
189 * @return string
190 * Return's WordPress public_dir relative to homedir, needed for nested sites (sites inside subfolders)
191 * Example
192 * - getWordPressHomedir: /home/user/sites/www.mydomain.com/subfolder
193 * - getUserHomedir: /home/user
194 * - getWordPressRelativePublicDir: /sites/wp2.jetbackup.com/subfolder
195 */
196 public function getWordPressRelativePublicDir() : string {
197
198 $public_dir = trim($this->getWordPressHomedir(), JetBackup::SEP);
199 $getUserHomedir = trim($this->getUserHomedir(), JetBackup::SEP);
200 $relative_path = $getUserHomedir;
201 if ($public_dir != $getUserHomedir && str_starts_with($public_dir, $getUserHomedir)) {
202 $relative_path = trim(substr($public_dir, strlen($getUserHomedir)), JetBackup::SEP);
203 }
204
205 return JetBackup::SEP . $relative_path;
206 }
207
208 /**
209 * @return string
210 * Example output: /home/user
211 */
212
213 public static function getUserHomedir(): ?string {
214
215 $user_details = Util::getpwuid(Util::geteuid());
216 return $user_details['dir'] ?? null;
217
218 }
219
220 /**
221 * @throws Exception
222 */
223 public static function parseWpConfig(): \stdClass {
224
225 $config_file = Factory::getSettingsGeneral()->getAlternateWpConfigLocation();
226 if(!file_exists($config_file)) throw new Exception("The wp-config.php file does not exist at the specified path. ($config_file)");
227
228 $output = new \stdClass();
229
230 if(!($f = fopen($config_file, 'r'))) throw new Exception("Unable to open the wp-config.php file.");
231
232 $patterns = self::MYSQL_AUTH_PATTERNS;
233
234 while (($line = fgets($f)) !== false) {
235 $line = trim($line);
236 // Skip commented lines
237 if (strpos($line, '//') === 0 || strpos($line, '#') === 0) continue;
238
239 foreach ($patterns as $key => $pattern) {
240 if (!preg_match($pattern, $line, $matches)) continue;
241 $value = stripcslashes($matches[1]);
242
243 if ($key === 'db_host' && strpos($value, ':') !== false) {
244 list($output->db_host, $output->db_port) = explode(':', $value, 2);
245 } else {
246 $output->{$key} = $value;
247 }
248
249 unset($patterns[$key]);
250 break; // Break the foreach loop if a pattern matches
251 }
252
253 // Break the while loop if all patterns are found
254 if (empty($patterns)) break;
255 }
256
257 fclose($f);
258
259 if (empty($output)) throw new Exception("Unable to find the database credentials in the wp-config.php file.");
260
261 // Set default port if not found
262 if (!isset($output->db_port)) $output->db_port = Factory::getSettingsGeneral()->getMySQLDefaultPort(); // Default MySQL port
263
264 return $output;
265
266 }
267
268 public function getUploadDir(): string {
269 $_uploads = Wordpress::getUploadDir()['basedir'] ?? 'uploads';
270 return Wordpress::WP_CONTENT . JetBackup::SEP . basename($_uploads);
271 }
272
273 public static function validateEmail($email): bool {
274 // Ensure $email is an array
275 $emails = is_array($email) ? $email : [$email];
276
277 foreach ($emails as $singleEmail) {
278 $sanitizedEmail = Wordpress::sanitizeEmail($singleEmail);
279 if (!Wordpress::isEmail($sanitizedEmail)) return false; // Invalid email found
280 }
281
282 return true;
283 }
284
285 static function getCurrentScreen():?string {
286 if($screen = Wordpress::getCurrentScreen()) return $screen->id;
287 return null;
288 }
289
290 public static function getUserId():?int {
291 if($user = Wordpress::getCurrentUser()) return $user->ID;
292 return null;
293 }
294
295 public static function getUserEmail():?string {
296 if($user = Wordpress::getCurrentUser()) return $user->user_email;
297 return null;
298 }
299
300 public static function getUserIP(): ?string {
301 $ip = $_SERVER['HTTP_CLIENT_IP'] ?? $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'] ?? null;
302 if ($ip === null) return null;
303 //If forwarded IPs are present, take the first one
304 if ( Wordpress::strContains( $ip, ',' ) ) {$ip = trim(explode(',', $ip)[0]);}
305 $ip = Wordpress::sanitizeTextField($ip);
306 if (filter_var($ip, FILTER_VALIDATE_IP)) return $ip;
307 return null;
308 }
309
310
311
312 public static function isWPCli(): bool {
313 return (defined('WP_CLI') && WP_CLI);
314 }
315
316
317 public static function isCLI():bool {
318
319 if (isset($_SERVER['HTTP_TE']) || isset($_SERVER['HTTP_COOKIE']) || isset($_SERVER['HTTP_ACCEPT'])) return false;
320 if(self::isWPCli() || in_array( PHP_SAPI, ['cli', 'cli-server']) || defined('STDIN')) return true;
321 return isset($_SERVER['argv']) && sizeof($_SERVER['argv']);
322
323 }
324 }
325