ManageWP Worker - Version 4.1.0

Version Description

  • New: Incremental backup capability for ManageWP Orion.
Download this release

Release Info

Developer freediver
Plugin Icon 128x128 ManageWP Worker
Version 4.1.0
Comparing to
See all releases

Code changes from version 4.0.1 to 4.1.0

Files changed (89) hide show
  1. functions.php +27 -7
  2. init.php +28 -14
  3. publickeys/{managewp_mt.pub → ManageWP_mt.pub} +0 -0
  4. readme.txt +80 -18
  5. src/Google/IO/Stream.php +5 -0
  6. src/MMB/Backup.php +53 -16
  7. src/MMB/Core.php +4 -30
  8. src/MMB/Helper.php +3 -115
  9. src/MMB/Installer.php +21 -17
  10. src/MMB/Stats.php +13 -20
  11. src/MWP/Action/DestroySessions.php +21 -0
  12. src/MWP/Action/GetState.php +29 -5
  13. src/MWP/Action/IncrementalBackup/Abstract.php +75 -0
  14. src/MWP/Action/IncrementalBackup/ChecksumTables.php +28 -0
  15. src/MWP/Action/IncrementalBackup/DumpTables.php +113 -0
  16. src/MWP/Action/IncrementalBackup/FetchFiles.php +45 -0
  17. src/MWP/Action/IncrementalBackup/HashFiles.php +77 -0
  18. src/MWP/Action/IncrementalBackup/ListFiles.php +220 -0
  19. src/MWP/Action/IncrementalBackup/ListTables.php +22 -0
  20. src/MWP/Action/IncrementalBackup/Stats.php +72 -0
  21. src/MWP/Action/IncrementalBackup/UploadCloner.php +35 -0
  22. src/MWP/Backup/ArrayHelper.php +15 -0
  23. src/MWP/Backup/MysqlDump/QuerySequenceDump.php +5 -4
  24. src/MWP/Event/ActionRequest.php +12 -1
  25. src/MWP/EventListener/ActionException/MultipartException.php +52 -0
  26. src/MWP/EventListener/ActionRequest/LogRequest.php +37 -0
  27. src/MWP/EventListener/{MasterRequest → ActionRequest}/SetCurrentUser.php +20 -16
  28. src/MWP/EventListener/ActionRequest/SetSettings.php +86 -2
  29. src/MWP/EventListener/ActionResponse/FetchFiles.php +71 -0
  30. src/MWP/EventListener/ActionResponse/SetLegacyPhpExecutionData.php +1 -3
  31. src/MWP/EventListener/ActionResponse/SetLegacyWebsiteConnectionData.php +9 -5
  32. src/MWP/EventListener/ActionResponse/SetUpdaterLog.php +46 -0
  33. src/MWP/EventListener/FixCompatibility.php +34 -0
  34. src/MWP/EventListener/MasterRequest/SetRequestSettings.php +77 -0
  35. src/MWP/EventListener/MasterResponse/LogResponse.php +48 -0
  36. src/MWP/EventListener/PublicRequest/AddStatusPage.php +73 -0
  37. src/MWP/EventListener/PublicRequest/AutomaticLogin.php +32 -1
  38. src/MWP/EventListener/PublicRequest/BrandContactSupport.php +26 -23
  39. src/MWP/EventListener/PublicRequest/SetHitCounter.php +15 -3
  40. src/MWP/EventListener/PublicRequest/SetPluginInfo.php +26 -2
  41. src/MWP/Http/JsonResponse.php +2 -2
  42. src/MWP/Http/MultipartResponse.php +129 -0
  43. src/MWP/Http/MultipartResponsePart.php +86 -0
  44. src/MWP/Http/RedirectResponse.php +2 -2
  45. src/MWP/Http/Response.php +107 -5
  46. src/MWP/Http/StreamingResponseInterface.php +17 -0
  47. src/MWP/IncrementalBackup/Database/Configuration.php +207 -0
  48. src/MWP/IncrementalBackup/Database/ConnectionInterface.php +26 -0
  49. src/MWP/IncrementalBackup/Database/DumpOptions.php +87 -0
  50. src/MWP/IncrementalBackup/Database/DumperInterface.php +19 -0
  51. src/MWP/IncrementalBackup/Database/Exception.php +13 -0
  52. src/MWP/IncrementalBackup/Database/Exception/ConnectionException.php +13 -0
  53. src/MWP/IncrementalBackup/Database/MysqlConnection.php +77 -0
  54. src/MWP/IncrementalBackup/Database/MysqlDumpDumper.php +88 -0
  55. src/MWP/IncrementalBackup/Database/MysqlStatement.php +50 -0
  56. src/MWP/IncrementalBackup/Database/MysqliConnection.php +70 -0
  57. src/MWP/IncrementalBackup/Database/MysqliStatement.php +52 -0
  58. src/MWP/IncrementalBackup/Database/PdoConnection.php +87 -0
  59. src/MWP/IncrementalBackup/Database/PdoStatement.php +39 -0
  60. src/MWP/IncrementalBackup/Database/PhpDumper.php +61 -0
  61. src/MWP/IncrementalBackup/Database/StatementInterface.php +22 -0
  62. src/MWP/IncrementalBackup/Database/StreamableQuerySequenceDump.php +249 -0
  63. src/MWP/IncrementalBackup/FileReader.php +79 -0
  64. src/MWP/IncrementalBackup/HashComputer.php +131 -0
  65. src/MWP/IncrementalBackup/Model/FetchFilesResult.php +67 -0
  66. src/MWP/IncrementalBackup/Model/File.php +55 -0
  67. src/MWP/IncrementalBackup/Model/ServerStatistics.php +117 -0
  68. src/MWP/ServiceContainer/Abstract.php +56 -0
  69. src/MWP/ServiceContainer/Interface.php +15 -0
  70. src/MWP/ServiceContainer/Production.php +74 -26
  71. src/MWP/Signer/PhpSecLibSigner.php +4 -2
  72. src/MWP/Stream/Append.php +131 -0
  73. src/MWP/Stream/Buffer.php +96 -0
  74. src/MWP/Stream/Callable.php +116 -0
  75. src/MWP/Stream/Interface.php +55 -0
  76. src/MWP/Stream/LazyFile.php +130 -0
  77. src/MWP/Stream/Limit.php +153 -0
  78. src/MWP/Stream/ProcessOutput.php +49 -0
  79. src/MWP/Stream/Stream.php +132 -0
  80. src/MWP/System/Environment.php +55 -0
  81. src/MWP/System/Utils.php +49 -0
  82. src/MWP/Updater/TraceableUpdaterSkin.php +183 -0
  83. src/MWP/WordPress/Context.php +77 -4
  84. src/MWP/WordPress/SessionStore.php +86 -0
  85. src/MWP/Worker/Exception.php +9 -3
  86. src/MWP/Worker/Kernel.php +1 -1
  87. src/MWP/Worker/Request.php +1 -1
  88. src/Monolog/Formatter/LineFormatter.php +1 -1
  89. version +2 -2
functions.php CHANGED
@@ -379,6 +379,10 @@ function mwp_is_nio_shell_available()
379
 
380
  function mwp_is_shell_available()
381
  {
 
 
 
 
382
  if (mwp_is_safe_mode()) {
383
  return false;
384
  }
@@ -512,12 +516,6 @@ function mmb_parse_request()
512
 
513
  function mmb_response($response = false, $success = true)
514
  {
515
- mwp_logger()->debug('Master response: {action_response_status}', array(
516
- 'action_response_status' => $success ? 'success' : 'error',
517
- 'action_response' => $response,
518
- 'headers_sent' => headers_sent(),
519
- ));
520
-
521
  if (!$success) {
522
  if (!is_scalar($response)) {
523
  $response = json_encode($response);
@@ -571,7 +569,7 @@ function mmb_stats_get($params)
571
  mwp_context()->requirePostTypes();
572
  mwp_context()->requireTheme();
573
 
574
- $data = array_merge($mmb_core->stats_instance->get($params), mmb_pre_init_stats($params));
575
  mmb_response($data, true);
576
  }
577
 
@@ -1480,3 +1478,25 @@ function mmb_change_comment_status($params)
1480
  mmb_response('Comment not updated', false);
1481
  }
1482
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
379
 
380
  function mwp_is_shell_available()
381
  {
382
+ if (mwp_container()->getParameter('disable_shell')) {
383
+ return false;
384
+ }
385
+
386
  if (mwp_is_safe_mode()) {
387
  return false;
388
  }
516
 
517
  function mmb_response($response = false, $success = true)
518
  {
 
 
 
 
 
 
519
  if (!$success) {
520
  if (!is_scalar($response)) {
521
  $response = json_encode($response);
569
  mwp_context()->requirePostTypes();
570
  mwp_context()->requireTheme();
571
 
572
+ $data = array_merge(mmb_pre_init_stats($params), $mmb_core->stats_instance->get($params));
573
  mmb_response($data, true);
574
  }
575
 
1478
  mmb_response('Comment not updated', false);
1479
  }
1480
  }
1481
+
1482
+ function mwp_uninstall()
1483
+ {
1484
+ $loaderName = '0-worker.php';
1485
+ try {
1486
+ $mustUsePluginDir = rtrim(WPMU_PLUGIN_DIR, '/');
1487
+ $loaderPath = $mustUsePluginDir.'/'.$loaderName;
1488
+
1489
+ if (!file_exists($loaderPath)) {
1490
+ return;
1491
+ }
1492
+
1493
+ $removed = @unlink($loaderPath);
1494
+
1495
+ if (!$removed) {
1496
+ $error = error_get_last();
1497
+ throw new Exception(sprintf('Unable to remove loader: %s', $error['message']));
1498
+ }
1499
+ } catch (Exception $e) {
1500
+ mwp_logger()->error('Unable to remove loader', array('exception' => $e));
1501
+ }
1502
+ }
init.php CHANGED
@@ -3,18 +3,21 @@
3
  Plugin Name: ManageWP - Worker
4
  Plugin URI: https://managewp.com
5
  Description: ManageWP Worker plugin allows you to manage your WordPress sites from one dashboard. Visit <a href="https://managewp.com">ManageWP.com</a> for more information.
6
- Version: 4.0.1
7
  Author: ManageWP
8
  Author URI: https://managewp.com
9
  License: GPL2
10
  */
11
 
12
- /*************************************************************
13
- * init.php
14
- * Initialize the communication with master
15
- * Copyright (c) 2011 Prelovac Media
16
- * www.prelovac.com
17
- **************************************************************/
 
 
 
18
  if (!defined('ABSPATH')) {
19
  exit;
20
  }
@@ -86,8 +89,8 @@ if (!function_exists('mwp_fail_safe')):
86
  if (!empty($workerSettings['dataown'])) {
87
  $userID = (int) $workerSettings['dataown'];
88
  }
89
- $body = sprintf('Worker deactivation due to an error. The site that was deactivated - %s. User email - %s (UserID: %s). The error that caused this: %s', $siteUrl, $to, $userID, $fullError);
90
- $mailFn('support@managewp.com', $title, $body);
91
 
92
  // If we're inside a cron scope, don't attempt to hide this error.
93
  if (defined('DOING_CRON') && DOING_CRON) {
@@ -120,6 +123,8 @@ if (!class_exists('MwpWorkerResponder', false)):
120
 
121
  private $container;
122
 
 
 
123
  function __construct(MWP_ServiceContainer_Interface $container)
124
  {
125
  $this->container = $container;
@@ -133,7 +138,16 @@ if (!class_exists('MwpWorkerResponder', false)):
133
  $lastResponse = $responseEvent->getResponse();
134
 
135
  if ($lastResponse !== null) {
136
- $lastResponse->send();
 
 
 
 
 
 
 
 
 
137
  exit;
138
  }
139
  } elseif ($e !== null) {
@@ -191,11 +205,11 @@ if (!function_exists('mwp_init')):
191
  spl_autoload_register('mwp_autoload', true, true);
192
  }
193
 
194
- $GLOBALS['MMB_WORKER_VERSION'] = '4.0.1';
195
- $GLOBALS['MMB_WORKER_REVISION'] = '2015-01-18 00:00:00';
196
  $GLOBALS['mmb_plugin_dir'] = WP_PLUGIN_DIR.'/'.basename(dirname(__FILE__));
197
  $GLOBALS['_mmb_item_filter'] = array();
198
- $GLOBALS['mmb_core'] = $core = $mmb_core_backup = new MMB_Core();
199
 
200
  $siteUrl = function_exists('get_site_option') ? get_site_option('siteurl') : get_option('siteurl');
201
  define('MMB_XFRAME_COOKIE', 'wordpress_'.md5($siteUrl).'_xframe');
@@ -223,7 +237,7 @@ if (!function_exists('mwp_init')):
223
  // Plugin management hooks.
224
  register_activation_hook(__FILE__, array($core, 'install'));
225
  register_deactivation_hook(__FILE__, array($core, 'deactivate'));
226
- register_uninstall_hook(__FILE__, array($core, 'uninstall'));
227
 
228
  // Don't send the "X-Frame-Options: SAMEORIGIN" header if we're logging in inside an iframe.
229
  if (isset($_COOKIE[MMB_XFRAME_COOKIE])) {
3
  Plugin Name: ManageWP - Worker
4
  Plugin URI: https://managewp.com
5
  Description: ManageWP Worker plugin allows you to manage your WordPress sites from one dashboard. Visit <a href="https://managewp.com">ManageWP.com</a> for more information.
6
+ Version: 4.1.0
7
  Author: ManageWP
8
  Author URI: https://managewp.com
9
  License: GPL2
10
  */
11
 
12
+ /*
13
+ * This file is part of the ManageWP Worker plugin.
14
+ *
15
+ * (c) ManageWP LLC <contact@managewp.com>
16
+ *
17
+ * For the full copyright and license information, please view the LICENSE
18
+ * file that was distributed with this source code.
19
+ */
20
+
21
  if (!defined('ABSPATH')) {
22
  exit;
23
  }
89
  if (!empty($workerSettings['dataown'])) {
90
  $userID = (int) $workerSettings['dataown'];
91
  }
92
+ $body = sprintf("Worker deactivation due to an error. The site that was affected - %s. User email - %s (User ID: %s). Worker version: %s (%s). The error that caused this:\n<pre>%s</pre>", $siteUrl, $to, $userID, $GLOBALS['MMB_WORKER_VERSION'], $GLOBALS['MMB_WORKER_REVISION'], $fullError);
93
+ $mailFn('dev@managewp.com', $title, $body);
94
 
95
  // If we're inside a cron scope, don't attempt to hide this error.
96
  if (defined('DOING_CRON') && DOING_CRON) {
123
 
124
  private $container;
125
 
126
+ private $responseSent = false;
127
+
128
  function __construct(MWP_ServiceContainer_Interface $container)
129
  {
130
  $this->container = $container;
138
  $lastResponse = $responseEvent->getResponse();
139
 
140
  if ($lastResponse !== null) {
141
+ if (!$this->responseSent) {
142
+ // This looks pretty ugly, but the "execute PHP" function handles fatal errors and wraps them
143
+ // in a valid action response. That fatal error may also be handled by the global fatal error
144
+ // handler, which also wraps the error in a response. We keep the state in this class, so we
145
+ // don't send a worker response twice, first time as an action response, second time as a
146
+ // global response.
147
+ // If this is to be removed, simply remove fatal error handling from the "execute PHP" action.
148
+ $lastResponse->send();
149
+ $this->responseSent = true;
150
+ }
151
  exit;
152
  }
153
  } elseif ($e !== null) {
205
  spl_autoload_register('mwp_autoload', true, true);
206
  }
207
 
208
+ $GLOBALS['MMB_WORKER_VERSION'] = '4.1.0';
209
+ $GLOBALS['MMB_WORKER_REVISION'] = '2015-04-23 00:00:00';
210
  $GLOBALS['mmb_plugin_dir'] = WP_PLUGIN_DIR.'/'.basename(dirname(__FILE__));
211
  $GLOBALS['_mmb_item_filter'] = array();
212
+ $GLOBALS['mmb_core'] = $core = $GLOBALS['mmb_core_backup'] = new MMB_Core();
213
 
214
  $siteUrl = function_exists('get_site_option') ? get_site_option('siteurl') : get_option('siteurl');
215
  define('MMB_XFRAME_COOKIE', 'wordpress_'.md5($siteUrl).'_xframe');
237
  // Plugin management hooks.
238
  register_activation_hook(__FILE__, array($core, 'install'));
239
  register_deactivation_hook(__FILE__, array($core, 'deactivate'));
240
+ register_uninstall_hook(dirname(__FILE__).'/functions.php', 'mwp_uninstall');
241
 
242
  // Don't send the "X-Frame-Options: SAMEORIGIN" header if we're logging in inside an iframe.
243
  if (isset($_COOKIE[MMB_XFRAME_COOKIE])) {
publickeys/{managewp_mt.pub → ManageWP_mt.pub} RENAMED
File without changes
readme.txt CHANGED
@@ -12,35 +12,97 @@ ManageWP is the ultimate WordPress productivity tool, allowing you to efficientl
12
 
13
  == Description ==
14
 
15
- [ManageWP](https://managewp.com/ "Manage WordPress Websites") is a revolutionary service that automates the management of multiple WordPress websites. ManageWP Worker Plugin allows your site to communicate with the service, and is needed in order to enjoy all these features:
16
 
17
- Main features:
 
18
 
19
- * Manage multiple WordPress sites securely and fast
20
- * Manage WordPress themes, plugins, users, pages and posts for all your websites from one dashboard
21
- * One click upgrades for WordPress, plugin and themes across all your sites
22
- * Schedule automatic backups of your websites (Amazon S3, Google Drive, FTP/SFTP and Dropbox supported)
23
- * Install WordPress, clone or migrate WordPress website to another domain
24
- * One click to access WP admin of any site
25
- * Bulk install themes and plugins to multiple sites at once
26
- * Bulk publish posts and pages to multiple sites at once
27
- * Add sub-users (writers, staff..) to your account
28
- * SEO Statistics, track your keyword rankings
29
- * Uptime monitoring - receive an SMS notification if your site goes down
30
 
 
 
31
 
32
- Check out the [ManageWP Tour video](http://www.youtube.com/watch?v=Cg_W9MQBWt4).
 
33
 
34
- http://www.youtube.com/watch?v=Cg_W9MQBWt4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
 
36
  ManageWP is also the creator of [ManageWP.org](https://managewp.org/ "WordPress news site"), community project capturing the pulse of the WordPress community.
37
 
38
  == Changelog ==
39
 
40
- = 4.0.0 =
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
 
42
- - New features for the [ManageWP Orion release](http://managewp.com/managewp-orion-official-announcement "ManageWP Orion Official Announcement")
43
- - Misc bug fixes and performance improvements
44
 
45
  = 3.9.30 =
46
 
12
 
13
  == Description ==
14
 
15
+ [ManageWP](https://managewp.com/ "Manage Multiple WordPress Websites") is a revolutionary service designed to automate most of your daily tasks when managing multiple WordPress websites, allowing you to use your time on more important matters.
16
 
17
+ = Everything in One Place =
18
+ Just the hassle of logging into each of your websites is enough to ruin your day. With ManageWP the data from all of your sites is compiled and shown on a single easy to use dashboard, allowing you to check up on your websites in a single glance.
19
 
20
+ = One-click Management =
21
+ With all the data on a single dashboard, all it takes is one click to perform plugin and theme updates on multiple websites. Got comments? Everything is on one single list. Or maybe you want to clean spam comments, table overhead or post revisions from all of your websites? It takes a single click.
 
 
 
 
 
 
 
 
 
22
 
23
+ = Backup & Restore =
24
+ Never leave home without a backup. With the scheduled backup tasks to remote destinations such as Amazon S3, Dropbox and Google Drive you will always have an up-to-date backup which you can use to restore your website if something happened to it (yeah, we know it was YOU who messed up the CSS!)
25
 
26
+ = Quick and Easy Migration =
27
+ Want to know how easy is to migrate a website with ManageWP? Pick a source website, pick a destination website, click Go. Yeah, it's that easy.
28
 
29
+ = Uptime Monitoring =
30
+ Be the first to know when your website is down with both email and SMS notifications, and get your website back online before anyone else notices.
31
+
32
+ = SEO & Keyword Ranking =
33
+ Be on top of your website rankings and figure out which keywords work best for you.
34
+
35
+ = Client Reports =
36
+ Keep track of what you're doing for your clients and dazzle them with a summary of your hard work.
37
+
38
+ = Is This All? =
39
+ No way! We've got a bunch of other awesome features, both free and premium, you can check out on our [ManageWP Features & Pricing Page](https://managewp.com/plans-and-pricing "ManageWP Plans & Pricing")
40
+
41
+ Check out the [ManageWP promo video](https://www.youtube.com/watch?v=C5nBQJQIfH4).
42
+
43
+ https://www.youtube.com/watch?v=C5nBQJQIfH4
44
 
45
  ManageWP is also the creator of [ManageWP.org](https://managewp.org/ "WordPress news site"), community project capturing the pulse of the WordPress community.
46
 
47
  == Changelog ==
48
 
49
+ = 4.1.0 =
50
+
51
+ - New: Incremental backup capability for [ManageWP Orion](http://managewp.com/managewp-orion-official-announcement "ManageWP Orion Official Announcement").
52
+
53
+ = 4.0.15 =
54
+
55
+ - Fix: Improve compatibility with some plugin updates in [ManageWP Orion](http://managewp.com/managewp-orion-official-announcement "ManageWP Orion Official Announcement").
56
+
57
+ = 4.0.14 =
58
+
59
+ - Fix: Show custom message when the plugin can not destroy active [ManageWP Orion](http://managewp.com/managewp-orion-official-announcement "ManageWP Orion Official Announcement") sessions when logging out.
60
+
61
+ = 4.0.13 =
62
+
63
+ - New: Destroy all admin sessions started from [ManageWP Orion](http://managewp.com/managewp-orion-official-announcement "ManageWP Orion Official Announcement") when a user logs out from the dashboard.
64
+ - Fix: Improve update detection.
65
+
66
+ = 4.0.12 =
67
+
68
+ - Fix: Improve white-labeling.
69
+ - Fix: Better compatibility with development builds of WordPress.
70
+ - Fix: Improve one-click restore functionality on non-English installations of WordPress.
71
+
72
+ = 4.0.11 =
73
+
74
+ - Fix: Better detect available updates
75
+ - Fix: Improve compatibility with other plugins
76
+
77
+ = 4.0.10 =
78
+
79
+ - Fix: Fix update functionality on some installations that use FTP credentials
80
+ - Fix: Fix Google Drive uploading on installations without cURL PHP extension
81
+
82
+ = 4.0.9 =
83
+
84
+ - New: Make the ManageWP Worker plugin upgradable through the dashboard widget
85
+ - Fix: Improve auto-connect functionality with [ManageWP Orion](http://managewp.com/managewp-orion-official-announcement "ManageWP Orion Official Announcement")
86
+
87
+ = 4.0.8 =
88
+
89
+ - Fix: Fix single-click restore functionality
90
+
91
+ = 4.0.7 =
92
+
93
+ - Fix: Fix issues related to cloning and backup restoration
94
+ - Fix: Improve precision of the hit counter
95
+ - Fix: Improve compatibility with other plugins
96
+ - Fix: Numerous small improvements and fixes
97
+
98
+ = 4.0.5 =
99
+
100
+ - Fix: Misc bug fixes and performance improvements
101
+
102
+ = 4.0.1 =
103
 
104
+ - New: New features for the [ManageWP Orion release](http://managewp.com/managewp-orion-official-announcement "ManageWP Orion Official Announcement")
105
+ - Fix: Misc bug fixes and performance improvements
106
 
107
  = 3.9.30 =
108
 
src/Google/IO/Stream.php CHANGED
@@ -171,4 +171,9 @@ class Google_IO_Stream extends Google_IO_Abstract
171
 
172
  return self::UNKNOWN_CODE;
173
  }
 
 
 
 
 
174
  }
171
 
172
  return self::UNKNOWN_CODE;
173
  }
174
+
175
+ protected function needsQuirk()
176
+ {
177
+ return false;
178
+ }
179
  }
src/MMB/Backup.php CHANGED
@@ -1423,13 +1423,16 @@ class MMB_Backup extends MMB_Core
1423
 
1424
  $task = $this->tasks[$params['task_name']];
1425
  $backups = $task['task_results'];
1426
- $result_id = !empty($params['result_id']) ? $params['result_id'] : null;
1427
  $backup = !empty($backups[$result_id]) ? $backups[$result_id] : false;
1428
- foreach ($backups as $key => $result) {
1429
- if ($result['resultUuid'] == $params['resultUuid']) {
1430
- $backup = $result;
1431
- $result_id = $key;
1432
- break;
 
 
 
1433
  }
1434
  }
1435
 
@@ -1547,7 +1550,7 @@ class MMB_Backup extends MMB_Core
1547
  );
1548
 
1549
  /* Replace options and content urls */
1550
- $this->replaceOptionsAndUrls($params['overwrite'], $params['new_user'], $params['new_password'], $params['old_user'], $params['clone_from_url'], $params['admin_email'], $params['mwp_clone'], $oldCredentialsAndOptions, $home, $params['current_tasks_tmp']);
1551
 
1552
  $newUrl = $wpdb->get_row($wpdb->prepare("SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", 'home'));
1553
  $restoreParams['newUrl'] = is_object($newUrl) ? $newUrl->option_value : null;
@@ -1785,7 +1788,7 @@ class MMB_Backup extends MMB_Core
1785
  }
1786
  }
1787
 
1788
- private function replaceOptionsAndUrls($overwrite, $newUser, $newPassword, $oldUser, $cloneFromUrl, $adminEmail, $mwpClone, $oldCredentialsAndOptions, $home, $currentTasksTmp)
1789
  {
1790
  global $wpdb;
1791
  $this->wpdb_reconnect();
@@ -1899,9 +1902,6 @@ class MMB_Backup extends MMB_Core
1899
  $query = "DELETE FROM ".$new_table_prefix."options WHERE option_name = 'user_hit_count'";
1900
  $wpdb->query($query);
1901
 
1902
- /* Restore previous backups */
1903
- $wpdb->query("UPDATE ".$new_table_prefix."options SET option_value = '".serialize($currentTasksTmp)."' WHERE option_name = 'mwp_backup_tasks'");
1904
-
1905
  /* Check for .htaccess permalinks update */
1906
  $this->replace_htaccess($home);
1907
  } else {
@@ -1950,7 +1950,7 @@ class MMB_Backup extends MMB_Core
1950
  if (!mwp_is_shell_available()) {
1951
  throw new MMB_Exception("Shell is not available");
1952
  }
1953
- $process = new Symfony_Process_Process($command, untrailingslashit(ABSPATH), null, null, 3600);
1954
  mwp_logger()->info('Database import process started', array(
1955
  'executable_location' => $mysql,
1956
  'command_line' => $process->getCommandLine(),
@@ -4129,7 +4129,7 @@ class MMB_Backup extends MMB_Core
4129
  $return = $this->google_drive_backup($account_info['mwp_google_drive']);
4130
  $this->wpdb_reconnect();
4131
 
4132
- if (!(is_array($return) && isset($return['error']))) {
4133
  $this->update_status($task_name, $this->statuses['google_drive'], true);
4134
  $this->update_status($task_name, $this->statuses['finished'], true);
4135
  }
@@ -4137,12 +4137,14 @@ class MMB_Backup extends MMB_Core
4137
 
4138
  $tasks = $this->tasks;
4139
  @file_put_contents(MWP_BACKUP_DIR.'/mwp_db/index.php', '');
4140
- if ($return == true && $del_host_file) {
4141
  @unlink($backup_file);
4142
  unset($tasks[$task_name]['task_results'][count($tasks[$task_name]['task_results']) - 1]['server']);
4143
  }
4144
  $this->update_tasks($tasks);
4145
- $return = $this->tasks[$task_name]['task_results'][$taskResultKey];
 
 
4146
  } else {
4147
  $return = array(
4148
  'error' => 'Backup file not found on your server. Please try again.',
@@ -4214,8 +4216,15 @@ class MMB_Backup extends MMB_Core
4214
  */
4215
  public function wpdb_reconnect()
4216
  {
 
4217
  global $wpdb;
4218
 
 
 
 
 
 
 
4219
  if (class_exists('wpdb') && function_exists('wp_set_wpdb_vars')) {
4220
  @mysql_close($wpdb->dbh);
4221
  $wpdb = new wpdb(DB_USER, DB_PASSWORD, DB_NAME, DB_HOST);
@@ -4326,6 +4335,31 @@ class MMB_Backup extends MMB_Core
4326
 
4327
  $this->notifyMyself('mmb_remote_upload', $args);
4328
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4329
  }
4330
 
4331
  if (!function_exists('get_all_files_from_dir')) {
@@ -4559,6 +4593,9 @@ function restore_migrate_urls()
4559
 
4560
  function restore_htaccess()
4561
  {
 
 
 
4562
  $htaccessRealpath = realpath(ABSPATH.'.htaccess');
4563
 
4564
  if ($htaccessRealpath) {
@@ -4568,7 +4605,7 @@ function restore_htaccess()
4568
  if (isset($GLOBALS['wp_rewrite'])) {
4569
  $wpRewrite = $GLOBALS['wp_rewrite'];
4570
  } else {
4571
- $wpRewrite = new WP_Rewrite();
4572
  }
4573
 
4574
  $wpRewrite->flush_rules(true);
1423
 
1424
  $task = $this->tasks[$params['task_name']];
1425
  $backups = $task['task_results'];
1426
+ $result_id = isset($params['result_id']) ? $params['result_id'] : null;
1427
  $backup = !empty($backups[$result_id]) ? $backups[$result_id] : false;
1428
+
1429
+ if (!empty($params['resultUuid'])) {
1430
+ foreach ($backups as $key => $result) {
1431
+ if ($result['resultUuid'] == $params['resultUuid']) {
1432
+ $backup = $result;
1433
+ $result_id = $key;
1434
+ break;
1435
+ }
1436
  }
1437
  }
1438
 
1550
  );
1551
 
1552
  /* Replace options and content urls */
1553
+ $this->replaceOptionsAndUrls($params['overwrite'], $params['new_user'], $params['new_password'], $params['old_user'], $params['clone_from_url'], $params['admin_email'], $params['mwp_clone'], $oldCredentialsAndOptions, $home);
1554
 
1555
  $newUrl = $wpdb->get_row($wpdb->prepare("SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", 'home'));
1556
  $restoreParams['newUrl'] = is_object($newUrl) ? $newUrl->option_value : null;
1788
  }
1789
  }
1790
 
1791
+ private function replaceOptionsAndUrls($overwrite, $newUser, $newPassword, $oldUser, $cloneFromUrl, $adminEmail, $mwpClone, $oldCredentialsAndOptions, $home)
1792
  {
1793
  global $wpdb;
1794
  $this->wpdb_reconnect();
1902
  $query = "DELETE FROM ".$new_table_prefix."options WHERE option_name = 'user_hit_count'";
1903
  $wpdb->query($query);
1904
 
 
 
 
1905
  /* Check for .htaccess permalinks update */
1906
  $this->replace_htaccess($home);
1907
  } else {
1950
  if (!mwp_is_shell_available()) {
1951
  throw new MMB_Exception("Shell is not available");
1952
  }
1953
+ $process = new Symfony_Process_Process($command, untrailingslashit(ABSPATH), $this->getEnv(), null, 3600);
1954
  mwp_logger()->info('Database import process started', array(
1955
  'executable_location' => $mysql,
1956
  'command_line' => $process->getCommandLine(),
4129
  $return = $this->google_drive_backup($account_info['mwp_google_drive']);
4130
  $this->wpdb_reconnect();
4131
 
4132
+ if (!isset($return['error'])) {
4133
  $this->update_status($task_name, $this->statuses['google_drive'], true);
4134
  $this->update_status($task_name, $this->statuses['finished'], true);
4135
  }
4137
 
4138
  $tasks = $this->tasks;
4139
  @file_put_contents(MWP_BACKUP_DIR.'/mwp_db/index.php', '');
4140
+ if ($return === true && $del_host_file) {
4141
  @unlink($backup_file);
4142
  unset($tasks[$task_name]['task_results'][count($tasks[$task_name]['task_results']) - 1]['server']);
4143
  }
4144
  $this->update_tasks($tasks);
4145
+ if (!isset($return['error'])) {
4146
+ $return = $this->tasks[$task_name]['task_results'][$taskResultKey];
4147
+ }
4148
  } else {
4149
  $return = array(
4150
  'error' => 'Backup file not found on your server. Please try again.',
4216
  */
4217
  public function wpdb_reconnect()
4218
  {
4219
+ /** @var wpdb $wpdb */
4220
  global $wpdb;
4221
 
4222
+ if (is_callable(array($wpdb, 'check_connection'))) {
4223
+ $wpdb->check_connection();
4224
+
4225
+ return;
4226
+ }
4227
+
4228
  if (class_exists('wpdb') && function_exists('wp_set_wpdb_vars')) {
4229
  @mysql_close($wpdb->dbh);
4230
  $wpdb = new wpdb(DB_USER, DB_PASSWORD, DB_NAME, DB_HOST);
4335
 
4336
  $this->notifyMyself('mmb_remote_upload', $args);
4337
  }
4338
+
4339
+ /**
4340
+ * @return array|null
4341
+ */
4342
+ private function getEnv()
4343
+ {
4344
+ $lang = getenv('LANG');
4345
+
4346
+ if (preg_match('{^.*\.UTF-?8$}i', $lang)) {
4347
+ // Allow the environment to be inherited.
4348
+ return null;
4349
+ }
4350
+
4351
+ if (!$lang) {
4352
+ $lang = 'en_US';
4353
+ }
4354
+
4355
+ $langParts = explode('.', $lang);
4356
+
4357
+ if (!isset($langParts[1]) || $langParts[1] !== 'UTF-8') {
4358
+ $lang = $langParts[0].'.UTF-8';
4359
+ }
4360
+
4361
+ return array('LANG' => $lang);
4362
+ }
4363
  }
4364
 
4365
  if (!function_exists('get_all_files_from_dir')) {
4593
 
4594
  function restore_htaccess()
4595
  {
4596
+ // This has to be done because it contains the function save_mod_rewrite_rules().
4597
+ include_once ABSPATH.'wp-admin/includes/admin.php';
4598
+
4599
  $htaccessRealpath = realpath(ABSPATH.'.htaccess');
4600
 
4601
  if ($htaccessRealpath) {
4605
  if (isset($GLOBALS['wp_rewrite'])) {
4606
  $wpRewrite = $GLOBALS['wp_rewrite'];
4607
  } else {
4608
+ $wpRewrite = $GLOBALS['wp_rewrite'] = new WP_Rewrite();
4609
  }
4610
 
4611
  $wpRewrite->flush_rules(true);
src/MMB/Core.php CHANGED
@@ -49,8 +49,8 @@ class MMB_Core extends MMB_Helper
49
  {
50
  global $blog_id, $_mmb_item_filter, $_mmb_options;
51
 
52
- $_mmb_options = get_option('wrksettings');
53
- $_mmb_options = !empty($_mmb_options) ? $_mmb_options : array();
54
 
55
  if (is_multisite()) {
56
  $this->mmb_multisite = $blog_id;
@@ -290,23 +290,6 @@ EOF;
290
  }
291
  }
292
 
293
- public function unRegisterMustUse($loaderName)
294
- {
295
- $mustUsePluginDir = rtrim(WPMU_PLUGIN_DIR, '/');
296
- $loaderPath = $mustUsePluginDir.'/'.$loaderName;
297
-
298
- if (!file_exists($loaderPath)) {
299
- return;
300
- }
301
-
302
- $removed = @unlink($loaderPath);
303
-
304
- if (!$removed) {
305
- $error = error_get_last();
306
- throw new Exception(sprintf('Unable to remove loader: %s', $error['message']));
307
- }
308
- }
309
-
310
  /**
311
  * Plugin install callback function
312
  * Check PHP version
@@ -380,22 +363,13 @@ EOF;
380
  update_option('wrksettings', $options);
381
  }
382
 
383
- public function uninstall()
384
- {
385
- try {
386
- $this->unRegisterMustUse('0-worker.php');
387
- } catch (Exception $e) {
388
- mwp_logger()->error('Unable to remove loader', array('exception' => $e));
389
- }
390
- }
391
-
392
  /**
393
  * Deletes options for communication with master
394
  */
395
  public function deactivate($deactivate = false)
396
  {
397
- $this->uninstall();
398
  /** @var wpdb $wpdb */
 
399
  global $current_user, $wpdb, $_wp_using_ext_object_cache;
400
  $_wp_using_ext_object_cache = false;
401
 
@@ -483,7 +457,7 @@ EOF;
483
 
484
  ob_start();
485
  @unlink(dirname(__FILE__));
486
- $upgrader = new Plugin_Upgrader();
487
  $result = $upgrader->run(
488
  array(
489
  'package' => $params['download_url'],
49
  {
50
  global $blog_id, $_mmb_item_filter, $_mmb_options;
51
 
52
+ $_mmb_options = get_option('wrksettings');
53
+ $_mmb_options = !empty($_mmb_options) ? $_mmb_options : array();
54
 
55
  if (is_multisite()) {
56
  $this->mmb_multisite = $blog_id;
290
  }
291
  }
292
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
293
  /**
294
  * Plugin install callback function
295
  * Check PHP version
363
  update_option('wrksettings', $options);
364
  }
365
 
 
 
 
 
 
 
 
 
 
366
  /**
367
  * Deletes options for communication with master
368
  */
369
  public function deactivate($deactivate = false)
370
  {
 
371
  /** @var wpdb $wpdb */
372
+ mwp_uninstall();
373
  global $current_user, $wpdb, $_wp_using_ext_object_cache;
374
  $_wp_using_ext_object_cache = false;
375
 
457
 
458
  ob_start();
459
  @unlink(dirname(__FILE__));
460
+ $upgrader = new Plugin_Upgrader(mwp_container()->getUpdaterSkin());
461
  $result = $upgrader->run(
462
  array(
463
  'package' => $params['download_url'],
src/MMB/Helper.php CHANGED
@@ -11,24 +11,6 @@ class MMB_Helper
11
 
12
  public $mmb_multisite;
13
 
14
- /**
15
- * Initializes the file system
16
- */
17
- public function init_filesystem()
18
- {
19
- global $wp_filesystem;
20
-
21
- if (!$wp_filesystem || !is_object($wp_filesystem)) {
22
- WP_Filesystem();
23
- }
24
-
25
- if (!is_object($wp_filesystem)) {
26
- return false;
27
- }
28
-
29
- return true;
30
- }
31
-
32
  public function mmb_get_user_info($user_info = false, $info = 'login')
33
  {
34
  if ($user_info === false) {
@@ -107,21 +89,9 @@ class MMB_Helper
107
  return $this->mmb_get_sitemeta_transient($option_name);
108
  }
109
 
110
- global $wp_version;
111
-
112
- if (version_compare($wp_version, '2.7.9', '<=')) {
113
- return get_option($option_name);
114
- } else {
115
- if (version_compare($wp_version, '2.9.9', '<=')) {
116
- $transient = get_option('_transient_'.$option_name);
117
-
118
- return apply_filters("transient_".$option_name, $transient);
119
- } else {
120
- $transient = get_option('_site_transient_'.$option_name);
121
 
122
- return apply_filters("site_transient_".$option_name, $transient);
123
- }
124
- }
125
  }
126
 
127
  public function mmb_delete_transient($option_name)
@@ -130,17 +100,7 @@ class MMB_Helper
130
  return;
131
  }
132
 
133
- global $wp_version;
134
-
135
- if (version_compare($wp_version, '2.7.9', '<=')) {
136
- delete_option($option_name);
137
- } else {
138
- if (version_compare($wp_version, '2.9.9', '<=')) {
139
- delete_option('_transient_'.$option_name);
140
- } else {
141
- delete_option('_site_transient_'.$option_name);
142
- }
143
- }
144
  }
145
 
146
  public function mmb_get_sitemeta_transient($option_name)
@@ -323,46 +283,6 @@ class MMB_Helper
323
  return $crypted;
324
  }
325
 
326
- public function check_if_user_exists($username = false)
327
- {
328
- global $wpdb;
329
-
330
- if (empty($username)) {
331
- return false;
332
- }
333
-
334
- if (!function_exists('username_exists')) {
335
- require_once ABSPATH.WPINC.'/registration.php';
336
- }
337
-
338
- require_once ABSPATH.'wp-includes/pluggable.php';
339
-
340
- if (username_exists($username) == null) {
341
- return false;
342
- }
343
-
344
- $user = (array) $this->mmb_get_user_info($username);
345
- if (
346
- (isset($user[$wpdb->prefix.'user_level']) && $user[$wpdb->prefix.'user_level'] == 10)
347
- || isset($user[$wpdb->prefix.'capabilities']['administrator'])
348
- || (isset($user['caps']['administrator']) && $user['caps']['administrator'] == 1)
349
- ) {
350
- return true;
351
- }
352
-
353
- return false;
354
- }
355
-
356
- public function refresh_updates()
357
- {
358
- if (rand(1, 3) == '2') {
359
- require_once ABSPATH.WPINC.'/update.php';
360
- wp_update_plugins();
361
- wp_update_themes();
362
- wp_version_check();
363
- }
364
- }
365
-
366
  public function remove_http($url = '')
367
  {
368
  if ($url == 'http://' or $url == 'https://') {
@@ -401,23 +321,6 @@ class MMB_Helper
401
  }
402
  }
403
 
404
- public function return_bytes($val)
405
- {
406
- $val = trim($val);
407
- $last = strtolower($val[strlen($val) - 1]);
408
- switch ($last) {
409
- // The 'G' modifier is available since PHP 5.1.0
410
- case 'g':
411
- $val *= 1024;
412
- case 'm':
413
- $val *= 1024;
414
- case 'k':
415
- $val *= 1024;
416
- }
417
-
418
- return $val;
419
- }
420
-
421
  public function w3tc_flush($flushAll = false)
422
  {
423
  if ($flushAll) {
@@ -468,19 +371,4 @@ class MMB_Helper
468
 
469
  return $users_authors;
470
  }
471
-
472
- private function verifySignature($data, $signature, $publicKey)
473
- {
474
- if (function_exists('openssl_verify')) {
475
- return (openssl_verify($data, $signature, $publicKey) === 1);
476
- }
477
-
478
- require_once dirname(__FILE__).'/../PHPSecLib/Crypt/RSA.php';
479
- $rsa = new Crypt_RSA();
480
- $rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
481
- $rsa->loadKey($publicKey);
482
- $verify = $rsa->verify($data, $signature);
483
-
484
- return $verify;
485
- }
486
  }
11
 
12
  public $mmb_multisite;
13
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  public function mmb_get_user_info($user_info = false, $info = 'login')
15
  {
16
  if ($user_info === false) {
89
  return $this->mmb_get_sitemeta_transient($option_name);
90
  }
91
 
92
+ $transient = get_option('_site_transient_'.$option_name);
 
 
 
 
 
 
 
 
 
 
93
 
94
+ return apply_filters("site_transient_".$option_name, $transient);
 
 
95
  }
96
 
97
  public function mmb_delete_transient($option_name)
100
  return;
101
  }
102
 
103
+ delete_option('_site_transient_'.$option_name);
 
 
 
 
 
 
 
 
 
 
104
  }
105
 
106
  public function mmb_get_sitemeta_transient($option_name)
283
  return $crypted;
284
  }
285
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
286
  public function remove_http($url = '')
287
  {
288
  if ($url == 'http://' or $url == 'https://') {
321
  }
322
  }
323
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
324
  public function w3tc_flush($flushAll = false)
325
  {
326
  if ($flushAll) {
371
 
372
  return $users_authors;
373
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
374
  }
src/MMB/Installer.php CHANGED
@@ -84,10 +84,8 @@ class MMB_Installer extends MMB_Core
84
  include_once ABSPATH.'wp-admin/includes/class-wp-upgrader.php';
85
  }
86
 
87
- $upgrader_skin = new WP_Upgrader_Skin();
88
- $upgrader_skin->done_header = true;
89
-
90
- $upgrader = new WP_Upgrader($upgrader_skin);
91
  $destination = $type == 'themes' ? WP_CONTENT_DIR.'/themes' : WP_PLUGIN_DIR;
92
  $clear_destination = isset($clear_destination) ? $clear_destination : false;
93
 
@@ -160,6 +158,18 @@ class MMB_Installer extends MMB_Core
160
  @ob_clean();
161
  $this->mmb_maintenance_mode(false);
162
 
 
 
 
 
 
 
 
 
 
 
 
 
163
  return $install_info;
164
  }
165
 
@@ -329,7 +339,7 @@ class MMB_Installer extends MMB_Core
329
  include_once ABSPATH.'wp-admin/includes/class-wp-upgrader.php';
330
  }
331
 
332
- $core = new Core_Upgrader();
333
  $result = $core->upgrade($current_update);
334
  $this->mmb_maintenance_mode(false);
335
  if (is_wp_error($result)) {
@@ -466,8 +476,8 @@ class MMB_Installer extends MMB_Core
466
  }
467
  }
468
  $return = array();
469
- if (class_exists('Plugin_Upgrader') && class_exists('Bulk_Plugin_Upgrader_Skin')) {
470
- $upgrader = new Plugin_Upgrader(new Bulk_Plugin_Upgrader_Skin(compact('nonce', 'url')));
471
  $result = $upgrader->bulk_upgrade(array_keys($plugins));
472
  if (!function_exists('wp_update_plugins')) {
473
  include_once ABSPATH.'wp-includes/update.php';
@@ -483,7 +493,6 @@ class MMB_Installer extends MMB_Core
483
  if (!empty($result[$plugin_slug]) || (isset($current->checked[$plugin_slug]) && version_compare(array_search($plugin_slug, $versions), $current->checked[$plugin_slug], '<') == true)) {
484
  $return[$plugin_slug] = 1;
485
  } else {
486
- update_option('mmb_forcerefresh', true);
487
  $return[$plugin_slug] = 'Could not refresh upgrade transients, please reload website data';
488
  }
489
  }
@@ -524,8 +533,8 @@ class MMB_Installer extends MMB_Core
524
  }
525
  }
526
  }
527
- if (class_exists('Theme_Upgrader') && class_exists('Bulk_Theme_Upgrader_Skin')) {
528
- $upgrader = new Theme_Upgrader(new Bulk_Theme_Upgrader_Skin(compact('title', 'nonce', 'url', 'theme')));
529
  $result = $upgrader->bulk_upgrade($themes);
530
 
531
  if (!function_exists('wp_update_themes')) {
@@ -543,7 +552,6 @@ class MMB_Installer extends MMB_Core
543
  if (!empty($result[$theme_tmp]) || (isset($current->checked[$theme_tmp]) && version_compare(array_search($theme_tmp, $versions), $current->checked[$theme_tmp], '<') == true)) {
544
  $return[$theme_tmp] = 1;
545
  } else {
546
- update_option('mmb_forcerefresh', true);
547
  $return[$theme_tmp] = 'Could not refresh upgrade transients, please reload website data';
548
  }
549
  }
@@ -659,7 +667,7 @@ class MMB_Installer extends MMB_Core
659
  $upgrader_skin = new WP_Upgrader_Skin();
660
  $upgrader_skin->done_header = true;
661
  $upgrader = new WP_Upgrader();
662
- @$update_result = $upgrader->run(
663
  array(
664
  'package' => $update['url'],
665
  'destination' => isset($update['type']) && $update['type'] == 'theme' ? WP_CONTENT_DIR.'/themes' : WP_PLUGIN_DIR,
@@ -712,10 +720,6 @@ class MMB_Installer extends MMB_Core
712
  include_once ABSPATH.'wp-admin/includes/plugin.php';
713
  }
714
  foreach ($current->response as $plugin_path => $plugin_data) {
715
- if ($plugin_path == 'worker/init.php') {
716
- continue;
717
- }
718
-
719
  $data = get_plugin_data(WP_PLUGIN_DIR.'/'.$plugin_path);
720
  if (isset($data['Name']) && in_array($data['Name'], $filter)) {
721
  continue;
@@ -745,7 +749,7 @@ class MMB_Installer extends MMB_Core
745
  $current = $this->mmb_get_transient('update_themes');
746
  if (!empty($current->response)) {
747
  foreach ((array) $all_themes as $theme_template => $theme_data) {
748
- if (isset($theme_data->{'Parent Theme'}) && !empty($theme_data->{'Parent Theme'})) {
749
  continue;
750
  }
751
 
84
  include_once ABSPATH.'wp-admin/includes/class-wp-upgrader.php';
85
  }
86
 
87
+ $upgrader = new WP_Upgrader(mwp_container()->getUpdaterSkin());
88
+ $upgrader->init();
 
 
89
  $destination = $type == 'themes' ? WP_CONTENT_DIR.'/themes' : WP_PLUGIN_DIR;
90
  $clear_destination = isset($clear_destination) ? $clear_destination : false;
91
 
158
  @ob_clean();
159
  $this->mmb_maintenance_mode(false);
160
 
161
+ if (mwp_container()->getRequestStack()->getMasterRequest()->getProtocol() >= 1) {
162
+ // WP_Error won't get JSON encoded, so unwrap the error here.
163
+ foreach ($install_info as $key => $value) {
164
+ if ($value instanceof WP_Error) {
165
+ $install_info[$key] = array(
166
+ 'error' => $value->get_error_message(),
167
+ 'code' => $value->get_error_code(),
168
+ );
169
+ }
170
+ }
171
+ }
172
+
173
  return $install_info;
174
  }
175
 
339
  include_once ABSPATH.'wp-admin/includes/class-wp-upgrader.php';
340
  }
341
 
342
+ $core = new Core_Upgrader(mwp_container()->getUpdaterSkin());
343
  $result = $core->upgrade($current_update);
344
  $this->mmb_maintenance_mode(false);
345
  if (is_wp_error($result)) {
476
  }
477
  }
478
  $return = array();
479
+ if (class_exists('Plugin_Upgrader')) {
480
+ $upgrader = new Plugin_Upgrader(mwp_container()->getUpdaterSkin());
481
  $result = $upgrader->bulk_upgrade(array_keys($plugins));
482
  if (!function_exists('wp_update_plugins')) {
483
  include_once ABSPATH.'wp-includes/update.php';
493
  if (!empty($result[$plugin_slug]) || (isset($current->checked[$plugin_slug]) && version_compare(array_search($plugin_slug, $versions), $current->checked[$plugin_slug], '<') == true)) {
494
  $return[$plugin_slug] = 1;
495
  } else {
 
496
  $return[$plugin_slug] = 'Could not refresh upgrade transients, please reload website data';
497
  }
498
  }
533
  }
534
  }
535
  }
536
+ if (class_exists('Theme_Upgrader')) {
537
+ $upgrader = new Theme_Upgrader(mwp_container()->getUpdaterSkin());
538
  $result = $upgrader->bulk_upgrade($themes);
539
 
540
  if (!function_exists('wp_update_themes')) {
552
  if (!empty($result[$theme_tmp]) || (isset($current->checked[$theme_tmp]) && version_compare(array_search($theme_tmp, $versions), $current->checked[$theme_tmp], '<') == true)) {
553
  $return[$theme_tmp] = 1;
554
  } else {
 
555
  $return[$theme_tmp] = 'Could not refresh upgrade transients, please reload website data';
556
  }
557
  }
667
  $upgrader_skin = new WP_Upgrader_Skin();
668
  $upgrader_skin->done_header = true;
669
  $upgrader = new WP_Upgrader();
670
+ @$update_result = $upgrader->run(
671
  array(
672
  'package' => $update['url'],
673
  'destination' => isset($update['type']) && $update['type'] == 'theme' ? WP_CONTENT_DIR.'/themes' : WP_PLUGIN_DIR,
720
  include_once ABSPATH.'wp-admin/includes/plugin.php';
721
  }
722
  foreach ($current->response as $plugin_path => $plugin_data) {
 
 
 
 
723
  $data = get_plugin_data(WP_PLUGIN_DIR.'/'.$plugin_path);
724
  if (isset($data['Name']) && in_array($data['Name'], $filter)) {
725
  continue;
749
  $current = $this->mmb_get_transient('update_themes');
750
  if (!empty($current->response)) {
751
  foreach ((array) $all_themes as $theme_template => $theme_data) {
752
+ if (!empty($theme_data['Parent Theme'])) {
753
  continue;
754
  }
755
 
src/MMB/Stats.php CHANGED
@@ -25,11 +25,11 @@ class MMB_Stats extends MMB_Core
25
  }
26
 
27
  if (!empty($options['approvedComments'])) {
28
- $siteStatistics['approvedComments'] = (int) $wpdb->get_var("SELECT COUNT(*) FROM {$prefix}comments WHERE comment_approved='1'");
29
  }
30
 
31
  if (!empty($options['activePlugins'])) {
32
- $siteStatistics['activePlugins'] = count((array) array(get_option('active_plugins', array())));
33
  }
34
 
35
  if (!empty($options['publishedPosts'])) {
@@ -391,27 +391,18 @@ class MMB_Stats extends MMB_Core
391
  include_once ABSPATH.'wp-admin/includes/update.php';
392
 
393
  $stats = $this->mmb_parse_action_params('pre_init_stats', $params, $this);
394
- $num = extract($params);
395
-
396
- if (function_exists('w3tc_pgcache_flush') || function_exists('wp_cache_clear_cache')) {
397
- $this->mmb_delete_transient('update_core');
398
- $this->mmb_delete_transient('update_plugins');
399
- $this->mmb_delete_transient('update_themes');
400
- @wp_version_check();
401
- @wp_update_plugins();
402
- @wp_update_themes();
403
- }
404
 
405
  if ($params['refresh'] == 'transient') {
406
- $current = $this->mmb_get_transient('update_core');
407
- if (isset($current->last_checked) || get_option('mmb_forcerefresh')) {
408
- update_option('mmb_forcerefresh', false);
409
- if (time() - $current->last_checked > 7200) {
410
- @wp_version_check();
411
- @wp_update_plugins();
412
- @wp_update_themes();
413
- }
414
  }
 
 
 
 
415
  }
416
 
417
  /** @var $wpdb wpdb */
@@ -433,6 +424,8 @@ class MMB_Stats extends MMB_Core
433
  $stats['blog_public'] = get_option('blog_public');
434
  $stats['timezone'] = get_option('timezone_string');
435
  $stats['timezone_offset'] = get_option('gmt_offset');
 
 
436
 
437
  if (!function_exists('get_filesystem_method')) {
438
  include_once ABSPATH.'wp-admin/includes/file.php';
25
  }
26
 
27
  if (!empty($options['approvedComments'])) {
28
+ $siteStatistics['approvedComments'] = (int) $wpdb->get_var("SELECT COUNT(*) FROM {$prefix}comments c INNER JOIN {$prefix}posts p ON c.comment_post_ID = p.ID WHERE comment_approved = '1' AND p.post_status = 'publish'");
29
  }
30
 
31
  if (!empty($options['activePlugins'])) {
32
+ $siteStatistics['activePlugins'] = count((array) get_option('active_plugins', array()));
33
  }
34
 
35
  if (!empty($options['publishedPosts'])) {
391
  include_once ABSPATH.'wp-admin/includes/update.php';
392
 
393
  $stats = $this->mmb_parse_action_params('pre_init_stats', $params, $this);
394
+ extract($params);
 
 
 
 
 
 
 
 
 
395
 
396
  if ($params['refresh'] == 'transient') {
397
+ if (function_exists('w3tc_pgcache_flush') || function_exists('wp_cache_clear_cache')) {
398
+ $this->mmb_delete_transient('update_core');
399
+ $this->mmb_delete_transient('update_plugins');
400
+ $this->mmb_delete_transient('update_themes');
 
 
 
 
401
  }
402
+
403
+ wp_version_check();
404
+ wp_update_plugins();
405
+ wp_update_themes();
406
  }
407
 
408
  /** @var $wpdb wpdb */
424
  $stats['blog_public'] = get_option('blog_public');
425
  $stats['timezone'] = get_option('timezone_string');
426
  $stats['timezone_offset'] = get_option('gmt_offset');
427
+ $stats['server_ip'] = isset($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR'] : null;
428
+ $stats['hostname'] = php_uname('n');
429
 
430
  if (!function_exists('get_filesystem_method')) {
431
  include_once ABSPATH.'wp-admin/includes/file.php';
src/MWP/Action/DestroySessions.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_Action_DestroySessions extends MWP_Action_Abstract
12
+ {
13
+ public function execute()
14
+ {
15
+ $store = $this->container->getSessionStore();
16
+
17
+ return array(
18
+ 'destroyed' => $store->destroyAll(),
19
+ );
20
+ }
21
+ }
src/MWP/Action/GetState.php CHANGED
@@ -16,6 +16,10 @@ class MWP_Action_GetState extends MWP_Action_Abstract
16
 
17
  const COMMENTS = 'comments';
18
 
 
 
 
 
19
  const PLUGINS = 'plugins';
20
 
21
  const THEMES = 'themes';
@@ -41,11 +45,9 @@ class MWP_Action_GetState extends MWP_Action_Abstract
41
  $queryResult = $this->getField($queryInfo['type'], $queryInfo['options']);
42
  $end = sprintf("%.6f", microtime(true) - $start);
43
  $result[$fieldName] = array(
44
- 'type' => $queryInfo['type'],
45
- 'options' => $queryInfo['options'],
46
- 'benchmark' => $end,
47
- 'result' => $queryResult,
48
- 'resultCount' => count($queryResult),
49
  );
50
  }
51
 
@@ -61,6 +63,10 @@ class MWP_Action_GetState extends MWP_Action_Abstract
61
  return $this->getPosts($options);
62
  case self::COMMENTS:
63
  return $this->getComments($options);
 
 
 
 
64
  case self::PLUGINS:
65
  return $this->getPlugins($options);
66
  case self::THEMES:
@@ -107,6 +113,24 @@ class MWP_Action_GetState extends MWP_Action_Abstract
107
  return $comments;
108
  }
109
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
  protected function getPlugins(array $options = array())
111
  {
112
  $options += array(
16
 
17
  const COMMENTS = 'comments';
18
 
19
+ const SQL_RESULT = 'sqlResult';
20
+
21
+ const SINGLE_SQL_RESULT = 'singleSqlResult';
22
+
23
  const PLUGINS = 'plugins';
24
 
25
  const THEMES = 'themes';
45
  $queryResult = $this->getField($queryInfo['type'], $queryInfo['options']);
46
  $end = sprintf("%.6f", microtime(true) - $start);
47
  $result[$fieldName] = array(
48
+ 'type' => $queryInfo['type'],
49
+ 'benchmark' => $end,
50
+ 'result' => $queryResult,
 
 
51
  );
52
  }
53
 
63
  return $this->getPosts($options);
64
  case self::COMMENTS:
65
  return $this->getComments($options);
66
+ case self::SQL_RESULT:
67
+ return $this->getSqlResult($options);
68
+ case self::SINGLE_SQL_RESULT:
69
+ return $this->getSingleSqlResult($options);
70
  case self::PLUGINS:
71
  return $this->getPlugins($options);
72
  case self::THEMES:
113
  return $comments;
114
  }
115
 
116
+ protected function getSingleSqlResult(array $options = array())
117
+ {
118
+ $options += array(
119
+ 'query' => null,
120
+ );
121
+
122
+ return $this->container->getWordPressContext()->getDb()->get_var($options['query']);
123
+ }
124
+
125
+ protected function getSqlResult(array $options = array())
126
+ {
127
+ $options += array(
128
+ 'query' => null,
129
+ );
130
+
131
+ return $this->container->getWordPressContext()->getDb()->get_results($options['query']);
132
+ }
133
+
134
  protected function getPlugins(array $options = array())
135
  {
136
  $options += array(
src/MWP/Action/IncrementalBackup/Abstract.php ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_Action_IncrementalBackup_Abstract extends MWP_Action_Abstract
12
+ {
13
+ /**
14
+ * @param array $result
15
+ *
16
+ * @return array
17
+ */
18
+ protected function createResult(array $result)
19
+ {
20
+ return array(
21
+ 'result' => $result,
22
+ 'server' => $this->getServerStatistics()->toArray(),
23
+ );
24
+ }
25
+
26
+ /**
27
+ * Get file real path given a path relative to WordPress root.
28
+ *
29
+ * @param $relativePath
30
+ *
31
+ * @return string
32
+ */
33
+ protected function getRealPath($relativePath)
34
+ {
35
+ return realpath(untrailingslashit(ABSPATH).'/'.$relativePath);
36
+ }
37
+
38
+ /**
39
+ * @return MWP_IncrementalBackup_Model_ServerStatistics
40
+ */
41
+ private function getServerStatistics()
42
+ {
43
+ return MWP_IncrementalBackup_Model_ServerStatistics::factory();
44
+ }
45
+
46
+ /**
47
+ * @param $files
48
+ *
49
+ * @return array
50
+ */
51
+ protected function replaceWindowsPaths($files)
52
+ {
53
+ if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
54
+ foreach ($files as $key => $file) {
55
+ $files[$key]['path'] = str_replace('\\', '/', $file['path']);
56
+ }
57
+ }
58
+
59
+ return $files;
60
+ }
61
+
62
+ /**
63
+ * @param $path
64
+ *
65
+ * @return string
66
+ */
67
+ protected function replaceWindowsPath($path)
68
+ {
69
+ if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
70
+ $path = str_replace('\\', '/', $path);
71
+ }
72
+
73
+ return $path;
74
+ }
75
+ }
src/MWP/Action/IncrementalBackup/ChecksumTables.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_Action_IncrementalBackup_ChecksumTables extends MWP_Action_IncrementalBackup_Abstract
12
+ {
13
+
14
+ public function execute(array $params = array(), MWP_Worker_Request $request)
15
+ {
16
+ $query = implode(',', $params['query']);
17
+
18
+ $wpdb = $this->container->getWordPressContext()->getDb();
19
+ $results = $wpdb->get_results('CHECKSUM TABLE '.$query, ARRAY_A);
20
+ $checksum = array();
21
+
22
+ foreach ($results as $row) {
23
+ $checksum[$row['Table']] = $row['Checksum'];
24
+ }
25
+
26
+ return $this->createResult(array('checksum' => $checksum, 'db' => $this->container->getWordPressContext()->getConstant('DB_NAME')));
27
+ }
28
+ }
src/MWP/Action/IncrementalBackup/DumpTables.php ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_Action_IncrementalBackup_DumpTables extends MWP_Action_IncrementalBackup_Abstract
12
+ {
13
+ const METHOD_MYSQLDUMP = 'mysqldump';
14
+ const METHOD_PHPDUMPER = 'phpdumper';
15
+
16
+ public function execute(array $params = array(), MWP_Worker_Request $request)
17
+ {
18
+ $method = $params['method'];
19
+ $tables = $params['tables'];
20
+
21
+ $this->assertTablesExist($tables);
22
+
23
+ if (isset($params['options']) && is_array($params['options'])) {
24
+ $options = $params['options'];
25
+ } else {
26
+ $options = array();
27
+ }
28
+
29
+ $dumper = $this->getDumper($method, $options);
30
+
31
+ try {
32
+ $stream = $dumper->dump($tables);
33
+ } catch (Exception $e) {
34
+ if ($e instanceof MWP_Worker_Exception) {
35
+ throw $e;
36
+ }
37
+
38
+ // Convert any other exception to MWP_Worker_Exception
39
+ throw new MWP_Worker_Exception(MWP_Worker_Exception::BACKUP_DATABASE_FAILED, $e->getMessage(), array(
40
+ 'code' => $e->getCode(),
41
+ 'message' => $e->getMessage(),
42
+ 'type' => get_class($e),
43
+ ));
44
+ }
45
+
46
+ $file = new MWP_IncrementalBackup_Model_File();
47
+ $file->setPathname('tables.sql');
48
+ $file->setStream($stream);
49
+
50
+ $result = new MWP_IncrementalBackup_Model_FetchFilesResult();
51
+ $result->setServerStatistics(MWP_IncrementalBackup_Model_ServerStatistics::factory());
52
+ $result->setFiles(array($file));
53
+
54
+ return $result;
55
+ }
56
+
57
+ /**
58
+ * @param array $tables
59
+ *
60
+ * @throws MWP_Worker_Exception
61
+ */
62
+ private function assertTablesExist(array $tables)
63
+ {
64
+ $rows = mwp_context()->getDb()->get_results("SHOW TABLES", ARRAY_N);
65
+ foreach ($rows as $row) {
66
+ // $row is always an array with only a single member
67
+ $table = $row[0];
68
+
69
+ $index = array_search($table, $tables);
70
+ if ($index !== false) {
71
+ // Remove from $tables - don't worry, $tables has not been passed by reference :)
72
+ array_splice($tables, $index, 1);
73
+ }
74
+ }
75
+
76
+ // Tables which have not been found are located in $tables
77
+ if (count($tables)) {
78
+ throw new MWP_Worker_Exception(MWP_Worker_Exception::BACKUP_DATABASE_MISSING_TABLES, "Some tables are missing", array(
79
+ // Return an array of missing tables
80
+ 'tables' => $tables,
81
+ ));
82
+ }
83
+ }
84
+
85
+ /**
86
+ * @param string $method
87
+ *
88
+ * @param array $options
89
+ *
90
+ * @throws MWP_Worker_Exception
91
+ * @return MWP_IncrementalBackup_Database_DumperInterface
92
+ */
93
+ private function getDumper($method, array $options = array())
94
+ {
95
+ $dumperOptions = MWP_IncrementalBackup_Database_DumpOptions::createFromArray($options);
96
+
97
+ switch ($method) {
98
+ case self::METHOD_MYSQLDUMP:
99
+ $configuration = MWP_IncrementalBackup_Database_Configuration::createFromWordPressContext(mwp_context());
100
+ $dumper = new MWP_IncrementalBackup_Database_MysqlDumpDumper($configuration, $dumperOptions);
101
+
102
+ return $dumper;
103
+ case self::METHOD_PHPDUMPER:
104
+ $configuration = MWP_IncrementalBackup_Database_Configuration::createFromWordPressContext(mwp_context());
105
+ $dumper = new MWP_IncrementalBackup_Database_PhpDumper($configuration, mwp_container()->getSystemEnvironment(), $dumperOptions);
106
+
107
+ return $dumper;
108
+ default:
109
+ throw new MWP_Worker_Exception(MWP_Worker_Exception::BACKUP_DATABASE_METHOD_NOT_AVAILABLE);
110
+ break;
111
+ }
112
+ }
113
+ }
src/MWP/Action/IncrementalBackup/FetchFiles.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_Action_IncrementalBackup_FetchFiles extends MWP_Action_IncrementalBackup_Abstract
12
+ {
13
+
14
+ public function execute(array $params = array(), MWP_Worker_Request $request)
15
+ {
16
+ /**
17
+ * Each file is structured like:
18
+ * [
19
+ * "relativePath" => file path relative to ABSPATH,
20
+ * "size" => file size sent for reference,
21
+ * "offset" => number of bytes to offset hash start (integer, optional, default 0),
22
+ * "limit" => number of bytes to hash (integer, optional, default 0),
23
+ * ]
24
+ */
25
+ $requestedFiles = $params['files'];
26
+
27
+ $result = new MWP_IncrementalBackup_Model_FetchFilesResult();
28
+
29
+ foreach ($requestedFiles as $requestedFile) {
30
+ $relativePath = $requestedFile['relativePath'];
31
+ $realPath = $this->getRealPath($relativePath);
32
+ $offset = isset($requestedFile['offset']) ? $requestedFile['offset'] : 0;
33
+ $limit = isset($requestedFile['limit']) ? $requestedFile['limit'] : -1;
34
+
35
+ $file = new MWP_IncrementalBackup_Model_File();
36
+ $file->setPathname($requestedFile['relativePath']);
37
+ $file->setStream(new MWP_Stream_Limit(new MWP_Stream_LazyFile($realPath), $offset, $limit));
38
+ $result->addFile($file);
39
+ }
40
+
41
+ $result->setServerStatistics(MWP_IncrementalBackup_Model_ServerStatistics::factory());
42
+
43
+ return $result;
44
+ }
45
+ }
src/MWP/Action/IncrementalBackup/HashFiles.php ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_Action_IncrementalBackup_HashFiles extends MWP_Action_IncrementalBackup_Abstract
12
+ {
13
+ // 100MB
14
+ const UNIX_HASH_THRESHOLD = 104857600;
15
+
16
+ // 100KB
17
+ const MAX_CHUNK_SIZE = 102400;
18
+
19
+ public function execute(array $params = array(), MWP_Worker_Request $request)
20
+ {
21
+ $hashComputer = new MWP_IncrementalBackup_HashComputer();
22
+
23
+ /**
24
+ * Each file is structured like:
25
+ * [
26
+ * "relativePath" => file path relative to ABSPATH,
27
+ * "size" => file size sent for reference,
28
+ * "offset" => number of bytes to offset hash start (integer, optional, default 0),
29
+ * "limit" => number of bytes to hash (integer, optional, default 0),
30
+ * "forcePartialHashing" => partially hashes file instead of md5_file always (boolean, optional, default false),
31
+ * ]
32
+ */
33
+ $files = $params['files'];
34
+ $result = array();
35
+
36
+ // Allow overriding max chunk byte size per request for doing partial hashes
37
+ $chunkByteSize = isset($params['maxChunkByteSize']) ? $params['maxChunkByteSize'] : self::MAX_CHUNK_SIZE;
38
+ $hashComputer->setMaxChunkByteSize($chunkByteSize);
39
+
40
+ $unixHashThreshold = isset($params['unixMd5Threshold']) ? $params['unixMd5Threshold'] : self::UNIX_HASH_THRESHOLD;
41
+
42
+ foreach ($files as $file) {
43
+ $relativePath = $file['path'];
44
+ $size = $file['size'];
45
+ $offset = isset($file['offset']) ? $file['offset'] : 0;
46
+ $limit = isset($file['limit']) ? $file['limit'] : 0;
47
+ $forcePartial = isset($file['forcePartialHashing']) ? $file['forcePartialHashing'] : false;
48
+ $realPath = $this->getRealPath($relativePath);
49
+
50
+ // Run a unix command to generate md5 hash if file size exceeds threshold
51
+ // Ignore partial requests for big files because of speed problems
52
+ if ($size > $unixHashThreshold && $offset === 0 && $limit === 0) {
53
+ $hash = $hashComputer->computeUnixMd5Sum($realPath);
54
+
55
+ if ($hash !== null) {
56
+ $result[] = array(
57
+ 'path' => $relativePath,
58
+ 'hash' => $hash,
59
+ );
60
+
61
+ continue;
62
+ }
63
+ // In case of a failed hashing fall back bellow to compute md5 hash from PHP
64
+ }
65
+
66
+ $hash = $hashComputer->computeMd5Hash($realPath, $offset, $limit, $forcePartial);
67
+ $result[] = array(
68
+ 'path' => $relativePath,
69
+ 'hash' => $hash,
70
+ );
71
+ }
72
+
73
+ return $this->createResult(array(
74
+ 'files' => $result,
75
+ ));
76
+ }
77
+ }
src/MWP/Action/IncrementalBackup/ListFiles.php ADDED
@@ -0,0 +1,220 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ /*
12
+ * This file is part of the ManageWP Worker plugin.
13
+ *
14
+ * (c) ManageWP LLC <contact@managewp.com>
15
+ *
16
+ * For the full copyright and license information, please view the LICENSE
17
+ * file that was distributed with this source code.
18
+ */
19
+
20
+ class MWP_Action_IncrementalBackup_ListFiles extends MWP_Action_IncrementalBackup_Abstract
21
+ {
22
+ /**
23
+ * Return a list of all files
24
+ *
25
+ * @param array $params
26
+ * @param MWP_Worker_Request $request
27
+ *
28
+ * @return array
29
+ */
30
+ public function queryFiles(array $params = array(), MWP_Worker_Request $request)
31
+ {
32
+ if (isset($params['query']) && is_array($params['query'])) {
33
+ $files = $this->getFilesInfo($params['query']);
34
+ } else {
35
+ $files = $this->listFiles(ABSPATH, true);
36
+ }
37
+
38
+ $files = $this->replaceWindowsPaths($files);
39
+
40
+ return $this->createResult(array('files' => $files));
41
+ }
42
+
43
+ /**
44
+ * @param array $params
45
+ * @param MWP_Worker_Request $request
46
+ *
47
+ * @return array
48
+ */
49
+ public function listDirectories(array $params = array(), MWP_Worker_Request $request)
50
+ {
51
+ $directories = $params['directories'];
52
+
53
+ $result = array();
54
+
55
+ foreach ($directories as $directory) {
56
+ $path = $directory['path'];
57
+ $recursive = isset($directory['recursive']) ? $directory['recursive'] : false;
58
+ $offset = isset($directory['offset']) ? $directory['offset'] : 0;
59
+ $limit = isset($directory['limit']) ? $directory['limit'] : 0;
60
+
61
+ $realPath = $this->getRealPath($path);
62
+ if (!file_exists($realPath)) {
63
+ $result[$path] = false;
64
+ continue;
65
+ }
66
+
67
+ $filesInDirectory = $this->listFiles($realPath, $recursive, $offset, $limit);
68
+ $filesInDirectory = $this->replaceWindowsPaths($filesInDirectory);
69
+ $result[$this->replaceWindowsPath($path)] = $filesInDirectory;
70
+ }
71
+
72
+ return $this->createResult(array('directories' => $result));
73
+ }
74
+
75
+ /**
76
+ * Return a list of files in the WordPress root directory, recursively
77
+ *
78
+ * @param string $rootPath
79
+ * @param bool $recursive
80
+ * @param int $offset
81
+ * @param int $limit
82
+ *
83
+ * @return array
84
+ */
85
+ private function listFiles($rootPath, $recursive = false, $offset = 0, $limit = 0)
86
+ {
87
+ $result = array();
88
+
89
+ $iterator = $this->createIterator($recursive, $rootPath);
90
+
91
+ $i = 0;
92
+
93
+ foreach ($iterator as $file) {
94
+ if ($i++ < $offset) {
95
+ continue;
96
+ }
97
+
98
+ if ($limit !== 0 && $i > $offset + $limit) {
99
+ break;
100
+ }
101
+
102
+ /** @var SplFileInfo $file */
103
+ $fileResult = $this->createFileResult($file);
104
+
105
+ $result[] = $fileResult;
106
+ }
107
+
108
+ return $result;
109
+ }
110
+
111
+ /**
112
+ * Get a list of file stats for given $files
113
+ *
114
+ * @param array $files
115
+ *
116
+ * @return array
117
+ */
118
+ protected function getFilesInfo(array $files)
119
+ {
120
+ $result = array();
121
+
122
+ foreach ($files as $path) {
123
+ $realPath = $this->getRealPath($path);
124
+
125
+ if (!file_exists($realPath)) {
126
+ $result[] = array(
127
+ 'path' => $path,
128
+ 'exists' => false,
129
+ );
130
+ continue;
131
+ }
132
+
133
+ $file = new SplFileInfo($realPath);
134
+ $result[] = $this->createFileResult($file);
135
+ }
136
+
137
+ return $result;
138
+ }
139
+
140
+ /**
141
+ * @param string $realPath
142
+ * @param string $rootPath
143
+ *
144
+ * @return string
145
+ */
146
+ private function getRelativePath($realPath, $rootPath)
147
+ {
148
+ if ($realPath === untrailingslashit($rootPath)) {
149
+ return '.';
150
+ } else {
151
+ $relative = str_replace(untrailingslashit($rootPath).'/', '', $realPath);
152
+ if ($relative == $realPath) {
153
+ $up = '';
154
+ while (($pos = strpos($realPath, $rootPath)) === false) {
155
+ $rootPath = dirname($rootPath);
156
+ $up .= '../';
157
+ }
158
+
159
+ return $up.substr($realPath, $pos + strlen($rootPath) + 1);
160
+ } else {
161
+ return $relative;
162
+ }
163
+ }
164
+ }
165
+
166
+ /**
167
+ * @param SplFileInfo $file
168
+ *
169
+ * @return array
170
+ */
171
+ private function createFileResult(SplFileInfo $file)
172
+ {
173
+ $fileResult = array(
174
+ 'path' => $this->getRelativePath($file->getRealPath(), ABSPATH),
175
+ 'size' => $file->getSize(),
176
+ 'isDirectory' => $file->isDir(),
177
+ 'isLink' => $file->isLink(),
178
+ 'owner' => $file->getOwner(),
179
+ 'group' => $file->getGroup(),
180
+ 'permissions' => $file->getPerms(),
181
+ 'exists' => true,
182
+ );
183
+
184
+ if ($file->isLink()) {
185
+ $fileResult['linkTarget'] = $file->getLinkTarget();
186
+ };
187
+
188
+ return $fileResult;
189
+ }
190
+
191
+ /**
192
+ * Create a recursive or non-recursive iterator for $path. Handles php 5.2 incompatiblity.
193
+ *
194
+ * @param bool $recursive
195
+ * @param string $path
196
+ *
197
+ * @return Iterator
198
+ */
199
+ private function createIterator($recursive, $path)
200
+ {
201
+ if ($recursive) {
202
+ // PHP 5.2.x does not have the SKIP_DOTS flag because it skips all dots by default
203
+ // The behavior was changed in PHP 5.3+ and it does not skip dots without the SKIP_DOTS flag
204
+ $php52 = version_compare(phpversion(), '5.3', '<');
205
+
206
+ if ($php52) {
207
+ $directory = new RecursiveDirectoryIterator($path);
208
+ } else {
209
+ $directory = new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS);
210
+ }
211
+
212
+ $iterator = new RecursiveIteratorIterator($directory, RecursiveIteratorIterator::SELF_FIRST);
213
+ } else {
214
+ $directory = new Symfony_Filesystem_FilesystemIterator($path, FilesystemIterator::SKIP_DOTS);
215
+ $iterator = new IteratorIterator($directory);
216
+ }
217
+
218
+ return $iterator;
219
+ }
220
+ }
src/MWP/Action/IncrementalBackup/ListTables.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_Action_IncrementalBackup_ListTables extends MWP_Action_IncrementalBackup_Abstract
12
+ {
13
+
14
+ public function listTables(array $params = array(), MWP_Worker_Request $request)
15
+ {
16
+ $wpdb = $this->container->getWordPressContext()->getDb();
17
+ $db = $this->container->getWordPressContext()->getConstant('DB_NAME');
18
+ $tables = $wpdb->get_results($wpdb->prepare('SELECT table_name AS "table", data_length as size FROM information_schema.TABLES WHERE table_schema = %s', $db), ARRAY_A);
19
+
20
+ return $this->createResult(array('tables' => $tables, 'db_prefix' => $wpdb->prefix));
21
+ }
22
+ }
src/MWP/Action/IncrementalBackup/Stats.php ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_Action_IncrementalBackup_Stats extends MWP_Action_IncrementalBackup_Abstract
12
+ {
13
+
14
+ public function execute(array $params = array(), MWP_Worker_Request $request)
15
+ {
16
+
17
+ $wpdb = $this->container->getWordPressContext()->getDb();
18
+ $getState = new MWP_Action_GetState();
19
+ $getState->setContainer($this->container);
20
+ $themesKey = MWP_Action_GetState::THEMES;
21
+ $themes = $getState->execute(array($themesKey => array('type' => $themesKey, 'options' => array())));
22
+ $pluginsKey = MWP_Action_GetState::PLUGINS;
23
+ $plugins = $getState->execute(array($pluginsKey => array('type' => $pluginsKey, 'options' => array())));
24
+ $statistics = array();
25
+ $statistics['themes'] = count($themes[$themesKey]['result']);
26
+ $statistics['plugins'] = count($plugins[$pluginsKey]['result']);
27
+ $statistics['posts'] = (int) $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->posts} WHERE post_type='post'");
28
+ $statistics['pages'] = (int) $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->posts} WHERE post_type='page'");
29
+ $statistics['uploads'] = (int) $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->posts} WHERE post_type='attachment'");
30
+ $statistics['comments'] = (int) $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->comments}");
31
+ $statistics['latest_post_title'] = $wpdb->get_var("SELECT post_title FROM {$wpdb->posts} WHERE post_type='post' AND post_status='publish' ORDER BY ID DESC LIMIT 1");
32
+ $statistics['wp_version'] = $this->container->getWordPressContext()->getVersion();
33
+ $currentTheme = $this->container->getWordPressContext()->getCurrentTheme();
34
+ $statistics['active_theme'] = $currentTheme['Name'].' v'.$currentTheme['Version'];
35
+ $statistics['platform'] = strtoupper(substr(PHP_OS, 0, 3));
36
+
37
+ if (!empty($params['file_count'])) {
38
+ $paths = !empty($params['file_paths']) ? $params['file_paths'] : array(ABSPATH);
39
+ $pathSize = array();
40
+ foreach ($paths as $path) {
41
+ $pathSize[$path] = $this->getFileCount($path);
42
+ }
43
+ $statistics['file_count'] = $pathSize;
44
+ }
45
+
46
+ return $this->createResult(array('statistic' => $statistics));
47
+ }
48
+
49
+ /**
50
+ * @param $path
51
+ *
52
+ * @return int
53
+ */
54
+ private function getFileCount($path)
55
+ {
56
+ $size = 0;
57
+ $ignore = array('.', '..');
58
+ $files = scandir($path);
59
+ foreach ($files as $file) {
60
+ if (in_array($file, $ignore)) {
61
+ continue;
62
+ }
63
+ if (is_dir(rtrim($path, '/').'/'.$file)) {
64
+ $size += $this->getFileCount(rtrim($path, '/').'/'.$file);
65
+ } else {
66
+ $size++;
67
+ }
68
+ }
69
+
70
+ return $size;
71
+ }
72
+ }
src/MWP/Action/IncrementalBackup/UploadCloner.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_Action_IncrementalBackup_UploadCloner extends MWP_Action_Abstract
12
+ {
13
+ public function execute(array $params = array(), MWP_Worker_Request $request)
14
+ {
15
+ $files = $params['files'];
16
+
17
+ $rootPath = ABSPATH;
18
+ $filesystem = new Symfony_Filesystem_Filesystem();
19
+
20
+ try {
21
+ foreach ($files as $file) {
22
+ $realpath = $rootPath.$file['pathname'];
23
+ if ($file['dir'] === true) {
24
+ $filesystem->mkdir($realpath);
25
+ } else {
26
+ $filesystem->dumpFile($realpath, $file['contents']);
27
+ }
28
+ }
29
+ } catch (Symfony_Filesystem_Exception_IOException $e) {
30
+ throw new MWP_Worker_Exception(MWP_Worker_Exception::IO_EXCEPTION, $e->getMessage());
31
+ }
32
+
33
+ return array();
34
+ }
35
+ }
src/MWP/Backup/ArrayHelper.php CHANGED
@@ -14,4 +14,19 @@ class MWP_Backup_ArrayHelper
14
  {
15
  return is_array($array) && array_key_exists($key, $array) ? $array[$key] : $default;
16
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  }
14
  {
15
  return is_array($array) && array_key_exists($key, $array) ? $array[$key] : $default;
16
  }
17
+
18
+ public static function arrayColumn($array, $columnIndex = 0)
19
+ {
20
+ $result = array();
21
+ foreach ($array as $arr) {
22
+ if (!is_array($arr)) {
23
+ continue;
24
+ }
25
+
26
+ $arr = array_values($arr);
27
+ $result[] = $arr[$columnIndex];
28
+ }
29
+
30
+ return $result;
31
+ }
32
  }
src/MWP/Backup/MysqlDump/QuerySequenceDump.php CHANGED
@@ -10,6 +10,7 @@
10
 
11
  class MWP_Backup_MysqlDump_QuerySequenceDump extends MWP_Backup_MysqlDump_MysqlDump
12
  {
 
13
  /** @var Resource File Pointer */
14
  protected $file;
15
 
@@ -19,7 +20,7 @@ class MWP_Backup_MysqlDump_QuerySequenceDump extends MWP_Backup_MysqlDump_MysqlD
19
  public function dumpToFile()
20
  {
21
  $writer = $this->getWriter();
22
- $allTables = $this->getConnection()->query('SHOW TABLES')->fetchAll(PDO::FETCH_COLUMN);
23
  $tables = array_intersect($allTables, $this->getOptions('tables', $allTables));
24
 
25
  $writer->open();
@@ -40,7 +41,7 @@ class MWP_Backup_MysqlDump_QuerySequenceDump extends MWP_Backup_MysqlDump_MysqlD
40
  foreach ($tables as $tableName) {
41
  // Get the SHOW CREATE TABLE part
42
  $content = $this->getConnection()
43
- ->query("SHOW CREATE TABLE `{$tableName}`;", PDO::FETCH_ASSOC)
44
  ->fetchAll();
45
  if (is_array($content)) {
46
  foreach ($content as $entry) {
@@ -59,7 +60,7 @@ class MWP_Backup_MysqlDump_QuerySequenceDump extends MWP_Backup_MysqlDump_MysqlD
59
  }
60
 
61
  $columns = $this->getConnection()
62
- ->query("SHOW COLUMNS IN `{$tableName}`;", PDO::FETCH_ASSOC)
63
  ->fetchAll();
64
 
65
  if (is_array($columns)) {
@@ -67,7 +68,7 @@ class MWP_Backup_MysqlDump_QuerySequenceDump extends MWP_Backup_MysqlDump_MysqlD
67
  }
68
 
69
  $allData = $this->getConnection()
70
- ->query($this->selectAllDataQuery($tableName, $columns), PDO::FETCH_ASSOC);
71
 
72
  // Go through row by row
73
  if (!$this->getOptions('skip_lock_tables')) {
10
 
11
  class MWP_Backup_MysqlDump_QuerySequenceDump extends MWP_Backup_MysqlDump_MysqlDump
12
  {
13
+
14
  /** @var Resource File Pointer */
15
  protected $file;
16
 
20
  public function dumpToFile()
21
  {
22
  $writer = $this->getWriter();
23
+ $allTables = MWP_Backup_ArrayHelper::arrayColumn($this->getConnection()->query('SHOW TABLES')->fetchAll());
24
  $tables = array_intersect($allTables, $this->getOptions('tables', $allTables));
25
 
26
  $writer->open();
41
  foreach ($tables as $tableName) {
42
  // Get the SHOW CREATE TABLE part
43
  $content = $this->getConnection()
44
+ ->query("SHOW CREATE TABLE `{$tableName}`;")
45
  ->fetchAll();
46
  if (is_array($content)) {
47
  foreach ($content as $entry) {
60
  }
61
 
62
  $columns = $this->getConnection()
63
+ ->query("SHOW COLUMNS IN `{$tableName}`;")
64
  ->fetchAll();
65
 
66
  if (is_array($columns)) {
68
  }
69
 
70
  $allData = $this->getConnection()
71
+ ->query($this->selectAllDataQuery($tableName, $columns));
72
 
73
  // Go through row by row
74
  if (!$this->getOptions('skip_lock_tables')) {
src/MWP/Event/ActionRequest.php CHANGED
@@ -21,10 +21,13 @@ class MWP_Event_ActionRequest extends Symfony_EventDispatcher_Event
21
  */
22
  private $params;
23
 
24
- public function __construct(MWP_Worker_Request $request, array $params)
 
 
25
  {
26
  $this->request = $request;
27
  $this->params = $params;
 
28
  }
29
 
30
  /**
@@ -50,4 +53,12 @@ class MWP_Event_ActionRequest extends Symfony_EventDispatcher_Event
50
  {
51
  $this->params = $params;
52
  }
 
 
 
 
 
 
 
 
53
  }
21
  */
22
  private $params;
23
 
24
+ private $actionDefinition;
25
+
26
+ public function __construct(MWP_Worker_Request $request, array $params, MWP_Action_Definition $actionDefinition)
27
  {
28
  $this->request = $request;
29
  $this->params = $params;
30
+ $this->actionDefinition = $actionDefinition;
31
  }
32
 
33
  /**
53
  {
54
  $this->params = $params;
55
  }
56
+
57
+ /**
58
+ * @return MWP_Action_Definition
59
+ */
60
+ public function getActionDefinition()
61
+ {
62
+ return $this->actionDefinition;
63
+ }
64
  }
src/MWP/EventListener/ActionException/MultipartException.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_EventListener_ActionException_MultipartException extends MWP_EventListener_ActionException_SetExceptionData
12
+ {
13
+
14
+ /**
15
+ * @var string
16
+ */
17
+ private $boundary;
18
+
19
+ public function __construct($boundary)
20
+ {
21
+ $this->boundary = $boundary;
22
+ }
23
+
24
+ public static function getSubscribedEvents()
25
+ {
26
+ return array(
27
+ MWP_Event_Events::ACTION_EXCEPTION => array('onActionException', 300),
28
+ );
29
+ }
30
+
31
+ public function onActionException(MWP_Event_ActionException $event)
32
+ {
33
+ if ($event->getRequest()->getAction() !== 'fetch_files' && $event->getRequest()->getAction() !== 'dump_tables') {
34
+ return;
35
+ }
36
+
37
+ $event->stopPropagation();
38
+ parent::onActionException($event);
39
+
40
+ $parts = array();
41
+
42
+ $parts[] = new MWP_Http_MultipartResponsePart(
43
+ array(
44
+ 'content-type' => 'application/json',
45
+ 'x-mwp-error' => 'error',
46
+ ),
47
+ json_encode($event->getData())
48
+ );
49
+
50
+ $event->setResponse(new MWP_Http_MultipartResponse($parts, $this->boundary));
51
+ }
52
+ }
src/MWP/EventListener/ActionRequest/LogRequest.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_EventListener_ActionRequest_LogRequest implements Symfony_EventDispatcher_EventSubscriberInterface
12
+ {
13
+
14
+ private $logger;
15
+
16
+ public function __construct(Monolog_Logger $logger)
17
+ {
18
+ $this->logger = $logger;
19
+ }
20
+
21
+ public static function getSubscribedEvents()
22
+ {
23
+ return array(
24
+ MWP_Event_Events::ACTION_REQUEST => array('onActionRequest', -200),
25
+ );
26
+ }
27
+
28
+ public function onActionRequest(MWP_Event_ActionRequest $event)
29
+ {
30
+ $request = $event->getRequest();
31
+ $this->logger->debug('Master request: "{action}"', array(
32
+ 'action' => $request->getAction(),
33
+ 'params' => $request->getParams(),
34
+ 'setting' => $request->getSetting(),
35
+ ));
36
+ }
37
+ }
src/MWP/EventListener/{MasterRequest → ActionRequest}/SetCurrentUser.php RENAMED
@@ -8,7 +8,7 @@
8
  * file that was distributed with this source code.
9
  */
10
 
11
- class MWP_EventListener_MasterRequest_SetCurrentUser implements Symfony_EventDispatcher_EventSubscriberInterface
12
  {
13
 
14
  private $context;
@@ -21,18 +21,34 @@ class MWP_EventListener_MasterRequest_SetCurrentUser implements Symfony_EventDis
21
  public static function getSubscribedEvents()
22
  {
23
  return array(
24
- MWP_Event_Events::MASTER_REQUEST => array('onMasterRequest', -300),
25
  );
26
  }
27
 
28
- public function onMasterRequest(MWP_Event_MasterRequest $event)
29
  {
30
  if (!$event->getRequest()->isAuthenticated()) {
31
  return;
32
  }
33
 
34
- $usernameUsed = $event->getRequest()->getUsername();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  $user = null;
 
36
 
37
  if ($usernameUsed) {
38
  $user = $this->context->getUserByUsername($usernameUsed);
@@ -48,17 +64,5 @@ class MWP_EventListener_MasterRequest_SetCurrentUser implements Symfony_EventDis
48
  }
49
 
50
  $this->context->setCurrentUser($user);
51
-
52
- /*
53
- if (isset($user)) {
54
- wp_set_current_user($user->ID);
55
- // Compatibility with All In One Security
56
- update_user_meta($user->ID, 'last_login_time', current_time('mysql'));
57
- }
58
-
59
- if (defined('ALTERNATE_WP_CRON') && !defined('DOING_AJAX') && ALTERNATE_WP_CRON === true) {
60
- define('DOING_AJAX', true);
61
- }
62
- */
63
  }
64
  }
8
  * file that was distributed with this source code.
9
  */
10
 
11
+ class MWP_EventListener_ActionRequest_SetCurrentUser implements Symfony_EventDispatcher_EventSubscriberInterface
12
  {
13
 
14
  private $context;
21
  public static function getSubscribedEvents()
22
  {
23
  return array(
24
+ MWP_Event_Events::ACTION_REQUEST => array('onActionRequest', -300),
25
  );
26
  }
27
 
28
+ public function onActionRequest(MWP_Event_ActionRequest $event)
29
  {
30
  if (!$event->getRequest()->isAuthenticated()) {
31
  return;
32
  }
33
 
34
+ $actionHook = $event->getActionDefinition()->getOption('hook_name');
35
+
36
+ if ($actionHook) {
37
+ // Set the user on the earliest hook after pluggable.php is loaded.
38
+ $hookProxy = new MWP_WordPress_HookProxy(array($this, 'setCurrentUserFromEvent'), $event);
39
+ $this->context->addAction('plugins_loaded', $hookProxy->getCallable(), -9999);
40
+
41
+ return;
42
+ }
43
+
44
+ // We're inside the MU context, so set the user immediately.
45
+ $this->setCurrentUserFromEvent($event);
46
+ }
47
+
48
+ public function setCurrentUserFromEvent(MWP_Event_ActionRequest $event)
49
+ {
50
  $user = null;
51
+ $usernameUsed = $event->getRequest()->getUsername();
52
 
53
  if ($usernameUsed) {
54
  $user = $this->context->getUserByUsername($usernameUsed);
64
  }
65
 
66
  $this->context->setCurrentUser($user);
 
 
 
 
 
 
 
 
 
 
 
 
67
  }
68
  }
src/MWP/EventListener/ActionRequest/SetSettings.php CHANGED
@@ -13,9 +13,12 @@ class MWP_EventListener_ActionRequest_SetSettings implements Symfony_EventDispat
13
 
14
  private $context;
15
 
16
- public function __construct(MWP_WordPress_Context $context)
 
 
17
  {
18
  $this->context = $context;
 
19
  }
20
 
21
  public static function getSubscribedEvents()
@@ -29,10 +32,91 @@ class MWP_EventListener_ActionRequest_SetSettings implements Symfony_EventDispat
29
  {
30
  set_time_limit(1800);
31
 
 
 
32
  $this->context->set('_wp_using_ext_object_cache', false);
33
 
34
- $data = $event->getRequest()->getData();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  if (empty($data['setting'])) {
37
  return;
38
  }
13
 
14
  private $context;
15
 
16
+ private $system;
17
+
18
+ public function __construct(MWP_WordPress_Context $context, MWP_System_Environment $system)
19
  {
20
  $this->context = $context;
21
+ $this->system = $system;
22
  }
23
 
24
  public static function getSubscribedEvents()
32
  {
33
  set_time_limit(1800);
34
 
35
+ $this->setMemoryLimit();
36
+
37
  $this->context->set('_wp_using_ext_object_cache', false);
38
 
39
+ // Alternate WP cron can run on 'init' hook.
40
+ $this->context->removeAction('init', 'wp_cron');
41
+
42
+ $this->saveWorkerConfiguration($event->getRequest()->getData());
43
+
44
+ $this->resetVersions($event);
45
+ }
46
+
47
+ /**
48
+ * Reset WordPress core versions, because a certain "security" plugin can modify it
49
+ * and break other plugins. Only do this for master requests.
50
+ *
51
+ * @param MWP_Event_ActionRequest $event
52
+ */
53
+ private function resetVersions(MWP_Event_ActionRequest $event)
54
+ {
55
+ $actionHook = $event->getActionDefinition()->getOption('hook_name');
56
+
57
+ if ($actionHook) {
58
+ // Set the user on the earliest hook after pluggable.php is loaded.
59
+ $hookProxy = new MWP_WordPress_HookProxy(array($this, 'requireVersions'));
60
+ $this->context->addAction('init', $hookProxy->getCallable(), 11);
61
 
62
+ return;
63
+ }
64
+
65
+ $this->requireVersions();
66
+ }
67
+
68
+ /**
69
+ * Callback for version resetting, has to work with PHP 5.2.
70
+ *
71
+ * @internal
72
+ */
73
+ public function requireVersions()
74
+ {
75
+ $versionFile = $this->context->getConstant('ABSPATH').$this->context->getConstant('WPINC').'/version.php';
76
+ if (!file_exists($versionFile)) {
77
+ // For whatever reason.
78
+ return;
79
+ }
80
+
81
+ include $versionFile;
82
+
83
+ $varNames = array(
84
+ 'wp_version',
85
+ 'wp_db_version',
86
+ 'tinymce_version',
87
+ 'required_php_version',
88
+ 'required_mysql_version',
89
+ );
90
+
91
+ foreach ($varNames as $varName) {
92
+ if (!isset($$varName)) {
93
+ continue;
94
+ }
95
+ $this->context->set($varName, $$varName);
96
+ }
97
+ }
98
+
99
+ /**
100
+ * By default, WordPress sets limits of 40MB for regular installations and 60MB for multi-sites.
101
+ * If the limit is lower, try to increase it a bit here.
102
+ */
103
+ private function setMemoryLimit()
104
+ {
105
+ if ($this->context->isMultisite()) {
106
+ $wantedLimit = 60 * 1024 * 1024;
107
+ } else {
108
+ $wantedLimit = 40 * 1024 * 1024;
109
+ }
110
+
111
+ $memoryLimit = $this->system->getMemoryLimit();
112
+
113
+ if ($memoryLimit !== -1 && $memoryLimit < $wantedLimit) {
114
+ ini_set('memory_limit', $wantedLimit);
115
+ }
116
+ }
117
+
118
+ private function saveWorkerConfiguration(array $data)
119
+ {
120
  if (empty($data['setting'])) {
121
  return;
122
  }
src/MWP/EventListener/ActionResponse/FetchFiles.php ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ /**
12
+ * Registered by MWP_Action_IncrementalBackup_FetchFiles and MWP_Action_IncrementalBackup_DumpTables actions
13
+ */
14
+ class MWP_EventListener_ActionResponse_FetchFiles implements Symfony_EventDispatcher_EventSubscriberInterface
15
+ {
16
+
17
+ /**
18
+ * @var string
19
+ */
20
+ private $boundary;
21
+
22
+ public function __construct($boundary)
23
+ {
24
+ $this->boundary = $boundary;
25
+ }
26
+
27
+ /**
28
+ * Set MWP_Action_IncrementalBackup_FetchFiles action response
29
+ */
30
+ public function onActionResponse(MWP_Event_ActionResponse $event)
31
+ {
32
+ if ($event->getRequest()->getAction() !== 'fetch_files' && $event->getRequest()->getAction() !== 'dump_tables') {
33
+ return;
34
+ }
35
+
36
+ // Prevent other listeners from hijacking this response
37
+ $event->stopPropagation();
38
+
39
+ /** @var MWP_IncrementalBackup_Model_FetchFilesResult $result */
40
+ $result = $event->getData();
41
+
42
+ $parts = array();
43
+
44
+ $parts[] = new MWP_Http_MultipartResponsePart(
45
+ array('content-type' => 'application/json'),
46
+ json_encode($result->getServerStatistics()->toArray())
47
+ );
48
+
49
+ foreach ($result->getFiles() as $file) {
50
+ $parts[] = new MWP_Http_MultipartResponsePart(
51
+ array(
52
+ 'content-type' => 'application/octet-stream',
53
+ 'content-location' => $file->getPathname(),
54
+ ),
55
+ $file->getStream()
56
+ );
57
+ }
58
+
59
+ $event->setResponse(new MWP_Http_MultipartResponse($parts, $this->boundary));
60
+ }
61
+
62
+ /**
63
+ * {@inheritdoc}
64
+ **/
65
+ public static function getSubscribedEvents()
66
+ {
67
+ return array(
68
+ MWP_Event_Events::ACTION_RESPONSE => array('onActionResponse', 200),
69
+ );
70
+ }
71
+ }
src/MWP/EventListener/ActionResponse/SetLegacyPhpExecutionData.php CHANGED
@@ -44,8 +44,6 @@ class MWP_EventListener_ActionResponse_SetLegacyPhpExecutionData implements Symf
44
  throw new MWP_Worker_Exception(MWP_Worker_Exception::PHP_EVAL_ERROR, sprintf('Fatal error [%s]: %s in %s on line %d', self::$errorMap[$data['fatalError']['type']], $data['fatalError']['message'], $data['fatalError']['file'], $data['fatalError']['line']));
45
  }
46
 
47
- if (isset($data['output'])) {
48
- $event->setData($data['output']);
49
- }
50
  }
51
  }
44
  throw new MWP_Worker_Exception(MWP_Worker_Exception::PHP_EVAL_ERROR, sprintf('Fatal error [%s]: %s in %s on line %d', self::$errorMap[$data['fatalError']['type']], $data['fatalError']['message'], $data['fatalError']['file'], $data['fatalError']['line']));
45
  }
46
 
47
+ $event->setData(isset($data['output']) ? $data['output'] : '');
 
 
48
  }
49
  }
src/MWP/EventListener/ActionResponse/SetLegacyWebsiteConnectionData.php CHANGED
@@ -36,20 +36,24 @@ class MWP_EventListener_ActionResponse_SetLegacyWebsiteConnectionData implements
36
  return;
37
  }
38
 
39
- $params = $event->getRequest()->getParams();
40
-
41
- if (!array_key_exists('notifications', $params)) {
42
- // This is not a legacy call.
43
  return;
44
  }
45
 
 
 
46
  $this->context->requireWpRewrite();
47
  $this->context->requireTaxonomies();
48
  $this->context->requirePostTypes();
49
  $this->context->requireTheme();
 
50
 
51
  $stats = new MMB_Stats();
52
- $this->context->optionSet('mwp_notifications', $params['notifications']);
 
 
 
 
53
  $event->setData($stats->get_initial_stats());
54
  }
55
  }
36
  return;
37
  }
38
 
39
+ if ($event->getRequest()->getProtocol() >= 100) {
 
 
 
40
  return;
41
  }
42
 
43
+ $params = $event->getRequest()->getParams();
44
+
45
  $this->context->requireWpRewrite();
46
  $this->context->requireTaxonomies();
47
  $this->context->requirePostTypes();
48
  $this->context->requireTheme();
49
+ $this->context->requireCookieConstants();
50
 
51
  $stats = new MMB_Stats();
52
+
53
+ if (!empty($params['notifications'])) {
54
+ $this->context->optionSet('mwp_notifications', $params['notifications']);
55
+ }
56
+
57
  $event->setData($stats->get_initial_stats());
58
  }
59
  }
src/MWP/EventListener/ActionResponse/SetUpdaterLog.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_EventListener_ActionResponse_SetUpdaterLog implements Symfony_EventDispatcher_EventSubscriberInterface
12
+ {
13
+
14
+ private $updaterSkin;
15
+
16
+ function __construct(MWP_Updater_TraceableUpdaterSkin $updaterSkin)
17
+ {
18
+ $this->updaterSkin = $updaterSkin;
19
+ }
20
+
21
+ public static function getSubscribedEvents()
22
+ {
23
+ return array(
24
+ MWP_Event_Events::ACTION_RESPONSE => 'onActionResponse',
25
+ );
26
+ }
27
+
28
+ public function onActionResponse(MWP_Event_ActionResponse $event)
29
+ {
30
+ $response = $event->getResponse();
31
+
32
+ if ($response === null) {
33
+ return;
34
+ }
35
+
36
+ $messages = $this->updaterSkin->get_upgrade_messages();
37
+
38
+ if (!$messages) {
39
+ return;
40
+ }
41
+
42
+ $data = $response->getContent();
43
+ $data['updaterLog'] = $messages;
44
+ $response->setContent($data);
45
+ }
46
+ }
src/MWP/EventListener/FixCompatibility.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_EventListener_FixCompatibility implements Symfony_EventDispatcher_EventSubscriberInterface
12
+ {
13
+
14
+ private $context;
15
+
16
+ public function __construct(MWP_WordPress_Context $context)
17
+ {
18
+ $this->context = $context;
19
+ }
20
+
21
+ public static function getSubscribedEvents()
22
+ {
23
+ return array(
24
+ MWP_Event_Events::ACTION_RESPONSE => 'fixWpSuperCache',
25
+ );
26
+ }
27
+
28
+ public function fixWpSuperCache()
29
+ {
30
+ if ($this->context->hasConstant('ADVANCEDCACHEPROBLEM') && $this->context->getConstant('ADVANCEDCACHEPROBLEM')) {
31
+ $this->context->set('wp_cache_config_file', null);
32
+ }
33
+ }
34
+ }
src/MWP/EventListener/MasterRequest/SetRequestSettings.php ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_EventListener_MasterRequest_SetRequestSettings implements Symfony_EventDispatcher_EventSubscriberInterface
12
+ {
13
+
14
+ private $context;
15
+
16
+ public function __construct(MWP_WordPress_Context $context)
17
+ {
18
+ $this->context = $context;
19
+ }
20
+
21
+ public static function getSubscribedEvents()
22
+ {
23
+ return array(
24
+ MWP_Event_Events::MASTER_REQUEST => array('onMasterRequest', -1000),
25
+ );
26
+ }
27
+
28
+ public function onMasterRequest(MWP_Event_MasterRequest $event)
29
+ {
30
+ if (!$event->getRequest()->isAuthenticated()) {
31
+ return;
32
+ }
33
+ $data = $event->getRequest()->getData();
34
+
35
+ $this->defineWpAdmin($data);
36
+ $this->defineWpAjax($data);
37
+ $this->setWpPage($data);
38
+
39
+ // Master should never get redirected by the worker, since it expects worker response.
40
+ $this->context->addFilter('wp_redirect', array($this, 'disableRedirect'));
41
+ }
42
+
43
+ private function defineWpAdmin(array $data)
44
+ {
45
+ if (empty($data['wpAdmin'])) {
46
+ return;
47
+ }
48
+
49
+ $this->context->setConstant('WP_ADMIN', true, false);
50
+ }
51
+
52
+ private function defineWpAjax(array $data)
53
+ {
54
+ if (empty($data['wpAjax'])) {
55
+ return;
56
+ }
57
+
58
+ $this->context->setConstant('DOING_AJAX', true, false);
59
+ }
60
+
61
+ private function setWpPage(array $data)
62
+ {
63
+ if (empty($data['wpPage'])) {
64
+ return;
65
+ }
66
+
67
+ $this->context->set('pagenow', $data['wpPage']);
68
+ }
69
+
70
+ /**
71
+ * @internal
72
+ */
73
+ public function disableRedirect()
74
+ {
75
+ return false;
76
+ }
77
+ }
src/MWP/EventListener/MasterResponse/LogResponse.php ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_EventListener_MasterResponse_LogResponse implements Symfony_EventDispatcher_EventSubscriberInterface
12
+ {
13
+
14
+ private $logger;
15
+
16
+ public function __construct(Monolog_Logger $logger)
17
+ {
18
+ $this->logger = $logger;
19
+ }
20
+
21
+ public static function getSubscribedEvents()
22
+ {
23
+ return array(
24
+ MWP_Event_Events::MASTER_RESPONSE => array('onMasterResponse'),
25
+ );
26
+ }
27
+
28
+ public function onMasterResponse(MWP_Event_MasterResponse $event)
29
+ {
30
+ $response = $event->getResponse();
31
+ $content = $response->getContent();
32
+
33
+ $status = 'unknown';
34
+
35
+ if (is_array($content)) {
36
+ if (array_key_exists('success', $content)) {
37
+ $status = 'success';
38
+ } elseif (array_key_exists('error', $content)) {
39
+ $status = 'error';
40
+ }
41
+ }
42
+
43
+ $this->logger->debug('Master response: {status}', array(
44
+ 'status' => $status,
45
+ 'content' => $content,
46
+ ));
47
+ }
48
+ }
src/MWP/EventListener/PublicRequest/AddStatusPage.php ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_EventListener_PublicRequest_AddStatusPage implements Symfony_EventDispatcher_EventSubscriberInterface
12
+ {
13
+
14
+ private $context;
15
+
16
+ private $configuration;
17
+
18
+ public function __construct(MWP_WordPress_Context $context, MWP_Worker_Configuration $configuration)
19
+ {
20
+ $this->context = $context;
21
+ $this->configuration = $configuration;
22
+ }
23
+
24
+ public static function getSubscribedEvents()
25
+ {
26
+ return array(
27
+ MWP_Event_Events::PUBLIC_REQUEST => 'onPublicRequest',
28
+ );
29
+ }
30
+
31
+ /**
32
+ * @internal
33
+ */
34
+ public function onPublicRequest(MWP_Event_PublicRequest $event)
35
+ {
36
+ $this->context->addAction('admin_menu', array($this, 'addStatusPage'));
37
+ }
38
+
39
+ /**
40
+ * @internal
41
+ */
42
+ public function addStatusPage()
43
+ {
44
+ $this->context->addSubMenuPage(null, 'ManageWP Worker Status', 'ManageWP Worker Status', 'activate_plugins', 'worker-status', array($this, 'statusPage'));
45
+ }
46
+
47
+ /**
48
+ * @internal
49
+ */
50
+ public function statusPage()
51
+ {
52
+ $pluginFile = 'worker/init.php';
53
+ $deactivateUrl = $this->context->wpNonceUrl('plugins.php?action=deactivate&amp;plugin='.$pluginFile, 'deactivate-plugin_'.$pluginFile);
54
+
55
+ $info = json_encode(array(
56
+ 'wrksettings' => $this->context->optionGet('wrksettings'),
57
+ 'connected' => (bool) $this->configuration->getPublicKey(),
58
+ 'connectedLegacy' => (bool) $this->configuration->getSecureKey(),
59
+ ));
60
+ ?>
61
+ <div class="wrap">
62
+ <div id="icon-tools" class="icon32"></div>
63
+ <h2>ManageWP Worker Status</h2>
64
+ </div>
65
+
66
+ <p>
67
+ <a id="worker-status-deactivate" class="button" href="<?php echo $deactivateUrl ?>">Deactivate</a>
68
+ </p>
69
+
70
+ <textarea id="worker-status-settings" style="display: none;"><?php echo htmlspecialchars($info, ENT_QUOTES) ?></textarea>
71
+ <?php
72
+ }
73
+ }
src/MWP/EventListener/PublicRequest/AutomaticLogin.php CHANGED
@@ -19,12 +19,15 @@ class MWP_EventListener_PublicRequest_AutomaticLogin implements Symfony_EventDis
19
 
20
  private $configuration;
21
 
22
- public function __construct(MWP_WordPress_Context $context, MWP_Security_NonceManager $nonceManager, MWP_Signer_Interface $signer, MWP_Worker_Configuration $configuration)
 
 
23
  {
24
  $this->context = $context;
25
  $this->nonceManager = $nonceManager;
26
  $this->signer = $signer;
27
  $this->configuration = $configuration;
 
28
  }
29
 
30
  public static function getSubscribedEvents()
@@ -93,6 +96,7 @@ class MWP_EventListener_PublicRequest_AutomaticLogin implements Symfony_EventDis
93
  }
94
 
95
  $this->context->setCurrentUser($user);
 
96
  $this->context->setAuthCookie($user);
97
 
98
  $currentUri = empty($request->server['REQUEST_URI']) ? '/' : $request->server['REQUEST_URI'];
@@ -142,4 +146,31 @@ class MWP_EventListener_PublicRequest_AutomaticLogin implements Symfony_EventDis
142
  // Replace everything from "?" onwards with "?key=value" or an empty string.
143
  return substr($uri, 0, strpos($uri, '?')).(count($query) ? '?'.http_build_query($query) : '');
144
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
  }
19
 
20
  private $configuration;
21
 
22
+ private $sessionStore;
23
+
24
+ public function __construct(MWP_WordPress_Context $context, MWP_Security_NonceManager $nonceManager, MWP_Signer_Interface $signer, MWP_Worker_Configuration $configuration, MWP_WordPress_SessionStore $sessionStore)
25
  {
26
  $this->context = $context;
27
  $this->nonceManager = $nonceManager;
28
  $this->signer = $signer;
29
  $this->configuration = $configuration;
30
+ $this->sessionStore = $sessionStore;
31
  }
32
 
33
  public static function getSubscribedEvents()
96
  }
97
 
98
  $this->context->setCurrentUser($user);
99
+ $this->attachSessionTokenListener();
100
  $this->context->setAuthCookie($user);
101
 
102
  $currentUri = empty($request->server['REQUEST_URI']) ? '/' : $request->server['REQUEST_URI'];
146
  // Replace everything from "?" onwards with "?key=value" or an empty string.
147
  return substr($uri, 0, strpos($uri, '?')).(count($query) ? '?'.http_build_query($query) : '');
148
  }
149
+
150
+ private function attachSessionTokenListener()
151
+ {
152
+ if (!$this->context->getSessionTokens($this->context->getCurrentUser()->ID)) {
153
+ return;
154
+ }
155
+
156
+ $this->context->addAction('set_auth_cookie', array($this, 'storeSessionToken'), 10, 1);
157
+ }
158
+
159
+ /**
160
+ * @param string $cookieValue
161
+ *
162
+ * @internal
163
+ */
164
+ public function storeSessionToken($cookieValue)
165
+ {
166
+ $cookieElements = explode('|', $cookieValue);
167
+
168
+ if (empty($cookieElements[2])) {
169
+ return;
170
+ }
171
+
172
+ $token = $cookieElements[2];
173
+
174
+ $this->sessionStore->add($this->context->getCurrentUser()->ID, $token);
175
+ }
176
  }
src/MWP/EventListener/PublicRequest/BrandContactSupport.php CHANGED
@@ -15,6 +15,8 @@ class MWP_EventListener_PublicRequest_BrandContactSupport implements Symfony_Eve
15
 
16
  private $brand;
17
 
 
 
18
  /**
19
  * Required WordPress capability to access the page.
20
  *
@@ -22,10 +24,11 @@ class MWP_EventListener_PublicRequest_BrandContactSupport implements Symfony_Eve
22
  */
23
  private $capability = 'read';
24
 
25
- public function __construct(MWP_WordPress_Context $context, MWP_Worker_Brand $brand)
26
  {
27
- $this->context = $context;
28
- $this->brand = $brand;
 
29
  }
30
 
31
  public static function getSubscribedEvents()
@@ -35,7 +38,7 @@ class MWP_EventListener_PublicRequest_BrandContactSupport implements Symfony_Eve
35
  );
36
  }
37
 
38
- public function enableContactSupport(MWP_Event_PublicRequest $event)
39
  {
40
  if (!$this->brand->isActive()) {
41
  return;
@@ -51,7 +54,7 @@ class MWP_EventListener_PublicRequest_BrandContactSupport implements Symfony_Eve
51
  $this->context->addAction('admin_head', array($this, 'printSupportScript'));
52
  $this->context->addAction('admin_footer', array($this, 'printSupportDialog'));
53
 
54
- $this->handleSupportForm($event);
55
  }
56
 
57
  /**
@@ -90,9 +93,9 @@ class MWP_EventListener_PublicRequest_BrandContactSupport implements Symfony_Eve
90
  ?>
91
  <script type="text/javascript">
92
  jQuery(document).ready(function ($) {
93
- var $dialog = $('#support_dialog');
94
- var $form = $('#support_form');
95
- var $messageContainer = $('#support_response_id');
96
  $form.submit(function (e) {
97
  e.preventDefault();
98
  var data = $(this).serialize();
@@ -125,7 +128,7 @@ class MWP_EventListener_PublicRequest_BrandContactSupport implements Symfony_Eve
125
  title: 'Contact Support',
126
  dialogClass: 'mwp-support-dialog',
127
  close: function () {
128
- $('#support_response_id').html('');
129
  $(this).dialog("destroy");
130
  }
131
  });
@@ -148,7 +151,7 @@ class MWP_EventListener_PublicRequest_BrandContactSupport implements Symfony_Eve
148
 
149
  ob_start();
150
  ?>
151
- <div id="support_dialog" style="display: none;">
152
  <?php if (!empty($contactText)): ?>
153
  <div>
154
  <p><?php echo $contactText ?></p>
@@ -156,11 +159,11 @@ class MWP_EventListener_PublicRequest_BrandContactSupport implements Symfony_Eve
156
  <?php endif ?>
157
  <?php if ($contactType == MWP_Worker_Brand::CONTACT_TYPE_TEXT_PLUS_FORM): ?>
158
  <div style="margin: 19px 0 0;">
159
- <form method="post" id="support_form">
160
- <textarea name="support_mwp_message" id="support_message" style="width:500px;height:150px;display:block;margin-left:auto;margin-right:auto;"></textarea>
161
  <button type="submit" class="button-primary" style="display:block;margin:20px auto 7px auto;border:1px solid #a1a1a1;padding:0 31px;border-radius: 4px;">Send</button>
162
  </form>
163
- <div id="support_response_id" style="margin-top: 14px"></div>
164
  <style scoped="scoped">
165
  .mwp-support-dialog.ui-dialog {
166
  z-index: 300002;
@@ -175,14 +178,14 @@ class MWP_EventListener_PublicRequest_BrandContactSupport implements Symfony_Eve
175
  $this->context->output($content);
176
  }
177
 
178
- private function handleSupportForm(MWP_Event_PublicRequest $event)
179
  {
180
- $request = $event->getRequest();
181
  if (!isset($request->request['support_mwp_message']) || !is_scalar($request->request['support_mwp_message'])) {
182
  return;
183
  }
184
 
185
- if ($this->context->isGranted($this->capability)) {
186
  return;
187
  }
188
 
@@ -195,13 +198,12 @@ class MWP_EventListener_PublicRequest_BrandContactSupport implements Symfony_Eve
195
 
196
  if (empty($message)) {
197
  // Message is set, but it's empty.
198
- $event->setResponse(new MWP_Http_JsonResponse(array(
199
  'success' => false,
200
  'message' => "Please enter a message.",
201
- )));
202
- $event->stopPropagation();
203
-
204
- return;
205
  }
206
  $subject = 'New ticket for site '.$this->context->getHomeUrl();
207
  $message = <<<EOF
@@ -216,7 +218,8 @@ EOF;
216
  'message' => $emailSent ? "Message successfully sent." : "Unable to send email. Please try again.",
217
  );
218
 
219
- $event->setResponse(new MWP_Http_JsonResponse($status));
220
- $event->stopPropagation();
 
221
  }
222
  }
15
 
16
  private $brand;
17
 
18
+ private $requestStack;
19
+
20
  /**
21
  * Required WordPress capability to access the page.
22
  *
24
  */
25
  private $capability = 'read';
26
 
27
+ public function __construct(MWP_WordPress_Context $context, MWP_Worker_Brand $brand, MWP_Worker_RequestStack $requestStack)
28
  {
29
+ $this->context = $context;
30
+ $this->brand = $brand;
31
+ $this->requestStack = $requestStack;
32
  }
33
 
34
  public static function getSubscribedEvents()
38
  );
39
  }
40
 
41
+ public function enableContactSupport()
42
  {
43
  if (!$this->brand->isActive()) {
44
  return;
54
  $this->context->addAction('admin_head', array($this, 'printSupportScript'));
55
  $this->context->addAction('admin_footer', array($this, 'printSupportDialog'));
56
 
57
+ $this->context->addAction('init', array($this, 'handleSupportForm'));
58
  }
59
 
60
  /**
93
  ?>
94
  <script type="text/javascript">
95
  jQuery(document).ready(function ($) {
96
+ var $dialog = $('#mwp_support_dialog');
97
+ var $form = $('#mwp_support_form');
98
+ var $messageContainer = $('#mwp_support_response_id');
99
  $form.submit(function (e) {
100
  e.preventDefault();
101
  var data = $(this).serialize();
128
  title: 'Contact Support',
129
  dialogClass: 'mwp-support-dialog',
130
  close: function () {
131
+ $('#mwp_support_response_id').html('');
132
  $(this).dialog("destroy");
133
  }
134
  });
151
 
152
  ob_start();
153
  ?>
154
+ <div id="mwp_support_dialog" style="display: none;">
155
  <?php if (!empty($contactText)): ?>
156
  <div>
157
  <p><?php echo $contactText ?></p>
159
  <?php endif ?>
160
  <?php if ($contactType == MWP_Worker_Brand::CONTACT_TYPE_TEXT_PLUS_FORM): ?>
161
  <div style="margin: 19px 0 0;">
162
+ <form method="post" id="mwp_support_form">
163
+ <textarea name="support_mwp_message" id="mwp_support_message" style="width:500px;height:150px;display:block;margin-left:auto;margin-right:auto;"></textarea>
164
  <button type="submit" class="button-primary" style="display:block;margin:20px auto 7px auto;border:1px solid #a1a1a1;padding:0 31px;border-radius: 4px;">Send</button>
165
  </form>
166
+ <div id="mwp_support_response_id" style="margin-top: 14px"></div>
167
  <style scoped="scoped">
168
  .mwp-support-dialog.ui-dialog {
169
  z-index: 300002;
178
  $this->context->output($content);
179
  }
180
 
181
+ public function handleSupportForm()
182
  {
183
+ $request = $this->requestStack->getMasterRequest();
184
  if (!isset($request->request['support_mwp_message']) || !is_scalar($request->request['support_mwp_message'])) {
185
  return;
186
  }
187
 
188
+ if (!$this->context->isGranted($this->capability)) {
189
  return;
190
  }
191
 
198
 
199
  if (empty($message)) {
200
  // Message is set, but it's empty.
201
+ $response = new MWP_Http_JsonResponse(array(
202
  'success' => false,
203
  'message' => "Please enter a message.",
204
+ ));
205
+ $response->send();
206
+ exit;
 
207
  }
208
  $subject = 'New ticket for site '.$this->context->getHomeUrl();
209
  $message = <<<EOF
218
  'message' => $emailSent ? "Message successfully sent." : "Unable to send email. Please try again.",
219
  );
220
 
221
+ $response = new MWP_Http_JsonResponse($status);
222
+ $response->send();
223
+ exit;
224
  }
225
  }
src/MWP/EventListener/PublicRequest/SetHitCounter.php CHANGED
@@ -41,14 +41,16 @@ class MWP_EventListener_PublicRequest_SetHitCounter implements Symfony_EventDisp
41
  /**
42
  * @param MWP_WordPress_Context $context
43
  * @param MWP_Extension_HitCounter $hitCounter
 
44
  * @param string[] $blacklistedIps
45
  * @param string[] $userAgentList
46
  * @param bool $userAgentMatchingMethod
47
  */
48
- public function __construct(MWP_WordPress_Context $context, MWP_Extension_HitCounter $hitCounter, array $blacklistedIps = array(), array $userAgentList = array(), $userAgentMatchingMethod = self::METHOD_BLACKLIST)
49
  {
50
  $this->context = $context;
51
  $this->hitCounter = $hitCounter;
 
52
  $this->blacklistedIps = $blacklistedIps;
53
  $this->userAgentList = $userAgentList;
54
  $this->userAgentMatchingMethod = $userAgentMatchingMethod;
@@ -60,13 +62,23 @@ class MWP_EventListener_PublicRequest_SetHitCounter implements Symfony_EventDisp
60
  public static function getSubscribedEvents()
61
  {
62
  return array(
63
- MWP_Event_Events::PUBLIC_REQUEST => array('onPublicRequest', -300),
64
  );
65
  }
66
 
67
  public function onPublicRequest(MWP_Event_PublicRequest $event)
68
  {
69
- $request = $event->getRequest();
 
 
 
 
 
 
 
 
 
 
70
 
71
  if ($this->context->isInAdminPanel()) {
72
  return;
41
  /**
42
  * @param MWP_WordPress_Context $context
43
  * @param MWP_Extension_HitCounter $hitCounter
44
+ * @param MWP_Worker_RequestStack $requestStack
45
  * @param string[] $blacklistedIps
46
  * @param string[] $userAgentList
47
  * @param bool $userAgentMatchingMethod
48
  */
49
+ public function __construct(MWP_WordPress_Context $context, MWP_Extension_HitCounter $hitCounter, MWP_Worker_RequestStack $requestStack, array $blacklistedIps = array(), array $userAgentList = array(), $userAgentMatchingMethod = self::METHOD_BLACKLIST)
50
  {
51
  $this->context = $context;
52
  $this->hitCounter = $hitCounter;
53
+ $this->requestStack = $requestStack;
54
  $this->blacklistedIps = $blacklistedIps;
55
  $this->userAgentList = $userAgentList;
56
  $this->userAgentMatchingMethod = $userAgentMatchingMethod;
62
  public static function getSubscribedEvents()
63
  {
64
  return array(
65
+ MWP_Event_Events::PUBLIC_REQUEST => 'onPublicRequest',
66
  );
67
  }
68
 
69
  public function onPublicRequest(MWP_Event_PublicRequest $event)
70
  {
71
+ $this->context->addAction('wp', array($this, 'countHit'));
72
+ }
73
+
74
+ public function countHit()
75
+ {
76
+ $request = $this->requestStack->getMasterRequest();
77
+
78
+ if (!$this->context->hasConstant('WP_USE_THEMES') || !$this->context->getConstant('WP_USE_THEMES')) {
79
+ // The file is not visited via "index.php".
80
+ return;
81
+ }
82
 
83
  if ($this->context->isInAdminPanel()) {
84
  return;
src/MWP/EventListener/PublicRequest/SetPluginInfo.php CHANGED
@@ -39,6 +39,20 @@ class MWP_EventListener_PublicRequest_SetPluginInfo implements Symfony_EventDisp
39
  // This is a horrible hack, but it will allow us to hide a MU plugin in rebranded installations.
40
  $this->context->addFilter('show_advanced_plugins', array($this, 'muPluginListFilter'), 10, 2);
41
  $this->context->addFilter('plugin_row_meta', array($this, 'hidePluginDetails'), 10, 2);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  }
43
 
44
  /**
@@ -94,7 +108,7 @@ class MWP_EventListener_PublicRequest_SetPluginInfo implements Symfony_EventDisp
94
  */
95
  public function muPluginListFilter($previousValue, $type)
96
  {
97
- if (!$this->brand->isActive() || !$this->brand->isHide()) {
98
  return $previousValue;
99
  }
100
 
@@ -113,7 +127,17 @@ class MWP_EventListener_PublicRequest_SetPluginInfo implements Symfony_EventDisp
113
  return $previousValue;
114
  }
115
 
116
- unset($plugins['mustuse'][$this->loaderName]);
 
 
 
 
 
 
 
 
 
 
117
 
118
  return $previousValue;
119
  }
39
  // This is a horrible hack, but it will allow us to hide a MU plugin in rebranded installations.
40
  $this->context->addFilter('show_advanced_plugins', array($this, 'muPluginListFilter'), 10, 2);
41
  $this->context->addFilter('plugin_row_meta', array($this, 'hidePluginDetails'), 10, 2);
42
+ $this->context->addFilter('site_transient_update_plugins', array($this, 'parseUpdatePlugins'));
43
+ }
44
+
45
+ public function parseUpdatePlugins($updates)
46
+ {
47
+ if (!$this->brand->isActive()) {
48
+ return $updates;
49
+ }
50
+
51
+ if (isset($updates->response[$this->slug])) {
52
+ unset($updates->response[$this->slug]);
53
+ }
54
+
55
+ return $updates;
56
  }
57
 
58
  /**
108
  */
109
  public function muPluginListFilter($previousValue, $type)
110
  {
111
+ if (!$this->brand->isActive()) {
112
  return $previousValue;
113
  }
114
 
127
  return $previousValue;
128
  }
129
 
130
+ if ($this->brand->isHide()) {
131
+ unset($plugins['mustuse'][$this->loaderName]);
132
+ } else {
133
+ $plugins['mustuse'][$this->loaderName]['Name'] = $this->brand->getName();
134
+ $plugins['mustuse'][$this->loaderName]['Title'] = $this->brand->getName();
135
+ $plugins['mustuse'][$this->loaderName]['Description'] = $this->brand->getDescription();
136
+ $plugins['mustuse'][$this->loaderName]['AuthorURI'] = $this->brand->getAuthorUrl();
137
+ $plugins['mustuse'][$this->loaderName]['Author'] = $this->brand->getAuthor();
138
+ $plugins['mustuse'][$this->loaderName]['AuthorName'] = $this->brand->getAuthor();
139
+ $plugins['mustuse'][$this->loaderName]['PluginURI'] = '';
140
+ }
141
 
142
  return $previousValue;
143
  }
src/MWP/Http/JsonResponse.php CHANGED
@@ -10,10 +10,10 @@
10
 
11
  class MWP_Http_JsonResponse extends MWP_Http_Response
12
  {
13
- public function __construct($content, $headers = array())
14
  {
15
  $headers['content-type'] = 'application/json';
16
- parent::__construct($content, $headers);
17
  }
18
 
19
  public function getContentAsString()
10
 
11
  class MWP_Http_JsonResponse extends MWP_Http_Response
12
  {
13
+ public function __construct($content, $statusCode = 200, array $headers = array())
14
  {
15
  $headers['content-type'] = 'application/json';
16
+ parent::__construct($content, $statusCode, $headers);
17
  }
18
 
19
  public function getContentAsString()
src/MWP/Http/MultipartResponse.php ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ /**
12
+ * Constructs a Multipart response into string or stream.
13
+ */
14
+ class MWP_Http_MultipartResponse extends MWP_Http_Response implements MWP_Http_StreamingResponseInterface
15
+ {
16
+
17
+ /** @var string Multipart boundary */
18
+ private $boundary = '';
19
+
20
+ public function __construct($parts, $boundary = null, $statusCode = 200, array $headers = array())
21
+ {
22
+ if ($boundary === null) {
23
+ $boundary = uniqid();
24
+ }
25
+
26
+ $this->boundary = $boundary;
27
+ $headers["content-type"] = "multipart/mixed; boundary=".$this->boundary;
28
+
29
+ if (!isset($headers["content-transfer-encoding"])) {
30
+ $headers["content-transfer-encoding"] = "binary";
31
+ }
32
+
33
+ parent::__construct($parts, $statusCode, $headers);
34
+ }
35
+
36
+ /**
37
+ * {@inheritdoc}
38
+ */
39
+ public function getContentAsString()
40
+ {
41
+ /** @var MWP_Http_MultipartResponsePart[] $parts */
42
+ $parts = $this->content;
43
+
44
+ // Multipart header
45
+ $output = "\r\n".$this->getMultipartBoundary()."\r\n";
46
+
47
+ foreach ($parts as $part) {
48
+ $output .= $this->createPartResponse($part).$this->getMultipartBoundary();
49
+ }
50
+
51
+ // End multipart boundary
52
+ $output .= '--';
53
+
54
+ return $output;
55
+ }
56
+
57
+ /**
58
+ * @return MWP_Stream_Interface
59
+ */
60
+ public function createResponseStream()
61
+ {
62
+ /** @var MWP_Http_MultipartResponsePart[] $parts */
63
+ $parts = $this->content;
64
+ $stream = new MWP_Stream_Append();
65
+
66
+ $stream->addStream(MWP_Stream_Stream::factory("\r\n".$this->getMultipartBoundary()));
67
+
68
+ foreach ($parts as $part) {
69
+ $stream->addStream(MWP_Stream_Stream::factory("\r\n"));
70
+ $stream->addStream($this->createPartStream($part));
71
+ $stream->addStream(MWP_Stream_Stream::factory("\r\n".$this->getMultipartBoundary()));
72
+ }
73
+
74
+ $stream->addStream(MWP_Stream_Stream::factory("--"));
75
+
76
+ return $stream;
77
+ }
78
+
79
+ /**
80
+ * @return string
81
+ */
82
+ public function getBoundary()
83
+ {
84
+ return $this->boundary;
85
+ }
86
+
87
+ private function createPartResponse(MWP_Http_MultipartResponsePart $part)
88
+ {
89
+ $response = '';
90
+
91
+ foreach ($part->getHeaders() as $header => $value) {
92
+ if (strcasecmp("content-location", $header) === 0) {
93
+ // Content-Location can contain special characters (like \r\n for example)
94
+ $value = urlencode($value);
95
+ }
96
+ $response .= sprintf("%s: %s\r\n", strtolower($header), $value);
97
+ }
98
+
99
+ $response .= sprintf("\r\n%s\r\n", (string) $part->getBody());
100
+
101
+ return $response;
102
+ }
103
+
104
+ private function createPartStream(MWP_Http_MultipartResponsePart $part)
105
+ {
106
+ $stream = new MWP_Stream_Append();
107
+
108
+ foreach ($part->getHeaders() as $header => $value) {
109
+ if (strcasecmp("content-location", $header) === 0) {
110
+ // Content-Location can contain special characters (like \r\n for example)
111
+ $value = urlencode($value);
112
+ }
113
+ $stream->addStream(MWP_Stream_Stream::factory(sprintf("%s: %s\r\n", strtolower($header), $value)));
114
+ }
115
+
116
+ $stream->addStream(MWP_Stream_Stream::factory("\r\n"));
117
+ $stream->addStream($part->getBody());
118
+
119
+ return $stream;
120
+ }
121
+
122
+ /**
123
+ * @return string
124
+ */
125
+ private function getMultipartBoundary()
126
+ {
127
+ return sprintf("--%s", $this->boundary);
128
+ }
129
+ }
src/MWP/Http/MultipartResponsePart.php ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_Http_MultipartResponsePart
12
+ {
13
+
14
+ /** @var array */
15
+ private $headers = array();
16
+
17
+ /** @var MWP_Stream_Interface */
18
+ private $body;
19
+
20
+ function __construct($headers, $body = null)
21
+ {
22
+ $this->headers = array_change_key_case($headers, CASE_LOWER);
23
+ $this->setBody($body);
24
+ }
25
+
26
+ /**
27
+ * @param string $header
28
+ * @param string $value
29
+ */
30
+ public function setHeader($header, $value)
31
+ {
32
+ $this->headers[strtolower($header)] = $value;
33
+ }
34
+
35
+ /**
36
+ * @param $header
37
+ *
38
+ * @return string|null
39
+ */
40
+ public function getHeader($header)
41
+ {
42
+ if ($this->hasHeader($header)) {
43
+ return $this->headers[strtolower($header)];
44
+ }
45
+
46
+ return null;
47
+ }
48
+
49
+ /**
50
+ * @param string $header
51
+ *
52
+ * @return bool
53
+ */
54
+ public function hasHeader($header)
55
+ {
56
+ return isset($this->headers[strtolower($header)]);
57
+ }
58
+
59
+ /**
60
+ * @return array
61
+ */
62
+ public function getHeaders()
63
+ {
64
+ return $this->headers;
65
+ }
66
+
67
+ /**
68
+ * @return MWP_Stream_Interface|null
69
+ */
70
+ public function getBody()
71
+ {
72
+ return $this->body;
73
+ }
74
+
75
+ /**
76
+ * @param MWP_Stream_Interface $body
77
+ */
78
+ public function setBody($body)
79
+ {
80
+ if ($body !== null && !$body instanceof MWP_Stream_Interface) {
81
+ $body = MWP_Stream_Stream::factory($body);
82
+ }
83
+
84
+ $this->body = $body;
85
+ }
86
+ }
src/MWP/Http/RedirectResponse.php CHANGED
@@ -10,10 +10,10 @@
10
 
11
  class MWP_Http_RedirectResponse extends MWP_Http_Response
12
  {
13
- public function __construct($url, $code = 302, array $headers = array())
14
  {
15
  $headers['location'] = $url;
16
- parent::__construct($url, $headers);
17
  }
18
 
19
  public function getContentAsString()
10
 
11
  class MWP_Http_RedirectResponse extends MWP_Http_Response
12
  {
13
+ public function __construct($url, $statusCode = 302, array $headers = array())
14
  {
15
  $headers['location'] = $url;
16
+ parent::__construct($url, $statusCode, $headers);
17
  }
18
 
19
  public function getContentAsString()
src/MWP/Http/Response.php CHANGED
@@ -11,14 +11,91 @@
11
  class MWP_Http_Response implements MWP_Http_ResponseInterface
12
  {
13
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  protected $content;
15
 
 
 
16
  protected $headers = array();
17
 
18
- public function __construct($content, $headers = array())
19
  {
20
- $this->content = $content;
21
- $this->headers = array_change_key_case($headers, CASE_LOWER);
 
22
  }
23
 
24
  public function getContentAsString()
@@ -50,7 +127,23 @@ class MWP_Http_Response implements MWP_Http_ResponseInterface
50
  public function send()
51
  {
52
  $this->sendHeaders();
53
- print $this->getContentAsString();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  }
55
 
56
  protected function sendHeaders()
@@ -59,8 +152,17 @@ class MWP_Http_Response implements MWP_Http_ResponseInterface
59
  return;
60
  }
61
 
 
 
 
 
 
 
 
 
 
62
  foreach ($this->headers as $headerName => $headerValue) {
63
- header(sprintf('%s: %s', $headerName, $headerValue), true);
64
  }
65
  }
66
  }
11
  class MWP_Http_Response implements MWP_Http_ResponseInterface
12
  {
13
 
14
+ /**
15
+ * Status codes translation table.
16
+ *
17
+ * The list of codes is complete according to the
18
+ * {@link http://www.iana.org/assignments/http-status-codes/ Hypertext Transfer Protocol (HTTP) Status Code Registry}
19
+ * (last updated 2012-02-13).
20
+ *
21
+ * Unless otherwise noted, the status code is defined in RFC2616.
22
+ *
23
+ * @var array
24
+ */
25
+ public static $statusTexts = array(
26
+ 100 => 'Continue',
27
+ 101 => 'Switching Protocols',
28
+ 102 => 'Processing', // RFC2518
29
+ 200 => 'OK',
30
+ 201 => 'Created',
31
+ 202 => 'Accepted',
32
+ 203 => 'Non-Authoritative Information',
33
+ 204 => 'No Content',
34
+ 205 => 'Reset Content',
35
+ 206 => 'Partial Content',
36
+ 207 => 'Multi-Status', // RFC4918
37
+ 208 => 'Already Reported', // RFC5842
38
+ 226 => 'IM Used', // RFC3229
39
+ 300 => 'Multiple Choices',
40
+ 301 => 'Moved Permanently',
41
+ 302 => 'Found',
42
+ 303 => 'See Other',
43
+ 304 => 'Not Modified',
44
+ 305 => 'Use Proxy',
45
+ 306 => 'Reserved',
46
+ 307 => 'Temporary Redirect',
47
+ 308 => 'Permanent Redirect', // RFC7238
48
+ 400 => 'Bad Request',
49
+ 401 => 'Unauthorized',
50
+ 402 => 'Payment Required',
51
+ 403 => 'Forbidden',
52
+ 404 => 'Not Found',
53
+ 405 => 'Method Not Allowed',
54
+ 406 => 'Not Acceptable',
55
+ 407 => 'Proxy Authentication Required',
56
+ 408 => 'Request Timeout',
57
+ 409 => 'Conflict',
58
+ 410 => 'Gone',
59
+ 411 => 'Length Required',
60
+ 412 => 'Precondition Failed',
61
+ 413 => 'Request Entity Too Large',
62
+ 414 => 'Request-URI Too Long',
63
+ 415 => 'Unsupported Media Type',
64
+ 416 => 'Requested Range Not Satisfiable',
65
+ 417 => 'Expectation Failed',
66
+ 418 => 'I\'m a teapot', // RFC2324
67
+ 422 => 'Unprocessable Entity', // RFC4918
68
+ 423 => 'Locked', // RFC4918
69
+ 424 => 'Failed Dependency', // RFC4918
70
+ 425 => 'Reserved for WebDAV advanced collections expired proposal', // RFC2817
71
+ 426 => 'Upgrade Required', // RFC2817
72
+ 428 => 'Precondition Required', // RFC6585
73
+ 429 => 'Too Many Requests', // RFC6585
74
+ 431 => 'Request Header Fields Too Large', // RFC6585
75
+ 500 => 'Internal Server Error',
76
+ 501 => 'Not Implemented',
77
+ 502 => 'Bad Gateway',
78
+ 503 => 'Service Unavailable',
79
+ 504 => 'Gateway Timeout',
80
+ 505 => 'HTTP Version Not Supported',
81
+ 506 => 'Variant Also Negotiates (Experimental)', // RFC2295
82
+ 507 => 'Insufficient Storage', // RFC4918
83
+ 508 => 'Loop Detected', // RFC5842
84
+ 510 => 'Not Extended', // RFC2774
85
+ 511 => 'Network Authentication Required', // RFC6585
86
+ );
87
+
88
  protected $content;
89
 
90
+ protected $statusCode;
91
+
92
  protected $headers = array();
93
 
94
+ public function __construct($content, $statusCode = 200, array $headers = array())
95
  {
96
+ $this->content = $content;
97
+ $this->statusCode = $statusCode;
98
+ $this->headers = array_change_key_case($headers, CASE_LOWER);
99
  }
100
 
101
  public function getContentAsString()
127
  public function send()
128
  {
129
  $this->sendHeaders();
130
+
131
+ // Some plugins leave open buffers and when it happens the returned output is blank
132
+ $bufferCount = count(ob_list_handlers());
133
+ while ($bufferCount) {
134
+ ob_end_clean();
135
+ --$bufferCount;
136
+ }
137
+
138
+ if ($this instanceof MWP_Http_StreamingResponseInterface) {
139
+ $stream = $this->createResponseStream();
140
+
141
+ while (!$stream->eof()) {
142
+ print $stream->read(1048576);
143
+ }
144
+ } else {
145
+ print $this->getContentAsString();
146
+ }
147
  }
148
 
149
  protected function sendHeaders()
152
  return;
153
  }
154
 
155
+ $protocol = 'HTTP/1.1';
156
+ if (isset($_SERVER['SERVER_PROTOCOL']) && $_SERVER['SERVER_PROTOCOL'] === 'HTTP/1.0') {
157
+ $protocol = 'HTTP/1.0';
158
+ }
159
+
160
+ if (isset(self::$statusTexts[$this->statusCode])) {
161
+ header(sprintf('%s %s %s', $protocol, $this->statusCode, self::$statusTexts[$this->statusCode]), true, $this->statusCode);
162
+ }
163
+
164
  foreach ($this->headers as $headerName => $headerValue) {
165
+ header(sprintf('%s: %s', $headerName, $headerValue), false, $this->statusCode);
166
  }
167
  }
168
  }
src/MWP/Http/StreamingResponseInterface.php ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ interface MWP_Http_StreamingResponseInterface
12
+ {
13
+ /**
14
+ * @return MWP_Stream_Interface
15
+ */
16
+ public function createResponseStream();
17
+ }
src/MWP/IncrementalBackup/Database/Configuration.php ADDED
@@ -0,0 +1,207 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_IncrementalBackup_Database_Configuration
12
+ {
13
+
14
+ /**
15
+ * @var string
16
+ */
17
+ private $username;
18
+
19
+ /**
20
+ * @var string
21
+ */
22
+ private $password;
23
+
24
+ /**
25
+ * @var string
26
+ */
27
+ private $database;
28
+
29
+ /**
30
+ * @var bool
31
+ */
32
+ private $socket;
33
+
34
+ /**
35
+ * @var string|null
36
+ */
37
+ private $host;
38
+
39
+ /**
40
+ * @var string|null
41
+ */
42
+ private $socketPath;
43
+
44
+ /**
45
+ * @var string
46
+ */
47
+ private $charset = 'utf8';
48
+
49
+ /**
50
+ * @var int
51
+ */
52
+ private $port;
53
+
54
+ /**
55
+ * @param array $parameters
56
+ */
57
+ public function __construct(array $parameters = array())
58
+ {
59
+ if (isset($parameters['username'])) {
60
+ $this->username = $parameters['username'];
61
+ }
62
+
63
+ if (isset($parameters['password'])) {
64
+ $this->password = $parameters['password'];
65
+ }
66
+
67
+ if (isset($parameters['socket'])) {
68
+ $this->socket = true;
69
+ $this->socketPath = $parameters['socket'];
70
+ } elseif (isset($parameters['host'])) {
71
+ $this->socket = false;
72
+ $this->host = $parameters['host'];
73
+ }
74
+
75
+ if (isset($parameters['port'])) {
76
+ $this->port = $parameters['port'];
77
+ }
78
+
79
+ if (isset($parameters['database'])) {
80
+ $this->database = $parameters['database'];
81
+ }
82
+
83
+ if (isset($parameters['charset'])) {
84
+ $this->charset = $parameters['charset'];
85
+ }
86
+ }
87
+
88
+ /**
89
+ * @return string|null
90
+ */
91
+ public function getHost()
92
+ {
93
+ return $this->host;
94
+ }
95
+
96
+ /**
97
+ * @return string|null
98
+ */
99
+ public function getSocketPath()
100
+ {
101
+ return $this->socketPath;
102
+ }
103
+
104
+ /**
105
+ * @return int
106
+ */
107
+ public function getPort()
108
+ {
109
+ return $this->port;
110
+ }
111
+
112
+ /**
113
+ * @return boolean
114
+ */
115
+ public function isSocket()
116
+ {
117
+ return $this->socket;
118
+ }
119
+
120
+ /**
121
+ * @return string
122
+ */
123
+ public function getUsername()
124
+ {
125
+ return $this->username;
126
+ }
127
+
128
+ /**
129
+ * @return string
130
+ */
131
+ public function getPassword()
132
+ {
133
+ return $this->password;
134
+ }
135
+
136
+ /**
137
+ * @return string
138
+ */
139
+ public function getDatabase()
140
+ {
141
+ return $this->database;
142
+ }
143
+
144
+ /**
145
+ * @return string
146
+ */
147
+ public function getCharset()
148
+ {
149
+ return $this->charset;
150
+ }
151
+
152
+ public static function createFromWordPressContext(MWP_WordPress_Context $context)
153
+ {
154
+ return self::createFromArray(array(
155
+ 'username' => $context->getConstant('DB_USER'),
156
+ 'password' => $context->getConstant('DB_PASSWORD'),
157
+ 'database' => $context->getConstant('DB_NAME'),
158
+ 'host' => $context->getConstant('DB_HOST'),
159
+ 'charset' => $context->hasConstant('DB_CHARSET') ? $context->getConstant('DB_CHARSET') : 'utf8',
160
+ ));
161
+ }
162
+
163
+ /**
164
+ * $parameters array should contain:
165
+ * - username: mysql username
166
+ * - password: mysql password
167
+ * - database: database name
168
+ * - host: host - can contain port or be a mysql socket
169
+ */
170
+ public static function createFromArray(array $parameters = array())
171
+ {
172
+ $configuration = array(
173
+ 'username' => isset($parameters['username']) ? $parameters['username'] : null,
174
+ 'password' => isset($parameters['password']) ? $parameters['password'] : null,
175
+ 'database' => $parameters['database'],
176
+ );
177
+
178
+ $databaseHost = $parameters['host'];
179
+
180
+ $port = 0;
181
+ $host = $databaseHost;
182
+
183
+ // Handle localhost:3306 cases
184
+ if (strpos($databaseHost, ':') !== false) {
185
+ list($host, $port) = explode(':', $databaseHost);
186
+ $port = (int) $port;
187
+ }
188
+
189
+ // Database host can be a path to mysql socket
190
+ if (strpos($databaseHost, '/') !== false || strpos($databaseHost, '\\') !== false) {
191
+ $socket = end(explode(':', $databaseHost));
192
+
193
+ $configuration['socket'] = $socket;
194
+ } else {
195
+ $configuration['host'] = $host;
196
+ if (!empty($port)) {
197
+ $configuration['port'] = $port;
198
+ }
199
+ }
200
+
201
+ if (isset($parameters['charset'])) {
202
+ $configuration['charset'] = $parameters['charset'];
203
+ }
204
+
205
+ return new MWP_IncrementalBackup_Database_Configuration($configuration);
206
+ }
207
+ }
src/MWP/IncrementalBackup/Database/ConnectionInterface.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ interface MWP_IncrementalBackup_Database_ConnectionInterface
12
+ {
13
+ /**
14
+ * @param string $query
15
+ *
16
+ * @return MWP_IncrementalBackup_Database_StatementInterface
17
+ */
18
+ public function query($query);
19
+
20
+ /**
21
+ * @param mixed $value any primitive value
22
+ *
23
+ * @return string
24
+ */
25
+ public function quote($value);
26
+ }
src/MWP/IncrementalBackup/Database/DumpOptions.php ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_IncrementalBackup_Database_DumpOptions
12
+ {
13
+
14
+ /**
15
+ * @var string[]
16
+ */
17
+ private $tables = null;
18
+
19
+ /**
20
+ * @var bool
21
+ */
22
+ private $skipLockTables = true;
23
+
24
+ /**
25
+ * @var bool
26
+ */
27
+ private $dropTables = true;
28
+
29
+ /**
30
+ * @return array
31
+ */
32
+ public function getTables()
33
+ {
34
+ return $this->tables;
35
+ }
36
+
37
+ /**
38
+ * @param array $tables
39
+ */
40
+ public function setTables($tables)
41
+ {
42
+ $this->tables = $tables;
43
+ }
44
+
45
+ /**
46
+ * @return boolean
47
+ */
48
+ public function isSkipLockTables()
49
+ {
50
+ return $this->skipLockTables;
51
+ }
52
+
53
+ /**
54
+ * @param boolean $skipLockTables
55
+ */
56
+ public function setSkipLockTables($skipLockTables)
57
+ {
58
+ $this->skipLockTables = $skipLockTables;
59
+ }
60
+
61
+ /**
62
+ * @return boolean
63
+ */
64
+ public function isDropTables()
65
+ {
66
+ return $this->dropTables;
67
+ }
68
+
69
+ /**
70
+ * @param boolean $dropTables
71
+ */
72
+ public function setDropTables($dropTables)
73
+ {
74
+ $this->dropTables = $dropTables;
75
+ }
76
+
77
+ public static function createFromArray(array $options = array())
78
+ {
79
+ $dumpOptions = new self();
80
+
81
+ if (isset($options['skip_lock_tables'])) {
82
+ $dumpOptions->setSkipLockTables($options['skip_lock_tables']);
83
+ }
84
+
85
+ return $dumpOptions;
86
+ }
87
+ }
src/MWP/IncrementalBackup/Database/DumperInterface.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ interface MWP_IncrementalBackup_Database_DumperInterface
12
+ {
13
+ /**
14
+ * @param array $tables Table names
15
+ *
16
+ * @return MWP_Stream_Interface
17
+ */
18
+ function dump(array $tables);
19
+ }
src/MWP/IncrementalBackup/Database/Exception.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_IncrementalBackup_Database_Exception extends Exception
12
+ {
13
+ }
src/MWP/IncrementalBackup/Database/Exception/ConnectionException.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_IncrementalBackup_Database_Exception_ConnectionException extends MWP_IncrementalBackup_Database_Exception
12
+ {
13
+ }
src/MWP/IncrementalBackup/Database/MysqlConnection.php ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_IncrementalBackup_Database_MysqlConnection implements MWP_IncrementalBackup_Database_ConnectionInterface
12
+ {
13
+
14
+ /**
15
+ * @var resource
16
+ */
17
+ private $connection;
18
+
19
+ /**
20
+ * @var
21
+ */
22
+ private $configuration;
23
+
24
+ public function __construct(MWP_IncrementalBackup_Database_Configuration $configuration)
25
+ {
26
+ $this->configuration = $configuration;
27
+
28
+ if (!extension_loaded('mysql')) {
29
+ throw new MWP_IncrementalBackup_Database_Exception_ConnectionException("Mysql extension is not loaded.");
30
+ }
31
+
32
+ if ($configuration->isSocket()) {
33
+ $this->connection = @mysql_connect(':'.$configuration->getSocketPath(), $configuration->getUsername(), $configuration->getPassword());
34
+ } else {
35
+ $host = $configuration->getHost();
36
+ if ($configuration->getPort() !== null) {
37
+ $host .= ':'.$configuration->getPort();
38
+ }
39
+ $this->connection = @mysql_connect($host, $configuration->getUsername(), $configuration->getPassword());
40
+ }
41
+
42
+ if (!is_resource($this->connection)) {
43
+ throw new MWP_IncrementalBackup_Database_Exception_ConnectionException(mysql_error(), mysql_errno());
44
+ }
45
+
46
+ @mysql_set_charset($configuration->getCharset(), $this->connection);
47
+ mysql_select_db($configuration->getDatabase(), $this->connection);
48
+ }
49
+
50
+ /**
51
+ * @param string $query
52
+ *
53
+ * @throws MWP_IncrementalBackup_Database_Exception_ConnectionException
54
+ *
55
+ * @return MWP_IncrementalBackup_Database_StatementInterface
56
+ */
57
+ public function query($query)
58
+ {
59
+ $result = mysql_query($query, $this->connection);
60
+
61
+ if ($result === false) {
62
+ throw new MWP_IncrementalBackup_Database_Exception_ConnectionException(mysql_error($this->connection), mysql_errno($this->connection));
63
+ }
64
+
65
+ return new MWP_IncrementalBackup_Database_MysqlStatement($result);
66
+ }
67
+
68
+ /**
69
+ * @param mixed $value any primitive value
70
+ *
71
+ * @return string
72
+ */
73
+ public function quote($value)
74
+ {
75
+ return mysql_real_escape_string($value, $this->connection);
76
+ }
77
+ }
src/MWP/IncrementalBackup/Database/MysqlDumpDumper.php ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_IncrementalBackup_Database_MysqlDumpDumper implements MWP_IncrementalBackup_Database_DumperInterface
12
+ {
13
+
14
+ /**
15
+ * @var MWP_IncrementalBackup_Database_Configuration
16
+ */
17
+ private $configuration;
18
+
19
+ /**
20
+ * @var MWP_IncrementalBackup_Database_DumpOptions
21
+ */
22
+ private $options;
23
+
24
+ /**
25
+ * @param MWP_IncrementalBackup_Database_Configuration $configuration
26
+ * @param MWP_IncrementalBackup_Database_DumpOptions $options
27
+ */
28
+ public function __construct(MWP_IncrementalBackup_Database_Configuration $configuration, MWP_IncrementalBackup_Database_DumpOptions $options)
29
+ {
30
+ $this->configuration = $configuration;
31
+ $this->options = $options;
32
+ }
33
+
34
+ /**
35
+ * {@inheritdoc}
36
+ */
37
+ function dump(array $tables = array())
38
+ {
39
+ if (!mwp_is_shell_available()) {
40
+ throw new MWP_Worker_Exception(MWP_Worker_Exception::SHELL_NOT_AVAILABLE, 'Shell not available.');
41
+ }
42
+
43
+ $mysqldump = mwp_container()->getExecutableFinder()->find('mysqldump', 'mysqldump');
44
+
45
+ $processBuilder = Symfony_Process_ProcessBuilder::create()
46
+ ->setWorkingDirectory(untrailingslashit(ABSPATH))
47
+ ->setTimeout(3600)
48
+ ->setPrefix($mysqldump)
49
+ // Continue even if we get an SQL error.
50
+ ->add('--force')
51
+ // User for login if not current user.
52
+ ->add('--user='.$this->configuration->getUsername())
53
+ // Password to use when connecting to server. If password is not given it's solicited on the tty.
54
+ ->add('--password='.$this->configuration->getPassword())
55
+ // Add a DROP TABLE before each create.
56
+ ->add('--add-drop-table');
57
+
58
+ if ($this->options->isSkipLockTables()) {
59
+ // Don't lock all tables for read.
60
+ $processBuilder->add('--lock-tables=false');
61
+ }
62
+
63
+ $processBuilder->add($this->configuration->getDatabase());
64
+
65
+ // Dump only specific tables
66
+ foreach ($tables as $table) {
67
+ $processBuilder->add($table);
68
+ }
69
+
70
+ if ($this->configuration->isSocket()) {
71
+ $processBuilder->add('--socket='.$this->configuration->getSocketPath());
72
+ } else {
73
+ $processBuilder->add('--host='.$this->configuration->getHost());
74
+ if (($port = $this->configuration->getPort()) !== null) {
75
+ $processBuilder->add('--port='.$port);
76
+ }
77
+ }
78
+
79
+ $process = $processBuilder->getProcess();
80
+
81
+ mwp_logger()->info('Database dumping process starting', array(
82
+ 'executable_location' => $mysqldump,
83
+ 'command_line' => $process->getCommandLine(),
84
+ ));
85
+
86
+ return new MWP_Stream_ProcessOutput($process);
87
+ }
88
+ }
src/MWP/IncrementalBackup/Database/MysqlStatement.php ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_IncrementalBackup_Database_MysqlStatement implements MWP_IncrementalBackup_Database_StatementInterface
12
+ {
13
+
14
+ /**
15
+ * @var resource
16
+ */
17
+ private $result;
18
+
19
+ public function __construct($result)
20
+ {
21
+ $this->result = $result;
22
+ }
23
+
24
+ /**
25
+ * @return array|null
26
+ */
27
+ public function fetch()
28
+ {
29
+ $row = @mysql_fetch_assoc($this->result);
30
+ if ($row === false) {
31
+ return null;
32
+ } else {
33
+ return $row;
34
+ }
35
+ }
36
+
37
+ /**
38
+ * @return array|null
39
+ */
40
+ public function fetchAll()
41
+ {
42
+ $rows = array();
43
+
44
+ while ($row = $this->fetch()) {
45
+ $rows[] = $row;
46
+ }
47
+
48
+ return $rows;
49
+ }
50
+ }
src/MWP/IncrementalBackup/Database/MysqliConnection.php ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_IncrementalBackup_Database_MysqliConnection implements MWP_IncrementalBackup_Database_ConnectionInterface
12
+ {
13
+
14
+ /**
15
+ * @var MWP_IncrementalBackup_Database_Configuration
16
+ */
17
+ private $configuration;
18
+
19
+ /**
20
+ * @var mysqli
21
+ */
22
+ private $connection;
23
+
24
+ public function __construct(MWP_IncrementalBackup_Database_Configuration $configuration)
25
+ {
26
+ $this->configuration = $configuration;
27
+
28
+ if (!extension_loaded('mysqli')) {
29
+ throw new MWP_IncrementalBackup_Database_Exception_ConnectionException("Mysqli extension is not enabled.");
30
+ }
31
+
32
+ // Silence possible warnings thrown by mysqli
33
+ // e.g. Warning: mysqli::mysqli(): Headers and client library minor version mismatch. Headers:50540 Library:50623
34
+ $this->connection = @new mysqli($configuration->getHost(), $configuration->getUsername(), $configuration->getPassword(), $configuration->getDatabase(), $configuration->getPort());
35
+
36
+ if ($this->connection === null || !$this->connection->ping()) {
37
+ throw new MWP_IncrementalBackup_Database_Exception_ConnectionException();
38
+ }
39
+
40
+ $this->connection->set_charset($configuration->getCharset());
41
+ }
42
+
43
+ /**
44
+ * @param string $query
45
+ *
46
+ * @throws MWP_IncrementalBackup_Database_Exception_ConnectionException
47
+ *
48
+ * @return MWP_IncrementalBackup_Database_StatementInterface
49
+ */
50
+ public function query($query)
51
+ {
52
+ $result = $this->connection->query($query);
53
+
54
+ if ($result === false) {
55
+ throw new MWP_IncrementalBackup_Database_Exception_ConnectionException($this->connection->error, $this->connection->errno);
56
+ }
57
+
58
+ return new MWP_IncrementalBackup_Database_MysqliStatement($result);
59
+ }
60
+
61
+ /**
62
+ * @param mixed $value any primitive value
63
+ *
64
+ * @return string
65
+ */
66
+ public function quote($value)
67
+ {
68
+ return $this->connection->real_escape_string($value);
69
+ }
70
+ }
src/MWP/IncrementalBackup/Database/MysqliStatement.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_IncrementalBackup_Database_MysqliStatement implements MWP_IncrementalBackup_Database_StatementInterface
12
+ {
13
+
14
+ /**
15
+ * @var mysqli_result|bool
16
+ */
17
+ private $result;
18
+
19
+ public function __construct($result)
20
+ {
21
+ $this->result = $result;
22
+ }
23
+
24
+ /**
25
+ * @return array|null
26
+ */
27
+ public function fetch()
28
+ {
29
+ if (is_bool($this->result)) {
30
+ return $this->result;
31
+ }
32
+
33
+ return $this->result->fetch_assoc();
34
+ }
35
+
36
+ /**
37
+ * @return array|null
38
+ */
39
+ public function fetchAll()
40
+ {
41
+ if (is_bool($this->result)) {
42
+ return $this->result;
43
+ }
44
+
45
+ $rows = array();
46
+ while ($row = $this->fetch()) {
47
+ $rows[] = $row;
48
+ }
49
+
50
+ return $rows;
51
+ }
52
+ }
src/MWP/IncrementalBackup/Database/PdoConnection.php ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_IncrementalBackup_Database_PdoConnection implements MWP_IncrementalBackup_Database_ConnectionInterface
12
+ {
13
+
14
+ /**
15
+ * @var MWP_IncrementalBackup_Database_Configuration
16
+ */
17
+ private $configuration;
18
+
19
+ /**
20
+ * @var PDO
21
+ */
22
+ private $connection;
23
+
24
+ public function __construct(MWP_IncrementalBackup_Database_Configuration $configuration)
25
+ {
26
+ $this->configuration = $configuration;
27
+
28
+ if (!extension_loaded('pdo_mysql')) {
29
+ throw new MWP_IncrementalBackup_Database_Exception_ConnectionException("PDO extension is disabled.");
30
+ }
31
+
32
+ $options = array(
33
+ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
34
+ PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
35
+ );
36
+
37
+ $this->connection = new PDO(self::getDsn($this->configuration), $this->configuration->getUsername(), $this->configuration->getPassword(), $options);
38
+ }
39
+
40
+ /**
41
+ * {@inheritdoc}
42
+ */
43
+ public function query($query)
44
+ {
45
+ return new MWP_IncrementalBackup_Database_PdoStatement($this->connection->query($query));
46
+ }
47
+
48
+ /**
49
+ * {@inheritdoc}
50
+ */
51
+ public function quote($value)
52
+ {
53
+ return $this->connection->quote($value);
54
+ }
55
+
56
+ /**
57
+ * @param MWP_IncrementalBackup_Database_Configuration $configuration
58
+ *
59
+ * @return string
60
+ */
61
+ private static function getDsn(MWP_IncrementalBackup_Database_Configuration $configuration)
62
+ {
63
+ $pdoParameters = array(
64
+ 'dbname' => $configuration->getDatabase(),
65
+ 'charset' => $configuration->getCharset(),
66
+ );
67
+
68
+ if ($configuration->isSocket()) {
69
+ $pdoParameters['unix_socket'] = $configuration->getSocketPath();
70
+ } else {
71
+ $pdoParameters['host'] = $configuration->getHost();
72
+
73
+ if (($port = $configuration->getPort()) !== null) {
74
+ $pdoParameters['port'] = $configuration->getPort();
75
+ }
76
+ }
77
+
78
+ $parameters = array();
79
+ foreach ($pdoParameters as $name => $value) {
80
+ $parameters[] = $name.'='.$value;
81
+ }
82
+
83
+ $dsn = sprintf("mysql:%s", implode(';', $parameters));
84
+
85
+ return $dsn;
86
+ }
87
+ }
src/MWP/IncrementalBackup/Database/PdoStatement.php ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_IncrementalBackup_Database_PdoStatement implements MWP_IncrementalBackup_Database_StatementInterface
12
+ {
13
+
14
+ /**
15
+ * @var PDOStatement
16
+ */
17
+ private $statement;
18
+
19
+ public function __construct(PDOStatement $statement)
20
+ {
21
+ $this->statement = $statement;
22
+ }
23
+
24
+ /**
25
+ * {@inheritdoc}
26
+ */
27
+ public function fetch()
28
+ {
29
+ return $this->statement->fetch();
30
+ }
31
+
32
+ /**
33
+ * {@inheritdoc}
34
+ */
35
+ public function fetchAll()
36
+ {
37
+ return $this->statement->fetchAll();
38
+ }
39
+ }
src/MWP/IncrementalBackup/Database/PhpDumper.php ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_IncrementalBackup_Database_PhpDumper implements MWP_IncrementalBackup_Database_DumperInterface
12
+ {
13
+
14
+ /**
15
+ * @var MWP_IncrementalBackup_Database_Configuration
16
+ */
17
+ private $configuration;
18
+
19
+ /**
20
+ * @var MWP_System_Environment
21
+ */
22
+ private $environment;
23
+
24
+ /**
25
+ * @var MWP_IncrementalBackup_Database_DumpOptions
26
+ */
27
+ private $options;
28
+
29
+ /**
30
+ * @param MWP_IncrementalBackup_Database_Configuration $configuration
31
+ * @param MWP_System_Environment $environment
32
+ * @param MWP_IncrementalBackup_Database_DumpOptions $options
33
+ */
34
+ public function __construct(MWP_IncrementalBackup_Database_Configuration $configuration, MWP_System_Environment $environment, MWP_IncrementalBackup_Database_DumpOptions $options)
35
+ {
36
+ $this->configuration = $configuration;
37
+ $this->environment = $environment;
38
+ $this->options = $options;
39
+ }
40
+
41
+ /**
42
+ * {@inheritdoc}
43
+ */
44
+ public function dump(array $tables)
45
+ {
46
+ if ($this->environment->isPdoEnabled()) {
47
+ $connection = new MWP_IncrementalBackup_Database_PdoConnection($this->configuration);
48
+ } elseif ($this->environment->isMysqliEnabled()) {
49
+ $connection = new MWP_IncrementalBackup_Database_MysqliConnection($this->configuration);
50
+ } elseif ($this->environment->isMysqlEnabled()) {
51
+ $connection = new MWP_IncrementalBackup_Database_MysqlConnection($this->configuration);
52
+ } else {
53
+ throw new MWP_IncrementalBackup_Database_Exception_ConnectionException("No mysql drivers available.");
54
+ }
55
+
56
+ $this->options->setTables($tables);
57
+ $dumper = new MWP_IncrementalBackup_Database_StreamableQuerySequenceDump($connection, $this->options);
58
+
59
+ return $dumper->createStream();
60
+ }
61
+ }
src/MWP/IncrementalBackup/Database/StatementInterface.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ interface MWP_IncrementalBackup_Database_StatementInterface
12
+ {
13
+ /**
14
+ * @return array|null
15
+ */
16
+ public function fetch();
17
+
18
+ /**
19
+ * @return array|null
20
+ */
21
+ public function fetchAll();
22
+ }
src/MWP/IncrementalBackup/Database/StreamableQuerySequenceDump.php ADDED
@@ -0,0 +1,249 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_IncrementalBackup_Database_StreamableQuerySequenceDump
12
+ {
13
+
14
+ /**
15
+ * @var MWP_IncrementalBackup_Database_ConnectionInterface
16
+ */
17
+ private $connection;
18
+
19
+ /**
20
+ * @var MWP_IncrementalBackup_Database_DumpOptions
21
+ */
22
+ private $options;
23
+
24
+ public function __construct(MWP_IncrementalBackup_Database_ConnectionInterface $connection, MWP_IncrementalBackup_Database_DumpOptions $options)
25
+ {
26
+ $this->connection = $connection;
27
+ $this->options = $options;
28
+ }
29
+
30
+ /**
31
+ * @return MWP_IncrementalBackup_Database_ConnectionInterface
32
+ */
33
+ protected function getConnection()
34
+ {
35
+ return $this->connection;
36
+ }
37
+
38
+ /**
39
+ * @inherit
40
+ */
41
+ public function createStream()
42
+ {
43
+ $stream = new MWP_Stream_Append();
44
+
45
+ $stream->addStream(MWP_Stream_Stream::factory("
46
+ /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
47
+ /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
48
+ /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
49
+ /*!40101 SET NAMES utf8 */;
50
+ /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
51
+ /*!40103 SET TIME_ZONE='+00:00' */;
52
+ /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
53
+ /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
54
+ /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
55
+ /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;\n\n"
56
+ ));
57
+
58
+ $allTables = MWP_Backup_ArrayHelper::arrayColumn($this->getConnection()->query('SHOW TABLES')->fetchAll());
59
+ $tables = array_intersect($allTables, $this->options->getTables() ? $this->options->getTables() : $allTables);
60
+
61
+ foreach ($tables as $tableName) {
62
+ $stream->addStream(
63
+ new MWP_Stream_Callable(array($this, 'streamCreateTable'), array($tableName))
64
+ );
65
+ }
66
+
67
+ $stream->addStream(MWP_Stream_Stream::factory("
68
+ /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
69
+ /*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
70
+ /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
71
+ /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
72
+ /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
73
+ /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
74
+ /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
75
+ /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;\n"
76
+ ));
77
+
78
+ return $stream;
79
+ }
80
+
81
+ public function streamCreateTable($length, $tableName)
82
+ {
83
+ // Get the SHOW CREATE TABLE part
84
+ $content = $this->getConnection()
85
+ ->query("SHOW CREATE TABLE `{$tableName}`;")
86
+ ->fetchAll();
87
+
88
+ if (!is_array($content)) {
89
+ return new MWP_Stream_Buffer();
90
+ }
91
+
92
+ $stream = new MWP_Stream_Append();
93
+
94
+ foreach ($content as $entry) {
95
+ // Add drop table query
96
+ if ($this->options->isDropTables()) {
97
+ $stream->addStream(MWP_Stream_Stream::factory("DROP TABLE IF EXISTS `$tableName`;\n"));
98
+ }
99
+
100
+ // Add create table query
101
+ $stream->addStream(MWP_Stream_Stream::factory("
102
+ /*!40101 SET @saved_cs_client = @@character_set_client */;
103
+ /*!40101 SET character_set_client = utf8 */;\n"
104
+ ));
105
+ $stream->addStream(MWP_Stream_Stream::factory($entry['Create Table'].";\n"));
106
+ $stream->addStream(MWP_Stream_Stream::factory("/*!40101 SET character_set_client = @saved_cs_client */;\n\n"));
107
+ }
108
+
109
+ // Export content
110
+ $stream->addStream(
111
+ new MWP_Stream_Callable(array($this, 'createExportTableStream'), array($tableName))
112
+ );
113
+
114
+ return $stream;
115
+ }
116
+
117
+ public function createExportTableStream($length, $tableName)
118
+ {
119
+ $stream = new MWP_Stream_Append();
120
+
121
+ $columns = $this->getConnection()
122
+ ->query("SHOW COLUMNS IN `{$tableName}`;")
123
+ ->fetchAll();
124
+
125
+ if (is_array($columns)) {
126
+ $columns = $this->repack($columns, 'Field');
127
+ }
128
+
129
+ $statement = $this->getConnection()
130
+ ->query($this->selectAllDataQuery($tableName, $columns));
131
+
132
+ // Go through row by row
133
+ if (!$this->options->isSkipLockTables()) {
134
+ $stream->addStream(MWP_Stream_Stream::factory("LOCK TABLES `$tableName` WRITE;\n"));
135
+ }
136
+
137
+ $stream->addStream(MWP_Stream_Stream::factory("/*!40000 ALTER TABLE `$tableName` DISABLE KEYS */;\n"));
138
+
139
+ $stream->addStream(
140
+ new MWP_Stream_Callable(array($this, 'createExportRowStream'), array($statement, $tableName, $columns))
141
+ );
142
+
143
+ $stream->addStream(MWP_Stream_Stream::factory(";\n"));
144
+ $stream->addStream(MWP_Stream_Stream::factory("/*!40000 ALTER TABLE `$tableName` ENABLE KEYS */;\n"));
145
+
146
+ if (!$this->options->isSkipLockTables()) {
147
+ $stream->addStream(MWP_Stream_Stream::factory("UNLOCK TABLES;\n"));
148
+ }
149
+
150
+ return $stream;
151
+ }
152
+
153
+ public function createExportRowStream($length, MWP_IncrementalBackup_Database_StatementInterface $statement, $tableName, $columns)
154
+ {
155
+ $row = $statement->fetch();
156
+ if (!$row) {
157
+ return false;
158
+ }
159
+
160
+ return $this->createRowInsertStatement($tableName, $row, $columns);
161
+ }
162
+
163
+ /**
164
+ * Repacks an array by making a key of a particular column
165
+ *
166
+ * @param array $array
167
+ * @param $column
168
+ *
169
+ * @return array
170
+ */
171
+ protected function repack(array $array, $column)
172
+ {
173
+ $repacked = array();
174
+ foreach ($array as $element) {
175
+ $repacked[$element[$column]] = $element;
176
+ }
177
+
178
+ return $repacked;
179
+ }
180
+
181
+ /**
182
+ * Creates an SQL statement for fetching all data from a particular table
183
+ *
184
+ * @param $tableName
185
+ * @param $columnData
186
+ *
187
+ * @return string
188
+ */
189
+ protected function selectAllDataQuery($tableName, $columnData)
190
+ {
191
+ $columns = array();
192
+ foreach ($columnData as $columnName => $metadata) {
193
+ if (strpos($metadata['Type'], 'blob') !== false) {
194
+ $fullColumnName = "`{$tableName}`.`{$columnName}`";
195
+ $columns[] = "HEX($fullColumnName) as `{$columnName}`";
196
+ } else {
197
+ $columns[] = "`{$tableName}`.`{$columnName}`";
198
+ }
199
+ }
200
+ $cols = join(', ', $columns);
201
+ $sql = "SELECT $cols FROM `$tableName`;";
202
+
203
+ return $sql;
204
+ }
205
+
206
+ /**
207
+ * Creates an sql statement for row insertion
208
+ *
209
+ * @param string $tableName
210
+ * @param array $row
211
+ * @param array $columns
212
+ *
213
+ * @return string
214
+ */
215
+ protected function createRowInsertStatement($tableName, array $row, array $columns = array())
216
+ {
217
+ $values = $this->createRowInsertValues($row, $columns);
218
+ $joined = join(', ', $values);
219
+ $sql = "INSERT INTO `$tableName` VALUES($joined);";
220
+
221
+ return $sql;
222
+ }
223
+
224
+ protected function createRowInsertValues($row, $columns)
225
+ {
226
+ $values = array();
227
+
228
+ foreach ($row as $columnName => $value) {
229
+ $type = $columns[$columnName]['Type'];
230
+ // If it should not be enclosed
231
+ if ($value === null) {
232
+ $values[] = 'null';
233
+ } elseif (strpos($type, 'int') !== false
234
+ || strpos($type, 'float') !== false
235
+ || strpos($type, 'double') !== false
236
+ || strpos($type, 'decimal') !== false
237
+ || strpos($type, 'bool') !== false
238
+ ) {
239
+ $values[] = $value;
240
+ } elseif (strpos($type, 'blob') !== false) {
241
+ $values[] = strlen($value) ? ('0x'.$value) : "''";
242
+ } else {
243
+ $values[] = $this->getConnection()->quote($value);
244
+ }
245
+ }
246
+
247
+ return $values;
248
+ }
249
+ }
src/MWP/IncrementalBackup/FileReader.php ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_IncrementalBackup_FileReader
12
+ {
13
+
14
+ /**
15
+ * @var int
16
+ */
17
+ private $chunkByteSize = 4096;
18
+
19
+ /**
20
+ * @return int
21
+ */
22
+ public function getChunkByteSize()
23
+ {
24
+ return $this->chunkByteSize;
25
+ }
26
+
27
+ /**
28
+ * @param int $chunkByteSize
29
+ */
30
+ public function setChunkByteSize($chunkByteSize)
31
+ {
32
+ $this->chunkByteSize = $chunkByteSize;
33
+ }
34
+
35
+ /**
36
+ *
37
+ *
38
+ * @param string $realPath
39
+ * @param int $offset
40
+ * @param int $limit
41
+ *
42
+ * @return mixed
43
+ */
44
+ public function readFileContents($realPath, $offset = 0, $limit = 0)
45
+ {
46
+ if (!file_exists($realPath)) {
47
+ return null;
48
+ }
49
+
50
+ $handle = fopen($realPath, "rb");
51
+ if (!$handle) {
52
+ return null;
53
+ }
54
+
55
+ $contentLength = 0;
56
+ $buffer = '';
57
+
58
+ if ($limit === 0) {
59
+ $limit = filesize($realPath) - $offset;
60
+ }
61
+
62
+ if ($offset !== 0) {
63
+ fseek($handle, $offset);
64
+ }
65
+
66
+ while ($limit > 0) {
67
+ $chunkSize = $limit > $this->chunkByteSize ? $this->chunkByteSize : $limit;
68
+ $limit = $limit - $chunkSize;
69
+ $contentLength = $contentLength + $chunkSize;
70
+
71
+ $contents = fread($handle, $chunkSize);
72
+ $buffer = $buffer.$contents;
73
+ }
74
+
75
+ fclose($handle);
76
+
77
+ return array($buffer, $contentLength);
78
+ }
79
+ }
src/MWP/IncrementalBackup/HashComputer.php ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_IncrementalBackup_HashComputer
12
+ {
13
+
14
+ // 100kb default value
15
+ private $maxChunkByteSize = 102400;
16
+
17
+ /**
18
+ * @param int $maxChunkByteSize
19
+ */
20
+ public function setMaxChunkByteSize($maxChunkByteSize)
21
+ {
22
+ $this->$maxChunkByteSize = $maxChunkByteSize;
23
+ }
24
+
25
+ /**
26
+ * @return int
27
+ */
28
+ public function getMaxChunkByteSize()
29
+ {
30
+ return $this->$maxChunkByteSize;
31
+ }
32
+
33
+ /**
34
+ * Compute a full md5 file hash or compute a partial hash if $limit is present.
35
+ * Returns null on failure.
36
+ *
37
+ * @param string $realPath
38
+ * @param int $offset in bytes
39
+ * @param int $limit in bytes
40
+ * @param boolean $forcePartialHashing
41
+ *
42
+ * @return null|string
43
+ */
44
+ public function computeMd5Hash($realPath, $offset = 0, $limit = 0, $forcePartialHashing = false)
45
+ {
46
+ if ($limit === 0 && $offset === 0 && !$forcePartialHashing) {
47
+ // md5_file is always faster if we don't chunk the file
48
+ $hash = md5_file($realPath);
49
+
50
+ return $hash !== false ? $hash : null;
51
+ }
52
+
53
+ $ctx = hash_init('md5');
54
+ if (!$ctx) {
55
+ // Fail to initialize file hashing
56
+ return null;
57
+ }
58
+
59
+ // Calculate limit from file size and offset
60
+ if ($limit === 0) {
61
+ $limit = filesize($realPath) - $offset;
62
+ }
63
+
64
+ $fh = fopen($realPath, "rb");
65
+ if ($fh === null) {
66
+ // Failed opening file, cleanup hash context
67
+ hash_final($ctx);
68
+
69
+ return null;
70
+ }
71
+
72
+ fseek($fh, $offset);
73
+
74
+ while ($limit > 0) {
75
+ // Limit chunk size to either our remaining chunk or max chunk size
76
+ $chunkSize = $limit < $this->maxChunkByteSize ? $limit : $this->maxChunkByteSize;
77
+ $limit -= $chunkSize;
78
+
79
+ $chunk = fread($fh, $chunkSize);
80
+ hash_update($ctx, $chunk);
81
+ }
82
+
83
+ fclose($fh);
84
+
85
+ return hash_final($ctx);
86
+ }
87
+
88
+ /**
89
+ * Run md5sum process and return file hash, or null in case of error
90
+ *
91
+ * @param $realPath
92
+ *
93
+ * @return string|null
94
+ */
95
+ public function computeUnixMd5Sum($realPath)
96
+ {
97
+ try {
98
+ $processBuilder = Symfony_Process_ProcessBuilder::create()
99
+ ->setPrefix('md5sum')
100
+ ->add($realPath);
101
+
102
+ if (!mwp_is_shell_available()) {
103
+ throw new MMB_Exception("Shell is not available");
104
+ }
105
+
106
+ $process = $processBuilder->getProcess();
107
+ $process->run();
108
+
109
+ if (!$process->isSuccessful()) {
110
+ throw new Symfony_Process_Exception_ProcessFailedException($process);
111
+ }
112
+
113
+ // Output is in the format of "md5hash filename"
114
+ $output = trim($process->getOutput());
115
+ $parts = explode(' ', $output);
116
+
117
+ // Return only the first part of the output
118
+ return trim($parts[0]);
119
+ } catch (Symfony_Process_Exception_ProcessFailedException $e) {
120
+ mwp_logger()->error('MD5 command line sum failed', array(
121
+ 'process' => $e->getProcess(),
122
+ ));
123
+ } catch (Exception $e) {
124
+ mwp_logger()->error('MD5 command line sum failed', array(
125
+ 'exception' => $e,
126
+ ));
127
+ }
128
+
129
+ return null;
130
+ }
131
+ }
src/MWP/IncrementalBackup/Model/FetchFilesResult.php ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_IncrementalBackup_Model_FetchFilesResult
12
+ {
13
+
14
+ /**
15
+ * @var MWP_IncrementalBackup_Model_File[]
16
+ */
17
+ private $files = array();
18
+
19
+ /**
20
+ * @var MWP_IncrementalBackup_Model_ServerStatistics
21
+ */
22
+ private $serverStatistics;
23
+
24
+ function __construct()
25
+ {
26
+ }
27
+
28
+ /**
29
+ * @return MWP_IncrementalBackup_Model_File[]
30
+ */
31
+ public function getFiles()
32
+ {
33
+ return $this->files;
34
+ }
35
+
36
+ /**
37
+ * @param MWP_IncrementalBackup_Model_File[] $files
38
+ */
39
+ public function setFiles($files)
40
+ {
41
+ $this->files = $files;
42
+ }
43
+
44
+ /**
45
+ * @param MWP_IncrementalBackup_Model_File $file
46
+ */
47
+ public function addFile(MWP_IncrementalBackup_Model_File $file)
48
+ {
49
+ $this->files[] = $file;
50
+ }
51
+
52
+ /**
53
+ * @return MWP_IncrementalBackup_Model_ServerStatistics
54
+ */
55
+ public function getServerStatistics()
56
+ {
57
+ return $this->serverStatistics;
58
+ }
59
+
60
+ /**
61
+ * @param MWP_IncrementalBackup_Model_ServerStatistics $serverStatistics
62
+ */
63
+ public function setServerStatistics($serverStatistics)
64
+ {
65
+ $this->serverStatistics = $serverStatistics;
66
+ }
67
+ }
src/MWP/IncrementalBackup/Model/File.php ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_IncrementalBackup_Model_File
12
+ {
13
+
14
+ /**
15
+ * @var string
16
+ */
17
+ private $pathname;
18
+
19
+ /**
20
+ * @var MWP_Stream_Interface
21
+ */
22
+ private $stream;
23
+
24
+ /**
25
+ * @return string
26
+ */
27
+ public function getPathname()
28
+ {
29
+ return $this->pathname;
30
+ }
31
+
32
+ /**
33
+ * @param string $pathname
34
+ */
35
+ public function setPathname($pathname)
36
+ {
37
+ $this->pathname = $pathname;
38
+ }
39
+
40
+ /**
41
+ * @return MWP_Stream_Interface
42
+ */
43
+ public function getStream()
44
+ {
45
+ return $this->stream;
46
+ }
47
+
48
+ /**
49
+ * @param MWP_Stream_Interface $stream
50
+ */
51
+ public function setStream($stream)
52
+ {
53
+ $this->stream = $stream;
54
+ }
55
+ }
src/MWP/IncrementalBackup/Model/ServerStatistics.php ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_IncrementalBackup_Model_ServerStatistics
12
+ {
13
+
14
+ /** @var int */
15
+ private $memoryPeak;
16
+
17
+ /** @var int */
18
+ private $memoryUsage;
19
+
20
+ /** @var int */
21
+ private $averageLoad;
22
+
23
+ /** @var bool */
24
+ private $shellAvailable;
25
+
26
+ function __construct($memoryPeak, $memoryUsage, $averageLoad, $shellAvailable)
27
+ {
28
+ $this->memoryPeak = $memoryPeak;
29
+ $this->memoryUsage = $memoryUsage;
30
+ $this->averageLoad = $averageLoad;
31
+ $this->shellAvailable = $shellAvailable;
32
+ }
33
+
34
+ /**
35
+ * @return int
36
+ */
37
+ public function getMemoryPeak()
38
+ {
39
+ return $this->memoryPeak;
40
+ }
41
+
42
+ /**
43
+ * @param int $memoryPeak
44
+ */
45
+ public function setMemoryPeak($memoryPeak)
46
+ {
47
+ $this->memoryPeak = $memoryPeak;
48
+ }
49
+
50
+ /**
51
+ * @return int
52
+ */
53
+ public function getMemoryUsage()
54
+ {
55
+ return $this->memoryUsage;
56
+ }
57
+
58
+ /**
59
+ * @param int $memoryUsage
60
+ */
61
+ public function setMemoryUsage($memoryUsage)
62
+ {
63
+ $this->memoryUsage = $memoryUsage;
64
+ }
65
+
66
+ /**
67
+ * @return int
68
+ */
69
+ public function getAverageLoad()
70
+ {
71
+ return $this->averageLoad;
72
+ }
73
+
74
+ /**
75
+ * @param int $averageLoad
76
+ */
77
+ public function setAverageLoad($averageLoad)
78
+ {
79
+ $this->averageLoad = $averageLoad;
80
+ }
81
+
82
+ /**
83
+ * @return boolean
84
+ */
85
+ public function isShellAvailable()
86
+ {
87
+ return $this->shellAvailable;
88
+ }
89
+
90
+ /**
91
+ * @param boolean $shellAvailable
92
+ */
93
+ public function setShellAvailable($shellAvailable)
94
+ {
95
+ $this->shellAvailable = $shellAvailable;
96
+ }
97
+
98
+ public function toArray()
99
+ {
100
+ return array(
101
+ 'memory_peak' => $this->getMemoryPeak(),
102
+ 'memory_usage' => $this->getMemoryUsage(),
103
+ 'average_load' => $this->getAverageLoad(),
104
+ 'shell_available' => $this->isShellAvailable(),
105
+ );
106
+ }
107
+
108
+ public static function factory()
109
+ {
110
+ return new self(
111
+ memory_get_peak_usage(true),
112
+ memory_get_usage(true),
113
+ strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' ? array(0, 0, 0) : sys_getloadavg(),
114
+ mwp_is_shell_available()
115
+ );
116
+ }
117
+ }
src/MWP/ServiceContainer/Abstract.php CHANGED
@@ -59,6 +59,12 @@ abstract class MWP_ServiceContainer_Abstract implements MWP_ServiceContainer_Int
59
 
60
  private $errorLogger;
61
 
 
 
 
 
 
 
62
  public function __construct(array $parameters = array())
63
  {
64
  $this->parameters = $parameters;
@@ -70,6 +76,14 @@ abstract class MWP_ServiceContainer_Abstract implements MWP_ServiceContainer_Int
70
  'worker_basename' => null,
71
  // Always use PhpSecLib, even if the PHP extension 'openssl' is loaded.
72
  'prefer_phpseclib' => false,
 
 
 
 
 
 
 
 
73
  // Log file to use for all worker logs.
74
  'log_file' => null,
75
  // GrayLog2 server to use for all worker logs.
@@ -83,6 +97,9 @@ abstract class MWP_ServiceContainer_Abstract implements MWP_ServiceContainer_Int
83
  'message_minimum_level' => Monolog_Logger::INFO,
84
  // Memory size (in kilobytes) to allocate for fatal error handling when the request is authenticated.
85
  'fatal_error_reserved_memory_size' => 1024,
 
 
 
86
  'hit_counter_blacklisted_ips' => array(
87
  // Uptime monitoring robot.
88
  '/^74\.86\.158\.106$/',
@@ -487,4 +504,43 @@ abstract class MWP_ServiceContainer_Abstract implements MWP_ServiceContainer_Int
487
  * @return Monolog_Logger
488
  */
489
  protected abstract function createErrorLogger();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
490
  }
59
 
60
  private $errorLogger;
61
 
62
+ private $systemEnvironment;
63
+
64
+ private $updaterSkin;
65
+
66
+ private $sessionStore;
67
+
68
  public function __construct(array $parameters = array())
69
  {
70
  $this->parameters = $parameters;
76
  'worker_basename' => null,
77
  // Always use PhpSecLib, even if the PHP extension 'openssl' is loaded.
78
  'prefer_phpseclib' => false,
79
+ // Force using fallbacks instead of shell commands
80
+ 'disable_shell' => false,
81
+ // Emulate disabled PDO extension
82
+ 'disable_pdo' => false,
83
+ // Emulate disabled mysqli extension
84
+ 'disable_mysqli' => false,
85
+ // Emulate disabled mysql
86
+ 'disable_mysql' => false,
87
  // Log file to use for all worker logs.
88
  'log_file' => null,
89
  // GrayLog2 server to use for all worker logs.
97
  'message_minimum_level' => Monolog_Logger::INFO,
98
  // Memory size (in kilobytes) to allocate for fatal error handling when the request is authenticated.
99
  'fatal_error_reserved_memory_size' => 1024,
100
+ // This boundary will be different with each request and it's pretty much a hack for handling exceptions
101
+ // @see MWP_EventListener_ActionException_MultipartException
102
+ 'multipart_boundary' => uniqid(),
103
  'hit_counter_blacklisted_ips' => array(
104
  // Uptime monitoring robot.
105
  '/^74\.86\.158\.106$/',
504
  * @return Monolog_Logger
505
  */
506
  protected abstract function createErrorLogger();
507
+
508
+ public function getSystemEnvironment()
509
+ {
510
+ if ($this->systemEnvironment === null) {
511
+ $this->systemEnvironment = $this->createSystemEnvironment();
512
+ }
513
+
514
+ return $this->systemEnvironment;
515
+ }
516
+
517
+ protected abstract function createSystemEnvironment();
518
+
519
+ public function getUpdaterSkin()
520
+ {
521
+ if ($this->updaterSkin === null) {
522
+ $this->updaterSkin = $this->createUpdaterSkin();
523
+ }
524
+
525
+ return $this->updaterSkin;
526
+ }
527
+
528
+ /**
529
+ * @return MWP_Updater_TraceableUpdaterSkin
530
+ */
531
+ protected abstract function createUpdaterSkin();
532
+
533
+ public function getSessionStore()
534
+ {
535
+ if ($this->sessionStore === null) {
536
+ $this->sessionStore = $this->createSessionStore();
537
+ }
538
+
539
+ return $this->sessionStore;
540
+ }
541
+
542
+ /**
543
+ * @return MWP_WordPress_SessionStore
544
+ */
545
+ protected abstract function createSessionStore();
546
  }
src/MWP/ServiceContainer/Interface.php CHANGED
@@ -138,4 +138,19 @@ interface MWP_ServiceContainer_Interface
138
  * @return Monolog_Logger
139
  */
140
  public function getErrorLogger();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
141
  }
138
  * @return Monolog_Logger
139
  */
140
  public function getErrorLogger();
141
+
142
+ /**
143
+ * @return MWP_System_Environment
144
+ */
145
+ public function getSystemEnvironment();
146
+
147
+ /**
148
+ * @return MWP_Updater_TraceableUpdaterSkin
149
+ */
150
+ public function getUpdaterSkin();
151
+
152
+ /**
153
+ * @return MWP_WordPress_SessionStore
154
+ */
155
+ public function getSessionStore();
156
  }
src/MWP/ServiceContainer/Production.php CHANGED
@@ -25,29 +25,39 @@ class MWP_ServiceContainer_Production extends MWP_ServiceContainer_Abstract
25
  {
26
  $dispatcher = new Symfony_EventDispatcher_EventDispatcher();
27
 
28
- $dispatcher->addSubscriber(new MWP_EventListener_PublicRequest_BrandContactSupport($this->getWordPressContext(), $this->getBrand()));
29
  $dispatcher->addSubscriber(new MWP_EventListener_PublicRequest_DisableEditor($this->getWordPressContext(), $this->getBrand()));
30
  $dispatcher->addSubscriber(new MWP_EventListener_PublicRequest_SetPluginInfo($this->getWordPressContext(), $this->getBrand()));
31
- $dispatcher->addSubscriber(new MWP_EventListener_PublicRequest_SetHitCounter($this->getWordPressContext(), $this->getHitCounter(), $this->getParameter('hit_counter_blacklisted_ips'), $this->getParameter('hit_counter_blacklisted_user_agents')));
32
- $dispatcher->addSubscriber(new MWP_EventListener_PublicRequest_AutomaticLogin($this->getWordPressContext(), $this->getNonceManager(), $this->getSigner(), $this->getConfiguration()));
 
33
 
34
  $dispatcher->addSubscriber(new MWP_EventListener_MasterRequest_VerifyConnectionInfo($this->getWordPressContext(), $this->getSigner()));
35
  $dispatcher->addSubscriber(new MWP_EventListener_MasterRequest_VerifyNonce($this->getNonceManager()));
36
- $dispatcher->addSubscriber(new MWP_EventListener_MasterRequest_SetCurrentUser($this->getWordPressContext()));
37
  $dispatcher->addSubscriber(new MWP_EventListener_MasterRequest_AuthenticateRequest($this->getConfiguration(), $this->getSigner()));
38
  $dispatcher->addSubscriber(new MWP_EventListener_MasterRequest_SetErrorHandler($this->getErrorLogger(), $this->getErrorHandler(), $this->getRequestStack(), $this->getResponseCallback(), $this, $this->getParameter('log_errors'), $this->getParameter('fatal_error_reserved_memory_size')));
39
  $dispatcher->addSubscriber(new MWP_EventListener_MasterRequest_AttachJsonMessageHandler($this->getLogger(), $this->getJsonMessageHandler()));
40
  $dispatcher->addSubscriber(new MWP_EventListener_MasterRequest_RemoveUsernameParam());
41
  $dispatcher->addSubscriber(new MWP_EventListener_MasterRequest_AuthenticateLegacyRequest($this->getConfiguration()));
 
42
 
43
- $dispatcher->addSubscriber(new MWP_EventListener_ActionRequest_SetSettings($this->getWordPressContext()));
 
 
44
 
45
  $dispatcher->addSubscriber(new MWP_EventListener_ActionException_SetExceptionData());
 
46
 
47
  $dispatcher->addSubscriber(new MWP_EventListener_ActionResponse_SetActionData());
48
  $dispatcher->addSubscriber(new MWP_EventListener_ActionResponse_SetLegacyWebsiteConnectionData($this->getWordPressContext()));
49
  $dispatcher->addSubscriber(new MWP_EventListener_ActionResponse_ChainState($this));
 
50
  $dispatcher->addSubscriber(new MWP_EventListener_ActionResponse_SetLegacyPhpExecutionData());
 
 
 
 
 
51
 
52
  $dispatcher->addSubscriber(new MWP_EventListener_EncodeMasterResponse());
53
 
@@ -66,43 +76,55 @@ class MWP_ServiceContainer_Production extends MWP_ServiceContainer_Abstract
66
  {
67
  $mapper = new MWP_Action_Registry();
68
 
69
- $mapper->addDefinition('do_upgrade', new MWP_Action_Definition('mmb_do_upgrade', array('hook_name' => 'setup_theme')));
70
- $mapper->addDefinition('get_stats', new MWP_Action_Definition('mmb_stats_get', array('hook_name' => 'setup_theme')));
71
  $mapper->addDefinition('remove_site', new MWP_Action_Definition('mmb_remove_site'));
72
  $mapper->addDefinition('backup_clone', new MWP_Action_Definition('mmb_backup_now'));
73
  $mapper->addDefinition('restore', new MWP_Action_Definition('mmb_restore_now'));
74
- $mapper->addDefinition('create_post', new MWP_Action_Definition('mmb_post_create', array('hook_name' => 'setup_theme')));
75
  $mapper->addDefinition('update_worker', new MWP_Action_Definition('mmb_update_worker_plugin'));
76
- $mapper->addDefinition('change_post_status', new MWP_Action_Definition('mmb_change_post_status', array('hook_name' => 'setup_theme')));
77
- $mapper->addDefinition('install_addon', new MWP_Action_Definition('mmb_install_addon', array('hook_name' => 'setup_theme')));
78
- $mapper->addDefinition('get_comments', new MWP_Action_Definition('mmb_get_comments', array('hook_name' => 'setup_theme')));
79
- $mapper->addDefinition('bulk_action_comments', new MWP_Action_Definition('mmb_bulk_action_comments', array('hook_name' => 'setup_theme')));
80
- $mapper->addDefinition('replyto_comment', new MWP_Action_Definition('mmb_reply_comment', array('hook_name' => 'setup_theme')));
81
- $mapper->addDefinition('add_user', new MWP_Action_Definition('mmb_add_user', array('hook_name' => 'setup_theme')));
82
  $mapper->addDefinition('scheduled_backup', new MWP_Action_Definition('mmb_scheduled_backup'));
83
  $mapper->addDefinition('run_task', new MWP_Action_Definition('mmb_run_task_now'));
84
  $mapper->addDefinition('execute_php_code', new MWP_Action_Definition('mmb_execute_php_code'));
85
  $mapper->addDefinition('delete_backup', new MWP_Action_Definition('mmm_delete_backup'));
86
  $mapper->addDefinition('remote_backup_now', new MWP_Action_Definition('mmb_remote_backup_now'));
87
- $mapper->addDefinition('get_users', new MWP_Action_Definition('mmb_get_users', array('hook_name' => 'setup_theme')));
88
- $mapper->addDefinition('edit_users', new MWP_Action_Definition('mmb_edit_users', array('hook_name' => 'setup_theme')));
89
- $mapper->addDefinition('get_posts', new MWP_Action_Definition('mmb_get_posts', array('hook_name' => 'setup_theme')));
90
- $mapper->addDefinition('delete_post', new MWP_Action_Definition('mmb_delete_post', array('hook_name' => 'setup_theme')));
91
- $mapper->addDefinition('delete_posts', new MWP_Action_Definition('mmb_delete_posts', array('hook_name' => 'setup_theme')));
92
- $mapper->addDefinition('get_pages', new MWP_Action_Definition('mmb_get_pages', array('hook_name' => 'setup_theme')));
93
- $mapper->addDefinition('delete_page', new MWP_Action_Definition('mmb_delete_page', array('hook_name' => 'setup_theme')));
94
- $mapper->addDefinition('get_plugins_themes', new MWP_Action_Definition('mmb_get_plugins_themes', array('hook_name' => 'setup_theme')));
95
- $mapper->addDefinition('edit_plugins_themes', new MWP_Action_Definition('mmb_edit_plugins_themes', array('hook_name' => 'setup_theme')));
96
  $mapper->addDefinition('worker_brand', new MWP_Action_Definition('mmb_worker_brand'));
97
  $mapper->addDefinition('maintenance', new MWP_Action_Definition('mmb_maintenance_mode'));
98
  $mapper->addDefinition('get_autoupdate_plugins_themes', new MWP_Action_Definition('mmb_get_autoupdate_plugins_themes'));
99
  $mapper->addDefinition('edit_autoupdate_plugins_themes', new MWP_Action_Definition('mmb_edit_autoupdate_plugins_themes'));
100
  $mapper->addDefinition('ping_backup', new MWP_Action_Definition('mwp_ping_backup'));
101
- $mapper->addDefinition('cleanup_delete', new MWP_Action_Definition('cleanup_delete_worker'));
102
  $mapper->addDefinition('backup_req', new MWP_Action_Definition('mmb_get_backup_req'));
103
- $mapper->addDefinition('change_comment_status', new MWP_Action_Definition('mmb_change_comment_status', array('hook_name' => null)));
104
  $mapper->addDefinition('get_state', new MWP_Action_Definition(array('MWP_Action_GetState', 'execute')));
105
  $mapper->addDefinition('add_site', new MWP_Action_Definition(array('MWP_Action_ConnectWebsite', 'execute')));
 
 
 
 
 
 
 
 
 
 
 
 
106
 
107
  return $mapper;
108
  }
@@ -219,6 +241,8 @@ class MWP_ServiceContainer_Production extends MWP_ServiceContainer_Abstract
219
  array(new MWP_Monolog_Processor_ExceptionProcessor(), 'callback'),
220
  array(new MWP_Monolog_Processor_ProcessProcessor(), 'callback'),
221
  );
 
 
222
  }
223
 
224
  $logger = new Monolog_Logger('worker', $handlers, $processors);
@@ -261,7 +285,7 @@ class MWP_ServiceContainer_Production extends MWP_ServiceContainer_Abstract
261
  */
262
  protected function createHitCounter()
263
  {
264
- $counter = new MWP_Extension_HitCounter($this->getWordPressContext(), 14);
265
 
266
  return $counter;
267
  }
@@ -290,4 +314,28 @@ class MWP_ServiceContainer_Production extends MWP_ServiceContainer_Abstract
290
 
291
  return $logger;
292
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
293
  }
25
  {
26
  $dispatcher = new Symfony_EventDispatcher_EventDispatcher();
27
 
28
+ $dispatcher->addSubscriber(new MWP_EventListener_PublicRequest_BrandContactSupport($this->getWordPressContext(), $this->getBrand(), $this->getRequestStack()));
29
  $dispatcher->addSubscriber(new MWP_EventListener_PublicRequest_DisableEditor($this->getWordPressContext(), $this->getBrand()));
30
  $dispatcher->addSubscriber(new MWP_EventListener_PublicRequest_SetPluginInfo($this->getWordPressContext(), $this->getBrand()));
31
+ $dispatcher->addSubscriber(new MWP_EventListener_PublicRequest_SetHitCounter($this->getWordPressContext(), $this->getHitCounter(), $this->getRequestStack(), $this->getParameter('hit_counter_blacklisted_ips'), $this->getParameter('hit_counter_blacklisted_user_agents')));
32
+ $dispatcher->addSubscriber(new MWP_EventListener_PublicRequest_AutomaticLogin($this->getWordPressContext(), $this->getNonceManager(), $this->getSigner(), $this->getConfiguration(), $this->getSessionStore()));
33
+ $dispatcher->addSubscriber(new MWP_EventListener_PublicRequest_AddStatusPage($this->getWordPressContext(), $this->getConfiguration()));
34
 
35
  $dispatcher->addSubscriber(new MWP_EventListener_MasterRequest_VerifyConnectionInfo($this->getWordPressContext(), $this->getSigner()));
36
  $dispatcher->addSubscriber(new MWP_EventListener_MasterRequest_VerifyNonce($this->getNonceManager()));
 
37
  $dispatcher->addSubscriber(new MWP_EventListener_MasterRequest_AuthenticateRequest($this->getConfiguration(), $this->getSigner()));
38
  $dispatcher->addSubscriber(new MWP_EventListener_MasterRequest_SetErrorHandler($this->getErrorLogger(), $this->getErrorHandler(), $this->getRequestStack(), $this->getResponseCallback(), $this, $this->getParameter('log_errors'), $this->getParameter('fatal_error_reserved_memory_size')));
39
  $dispatcher->addSubscriber(new MWP_EventListener_MasterRequest_AttachJsonMessageHandler($this->getLogger(), $this->getJsonMessageHandler()));
40
  $dispatcher->addSubscriber(new MWP_EventListener_MasterRequest_RemoveUsernameParam());
41
  $dispatcher->addSubscriber(new MWP_EventListener_MasterRequest_AuthenticateLegacyRequest($this->getConfiguration()));
42
+ $dispatcher->addSubscriber(new MWP_EventListener_MasterRequest_SetRequestSettings($this->getWordPressContext()));
43
 
44
+ $dispatcher->addSubscriber(new MWP_EventListener_ActionRequest_SetCurrentUser($this->getWordPressContext()));
45
+ $dispatcher->addSubscriber(new MWP_EventListener_ActionRequest_SetSettings($this->getWordPressContext(), $this->getSystemEnvironment()));
46
+ $dispatcher->addSubscriber(new MWP_EventListener_ActionRequest_LogRequest($this->getLogger()));
47
 
48
  $dispatcher->addSubscriber(new MWP_EventListener_ActionException_SetExceptionData());
49
+ $dispatcher->addSubscriber(new MWP_EventListener_ActionException_MultipartException($this->getParameter('multipart_boundary')));
50
 
51
  $dispatcher->addSubscriber(new MWP_EventListener_ActionResponse_SetActionData());
52
  $dispatcher->addSubscriber(new MWP_EventListener_ActionResponse_SetLegacyWebsiteConnectionData($this->getWordPressContext()));
53
  $dispatcher->addSubscriber(new MWP_EventListener_ActionResponse_ChainState($this));
54
+ $dispatcher->addSubscriber(new MWP_EventListener_ActionResponse_SetUpdaterLog($this->getUpdaterSkin()));
55
  $dispatcher->addSubscriber(new MWP_EventListener_ActionResponse_SetLegacyPhpExecutionData());
56
+ $dispatcher->addSubscriber(new MWP_EventListener_ActionResponse_FetchFiles($this->getParameter('multipart_boundary')));
57
+
58
+ $dispatcher->addSubscriber(new MWP_EventListener_MasterResponse_LogResponse($this->getLogger()));
59
+
60
+ $dispatcher->addSubscriber(new MWP_EventListener_FixCompatibility($this->getWordPressContext()));
61
 
62
  $dispatcher->addSubscriber(new MWP_EventListener_EncodeMasterResponse());
63
 
76
  {
77
  $mapper = new MWP_Action_Registry();
78
 
79
+ $mapper->addDefinition('do_upgrade', new MWP_Action_Definition('mmb_do_upgrade', array('hook_name' => 'init', 'hook_priority' => 9999)));
80
+ $mapper->addDefinition('get_stats', new MWP_Action_Definition('mmb_stats_get', array('hook_name' => 'init', 'hook_priority' => 9999)));
81
  $mapper->addDefinition('remove_site', new MWP_Action_Definition('mmb_remove_site'));
82
  $mapper->addDefinition('backup_clone', new MWP_Action_Definition('mmb_backup_now'));
83
  $mapper->addDefinition('restore', new MWP_Action_Definition('mmb_restore_now'));
84
+ $mapper->addDefinition('create_post', new MWP_Action_Definition('mmb_post_create', array('hook_name' => 'init', 'hook_priority' => 9999)));
85
  $mapper->addDefinition('update_worker', new MWP_Action_Definition('mmb_update_worker_plugin'));
86
+ $mapper->addDefinition('change_post_status', new MWP_Action_Definition('mmb_change_post_status', array('hook_name' => 'init', 'hook_priority' => 9999)));
87
+ $mapper->addDefinition('install_addon', new MWP_Action_Definition('mmb_install_addon', array('hook_name' => 'init', 'hook_priority' => 9999)));
88
+ $mapper->addDefinition('get_comments', new MWP_Action_Definition('mmb_get_comments', array('hook_name' => 'init', 'hook_priority' => 9999)));
89
+ $mapper->addDefinition('bulk_action_comments', new MWP_Action_Definition('mmb_bulk_action_comments', array('hook_name' => 'init', 'hook_priority' => 9999)));
90
+ $mapper->addDefinition('replyto_comment', new MWP_Action_Definition('mmb_reply_comment', array('hook_name' => 'init', 'hook_priority' => 9999)));
91
+ $mapper->addDefinition('add_user', new MWP_Action_Definition('mmb_add_user', array('hook_name' => 'init', 'hook_priority' => 9999)));
92
  $mapper->addDefinition('scheduled_backup', new MWP_Action_Definition('mmb_scheduled_backup'));
93
  $mapper->addDefinition('run_task', new MWP_Action_Definition('mmb_run_task_now'));
94
  $mapper->addDefinition('execute_php_code', new MWP_Action_Definition('mmb_execute_php_code'));
95
  $mapper->addDefinition('delete_backup', new MWP_Action_Definition('mmm_delete_backup'));
96
  $mapper->addDefinition('remote_backup_now', new MWP_Action_Definition('mmb_remote_backup_now'));
97
+ $mapper->addDefinition('get_users', new MWP_Action_Definition('mmb_get_users', array('hook_name' => 'init', 'hook_priority' => 9999)));
98
+ $mapper->addDefinition('edit_users', new MWP_Action_Definition('mmb_edit_users', array('hook_name' => 'init', 'hook_priority' => 9999)));
99
+ $mapper->addDefinition('get_posts', new MWP_Action_Definition('mmb_get_posts', array('hook_name' => 'init', 'hook_priority' => 9999)));
100
+ $mapper->addDefinition('delete_post', new MWP_Action_Definition('mmb_delete_post', array('hook_name' => 'init', 'hook_priority' => 9999)));
101
+ $mapper->addDefinition('delete_posts', new MWP_Action_Definition('mmb_delete_posts', array('hook_name' => 'init', 'hook_priority' => 9999)));
102
+ $mapper->addDefinition('get_pages', new MWP_Action_Definition('mmb_get_pages', array('hook_name' => 'init', 'hook_priority' => 9999)));
103
+ $mapper->addDefinition('delete_page', new MWP_Action_Definition('mmb_delete_page', array('hook_name' => 'init', 'hook_priority' => 9999)));
104
+ $mapper->addDefinition('get_plugins_themes', new MWP_Action_Definition('mmb_get_plugins_themes', array('hook_name' => 'init', 'hook_priority' => 9999)));
105
+ $mapper->addDefinition('edit_plugins_themes', new MWP_Action_Definition('mmb_edit_plugins_themes', array('hook_name' => 'init', 'hook_priority' => 9999)));
106
  $mapper->addDefinition('worker_brand', new MWP_Action_Definition('mmb_worker_brand'));
107
  $mapper->addDefinition('maintenance', new MWP_Action_Definition('mmb_maintenance_mode'));
108
  $mapper->addDefinition('get_autoupdate_plugins_themes', new MWP_Action_Definition('mmb_get_autoupdate_plugins_themes'));
109
  $mapper->addDefinition('edit_autoupdate_plugins_themes', new MWP_Action_Definition('mmb_edit_autoupdate_plugins_themes'));
110
  $mapper->addDefinition('ping_backup', new MWP_Action_Definition('mwp_ping_backup'));
111
+ $mapper->addDefinition('cleanup_delete', new MWP_Action_Definition('cleanup_delete_worker', array('hook_name' => 'init', 'hook_priority' => 9999)));
112
  $mapper->addDefinition('backup_req', new MWP_Action_Definition('mmb_get_backup_req'));
113
+ $mapper->addDefinition('change_comment_status', new MWP_Action_Definition('mmb_change_comment_status', array('hook_name' => 'init', 'hook_priority' => 9999)));
114
  $mapper->addDefinition('get_state', new MWP_Action_Definition(array('MWP_Action_GetState', 'execute')));
115
  $mapper->addDefinition('add_site', new MWP_Action_Definition(array('MWP_Action_ConnectWebsite', 'execute')));
116
+ $mapper->addDefinition('destroy_sessions', new MWP_Action_Definition(array('MWP_Action_DestroySessions', 'execute')));
117
+
118
+ // Incremental backup actions
119
+ $mapper->addDefinition('list_files', new MWP_Action_Definition(array('MWP_Action_IncrementalBackup_ListFiles', 'queryFiles')));
120
+ $mapper->addDefinition('list_directories', new MWP_Action_Definition(array('MWP_Action_IncrementalBackup_ListFiles', 'listDirectories')));
121
+ $mapper->addDefinition('hash_files', new MWP_Action_Definition(array('MWP_Action_IncrementalBackup_HashFiles', 'execute')));
122
+ $mapper->addDefinition('fetch_files', new MWP_Action_Definition(array('MWP_Action_IncrementalBackup_FetchFiles', 'execute')));
123
+ $mapper->addDefinition('list_tables', new MWP_Action_Definition(array('MWP_Action_IncrementalBackup_ListTables', 'listTables')));
124
+ $mapper->addDefinition('checksum_tables', new MWP_Action_Definition(array('MWP_Action_IncrementalBackup_ChecksumTables', 'execute')));
125
+ $mapper->addDefinition('dump_tables', new MWP_Action_Definition(array('MWP_Action_IncrementalBackup_DumpTables', 'execute')));
126
+ $mapper->addDefinition('backup_stats', new MWP_Action_Definition(array('MWP_Action_IncrementalBackup_Stats', 'execute')));
127
+ $mapper->addDefinition('upload_cloner', new MWP_Action_Definition(array('MWP_Action_IncrementalBackup_UploadCloner', 'execute')));
128
 
129
  return $mapper;
130
  }
241
  array(new MWP_Monolog_Processor_ExceptionProcessor(), 'callback'),
242
  array(new MWP_Monolog_Processor_ProcessProcessor(), 'callback'),
243
  );
244
+ } else {
245
+ $handlers[] = new Monolog_Handler_NullHandler();
246
  }
247
 
248
  $logger = new Monolog_Logger('worker', $handlers, $processors);
285
  */
286
  protected function createHitCounter()
287
  {
288
+ $counter = new MWP_Extension_HitCounter($this->getWordPressContext(), 60);
289
 
290
  return $counter;
291
  }
314
 
315
  return $logger;
316
  }
317
+
318
+ /**
319
+ * @return MWP_System_Environment
320
+ */
321
+ protected function createSystemEnvironment()
322
+ {
323
+ return new MWP_System_Environment($this);
324
+ }
325
+
326
+ /**
327
+ * @return MWP_Updater_TraceableUpdaterSkin
328
+ */
329
+ protected function createUpdaterSkin()
330
+ {
331
+ return new MWP_Updater_TraceableUpdaterSkin();
332
+ }
333
+
334
+ /**
335
+ * @return MWP_WordPress_SessionStore
336
+ */
337
+ protected function createSessionStore()
338
+ {
339
+ return new MWP_WordPress_SessionStore($this->getWordPressContext());
340
+ }
341
  }
src/MWP/Signer/PhpSecLibSigner.php CHANGED
@@ -23,8 +23,10 @@ class MWP_Signer_PhpSecLibSigner implements MWP_Signer_Interface
23
  $verify = $rsa->verify($data, $signature);
24
  $errorMessage = $errorCatcher->yieldErrorMessage(true);
25
 
26
- if ($errorMessage !== null && $errorMessage !== 'Signature representative out of range') {
27
- throw new MWP_Worker_Exception(MWP_Worker_Exception::PHPSECLIB_VERIFY_ERROR);
 
 
28
  }
29
 
30
  return $verify;
23
  $verify = $rsa->verify($data, $signature);
24
  $errorMessage = $errorCatcher->yieldErrorMessage(true);
25
 
26
+ if ($errorMessage !== null && $errorMessage !== 'Signature representative out of range' && $errorMessage !== 'Invalid signature') {
27
+ throw new MWP_Worker_Exception(MWP_Worker_Exception::PHPSECLIB_VERIFY_ERROR, null, array(
28
+ 'error' => $errorMessage,
29
+ ));
30
  }
31
 
32
  return $verify;
src/MWP/Stream/Append.php ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ /**
12
+ * Append stream.
13
+ */
14
+ class MWP_Stream_Append implements MWP_Stream_Interface
15
+ {
16
+
17
+ /**
18
+ * @var MWP_Stream_Interface[]
19
+ */
20
+ private $streams = array();
21
+
22
+ private $current = 0;
23
+
24
+ /**
25
+ * Add a stream to the AppendStream
26
+ *
27
+ * @param MWP_Stream_Interface $stream Stream to append. Must be readable.
28
+ */
29
+ public function addStream(MWP_Stream_Interface $stream)
30
+ {
31
+ $this->streams[] = $stream;
32
+ }
33
+
34
+ /**
35
+ * @return bool
36
+ */
37
+ public function isSeekable()
38
+ {
39
+ return false;
40
+ }
41
+
42
+ /**
43
+ * {@inheritdoc}
44
+ */
45
+ public function seek($offset, $whence = SEEK_SET)
46
+ {
47
+ return false;
48
+ }
49
+
50
+ /**
51
+ * {@inheritdoc}
52
+ */
53
+ public function eof()
54
+ {
55
+ return $this->isAtLastStream() && $this->getCurrentStream()->eof();
56
+ }
57
+
58
+ /**
59
+ * {@inheritdoc}
60
+ */
61
+ public function read($length)
62
+ {
63
+ $data = '';
64
+
65
+ while (!$this->eof()) {
66
+ while ($this->getCurrentStream()->eof() && !$this->eof()) {
67
+ $this->moveToNextStream();
68
+ }
69
+
70
+ $currentStreamData = $this->getCurrentStream()->read($length);
71
+ $data .= $currentStreamData;
72
+ $length -= strlen($currentStreamData);
73
+
74
+ if ($length <= 0) {
75
+ break;
76
+ }
77
+ }
78
+
79
+ return $data;
80
+ }
81
+
82
+ /**
83
+ * {@inheritdoc}
84
+ */
85
+ public function close()
86
+ {
87
+ foreach ($this->streams as $stream) {
88
+ $stream->close();
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Tell is not supported.
94
+ */
95
+ public function tell()
96
+ {
97
+ return false;
98
+ }
99
+
100
+ public function __toString()
101
+ {
102
+ $buffer = '';
103
+
104
+ while (!$this->eof()) {
105
+ $buffer .= $this->read(1048576);
106
+ }
107
+
108
+ return $buffer;
109
+ }
110
+
111
+ private function moveToNextStream()
112
+ {
113
+ if ($this->current >= count($this->streams)) {
114
+ return false;
115
+ }
116
+
117
+ $this->current++;
118
+
119
+ return true;
120
+ }
121
+
122
+ private function isAtLastStream()
123
+ {
124
+ return $this->current === count($this->streams) - 1;
125
+ }
126
+
127
+ private function getCurrentStream()
128
+ {
129
+ return $this->streams[$this->current];
130
+ }
131
+ }
src/MWP/Stream/Buffer.php ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_Stream_Buffer
12
+ {
13
+
14
+ private $hwm;
15
+
16
+ private $buffer = '';
17
+
18
+ /**
19
+ * @param int $hwm High water mark, representing the preferred maximum
20
+ * buffer size. If the size of the buffer exceeds the high
21
+ * water mark, then calls to write will continue to succeed
22
+ * but will return false to inform writers to slow down
23
+ * until the buffer has been drained by reading from it.
24
+ */
25
+ public function __construct($hwm = 16384)
26
+ {
27
+ $this->hwm = $hwm;
28
+ }
29
+
30
+ public function close()
31
+ {
32
+ $this->buffer = '';
33
+ }
34
+
35
+ public function isSeekable()
36
+ {
37
+ return false;
38
+ }
39
+
40
+ public function seek($offset, $whence = SEEK_SET)
41
+ {
42
+ return false;
43
+ }
44
+
45
+ public function eof()
46
+ {
47
+ return strlen($this->buffer) === 0;
48
+ }
49
+
50
+ public function tell()
51
+ {
52
+ return false;
53
+ }
54
+
55
+ /**
56
+ * Reads data from the buffer.
57
+ *
58
+ * @param $length
59
+ *
60
+ * @return string
61
+ */
62
+ public function read($length)
63
+ {
64
+ $currentLength = strlen($this->buffer);
65
+
66
+ if ($length >= $currentLength) {
67
+ // No need to slice the buffer because we don't have enough data.
68
+ $result = $this->buffer;
69
+ $this->buffer = '';
70
+ } else {
71
+ // Slice up the result to provide a subset of the buffer.
72
+ $result = substr($this->buffer, 0, $length);
73
+ $this->buffer = substr($this->buffer, $length);
74
+ }
75
+
76
+ return $result;
77
+ }
78
+
79
+ /**
80
+ * Writes data to the buffer.
81
+ *
82
+ * @param $string
83
+ *
84
+ * @return bool|int
85
+ */
86
+ public function write($string)
87
+ {
88
+ $this->buffer .= $string;
89
+
90
+ if (strlen($this->buffer) >= $this->hwm) {
91
+ return false;
92
+ }
93
+
94
+ return strlen($string);
95
+ }
96
+ }
src/MWP/Stream/Callable.php ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_Stream_Callable implements MWP_Stream_Interface
12
+ {
13
+
14
+ /** @var callable */
15
+ private $source;
16
+
17
+ /** @var int */
18
+ private $tellPos = 0;
19
+
20
+ /** @var MWP_Stream_Buffer */
21
+ private $buffer;
22
+
23
+ /** @var array */
24
+ private $arguments;
25
+
26
+ /**
27
+ * @param callable $source Source of the stream data. The callable MAY
28
+ * accept an integer argument used to control the
29
+ * amount of data to return. The callable MUST
30
+ * return a string when called, or false on error
31
+ * or EOF.
32
+ * @param array $arguments
33
+ */
34
+ public function __construct($source, array $arguments = array())
35
+ {
36
+ $this->source = $source;
37
+ $this->buffer = new MWP_Stream_Buffer();
38
+ $this->arguments = $arguments;
39
+ }
40
+
41
+ public function close()
42
+ {
43
+ $this->tellPos = false;
44
+ $this->source = null;
45
+ $this->arguments = array();
46
+ }
47
+
48
+ public function tell()
49
+ {
50
+ return $this->tellPos;
51
+ }
52
+
53
+ public function eof()
54
+ {
55
+ return !$this->source;
56
+ }
57
+
58
+ public function isSeekable()
59
+ {
60
+ return false;
61
+ }
62
+
63
+ public function seek($offset, $whence = SEEK_SET)
64
+ {
65
+ return false;
66
+ }
67
+
68
+ public function read($length)
69
+ {
70
+ $data = $this->buffer->read($length);
71
+ $readLen = strlen($data);
72
+ $this->tellPos += $readLen;
73
+ $remaining = $length - $readLen;
74
+
75
+ if ($remaining) {
76
+ $this->pump($remaining);
77
+ $data .= $this->buffer->read($remaining);
78
+ $this->tellPos += strlen($data) - $readLen;
79
+ }
80
+
81
+ return $data;
82
+ }
83
+
84
+ public function __toString()
85
+ {
86
+ $buffer = '';
87
+
88
+ while (!$this->eof()) {
89
+ $buffer .= $this->read(1048576);
90
+ }
91
+
92
+ return $buffer;
93
+ }
94
+
95
+ private function pump($length)
96
+ {
97
+ if ($this->source) {
98
+ do {
99
+ $data = call_user_func_array($this->source, array_merge(array($length), $this->arguments));
100
+ if ($data === false || $data === null) {
101
+ $this->source = null;
102
+
103
+ return;
104
+ }
105
+ if ($data instanceof MWP_Stream_Interface) {
106
+ $this->source = null;
107
+ $this->buffer = $data;
108
+
109
+ return;
110
+ }
111
+ $this->buffer->write($data);
112
+ $length -= strlen($data);
113
+ } while ($length > 0);
114
+ }
115
+ }
116
+ }
src/MWP/Stream/Interface.php ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ interface MWP_Stream_Interface
12
+ {
13
+ /**
14
+ * Closes the stream and any underlying resources.
15
+ */
16
+ public function close();
17
+
18
+ /**
19
+ * Returns the current position of the file read/write pointer
20
+ *
21
+ * @return int|bool Returns the position of the file pointer or false on error
22
+ */
23
+ public function tell();
24
+
25
+ /**
26
+ * @return bool
27
+ */
28
+ public function isSeekable();
29
+
30
+ /**
31
+ * @param int $offset
32
+ * @param int $whence
33
+ *
34
+ * @return bool
35
+ */
36
+ public function seek($offset, $whence = SEEK_SET);
37
+
38
+ /**
39
+ * Returns true if the stream is at the end of the stream.
40
+ *
41
+ * @return bool
42
+ */
43
+ public function eof();
44
+
45
+ /**
46
+ * Read data from the stream
47
+ *
48
+ * @param int $length Read up to $length bytes from the object and return
49
+ * them. Fewer than $length bytes may be returned if
50
+ * underlying stream call returns fewer bytes.
51
+ *
52
+ * @return string Returns the data read from the stream.
53
+ */
54
+ public function read($length);
55
+ }
src/MWP/Stream/LazyFile.php ADDED
@@ -0,0 +1,130 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ /**
12
+ * Lazily open file stream for reading and close it when EOF is reached.
13
+ */
14
+ class MWP_Stream_LazyFile implements MWP_Stream_Interface
15
+ {
16
+
17
+ /**
18
+ * @var MWP_Stream_Interface
19
+ */
20
+ private $stream = null;
21
+
22
+ /**
23
+ * @var mixed
24
+ */
25
+ private $realPath;
26
+
27
+ /**
28
+ * @var bool
29
+ */
30
+ private $initialized = false;
31
+
32
+ public function __construct($realPath)
33
+ {
34
+ $this->realPath = $realPath;
35
+ }
36
+
37
+ /**
38
+ * {@inheritdoc}
39
+ */
40
+ public function close()
41
+ {
42
+ if ($this->stream !== null) {
43
+ $this->stream->close();
44
+ }
45
+ }
46
+
47
+ /**
48
+ * {@inheritdoc}
49
+ */
50
+ public function tell()
51
+ {
52
+ $this->initialize();
53
+
54
+ return $this->stream !== null ? $this->stream->tell() : false;
55
+ }
56
+
57
+ /**
58
+ * {@inheritdoc}
59
+ */
60
+ public function isSeekable()
61
+ {
62
+ $this->initialize();
63
+
64
+ return $this->stream !== null ? $this->stream->isSeekable() : false;
65
+ }
66
+
67
+ /**
68
+ * {@inheritdoc}
69
+ */
70
+ public function seek($offset, $whence = SEEK_SET)
71
+ {
72
+ $this->initialize();
73
+
74
+ return $this->stream !== null ? $this->stream->seek($offset, $whence) : false;
75
+ }
76
+
77
+ /**
78
+ * {@inheritdoc}
79
+ */
80
+ public function eof()
81
+ {
82
+ $this->initialize();
83
+
84
+ return $this->stream !== null ? $this->stream->eof() : true;
85
+ }
86
+
87
+ /**
88
+ * {@inheritdoc}
89
+ */
90
+ public function read($length)
91
+ {
92
+ $this->initialize();
93
+
94
+ if ($this->stream === null) {
95
+ return null;
96
+ }
97
+
98
+ $data = $this->stream->read($length);
99
+
100
+ if ($this->eof()) {
101
+ $this->close();
102
+ }
103
+
104
+ return $data;
105
+ }
106
+
107
+ public function __toString()
108
+ {
109
+ $buffer = '';
110
+
111
+ while (!$this->eof()) {
112
+ $buffer .= $this->read(1048576);
113
+ }
114
+
115
+ return $buffer;
116
+ }
117
+
118
+ private function initialize()
119
+ {
120
+ if ($this->initialized === false) {
121
+ if (file_exists($this->realPath)) {
122
+ $handle = @fopen($this->realPath, "rb");
123
+ if ($handle !== false) {
124
+ $this->stream = MWP_Stream_Stream::factory($handle);
125
+ }
126
+ }
127
+ $this->initialized = true;
128
+ }
129
+ }
130
+ }
src/MWP/Stream/Limit.php ADDED
@@ -0,0 +1,153 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_Stream_Limit implements MWP_Stream_Interface
12
+ {
13
+
14
+ /**
15
+ * @var MWP_Stream_Interface
16
+ */
17
+ private $stream;
18
+
19
+ /**
20
+ * @var int
21
+ */
22
+ private $offset = 0;
23
+
24
+ /**
25
+ * @var int
26
+ */
27
+ private $limit = -1;
28
+
29
+ public function __construct(MWP_Stream_Interface $stream, $offset = 0, $limit = -1)
30
+ {
31
+ $this->stream = $stream;
32
+ $this->setOffset($offset);
33
+ $this->limit = $limit;
34
+ }
35
+
36
+ /**
37
+ * {@inheritdoc}
38
+ */
39
+ public function eof()
40
+ {
41
+ // Always return true if the underlying stream is EOF
42
+ if ($this->stream->eof()) {
43
+ return true;
44
+ }
45
+
46
+ // No limit and the underlying stream is not at EOF
47
+ if ($this->limit == -1) {
48
+ return false;
49
+ }
50
+
51
+ $tell = $this->stream->tell();
52
+ if ($tell === false) {
53
+ return false;
54
+ }
55
+
56
+ return $tell >= $this->offset + $this->limit;
57
+ }
58
+
59
+ /**
60
+ * {@inheritdoc}
61
+ */
62
+ public function read($length)
63
+ {
64
+ if ($this->limit == -1) {
65
+ return $this->stream->read($length);
66
+ }
67
+
68
+ // Check if the current position is less than the total allowed
69
+ // bytes + original offset
70
+ $remaining = ($this->offset + $this->limit) - $this->stream->tell();
71
+ if ($remaining > 0) {
72
+ // Only return the amount of requested data, ensuring that the byte
73
+ // limit is not exceeded
74
+ return $this->stream->read(min($remaining, $length));
75
+ } else {
76
+ return false;
77
+ }
78
+ }
79
+
80
+ /**
81
+ * {@inheritdoc}
82
+ */
83
+ public function setOffset($offset)
84
+ {
85
+ $current = $this->stream->tell();
86
+
87
+ if ($current !== $offset) {
88
+ // If the stream cannot seek to the offset position, then read to it
89
+ if (!$this->stream->seek($offset)) {
90
+ $this->stream->read($offset - $current);
91
+ }
92
+ }
93
+
94
+ $this->offset = $offset;
95
+
96
+ return $this;
97
+ }
98
+
99
+ /**
100
+ * {@inheritdoc}
101
+ */
102
+ public function tell()
103
+ {
104
+ return $this->stream->tell() - $this->offset;
105
+ }
106
+
107
+ /**
108
+ * {@inheritdoc}
109
+ */
110
+ public function isSeekable()
111
+ {
112
+ return $this->stream->isSeekable();
113
+ }
114
+
115
+ /**
116
+ * {@inheritdoc}
117
+ */
118
+ public function seek($offset, $whence = SEEK_SET)
119
+ {
120
+ if ($whence !== SEEK_SET || $offset < 0) {
121
+ return false;
122
+ }
123
+
124
+ $offset += $this->offset;
125
+
126
+ if ($this->limit !== -1) {
127
+ if ($offset > $this->offset + $this->limit) {
128
+ $offset = $this->offset + $this->limit;
129
+ }
130
+ }
131
+
132
+ return $this->stream->seek($offset);
133
+ }
134
+
135
+ /**
136
+ * {@inheritdoc}
137
+ */
138
+ public function close()
139
+ {
140
+ $this->stream->close();
141
+ }
142
+
143
+ public function __toString()
144
+ {
145
+ $buffer = '';
146
+
147
+ while (!$this->eof()) {
148
+ $buffer .= $this->read(1048576);
149
+ }
150
+
151
+ return $buffer;
152
+ }
153
+ }
src/MWP/Stream/ProcessOutput.php ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_Stream_ProcessOutput extends MWP_Stream_Callable
12
+ {
13
+
14
+ /**
15
+ * @var Symfony_Process_Process
16
+ */
17
+ private $process;
18
+
19
+ /**
20
+ * @var bool
21
+ */
22
+ private $ran = false;
23
+
24
+ public function __construct(Symfony_Process_Process $process)
25
+ {
26
+ parent::__construct(array($this, 'getIncrementalOutput'));
27
+ $this->process = $process;
28
+ }
29
+
30
+ public function getIncrementalOutput()
31
+ {
32
+ if (!$this->ran) {
33
+ $this->ran = true;
34
+ try {
35
+ $this->process->start();
36
+ } catch (Symfony_Process_Exception_ExceptionInterface $e) {
37
+ throw new Symfony_Process_Exception_ProcessFailedException($this->process);
38
+ }
39
+ usleep(100);
40
+ }
41
+
42
+ $output = $this->process->getIncrementalOutput();
43
+ if (!$this->process->isRunning() && empty($output)) {
44
+ return false;
45
+ }
46
+
47
+ return empty($output) ? '' : $output;
48
+ }
49
+ }
src/MWP/Stream/Stream.php ADDED
@@ -0,0 +1,132 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_Stream_Stream implements MWP_Stream_Interface
12
+ {
13
+
14
+ /**
15
+ * @var resource
16
+ */
17
+ private $stream;
18
+
19
+ /**
20
+ * @var bool
21
+ */
22
+ private $seekable;
23
+
24
+ public function __construct($stream)
25
+ {
26
+ if (!is_resource($stream)) {
27
+ throw new \InvalidArgumentException('Stream must be a resource');
28
+ }
29
+
30
+ $this->stream = $stream;
31
+
32
+ $meta = stream_get_meta_data($this->stream);
33
+ $this->seekable = $meta['seekable'];
34
+ }
35
+
36
+ /**
37
+ * Returns true if the stream is at the end of the stream.
38
+ *
39
+ * @return bool
40
+ */
41
+ public function eof()
42
+ {
43
+ return !$this->stream || feof($this->stream);
44
+ }
45
+
46
+ /**
47
+ * Read data from the stream
48
+ *
49
+ * @param int $length Read up to $length bytes from the object and return
50
+ * them. Fewer than $length bytes may be returned if
51
+ * underlying stream call returns fewer bytes.
52
+ *
53
+ * @return string Returns the data read from the stream.
54
+ */
55
+ public function read($length)
56
+ {
57
+ return fread($this->stream, $length);
58
+ }
59
+
60
+ public static function factory($resource)
61
+ {
62
+ $type = gettype($resource);
63
+
64
+ if ($type == 'string') {
65
+ $stream = fopen('php://temp', 'r+');
66
+ if ($resource !== '') {
67
+ fwrite($stream, $resource);
68
+ fseek($stream, 0);
69
+ }
70
+
71
+ return new self($stream);
72
+ }
73
+
74
+ if ($type == 'resource') {
75
+ return new self($resource);
76
+ }
77
+
78
+ if ($resource instanceof MWP_Stream_Interface) {
79
+ return $resource;
80
+ }
81
+
82
+ throw new InvalidArgumentException('Invalid resource type: '.$type);
83
+ }
84
+
85
+ /**
86
+ * {@inheritdoc}
87
+ */
88
+ public function isSeekable()
89
+ {
90
+ return $this->seekable;
91
+ }
92
+
93
+ /**
94
+ * {@inheritdoc}
95
+ */
96
+ public function seek($offset, $whence = SEEK_SET)
97
+ {
98
+ return $this->seekable
99
+ ? fseek($this->stream, $offset, $whence) === 0
100
+ : false;
101
+ }
102
+
103
+ /**
104
+ * {@inheritdoc}
105
+ */
106
+ public function close()
107
+ {
108
+ if ($this->stream !== null) {
109
+ fclose($this->stream);
110
+ $this->stream = null;
111
+ }
112
+ }
113
+
114
+ /**
115
+ * {@inheritdoc}
116
+ */
117
+ public function tell()
118
+ {
119
+ return $this->stream !== null ? ftell($this->stream) : false;
120
+ }
121
+
122
+ public function __toString()
123
+ {
124
+ $buffer = '';
125
+
126
+ while (!$this->eof()) {
127
+ $buffer .= $this->read(1048576);
128
+ }
129
+
130
+ return $buffer;
131
+ }
132
+ }
src/MWP/System/Environment.php ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_System_Environment
12
+ {
13
+
14
+ /**
15
+ * @var MWP_ServiceContainer_Interface
16
+ */
17
+ private $container;
18
+
19
+ public function __construct(MWP_ServiceContainer_Interface $container)
20
+ {
21
+ $this->container = $container;
22
+ }
23
+
24
+ public function getMemoryLimit()
25
+ {
26
+ return MWP_System_Utils::convertToBytes(ini_get('memory_limit'));
27
+ }
28
+
29
+ public function isPdoEnabled()
30
+ {
31
+ if ($this->container->getParameter('disable_pdo')) {
32
+ return false;
33
+ }
34
+
35
+ return extension_loaded('pdo_mysql');
36
+ }
37
+
38
+ public function isMysqliEnabled()
39
+ {
40
+ if ($this->container->getParameter('disable_mysqli')) {
41
+ return false;
42
+ }
43
+
44
+ return extension_loaded('mysqli');
45
+ }
46
+
47
+ public function isMysqlEnabled()
48
+ {
49
+ if ($this->container->getParameter('disable_mysql')) {
50
+ return false;
51
+ }
52
+
53
+ return extension_loaded('mysql');
54
+ }
55
+ }
src/MWP/System/Utils.php ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_System_Utils
12
+ {
13
+ /**
14
+ * Converts output of 'memory_limit' php.ini directive to bytes.
15
+ *
16
+ * @param $memoryLimit
17
+ *
18
+ * @return int|string
19
+ */
20
+ public static function convertToBytes($memoryLimit)
21
+ {
22
+ if ('-1' === $memoryLimit) {
23
+ return -1;
24
+ }
25
+
26
+ $memoryLimit = strtolower($memoryLimit);
27
+ $max = strtolower(ltrim($memoryLimit, '+'));
28
+ if (0 === strpos($max, '0x')) {
29
+ $max = intval($max, 16);
30
+ } elseif (0 === strpos($max, '0')) {
31
+ $max = intval($max, 8);
32
+ } else {
33
+ $max = intval($max);
34
+ }
35
+
36
+ switch (substr($memoryLimit, -1)) {
37
+ case 't':
38
+ $max *= 1024;
39
+ case 'g':
40
+ $max *= 1024;
41
+ case 'm':
42
+ $max *= 1024;
43
+ case 'k':
44
+ $max *= 1024;
45
+ }
46
+
47
+ return $max;
48
+ }
49
+ }
src/MWP/Updater/TraceableUpdaterSkin.php ADDED
@@ -0,0 +1,183 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ /**
12
+ * Taken from WordPress's automatic updater skin, which was added in version 3.7.
13
+ *
14
+ * @see Automatic_Upgrader_Skin
15
+ */
16
+ class MWP_Updater_TraceableUpdaterSkin
17
+ {
18
+
19
+ public $options = array(
20
+ 'url' => '',
21
+ 'nonce' => '',
22
+ 'title' => '',
23
+ 'context' => false,
24
+ );
25
+
26
+ public $upgrader;
27
+
28
+ public $result;
29
+
30
+ public $done_header = false;
31
+
32
+ protected $messages = array();
33
+
34
+ public function request_filesystem_credentials($error = false, $context = '', $allow_relaxed_file_ownership = false)
35
+ {
36
+ if ($error instanceof WP_Error) {
37
+ throw new MWP_Worker_Exception(MWP_Worker_Exception::FILESYSTEM_CREDENTIALS_ERROR, $error->get_error_message());
38
+ }
39
+
40
+ if ($context) {
41
+ $this->options['context'] = $context;
42
+ }
43
+
44
+ require_once ABSPATH.'wp-admin/includes/file.php';
45
+ // This will output a credentials form in event of failure; we don't want that, so just hide with a buffer.
46
+ ob_start();
47
+ $result = request_filesystem_credentials('', '', $error, $context, null, $allow_relaxed_file_ownership);
48
+ ob_end_clean();
49
+
50
+ return $result;
51
+ }
52
+
53
+ public function get_upgrade_messages()
54
+ {
55
+ return $this->messages;
56
+ }
57
+
58
+ /**
59
+ * @param string|array|WP_Error $data
60
+ */
61
+ public function feedback($data)
62
+ {
63
+ if (is_wp_error($data)) {
64
+ $string = $data->get_error_message();
65
+ } else {
66
+ if (is_array($data)) {
67
+ return;
68
+ } else {
69
+ $string = $data;
70
+ }
71
+ }
72
+
73
+ if (!empty($this->upgrader->strings[$string])) {
74
+ $string = $this->upgrader->strings[$string];
75
+ }
76
+
77
+ if (strpos($string, '%') !== false) {
78
+ $args = func_get_args();
79
+ $args = array_splice($args, 1);
80
+ if (!empty($args)) {
81
+ $string = vsprintf($string, $args);
82
+ }
83
+ }
84
+
85
+ $string = trim($string);
86
+
87
+ // Only allow basic HTML in the messages, as it'll be used in emails/logs rather than direct browser output.
88
+ $string = wp_kses($string, array(
89
+ 'a' => array(
90
+ 'href' => true
91
+ ),
92
+ 'br' => true,
93
+ 'em' => true,
94
+ 'strong' => true,
95
+ ));
96
+
97
+ if (empty($string)) {
98
+ return;
99
+ }
100
+
101
+ $this->messages[] = array(
102
+ 'message' => $string,
103
+ 'key' => $data,
104
+ 'args' => isset($args) ? $args : array(),
105
+ );
106
+ }
107
+
108
+ public function header()
109
+ {
110
+ ob_start();
111
+ }
112
+
113
+ public function footer()
114
+ {
115
+ $output = ob_get_contents();
116
+ if (!empty($output)) {
117
+ $this->feedback($output);
118
+ }
119
+ ob_end_clean();
120
+ }
121
+
122
+ public function bulk_header()
123
+ {
124
+ }
125
+
126
+ public function bulk_footer()
127
+ {
128
+ }
129
+
130
+ public function before()
131
+ {
132
+ }
133
+
134
+ public function after()
135
+ {
136
+ }
137
+
138
+ // Below was taken from WP_Upgrader_Skin, so we don't autoload it and cause trouble.
139
+ public function decrement_update_count()
140
+ {
141
+ }
142
+
143
+ public function error($errors)
144
+ {
145
+ if (is_string($errors)) {
146
+ $this->feedback($errors);
147
+
148
+ return;
149
+ }
150
+
151
+ if (!$errors instanceof WP_Error || !$errors->get_error_code()) {
152
+ return;
153
+ }
154
+
155
+ foreach ($errors->get_error_messages() as $message) {
156
+ if ($errors->get_error_data() && is_string($errors->get_error_data())) {
157
+ $this->feedback($message.' '.esc_html(strip_tags($errors->get_error_data())));
158
+ } else {
159
+ $this->feedback($message);
160
+ }
161
+ }
162
+ }
163
+
164
+ /**
165
+ * @param WP_Upgrader $upgrader
166
+ */
167
+ public function set_upgrader($upgrader)
168
+ {
169
+ if (is_object($upgrader)) {
170
+ $this->upgrader = $upgrader;
171
+ }
172
+ $this->add_strings();
173
+ }
174
+
175
+ public function add_strings()
176
+ {
177
+ }
178
+
179
+ public function set_result($result)
180
+ {
181
+ $this->result = $result;
182
+ }
183
+ }
src/MWP/WordPress/Context.php CHANGED
@@ -288,6 +288,21 @@ class MWP_WordPress_Context
288
  return get_themes();
289
  }
290
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
291
  public function getStylesheetDirectory()
292
  {
293
  return get_stylesheet_directory();
@@ -397,6 +412,9 @@ class MWP_WordPress_Context
397
 
398
  public function isGranted($capability)
399
  {
 
 
 
400
  return current_user_can($capability);
401
  }
402
 
@@ -460,7 +478,7 @@ class MWP_WordPress_Context
460
  /**
461
  * @param string $username
462
  *
463
- * @return WP_User|null
464
  */
465
  public function getUserByUsername($username)
466
  {
@@ -478,7 +496,7 @@ class MWP_WordPress_Context
478
  /**
479
  * @param $criteria
480
  *
481
- * @return WP_User[]
482
  *
483
  * @link http://codex.wordpress.org/Function_Reference/get_users
484
  *
@@ -512,7 +530,10 @@ class MWP_WordPress_Context
512
  return in_array($pluginBasename, $plugins);
513
  }
514
 
515
- public function setCurrentUser(WP_User $user)
 
 
 
516
  {
517
  $this->requirePluggable();
518
 
@@ -523,7 +544,12 @@ class MWP_WordPress_Context
523
  wp_set_current_user($user->ID);
524
  }
525
 
526
- public function setAuthCookie(WP_User $user, $remember = false, $secure = '')
 
 
 
 
 
527
  {
528
  $this->requireCookieConstants();
529
 
@@ -671,4 +697,51 @@ class MWP_WordPress_Context
671
  {
672
  remove_action($tag, $function, $priority);
673
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
674
  }
288
  return get_themes();
289
  }
290
 
291
+ public function getCurrentTheme()
292
+ {
293
+ // When the plugin is MU-loaded, the WordPress theme directories are not set.
294
+ if ($this->isMustUse() && empty($this->context['wp_theme_directories'])) {
295
+ // Register the default theme directory root.
296
+ register_theme_directory(get_theme_root());
297
+ }
298
+
299
+ if ($this->isVersionAtLeast('3.4')) {
300
+ return wp_get_theme();
301
+ }
302
+
303
+ return get_current_theme();
304
+ }
305
+
306
  public function getStylesheetDirectory()
307
  {
308
  return get_stylesheet_directory();
412
 
413
  public function isGranted($capability)
414
  {
415
+ $this->requirePluggable();
416
+ $this->requireCookieConstants();
417
+
418
  return current_user_can($capability);
419
  }
420
 
478
  /**
479
  * @param string $username
480
  *
481
+ * @return WP_User|stdClass|null
482
  */
483
  public function getUserByUsername($username)
484
  {
496
  /**
497
  * @param $criteria
498
  *
499
+ * @return WP_User[]|stdClass[]
500
  *
501
  * @link http://codex.wordpress.org/Function_Reference/get_users
502
  *
530
  return in_array($pluginBasename, $plugins);
531
  }
532
 
533
+ /**
534
+ * @param WP_User|stdClass $user
535
+ */
536
+ public function setCurrentUser($user)
537
  {
538
  $this->requirePluggable();
539
 
544
  wp_set_current_user($user->ID);
545
  }
546
 
547
+ /**
548
+ * @param WP_User|stdClass $user
549
+ * @param bool $remember
550
+ * @param string $secure
551
+ */
552
+ public function setAuthCookie($user, $remember = false, $secure = '')
553
  {
554
  $this->requireCookieConstants();
555
 
697
  {
698
  remove_action($tag, $function, $priority);
699
  }
700
+
701
+ public function addSubMenuPage($parentSlug, $pageTitle, $menuTitle, $capability, $menuSlug, $function = '')
702
+ {
703
+ return add_submenu_page($parentSlug, $pageTitle, $menuTitle, $capability, $menuSlug, $function);
704
+ }
705
+
706
+ public function wpNonceUrl($url, $action = -1, $name = '_wpnonce')
707
+ {
708
+ return wp_nonce_url($url, $action, $name);
709
+ }
710
+
711
+ /**
712
+ * @param int $userId
713
+ * @param string $metaKey
714
+ *
715
+ * @return mixed
716
+ */
717
+ public function getUserMeta($userId, $metaKey)
718
+ {
719
+ return get_user_meta($userId, $metaKey, true);
720
+ }
721
+
722
+ /**
723
+ * @param int $userId
724
+ * @param string $metaKey
725
+ * @param mixed $metaValue
726
+ *
727
+ * @return int|bool Meta ID if the key didn't exist, true on successful update, false on failure.
728
+ */
729
+ public function setUserMeta($userId, $metaKey, $metaValue)
730
+ {
731
+ return update_user_meta($userId, $metaKey, $metaValue);
732
+ }
733
+
734
+ /**
735
+ * @param int $userId
736
+ *
737
+ * @return WP_Session_Tokens|null Returns null if the class does not exist, ie. before WordPress version 4.0.0.
738
+ */
739
+ public function getSessionTokens($userId)
740
+ {
741
+ if (!class_exists('WP_Session_Tokens', false)) {
742
+ return null;
743
+ }
744
+
745
+ return WP_Session_Tokens::get_instance($userId);
746
+ }
747
  }
src/MWP/WordPress/SessionStore.php ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * This file is part of the ManageWP Worker plugin.
4
+ *
5
+ * (c) ManageWP LLC <contact@managewp.com>
6
+ *
7
+ * For the full copyright and license information, please view the LICENSE
8
+ * file that was distributed with this source code.
9
+ */
10
+
11
+ class MWP_WordPress_SessionStore
12
+ {
13
+
14
+ private $context;
15
+
16
+ private $sessionsKey = 'mwp_sessions';
17
+
18
+ public function __construct(MWP_WordPress_Context $context)
19
+ {
20
+ $this->context = $context;
21
+ }
22
+
23
+ /**
24
+ * @param int $userId
25
+ * @param string $token
26
+ */
27
+ public function add($userId, $token)
28
+ {
29
+ $sessions = $this->getSessions();
30
+ $sessions[(int) $userId][] = (string) $token;
31
+
32
+ $this->saveSessions($sessions);
33
+ }
34
+
35
+ /**
36
+ * @return int Number of destroyed sessions.
37
+ */
38
+ public function destroyAll()
39
+ {
40
+ if (!$this->context->isVersionAtLeast('4.0.0')) {
41
+ // Not supported before WordPress 4.0.0.
42
+ return -1;
43
+ }
44
+
45
+ $removed = 0;
46
+ foreach ($this->getSessions() as $userId => $tokens) {
47
+ $sessionTokens = $this->context->getSessionTokens($userId);
48
+ foreach ($tokens as $token) {
49
+ $sessionTokens->destroy($token);
50
+ $removed++;
51
+ }
52
+ }
53
+
54
+ $this->saveSessions(array());
55
+
56
+ return $removed;
57
+ }
58
+
59
+ /**
60
+ * Returns array of arrays of session IDs, indexed by user ID.
61
+ *
62
+ * @example
63
+ * -
64
+ * user_id_1:
65
+ * - token_id_1
66
+ * - token_id_2
67
+ * user_id_2:
68
+ * - token_id_3
69
+ * - token_id_4
70
+ * - token_id_5
71
+ * ...
72
+ *
73
+ * @return array[]
74
+ */
75
+ private function getSessions()
76
+ {
77
+ $sessions = $this->context->transientGet($this->sessionsKey);
78
+
79
+ return $sessions ? $sessions : array();
80
+ }
81
+
82
+ private function saveSessions($sessions)
83
+ {
84
+ $this->context->transientSet($this->sessionsKey, $sessions);
85
+ }
86
+ }
src/MWP/Worker/Exception.php CHANGED
@@ -31,9 +31,15 @@ class MWP_Worker_Exception extends Exception
31
  const CONNECTION_PUBLIC_KEY_NOT_PROVIDED = 10021;
32
  const CONNECTION_VERIFICATION_TEST_FAILED = 10022;
33
  const PHP_EVAL_ERROR = 10023;
34
- const LEGACY_AUTHENTICATION_INVALID_SIGNATURE = 1024;
35
- const LEGACY_AUTHENTICATION_KEY_EXISTS = 1025;
36
- const AUTO_LOGIN_USERNAME_REQUIRED = 1026;
 
 
 
 
 
 
37
 
38
  const GENERAL_ERROR = 10000;
39
 
31
  const CONNECTION_PUBLIC_KEY_NOT_PROVIDED = 10021;
32
  const CONNECTION_VERIFICATION_TEST_FAILED = 10022;
33
  const PHP_EVAL_ERROR = 10023;
34
+ const LEGACY_AUTHENTICATION_INVALID_SIGNATURE = 10024;
35
+ const LEGACY_AUTHENTICATION_KEY_EXISTS = 10025;
36
+ const AUTO_LOGIN_USERNAME_REQUIRED = 10026;
37
+ const FILESYSTEM_CREDENTIALS_ERROR = 10027;
38
+ const SHELL_NOT_AVAILABLE = 10028;
39
+ const BACKUP_DATABASE_METHOD_NOT_AVAILABLE = 10029;
40
+ const BACKUP_DATABASE_FAILED = 10030;
41
+ const BACKUP_DATABASE_MISSING_TABLES = 10031;
42
+ const IO_EXCEPTION = 10032;
43
 
44
  const GENERAL_ERROR = 10000;
45
 
src/MWP/Worker/Kernel.php CHANGED
@@ -96,7 +96,7 @@ class MWP_Worker_Kernel
96
  }
97
 
98
  // Allow listeners to modify action parameters.
99
- $actionRequestEvent = new MWP_Event_ActionRequest($request, $params);
100
  $this->dispatcher->dispatch(MWP_Event_Events::ACTION_REQUEST, $actionRequestEvent);
101
  $params = $actionRequestEvent->getParams();
102
 
96
  }
97
 
98
  // Allow listeners to modify action parameters.
99
+ $actionRequestEvent = new MWP_Event_ActionRequest($request, $params, $actionDefinition);
100
  $this->dispatcher->dispatch(MWP_Event_Events::ACTION_REQUEST, $actionRequestEvent);
101
  $params = $actionRequestEvent->getParams();
102
 
src/MWP/Worker/Request.php CHANGED
@@ -180,7 +180,7 @@ class MWP_Worker_Request
180
  $this->attributes['data'] = $data;
181
  $this->attributes['params'] = $data['params'];
182
  $this->attributes['setting'] = array_key_exists('setting', $data) ? $data['setting'] : null;
183
- $this->attributes['user'] = (array_key_exists('username', $data) && is_scalar($data['username'])) ? $data['username'] : null;
184
  }
185
  }
186
 
180
  $this->attributes['data'] = $data;
181
  $this->attributes['params'] = $data['params'];
182
  $this->attributes['setting'] = array_key_exists('setting', $data) ? $data['setting'] : null;
183
+ $this->attributes['user'] = (isset($data['params']['username']) && is_scalar($data['params']['username'])) ? $data['params']['username'] : null;
184
  }
185
  }
186
 
src/Monolog/Formatter/LineFormatter.php CHANGED
@@ -69,7 +69,7 @@ class Monolog_Formatter_LineFormatter extends Monolog_Formatter_NormalizerFormat
69
  protected function normalizeException(Exception $e)
70
  {
71
  $previousText = '';
72
- if ($previous = $e->getPrevious()) {
73
  do {
74
  $previousText .= ', '.get_class($previous).': '.$previous->getMessage().' at '.$previous->getFile().':'.$previous->getLine();
75
  } while ($previous = $previous->getPrevious());
69
  protected function normalizeException(Exception $e)
70
  {
71
  $previousText = '';
72
+ if (is_callable(array($e, 'getPrevious')) && $previous = $e->getPrevious()) {
73
  do {
74
  $previousText .= ', '.get_class($previous).': '.$previous->getMessage().' at '.$previous->getFile().':'.$previous->getLine();
75
  } while ($previous = $previous->getPrevious());
version CHANGED
@@ -1,2 +1,2 @@
1
- 4.0.1
2
- 2015-01-18 00:00:00
1
+ 4.1.0
2
+ 2015-04-23 00:00:00