From e3cc1c03c9e7e795385fe2560e2dcbe27539e0d0 Mon Sep 17 00:00:00 2001 From: Yahnis Elsts Date: Sat, 15 Feb 2020 15:28:12 +0200 Subject: [PATCH] Fixed a potential fatal error when the current PUC version is removed during an upgrade. By default, PUC automatically checks for updates immediately after the user upgrades the plugin or theme. This can become a problem if the upgrade overwrites the PUC library with a different version. While checking for updates, PUC may attempt to autoload a class, which will trigger a fatal error if the class file was deleted during the upgrade. Fixed by checking if the running PUC version still exists after the upgrade. If it doesn't, remove hooks and stop. --- Puc/v4p9/Scheduler.php | 30 +++++++++++++++++++++++++++++- Puc/v4p9/UpdateChecker.php | 6 +++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/Puc/v4p9/Scheduler.php b/Puc/v4p9/Scheduler.php index ce81463..ef6ed99 100644 --- a/Puc/v4p9/Scheduler.php +++ b/Puc/v4p9/Scheduler.php @@ -87,6 +87,7 @@ if ( !class_exists('Puc_v4p9_Scheduler', false) ): * Runs upon the WP action upgrader_process_complete. * * We look at the parameters to decide whether to call maybeCheckForUpdates() or not. + * We also check if the update checker has been removed by the update. * * @param WP_Upgrader $upgrader WP_Upgrader instance * @param array $upgradeInfo extra information about the upgrade @@ -95,6 +96,15 @@ if ( !class_exists('Puc_v4p9_Scheduler', false) ): /** @noinspection PhpUnusedParameterInspection */ $upgrader, $upgradeInfo ) { + //Cancel all further actions if the current version of PUC has been deleted or overwritten + //by a different version during the upgrade. If we try to do anything more in that situation, + //we could trigger a fatal error by trying to autoload a deleted class. + clearstatcache(); + if ( !file_exists(__FILE__) ) { + $this->removeHooks(); + $this->updateChecker->removeHooks(); + return; + } //Sanity check and limitation to relevant types. if ( @@ -136,7 +146,7 @@ if ( !class_exists('Puc_v4p9_Scheduler', false) ): $this->maybeCheckForUpdates(); } - + /** * Check for updates if the configured check interval has already elapsed. * Will use a shorter check interval on certain admin pages like "Dashboard -> Updates" or when doing cron. @@ -233,6 +243,24 @@ if ( !class_exists('Puc_v4p9_Scheduler', false) ): public function getCronHookName() { return $this->cronHook; } + + /** + * Remove most hooks added by the scheduler. + */ + public function removeHooks() { + remove_filter('cron_schedules', array($this, '_addCustomSchedule')); + remove_action('admin_init', array($this, 'maybeCheckForUpdates')); + remove_action('load-update-core.php', array($this, 'maybeCheckForUpdates')); + + if ( $this->cronHook !== null ) { + remove_action($this->cronHook, array($this, 'maybeCheckForUpdates')); + } + if ( !empty($this->hourlyCheckHooks) ) { + foreach ($this->hourlyCheckHooks as $hook) { + remove_action($hook, array($this, 'maybeCheckForUpdates')); + } + } + } } endif; diff --git a/Puc/v4p9/UpdateChecker.php b/Puc/v4p9/UpdateChecker.php index 193a014..2172b1f 100644 --- a/Puc/v4p9/UpdateChecker.php +++ b/Puc/v4p9/UpdateChecker.php @@ -151,7 +151,7 @@ if ( !class_exists('Puc_v4p9_UpdateChecker', false) ): /** * Remove hooks that were added by this update checker instance. */ - protected function removeHooks() { + public function removeHooks() { remove_filter('site_transient_' . $this->updateTransient, array($this,'injectUpdate')); remove_filter('site_transient_' . $this->updateTransient, array($this, 'injectTranslationUpdates')); remove_action( @@ -164,6 +164,10 @@ if ( !class_exists('Puc_v4p9_UpdateChecker', false) ): remove_action('plugins_loaded', array($this, 'maybeInitDebugBar')); remove_action('init', array($this, 'loadTextDomain')); + + if ( $this->scheduler ) { + $this->scheduler->removeHooks(); + } } /**