PluginProbe
ManageWP Worker / 4.9.27
ManageWP Worker v4.9.27
4.9.38 4.9.37 4.9.36 4.9.35 4.9.34 3.8.7 3.8.8 3.9.0 3.9.1 3.9.10 3.9.11 3.9.12 3.9.13 3.9.14 3.9.15 3.9.16 3.9.17 3.9.18 3.9.19 3.9.2 3.9.20 3.9.21 3.9.22 3.9.23 3.9.24 All 73 releases
worker / functions.php

functions.php in ManageWP Worker 4.9.27, at functions.php

1,128 lines 31.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 function mwp_autoload($class)
4 {
5 if (substr($class, 0, 8) === 'Symfony_'
6 || substr($class, 0, 8) === 'Monolog_'
7 || substr($class, 0, 5) === 'Gelf_'
8 || substr($class, 0, 4) === 'MWP_'
9 || substr($class, 0, 4) === 'MMB_'
10 ) {
11 $file = dirname(__FILE__).'/src/'.str_replace('_', '/', $class).'.php';
12 if (file_exists($file)) {
13 include_once $file;
14 }
15 }
16 }
17
18 /**
19 * @return Monolog_Psr_LoggerInterface
20 */
21 function mwp_logger()
22 {
23 return mwp_container()->getLogger();
24 }
25
26 /**
27 * @return MWP_WordPress_Context
28 */
29 function mwp_context()
30 {
31 return mwp_container()->getWordPressContext();
32 }
33
34 function mwp_worker_configuration()
35 {
36 return mwp_container()->getConfiguration();
37 }
38
39 function mwp_format_memory_limit($limit)
40 {
41 if ((string)(int)$limit === (string)$limit) {
42 // The number is numeric.
43 return mwp_format_bytes($limit);
44 }
45
46 $units = strtolower(substr($limit, -1));
47
48 if (!in_array($units, array('b', 'k', 'm', 'g'))) {
49 // Invalid size unit.
50 return $limit;
51 }
52
53 $number = substr($limit, 0, -1);
54
55 if ((string)(int)$number !== $number) {
56 // The number isn't numeric.
57 return $number;
58 }
59
60 switch ($units) {
61 case 'g':
62 return $number.' GB';
63 case 'm':
64 return $number.' MB';
65 case 'k':
66 return $number.' KB';
67 case 'b':
68 default:
69 return $number.' B';
70 }
71 }
72
73 function mwp_format_bytes($bytes)
74 {
75 $bytes = (int)$bytes;
76
77 if ($bytes > 1024 * 1024 * 1024) {
78 return round($bytes / 1024 / 1024 / 1024, 2).' GB';
79 } elseif ($bytes > 1024 * 1024) {
80 return round($bytes / 1024 / 1024, 2).' MB';
81 } elseif ($bytes > 1024) {
82 return round($bytes / 1024, 2).' KB';
83 }
84
85 return $bytes.' B';
86 }
87
88 function cleanup_delete_worker($params = array())
89 {
90 $revision_params = get_option('mmb_stats_filter');
91 $revision_limit = isset($revision_params['plugins']['cleanup']['revisions']) ? str_replace('r_', '', $revision_params['plugins']['cleanup']['revisions']) : 5;
92
93 $params_array = explode('_', $params['actions']);
94 $return_array = array();
95
96 foreach ($params_array as $param) {
97 switch ($param) {
98 case 'revision':
99 if (mmb_delete_all_revisions($revision_limit)) {
100 $return_array['revision'] = 'OK';
101 } else {
102 $return_array['revision_error'] = 'OK, nothing to do';
103 }
104 break;
105 case 'overhead':
106 if (mmb_handle_overhead(true)) {
107 $return_array['overhead'] = 'OK';
108 } else {
109 $return_array['overhead_error'] = 'OK, nothing to do';
110 }
111 break;
112 case 'comment':
113 if (mmb_delete_spam_comments()) {
114 $return_array['comment'] = 'OK';
115 } else {
116 $return_array['comment_error'] = 'OK, nothing to do';
117 }
118 break;
119 default:
120 break;
121 }
122 }
123
124 unset($params);
125
126 mmb_response($return_array, true);
127 }
128
129 function mmb_num_revisions($leaveRevsPerPost)
130 {
131 global $wpdb;
132
133 $query = "SELECT SUM(t.cnt) FROM (SELECT COUNT(ID) - {$leaveRevsPerPost} as cnt FROM {$wpdb->posts} WHERE post_type = 'revision' AND post_parent != 0 GROUP BY post_parent HAVING COUNT(ID) > {$leaveRevsPerPost}) as t";
134
135 return $wpdb->get_var($query);
136 }
137
138 function mmb_delete_all_revisions($filter)
139 {
140 global $wpdb;
141
142 $num_rev = isset($filter['num_to_keep']) ? (int)str_replace("r_", "", $filter['num_to_keep']) : 5;
143
144 $allRevisions = $wpdb->get_results("SELECT post_parent FROM {$wpdb->posts} WHERE post_type = 'revision' AND post_parent != 0 GROUP BY post_parent HAVING COUNT(ID) > {$num_rev}");
145
146 if (!is_array($allRevisions)) {
147 return false;
148 }
149
150 foreach ($allRevisions as $revision) {
151 $toKeep = $wpdb->get_results("SELECT ID FROM {$wpdb->posts} WHERE post_type = 'revision' AND post_parent = '{$revision->post_parent}' ORDER BY post_date DESC LIMIT ".$num_rev);
152
153 $keepArray = array();
154 foreach ($toKeep as $keep) {
155 $keepArray[] = $keep->ID;
156 }
157
158 if (empty($keepArray)) {
159 continue;
160 }
161
162 $keepQuery = implode(', ', $keepArray);
163 $wpdb->query("DELETE FROM {$wpdb->posts} WHERE post_type = 'revision' AND post_parent = '{$revision->post_parent}' AND ID NOT IN ({$keepQuery})");
164 }
165
166 return true;
167 }
168
169 function mmb_handle_overhead($clear = false)
170 {
171 /** @var wpdb $wpdb */
172 global $wpdb;
173 $query = 'SHOW TABLE STATUS';
174 $tables = $wpdb->get_results($query, ARRAY_A);
175 $tableOverhead = 0;
176 $tablesToOptimize = array();
177
178 foreach ($tables as $table) {
179 if (!isset($table['Engine']) || $table['Engine'] !== 'MyISAM' || $table['Data_free'] == 0) {
180 continue;
181 }
182
183 if ($wpdb->base_prefix === $wpdb->prefix && !preg_match('/^'.preg_quote($wpdb->prefix).'/Ui', $table['Name'])) {
184 continue;
185 }
186
187 if ($wpdb->base_prefix !== $wpdb->prefix && !preg_match('/^'.preg_quote($wpdb->prefix).'\d+_/Ui', $table['Name'])) {
188 continue;
189 }
190
191 $tableOverhead += $table['Data_free'] / 1024;
192 $tablesToOptimize[] = $table['Name'];
193 }
194
195 if (!$clear) { // we should only return the overhead
196 return round($tableOverhead, 3);
197 }
198
199 $optimize = true;
200
201 foreach ($tablesToOptimize as $tableToOptimize) {
202 $query = 'OPTIMIZE TABLE '.$tableToOptimize;
203 $optimize = ((bool)$wpdb->query($query)) && $optimize;
204 }
205
206 return $optimize;
207 }
208
209 function mmb_num_spam_comments()
210 {
211 global $wpdb;
212 $sql = "SELECT COUNT(*) FROM $wpdb->comments WHERE comment_approved = 'spam'";
213 $num_spams = $wpdb->get_var($sql);
214
215 return $num_spams;
216 }
217
218 function mmb_delete_spam_comments()
219 {
220 global $wpdb;
221 $spam = 1;
222 $total = 0;
223 while (!empty($spam)) {
224 $getCommentsQuery = "SELECT * FROM $wpdb->comments WHERE comment_approved = 'spam' LIMIT 1000";
225 $spam = $wpdb->get_results($getCommentsQuery);
226
227 if (empty($spam)) {
228 break;
229 }
230
231 $commentIds = array();
232 foreach ($spam as $comment) {
233 $commentIds[] = $comment->comment_ID;
234
235 // Avoid queries to comments by caching the comment.
236 // Plugins which hook to 'delete_comment' might call get_comment($id), which in turn returns the cached version.
237 wp_cache_add($comment->comment_ID, $comment, 'comment');
238 do_action('delete_comment', $comment->comment_ID);
239 wp_cache_delete($comment->comment_ID, 'comment');
240 }
241
242 $commentIdsList = implode(', ', array_map('intval', $commentIds));
243 $wpdb->query("DELETE FROM {$wpdb->comments} WHERE comment_ID IN ($commentIdsList)");
244 $wpdb->query("DELETE FROM {$wpdb->commentmeta} WHERE comment_id IN ($commentIdsList)");
245
246 $total += count($spam);
247 if (!empty($spam)) {
248 usleep(10000);
249 }
250 }
251
252 return $total;
253 }
254
255 function mwp_is_nio_shell_available()
256 {
257 static $check;
258 if (isset($check)) {
259 return $check;
260 }
261 try {
262 $process = new Symfony_Process_Process("cd .", dirname(__FILE__), array(), null, 1);
263 $process->run();
264 $check = $process->isSuccessful();
265 } catch (Exception $e) {
266 $check = false;
267 }
268
269 return $check;
270 }
271
272 function mwp_is_shell_available()
273 {
274 if (mwp_container()->getParameter('disable_shell')) {
275 return false;
276 }
277
278 if (mwp_is_safe_mode()) {
279 return false;
280 }
281 if (!function_exists('proc_open') || !function_exists('escapeshellarg')) {
282 return false;
283 }
284
285 $neededFunction = array('proc_get_status', 'proc_open');
286 $disabledFunction = mwp_get_disabled_functions();
287
288 if (count(array_diff($neededFunction, $disabledFunction)) != count($neededFunction)) {
289 return false;
290 }
291
292 if (!mwp_is_nio_shell_available()) {
293 return false;
294 }
295
296 return true;
297 }
298
299 function mwp_get_disabled_functions()
300 {
301 $list = array_merge(explode(',', ini_get('disable_functions')), explode(',', ini_get('suhosin.executor.func.blacklist')));
302 $list = array_map('trim', $list);
303 $list = array_map('strtolower', $list);
304 $list = array_filter($list);
305
306 return $list;
307 }
308
309 function mwp_is_safe_mode()
310 {
311 $value = ini_get("safe_mode");
312 if ((int)$value === 0 || strtolower($value) === "off") {
313 return false;
314 }
315
316 return true;
317 }
318
319 function mmb_response($response = false, $success = true)
320 {
321 if (!$success) {
322 if (!is_scalar($response)) {
323 $response = json_encode($response);
324 }
325 throw new MWP_Worker_Exception(MWP_Worker_Exception::GENERAL_ERROR, $response);
326 }
327
328 throw new MWP_Worker_ActionResponse($response);
329 }
330
331 function mmb_remove_site($params)
332 {
333 mwp_core()->deactivate(false, false);
334 mwp_remove_current_key();
335
336 mmb_response(
337 array(
338 'removed_data' => 'Site removed successfully. <br /><br /><b>ManageWP Worker plugin was not deactivated.</b>',
339 ),
340 true
341 );
342 }
343
344 function mwp_get_stats(array $params)
345 {
346 mwp_context()->requireWpRewrite();
347 mwp_context()->requireTaxonomies();
348 mwp_context()->requirePostTypes();
349 mwp_context()->requireTheme();
350
351 mwp_logger()->debug('Starting get_stats after everything was required');
352
353 $return = mwp_core()->get_stats_instance()->get_stats($params);
354 mmb_response($return);
355 }
356
357 function mmb_update_worker_plugin($params)
358 {
359 if (!empty($params['version'])) {
360 $recoveryKit = new MwpRecoveryKit();
361 update_option('mwp_incremental_update_active', time());
362 try {
363 $files = $recoveryKit->recover($params['version']);
364 } catch (Exception $e) {
365 update_option('mwp_incremental_update_active', '');
366 throw $e;
367 }
368 update_option('mwp_incremental_update_active', '');
369 mmb_response(array('files' => $files, 'success' => 'ManageWP Worker plugin successfully updated'), true);
370 } else {
371 mmb_response(mwp_core()->update_worker_plugin($params), true);
372 }
373 }
374
375 function mmb_install_addon($params)
376 {
377 mwp_context()->requireTheme();
378 mwp_load_required_components();
379 $return = mwp_core()->get_installer_instance()->install_remote_file($params);
380 mmb_response($return, true);
381 }
382
383 function mmb_do_upgrade($params)
384 {
385 mwp_context()->requireTheme();
386 $return = mwp_core()->get_installer_instance()->do_upgrade($params);
387 mmb_response($return, true);
388 }
389
390 function mmb_bulk_action_comments($params)
391 {
392 $return = mwp_core()->get_comment_instance()->bulk_action_comments($params);
393 if (is_array($return) && array_key_exists('error', $return)) {
394 mmb_response($return['error'], false);
395 } else {
396 mmb_response($return, true);
397 }
398 }
399
400 function mmb_add_user($params)
401 {
402 $return = mwp_core()->get_user_instance()->add_user($params);
403 if (is_array($return) && array_key_exists('error', $return)) {
404 mmb_response($return['error'], false);
405 } else {
406 mmb_response($return, true);
407 }
408 }
409
410 function mmb_edit_users($params)
411 {
412 $users = mwp_core()->get_user_instance()->edit_users($params);
413 $response = 'User updated.';
414 $check_error = false;
415 foreach ($users as $username => $user) {
416 $check_error = is_array($user) && array_key_exists('error', $user);
417 if ($check_error) {
418 $response = $username.': '.$user['error'];
419 }
420 }
421 mmb_response($response, !$check_error);
422 }
423
424 function mmb_iframe_plugins_fix($update_actions)
425 {
426 foreach ($update_actions as $key => $action) {
427 $update_actions[$key] = str_replace('target="_parent"', '', $action);
428 }
429
430 return $update_actions;
431 }
432
433 function mmb_execute_php_code($params)
434 {
435 ob_start();
436 $errorHandler = new MWP_Debug_EvalErrorHandler();
437 set_error_handler(array($errorHandler, 'handleError'));
438
439 if (!empty($params['code64'])) {
440 $params['code'] = base64_decode(substr($params['code64'], 2));
441 }
442
443 $returnValue = eval($params['code']); // This code handles the "Execute PHP Snippet" functionality on ManageWP and is not a security issue.
444 $errors = $errorHandler->getErrorMessages();
445 restore_error_handler();
446 $return = array('output' => ob_get_clean(), 'returnValue' => $returnValue);
447
448 if (count($errors)) {
449 $return['errorLog'] = $errors;
450 }
451
452 $lastError = error_get_last();
453 $fatalError = null;
454
455 if (($lastError !== null)
456 && ($lastError['type'] & (E_PARSE | E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR))
457 && (strpos($lastError['file'], __FILE__) !== false)
458 && (strpos($lastError['file'], 'eval()') !== false)
459 ) {
460 $return['fatalError'] = $lastError;
461 }
462
463 mmb_response($return, true);
464 }
465
466 function mmb_upload_file_action($params)
467 {
468 $transactions = getUploadMessages();
469
470 if (!file_exists($params['file_path'])) {
471 mmb_response(array('message' => $transactions['path_not_exist'], 'ok' => false), true);
472 }
473
474 if (!is_writable($params['file_path'])) {
475 mmb_response(array('message' => $transactions['permissions_denied'], 'ok' => false), true);
476 }
477
478 $pathName = $params['file_path'];
479 if (substr($pathName, -1) !== '/') {
480 $pathName = $pathName.'/';
481 }
482 $filePath = $pathName.$params['file_name'];
483
484 if (file_exists($filePath) && !$params['overwrite']) {
485 mmb_response(array('message' => $transactions['file_exist'], 'ok' => false), true);
486 }
487
488 $file = fopen($filePath, 'w');
489 if (!fwrite($file, base64_decode($params['content']))) {
490 mmb_response(array('message' => $transactions['upload_failed'], 'ok' => false), true);
491 }
492
493 fclose($file);
494 $isWritable = is_writable($filePath);
495 $result = array(
496 'pathName' => $filePath,
497 'fileName' => basename($filePath),
498 'date' => filemtime($filePath),
499 'permissions' => substr(sprintf('%o', fileperms($filePath)), -4),
500 'fileType' => pathinfo($filePath, PATHINFO_EXTENSION),
501 'fileSize' => filesize($filePath),
502 'hasSubDir' => false,
503 'writable' => $isWritable,
504 'editable' => $isWritable
505 );
506
507 mmb_response(array('message' => $transactions['upload_success'], 'ok' => true, 'result' => $result), true);
508 }
509
510 function mmb_edit_plugins_themes($params)
511 {
512 $return = mwp_core()->get_installer_instance()->edit($params);
513 mmb_response($return, true);
514 }
515
516 function mmb_worker_brand($params)
517 {
518 $worker_brand = get_option('mwp_worker_brand');
519 $current_from_orion = !empty($worker_brand['from_orion']) ? $worker_brand['from_orion'] : false;
520 $from_orion = !empty($params['brand']['from_orion']) ? $params['brand']['from_orion'] : false;
521
522 if ($from_orion === false && $current_from_orion !== $from_orion) {
523 mmb_response(true, true); //@TODO: Maybe return mmb_response(true, false)
524 return;
525 }
526
527 update_option("mwp_worker_brand", $params['brand']);
528 mmb_response(true, true);
529 }
530
531 function mmb_maintenance_mode($params)
532 {
533 global $wp_object_cache;
534
535 $default = get_option('mwp_maintenace_mode');
536 $params = empty($default) ? $params : array_merge($default, $params);
537 update_option("mwp_maintenace_mode", $params);
538
539 if (!empty($wp_object_cache)) {
540 @$wp_object_cache->flush();
541 }
542 mmb_response(true, true);
543 }
544
545 function mmb_plugin_actions()
546 {
547 global $pagenow, $current_user, $mmode;
548 if (!is_admin() && !(defined('WP_CLI') && WP_CLI) && !in_array($pagenow, array('wp-login.php'))) {
549 $mmode = get_option('mwp_maintenace_mode');
550 if (!empty($mmode)) {
551 if (isset($mmode['active']) && $mmode['active'] == true) {
552 $status_code = empty($mmode['status_code']) ? 503 : $mmode['status_code'];
553 if (!empty($current_user->ID) && !empty($mmode['hidecaps'])) {
554 $usercaps = array();
555 if (isset($current_user->caps) && !empty($current_user->caps)) {
556 $usercaps = $current_user->caps;
557 }
558 foreach ($mmode['hidecaps'] as $cap => $hide) {
559 if (!$hide) {
560 continue;
561 }
562
563 foreach ($usercaps as $ucap => $val) {
564 if ($ucap == $cap) {
565 ob_end_clean();
566 ob_end_flush();
567 if (!headers_sent()) {
568 if ($status_code == 503) {
569 header(sprintf('%s 503 Service Unavailable', isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.1'), true, $status_code);
570 } else {
571 header(sprintf('%s %d Service Unavailable', isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.1', $status_code), true, $status_code);
572 }
573 }
574 die($mmode['template']);
575 }
576 }
577 }
578 } else {
579 if (!headers_sent()) {
580 if ($status_code == 503) {
581 header(sprintf('%s 503 Service Unavailable', isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.1'), true, 503);
582 } else {
583 header(sprintf('%s %d Service Unavailable', isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.1', $status_code), true, $status_code);
584 }
585 }
586 die($mmode['template']);
587 }
588 }
589 }
590 }
591
592 if (file_exists(dirname(__FILE__).'/log')) {
593 unlink(dirname(__FILE__).'/log');
594 }
595 }
596
597 function mwb_edit_redirect_override($location = false, $comment_id = false)
598 {
599 if (isset($_COOKIE[MMB_XFRAME_COOKIE])) {
600 $location = get_site_url().'/wp-admin/edit-comments.php';
601 }
602
603 return $location;
604 }
605
606 function mwp_set_plugin_priority()
607 {
608 $pluginBasename = 'worker/init.php';
609 $activePlugins = get_option('active_plugins');
610
611 if (!is_array($activePlugins) || reset($activePlugins) === $pluginBasename) {
612 return;
613 }
614
615 $workerKey = array_search($pluginBasename, $activePlugins);
616
617 if ($workerKey === false || $workerKey === null) {
618 return;
619 }
620
621 unset($activePlugins[$workerKey]);
622 array_unshift($activePlugins, $pluginBasename);
623 update_option('active_plugins', array_values($activePlugins));
624 }
625
626 /**
627 * @return MMB_Core
628 */
629 function mwp_core()
630 {
631 static $core;
632
633 if (!$core instanceof MMB_Core) {
634 $core = new MMB_Core();
635 }
636
637 return $core;
638 }
639
640 /**
641 * Auto-loads classes that may not exists after this plugin's update.
642 */
643 function mwp_load_required_components()
644 {
645 class_exists('MWP_Http_ResponseInterface');
646 class_exists('MWP_Http_Response');
647 class_exists('MWP_Http_LegacyWorkerResponse');
648 class_exists('MWP_Http_JsonResponse');
649 class_exists('MWP_Worker_ActionResponse');
650 class_exists('MWP_Worker_Exception');
651 class_exists('MWP_Event_ActionResponse');
652 class_exists('MWP_Event_MasterResponse');
653 }
654
655 function mwp_uninstall()
656 {
657 delete_option('mwp_core_autoupdate');
658 delete_option('mwp_recovering');
659 delete_option('mwp_container_parameters');
660 delete_option('mwp_container_site_parameters');
661 $loaderName = '0-worker.php';
662 try {
663 $mustUsePluginDir = rtrim(WPMU_PLUGIN_DIR, '/');
664 $loaderPath = $mustUsePluginDir.'/'.$loaderName;
665
666 if (!file_exists($loaderPath)) {
667 return;
668 }
669
670 $removed = @unlink($loaderPath);
671
672 if (!$removed) {
673 $error = error_get_last();
674 throw new Exception(sprintf('Unable to remove loader: %s', $error['message']));
675 }
676 } catch (Exception $e) {
677 mwp_logger()->error('Unable to remove loader', array('exception' => $e));
678 }
679 }
680
681 function mwp_get_service_key()
682 {
683 $serviceKey = mwp_context()->optionGet('mwp_service_key');
684 if (empty($serviceKey)) {
685 $serviceKey = mwp_generate_uuid4();
686 mwp_context()->optionSet('mwp_service_key', $serviceKey, true);
687 }
688
689 return $serviceKey;
690 }
691
692 function mwp_get_communication_keys()
693 {
694 return mwp_context()->optionGet('mwp_communication_keys', array());
695 }
696
697 function mwp_remove_current_key()
698 {
699 mwp_remove_communication_key(!empty($_SERVER['HTTP_MWP_SITE_ID']) ? $_SERVER['HTTP_MWP_SITE_ID'] : 'any');
700 }
701
702 function mwp_remove_communication_key($siteId)
703 {
704 if ($siteId === 'any') {
705 mwp_context()->optionDelete('mwp_communication_key');
706 return;
707 }
708
709 $keys = mwp_context()->optionGet('mwp_communication_keys', array());
710
711 if (empty($keys[$siteId])) {
712 return;
713 }
714
715 unset($keys[$siteId]);
716 mwp_context()->optionSet('mwp_communication_keys', $keys, true);
717 }
718
719 function mwp_get_basic_communication_key()
720 {
721 $key = mwp_context()->optionGet('mwp_communication_key');
722 if (!empty($key)) {
723 mwp_context()->optionSet('mwp_key_last_used_any', time(), true);
724 }
725
726 return $key;
727 }
728
729 function mwp_add_as_site_communication_key($key)
730 {
731 $siteId = !empty($_SERVER['HTTP_MWP_SITE_ID']) ? $_SERVER['HTTP_MWP_SITE_ID'] : null;
732
733 if (empty($siteId)) {
734 return;
735 }
736
737 $keys = mwp_context()->optionGet('mwp_communication_keys', array());
738
739 if (is_array($keys) && !empty($keys[$siteId])) {
740 return;
741 }
742
743 mwp_accept_potential_key($key);
744 }
745
746 function mwp_get_communication_key($id = null)
747 {
748 $siteId = !empty($_SERVER['HTTP_MWP_SITE_ID']) ? $_SERVER['HTTP_MWP_SITE_ID'] : $id;
749
750 if (empty($siteId)) {
751 return mwp_get_basic_communication_key();
752 }
753
754 $keys = mwp_context()->optionGet('mwp_communication_keys', array());
755
756 if (is_array($keys) && !empty($keys[$siteId])) {
757 mwp_context()->optionSet('mwp_key_last_used_'.$siteId, time(), true);
758
759 return $keys[$siteId]['key'];
760 }
761
762 return mwp_get_basic_communication_key();
763 }
764
765 function mwp_accept_potential_key($keyToAccept = '')
766 {
767 $siteId = !empty($_SERVER['HTTP_MWP_SITE_ID']) ? $_SERVER['HTTP_MWP_SITE_ID'] : null;
768 $addKey = !empty($keyToAccept) ? $keyToAccept : mwp_get_potential_key();
769
770 if (!empty($siteId)) {
771 $keys = mwp_context()->optionGet('mwp_communication_keys', array());
772
773 if (empty($keys) || !is_array($keys)) {
774 $keys = array();
775 }
776
777 $time = time();
778 $keys[$siteId] = array(
779 'key' => $addKey,
780 'added' => $time,
781 );
782
783 mwp_context()->optionSet('mwp_communication_keys', $keys, true);
784 mwp_context()->optionSet('mwp_key_last_used_'.$addKey, $time, true);
785 } else {
786 mwp_context()->optionSet('mwp_communication_key', $addKey, true);
787 }
788
789 mwp_context()->optionDelete('mwp_potential_key', true);
790 mwp_context()->optionDelete('mwp_potential_key_time', true);
791
792 return $addKey;
793 }
794
795 function mwp_get_potential_key()
796 {
797 $potentialKey = mwp_context()->optionGet('mwp_potential_key', null);
798 $potentialKeyTime = mwp_context()->optionGet('mwp_potential_key_time', 0);
799 $now = time();
800
801 if (empty($potentialKey) || empty($potentialKeyTime) || !is_numeric($potentialKeyTime) || ($now - $potentialKeyTime) > 86400) {
802 $potentialKey = mwp_generate_uuid4();
803 $potentialKeyTime = $now;
804 mwp_context()->optionSet('mwp_potential_key', $potentialKey, true);
805 mwp_context()->optionSet('mwp_potential_key_time', $potentialKeyTime, true);
806 }
807
808 return $potentialKey;
809 }
810
811 function mwp_provision_keys()
812 {
813 mwp_get_service_key();
814 mwp_get_potential_key();
815 }
816
817 function mwp_add_post_to_link_monitor_check($postId)
818 {
819 if (wp_get_post_parent_id($postId) !== 0) {
820 return;
821 }
822
823 $postsToSendToLinkMonitor = mwp_context()->transientGet('mwp_link_monitor_posts');
824 if ($postsToSendToLinkMonitor === false) {
825 $postsToSendToLinkMonitor = array();
826 }
827
828 if (in_array($postId, $postsToSendToLinkMonitor)) {
829 return;
830 }
831
832 $postsToSendToLinkMonitor[] = $postId;
833
834 //transient will expire after 30 days from time of update
835 mwp_context()->transientSet('link_monitor_posts', $postsToSendToLinkMonitor, 2592000);
836 }
837
838 function mwp_link_monitor_cron_recurrence_interval($schedules)
839 {
840 $schedules['every_five_minutes'] = array(
841 'interval' => 300,
842 'display' => __('Every 5 Minutes')
843 );
844
845 return $schedules;
846 }
847
848 function mwp_generate_uuid4()
849 {
850 $data = null;
851 if (function_exists('openssl_random_pseudo_bytes')) {
852 $data = @openssl_random_pseudo_bytes(16);
853 }
854
855 if (empty($data)) {
856 $data = '';
857 for ($i = 0; $i < 16; ++$i) {
858 $data .= chr(mt_rand(0, 255));
859 }
860 }
861
862 $data[6] = chr(ord($data[6]) & 0x0f | 0x40); // set version to 0100
863 $data[8] = chr(ord($data[8]) & 0x3f | 0x80); // set bits 6-7 to 10
864 return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
865 }
866
867 function mwp_refresh_live_public_keys($params = array())
868 {
869 $liveKeys = null;
870 $lastResponse = null;
871 $servers = array('cdn.managewp.com', 'keys.managewp.com');
872
873 foreach ($servers as $server) {
874 if (!empty($liveKeys)) {
875 continue;
876 }
877
878 $lastResponse = mwp_get_and_decode_public_keys($server);
879
880 if (is_array($lastResponse) && !empty($lastResponse['keys']) && !empty($lastResponse['success'])) {
881 $liveKeys = $lastResponse['keys'];
882 }
883 }
884
885 if (empty($liveKeys)) {
886 return $lastResponse;
887 }
888
889 mwp_context()->optionSet('mwp_public_keys_refresh_time', time(), true);
890 mwp_context()->optionSet('mwp_public_keys', $liveKeys, true);
891
892 return $lastResponse;
893 }
894
895 function mwp_get_and_decode_public_keys($domain)
896 {
897 $liveContent = mwp_get_public_keys_from_live($domain);
898
899 if ($liveContent['success'] === false) {
900 return array(
901 'success' => false,
902 'message' => $liveContent['message'],
903 );
904 }
905
906 $liveContent = $liveContent['result'];
907
908 if (empty($liveContent)) {
909 return array(
910 'success' => false,
911 'message' => 'Empty content received from live.',
912 );
913 }
914
915 $liveKeys = @json_decode($liveContent, true);
916
917 if (empty($liveKeys)) {
918 return array(
919 'success' => false,
920 'message' => 'Could not json decode the received keys. Received: '.$liveKeys,
921 );
922 }
923
924 return array(
925 'success' => true,
926 'keys' => $liveKeys,
927 );
928 }
929
930 function mwp_get_public_keys_from_live($domain)
931 {
932 $result = wp_remote_get("https://$domain/public-keys");
933
934 if (!is_array($result) || empty($result['body'])) {
935 return mwp_get_public_keys_from_live_fallback($domain);
936 }
937
938 return array(
939 'success' => true,
940 'result' => $result['body'],
941 );
942 }
943
944 function mwp_get_public_keys_from_live_fallback($domain)
945 {
946 $fixedDomainMap = array(
947 'keys.managewp.com' => '216.69.138.218',
948 );
949
950 $originalDomain = $domain;
951 $domain = dns_resolve_key_domain($domain);
952
953 if (preg_match('/^\d+\.\d+\.\d+\.\d+$/', $domain) !== 1 && !empty($fixedDomainMap[$domain])) {
954 $domain = $fixedDomainMap[$domain];
955 }
956
957 $transportToUse = get_secure_protocol();
958
959 if ($transportToUse == null) {
960 return array(
961 'success' => false,
962 'message' => 'Could not find a transport to use.',
963 );
964 }
965
966 $socket = @stream_socket_client("$transportToUse://$domain:443", $errno, $errstr, 30, STREAM_CLIENT_CONNECT, @stream_context_create(array(
967 'ssl' => array(
968 'peer_name' => $originalDomain,
969 'verify_peer' => true,
970 'verify_peer_name' => true,
971 'allow_self_signed' => false,
972 'cafile' => dirname(__FILE__).'/publickeys/godaddy_g2_root.cer',
973 ),
974 )));
975
976 if (!$socket) {
977 return array(
978 'success' => false,
979 'message' => 'Failed opening a socket to ManageWP keys (on '.$domain.'). Error: '.$errstr.', Error number: '.$errno,
980 );
981 }
982
983 $requestContent = <<<EOL
984 GET /public-keys HTTP/1.1
985 Host: cdn.managewp.com
986 Accept-Language: en-US,en;q=0.9,hr;q=0.8,sr;q=0.7
987 Upgrade-Insecure-Requests: 1
988 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36
989 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
990 Cache-Control: max-age=0
991 Authority: cdn.managewp.com
992 Connection: close
993
994
995 EOL;
996
997
998 if (@fwrite($socket, $requestContent) === false) {
999 return array(
1000 'success' => false,
1001 'message' => 'Could not write the public-key request to the socket.',
1002 );
1003 }
1004
1005 return read_stream_response($socket);
1006 }
1007
1008 function get_secure_protocol()
1009 {
1010 $transports = array_flip(stream_get_transports());
1011 $preferredTransport = array(
1012 'tls',
1013 'tlsv1.2',
1014 'tlsv1.1',
1015 'tlsv1.0',
1016 );
1017
1018 $transportToUse = null;
1019
1020 foreach ($preferredTransport as $transport) {
1021 if (!empty($transportToUse) || !isset($transports[$transport])) {
1022 continue;
1023 }
1024
1025 $transportToUse = $transport;
1026 }
1027
1028 return $transportToUse;
1029 }
1030
1031 function read_stream_response($socket)
1032 {
1033 do {
1034 $line = @fgets($socket);
1035 } while ($line !== false && $line !== "\n" && $line !== "\r\n");
1036
1037 if ($line === false) {
1038 return array(
1039 'success' => false,
1040 'message' => 'No response received from the public-key server.',
1041 );
1042 }
1043
1044 $content = @stream_get_contents($socket);
1045
1046 @fclose($socket);
1047
1048 if ($content === false || !is_string($content)) {
1049 return array(
1050 'success' => false,
1051 'message' => 'Invalid response received from the public-key server.',
1052 );
1053 }
1054
1055 return array(
1056 'success' => true,
1057 'result' => $content,
1058 );
1059 }
1060
1061 function dns_resolve_key_domain($domain)
1062 {
1063 $transportToUse = get_secure_protocol();
1064
1065 if ($transportToUse == null) {
1066 return $domain;
1067 }
1068
1069 $socket = @stream_socket_client("$transportToUse://1.1.1.1:443", $errno, $errstr, 30, STREAM_CLIENT_CONNECT);
1070
1071 if (!$socket) {
1072 return $domain;
1073 }
1074
1075 $requestContent = <<<PHP
1076 GET /dns-query?name=[DOMAIN]&type=A HTTP/1.1
1077 Host: 1.1.1.1
1078 Accept: application/dns-json
1079 Connection: close
1080
1081
1082 PHP;
1083
1084 $requestContent = str_replace('[DOMAIN]', $domain, $requestContent);
1085
1086 if (@fwrite($socket, $requestContent) === false) {
1087 return $domain;
1088 }
1089
1090 $result = read_stream_response($socket);
1091
1092 if ($result['success'] === false || empty($result['result'])) {
1093 return $domain;
1094 }
1095
1096 $content = @json_decode($result['result'], true);
1097
1098 if (empty($content['Answer']) || !is_array($content['Answer'])) {
1099 return $domain;
1100 }
1101
1102 $record = $content['Answer'][count($content['Answer']) - 1];
1103
1104 if (empty($record['data']) || preg_match('/^\d+\.\d+\.\d+\.\d+$/', $record['data']) !== 1) {
1105 return $domain;
1106 }
1107
1108 return $record['data'];
1109 }
1110
1111 function site_in_mwp_maintenance_mode()
1112 {
1113 $class = 'notice notice-warning is-dismissible';
1114 $message = esc_html__('The site is currently in maintenance mode.', 'worker');
1115 printf('<div class="%1$s"><p>%2$s</p></div>', esc_attr($class), esc_html($message));
1116 }
1117
1118 function getUploadMessages()
1119 {
1120 return array(
1121 'path_not_exist' => 8,
1122 'file_exist' => 9,
1123 'upload_failed' => 10,
1124 'upload_success' => 11,
1125 'permissions_denied' => 13,
1126 );
1127 }
1128