PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 4.0.2
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v4.0.2
5.13.0 5.12.1 5.12.0 5.11.1 5.11.0 5.10.2 5.10.1 trunk 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.3.2 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.10.0 4.11.0 4.12.0 4.13.0 4.13.2 4.13.3 4.13.4 4.13.5 4.14.0 4.14.1 4.14.2 4.15.0 4.15.1 4.15.2 4.15.3 4.2.0 4.3.0 4.3.1 4.4.1 4.4.2 4.5.0 4.6.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.10.0 5.2.0 5.2.1 5.2.2 5.3.0 5.3.1 5.3.2 5.3.3 5.6.0 5.6.1 5.7.0 5.7.1 5.8.0 5.8.1 5.8.2
matomo / classes / WpMatomo / Updater.php
matomo / classes / WpMatomo Last commit date
Admin 5 years ago Commands 5 years ago Db 5 years ago Ecommerce 5 years ago Report 6 years ago Site 5 years ago TrackingCode 5 years ago Updater 5 years ago User 5 years ago views 6 years ago API.php 5 years ago Access.php 6 years ago AjaxTracker.php 5 years ago Annotations.php 6 years ago Bootstrap.php 6 years ago Capabilities.php 6 years ago Compatibility.php 6 years ago Email.php 5 years ago Installer.php 5 years ago Logger.php 5 years ago OptOut.php 6 years ago Paths.php 6 years ago PrivacyBadge.php 6 years ago Referral.php 6 years ago Roles.php 6 years ago ScheduledTasks.php 5 years ago Settings.php 5 years ago Site.php 6 years ago TrackingCode.php 5 years ago Uninstaller.php 6 years ago Updater.php 5 years ago User.php 6 years ago
Updater.php
247 lines
1 <?php
2 /**
3 * Matomo - free/libre analytics platform
4 *
5 * @link https://matomo.org
6 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
7 * @package matomo
8 */
9
10 namespace WpMatomo;
11
12 use Piwik\Cache as PiwikCache;
13 use Piwik\Filesystem;
14 use Piwik\Option;
15 use Piwik\Plugins\Installation\ServerFilesGenerator;
16 use Piwik\SettingsServer;
17 use Piwik\Version;
18 use WpMatomo\Updater\UpdateInProgressException;
19
20 if ( ! defined( 'ABSPATH' ) ) {
21 exit; // if accessed directly
22 }
23
24 class Updater {
25 const LOCK_NAME = 'matomo_updater';
26
27 /**
28 * @var Settings
29 */
30 private $settings;
31
32 /**
33 * @var Logger
34 */
35 private $logger;
36
37 public function __construct( Settings $settings ) {
38 $this->settings = $settings;
39 $this->logger = new Logger();
40 }
41
42 public function load_plugin_functions() {
43 if ( ! function_exists( 'get_plugin_data' ) ) {
44 require_once ABSPATH . '/wp-admin/includes/plugin.php';
45 }
46
47 return function_exists( 'get_plugin_data' );
48 }
49
50 public function get_plugins_requiring_update()
51 {
52 if ( ! $this->load_plugin_functions() ) {
53 return [];
54 }
55
56 $keys = [];
57 $plugin_files = $GLOBALS['MATOMO_PLUGIN_FILES'];
58 if ( ! in_array( MATOMO_ANALYTICS_FILE, $plugin_files, true ) ) {
59 $plugin_files[] = MATOMO_ANALYTICS_FILE;
60 // making sure this plugin is in the list so when itself gets updated
61 // it will execute the core updates
62 }
63
64 foreach ( $GLOBALS['MATOMO_PLUGIN_FILES'] as $plugin_file ) {
65 $plugin_data = get_plugin_data( $plugin_file, $markup = false, $translate = false );
66
67 $key = Settings::OPTION_PREFIX . 'plugin-version-' . basename( str_ireplace( '.php', '', $plugin_file ) );
68 $installed_ver = get_option( $key );
69 if ( ! $installed_ver || $installed_ver !== $plugin_data['Version'] ) {
70 if ( ! Installer::is_intalled() ) {
71 return [];
72 }
73 $keys[$key] = $plugin_data['Version'];
74 }
75 }
76
77 return $keys;
78 }
79
80 public function update_if_needed() {
81 $executed_updates = array();
82
83 $plugins_requiring_update = $this->get_plugins_requiring_update();
84 foreach ($plugins_requiring_update as $key => $plugin_version) {
85 try {
86 $this->update();
87 } catch ( UpdateInProgressException $e ) {
88 $this->logger->log( 'Matomo update is already in progress');
89 return; // we also don't execute any further update as they should be executed in another process
90 }catch ( \Exception $e ) {
91 $this->logger->log_exception( 'plugin_update', $e );
92 continue;
93 }
94 $executed_updates[] = $key;
95
96 // we're scheduling another update in case there are some dimensions to be updated or anything
97 // we do not do this in the "update" method as otherwise we might be calling this recursively...
98 // it is possible that because the plugins need to be reloaded etc that those updates are not executed right
99 // away but need an actual reload and cache clearance etc
100 wp_schedule_single_event( time() + 15, ScheduledTasks::EVENT_UPDATE );
101
102 update_option( $key, $plugin_version );
103
104 // we make sure to delete cache even if no component was updated eg there may be translation updates etc
105 // and caches need to be invalidated
106 Filesystem::deleteAllCacheOnUpdate();
107 }
108
109 return $executed_updates;
110 }
111
112 public function update() {
113 Bootstrap::do_bootstrap();
114
115 if ( $this->load_plugin_functions() ) {
116 $plugin_data = get_plugin_data( MATOMO_ANALYTICS_FILE, $markup = false, $translate = false );
117
118 $history = $this->settings->get_global_option( 'version_history' );
119 if ( empty( $history ) || ! is_array( $history ) ) {
120 $history = array();
121 }
122
123 if ( ! empty( $plugin_data['Version'] )
124 && ! in_array( $plugin_data['Version'], $history, true ) ) {
125 // this allows us to see which versions of matomo the user was using before this update so we better understand
126 // which version maybe regressed something
127 array_unshift( $history, $plugin_data['Version'] );
128 $history = array_slice( $history, 0, 5 ); // lets keep only the last 5 versions
129 $this->settings->set_global_option( 'version_history', $history );
130 }
131 }
132
133 $this->settings->set_global_option( 'core_version', Version::VERSION );
134 $this->settings->save();
135
136 $paths = new Paths();
137 $paths->clear_cache_dir();
138
139 Option::clearCache();
140 PiwikCache::flushAll();
141
142 \Piwik\Access::doAsSuperUser(
143 function () {
144 self::update_components();
145 self::update_components();
146 }
147 );
148
149 $upload_dir = $paths->get_upload_base_dir();
150 if ( is_dir( $upload_dir ) && is_writable( $upload_dir ) ) {
151 @file_put_contents( $upload_dir . '/index.php', '//hello' );
152 @file_put_contents( $upload_dir . '/index.html', '//hello' );
153 @file_put_contents( $upload_dir . '/index.htm', '//hello' );
154 @file_put_contents(
155 $upload_dir . '/.htaccess',
156 '<Files ~ "(\.mmdb)$">
157 ' . ServerFilesGenerator::getDenyHtaccessContent() . '
158 </Files>
159 <Files ~ "(\.js)$">
160 ' . ServerFilesGenerator::getAllowHtaccessContent() . '
161 </Files>'
162 );
163 }
164 $config_dir = $paths->get_config_ini_path();
165 if ( is_dir( $config_dir ) && is_writable( $config_dir ) ) {
166 @file_put_contents( $config_dir . '/index.php', '//hello' );
167 @file_put_contents( $config_dir . '/index.html', '//hello' );
168 @file_put_contents( $config_dir . '/index.htm', '//hello' );
169 }
170
171 if ($this->settings->should_disable_addhandler()) {
172 wp_schedule_single_event( time() + 10, ScheduledTasks::EVENT_DISABLE_ADDHANDLER );
173 }
174 }
175
176 public function is_upgrade_in_progress() {
177 if ( ! self::load_upgrader() ) {
178 return 'no upgrader';
179 }
180
181 if (self::lock()) {
182 // we can get the lock meaning no update is in progress
183 self::unlock();
184 return false;
185 }
186
187 return true;
188 }
189
190 private static function load_upgrader() {
191 if (!class_exists('\WP_Upgrader', false)) {
192 @include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
193 }
194 return class_exists('\WP_Upgrader', false);
195 }
196
197 public static function lock()
198 {
199 // prevent the upgrade from being started several times at once
200 // we lock for 4 minutes. In case of major Matomo upgrades the upgrade may take much longer but it should be
201 // safe in this case to run the upgrade several times
202 // important: we always need to use the same timeout otherwise if something did use `create_lock(2)` then
203 // even though another job locked it for 4 minutes, the other job that locks it only for 2 seconds would release
204 // the lock basically since WP does not remember the initialy set release timeout
205 return self::load_upgrader() && \WP_Upgrader::create_lock(self::LOCK_NAME, 60*4);
206 }
207
208 public static function unlock()
209 {
210 return self::load_upgrader() && \WP_Upgrader::release_lock(self::LOCK_NAME);
211 }
212
213 private static function update_components() {
214 $updater = new \Piwik\Updater();
215 $components_with_update_file = $updater->getComponentUpdates( );
216
217 if ( empty( $components_with_update_file ) ) {
218 return false;
219 }
220
221 if (!self::lock()) {
222 throw new UpdateInProgressException();
223 }
224
225 try {
226 SettingsServer::setMaxExecutionTime(0);
227
228 if (function_exists('ignore_user_abort')) {
229 @ignore_user_abort(true);
230 }
231
232 $result = $updater->updateComponents( $components_with_update_file );
233 } catch (\Exception $e) {
234 self::unlock();
235 throw $e;
236 }
237 self::unlock();
238
239 if (!empty($result['errors'])) {
240 throw new \Exception('Error while updating components: ' . implode(', ' , $result['errors']));
241 }
242
243 \Piwik\Updater::recordComponentSuccessfullyUpdated( 'core', Version::VERSION );
244 Filesystem::deleteAllCacheOnUpdate();
245 }
246 }
247