PluginProbe ʕ •ᴥ•ʔ
UpdraftPlus: WP Backup & Migration Plugin / 1.26.4
UpdraftPlus: WP Backup & Migration Plugin v1.26.4
1.26.4 1.26.3 1.9.19 1.9.25 1.9.26 1.9.30 1.9.31 1.9.32 1.9.4 1.9.40 1.9.41 1.9.42 1.9.43 1.9.44 1.9.45 1.9.46 1.9.5 1.9.50 1.9.51 1.9.60 1.9.62 1.9.63 1.9.64 1.11.12 1.4.8 1.11.15 1.4.9 1.11.17 1.5.16 1.11.18 1.5.20 1.11.2 1.5.21 1.11.20 1.5.22 1.11.23 1.5.5 1.11.24 1.5.6 1.11.25 1.5.7 1.11.26 1.5.8 1.11.27 1.5.9 1.11.28 1.6.1 1.11.3 1.6.17 1.11.4 1.6.2 1.11.5 1.6.46 1.11.8 1.7.0 1.11.9 1.7.1 1.12.0 1.7.18 1.12.1 1.7.20 1.12.12 1.7.3 1.12.13 1.7.34 1.12.15 1.7.35 1.12.17 1.7.39 1.12.2 1.7.40 1.12.20 1.7.41 1.12.23 1.8.1 1.12.24 1.8.11 1.12.25 1.8.12 1.12.28 1.8.13 1.12.29 1.8.2 1.12.30 1.8.5 1.12.32 1.8.8 1.12.34 1.9.0 1.12.35 1.9.13 1.12.37 1.9.15 1.12.39 1.9.17 1.12.4 1.12.40 1.12.6 1.13.1 1.13.11 1.13.12 1.13.15 1.13.16 1.13.2 1.13.3 1.13.4 1.13.5 1.13.6 1.13.7 1.13.8 1.13.9 1.14.10 1.14.11 1.14.12 1.14.13 1.14.2 1.14.3 1.14.4 1.14.5 1.14.7 1.14.9 1.15.0 1.15.2 1.15.3 1.15.5 1.15.6 1.15.7 1.16.0 1.16.10 1.16.11 1.16.12 1.16.13 1.16.14 1.16.15 1.16.16 1.16.17 1.16.20 1.16.21 1.16.22 1.16.23 1.16.24 1.16.25 1.16.26 1.16.28 1.16.29 1.16.32 1.16.34 1.16.35 1.16.36 1.16.37 1.16.4 1.16.40 1.16.41 1.16.42 1.16.43 1.16.44 1.16.45 1.16.46 1.16.47 1.16.48 1.16.49 1.16.5 1.16.50 1.16.51 1.16.53 1.16.55 1.16.56 1.16.59 1.16.6 1.16.60 1.16.61 1.16.62 1.16.63 1.16.64 1.16.65 1.16.66 1.16.67 1.16.68 1.16.69 1.16.7 1.16.8 1.16.9 1.2.0 1.2.1 1.2.10 1.2.11 1.2.12 1.2.14 1.2.15 1.2.16 1.2.17 1.2.19 1.2.2 1.2.20 1.2.24 1.2.25 1.2.26 1.2.27 1.2.28 1.2.29 1.2.3 1.2.30 1.2.31 1.2.33 1.2.35 1.2.36 1.2.38 1.2.39 1.2.4 1.2.40 1.2.41 1.2.42 1.2.43 1.2.44 1.2.45 1.2.46 1.2.5 1.2.7 1.2.8 1.2.9 1.22.1 1.22.10 1.22.11 1.22.12 1.22.14 1.22.15 1.22.16 1.22.17 1.22.18 1.22.19 1.22.20 1.22.21 1.22.22 1.22.23 1.22.24 1.22.3 1.22.4 1.22.5 1.22.6 1.22.7 1.22.8 1.22.9 1.23.1 1.23.10 1.23.11 1.23.12 1.23.13 1.23.15 1.23.16 1.23.2 1.23.3 1.23.4 1.23.5 1.23.6 1.23.7 1.23.8 1.23.9 1.24.1 1.24.10 1.24.11 1.24.12 1.24.2 trunk 1.24.3 0.7.4 1.24.4 0.7.7 1.24.5 0.8.28 1.24.6 0.8.29 1.24.7 0.8.30 1.24.8 0.8.31 1.24.9 0.8.32 1.25.1 0.8.33 1.25.2 0.8.36 1.25.3 0.8.37 1.25.5 0.8.50 1.25.6 0.8.51 1.25.7 0.9.1 1.25.8 0.9.10 1.25.9 0.9.11 1.26.1 0.9.12 1.26.2 0.9.2 1.3.10 0.9.20 1.3.12 0.9.21 1.3.14 0.9.22 1.3.15 1.0.10 1.3.17 1.0.11 1.3.18 1.0.12 1.3.19 1.0.15 1.3.2 1.0.16 1.3.20 1.0.18 1.3.22 1.0.20 1.3.23 1.0.3 1.3.24 1.0.4 1.3.25 1.0.5 1.3.3 1.0.6 1.3.4 1.0.7 1.3.6 1.0.8 1.3.7 1.0.9 1.3.8 1.1.0 1.3.9 1.1.10 1.4.0 1.1.11 1.4.10 1.1.12 1.4.11 1.1.13 1.4.12 1.1.14 1.4.13 1.1.15 1.4.14 1.1.16 1.4.15 1.1.17 1.4.2 1.1.2 1.4.27 1.1.3 1.4.28 1.1.5 1.4.29 1.1.6 1.4.30 1.1.8 1.4.4 1.1.9 1.4.48 1.10.1 1.4.5 1.10.3 1.4.6 1.11.1 1.4.7
updraftplus / includes / class-updraft-semaphore.php
updraftplus / includes Last commit date
Dropbox2 3 weeks ago Google 3 weeks ago blockui 3 weeks ago checkout-embed 3 weeks ago cloudfiles 3 weeks ago handlebars 1 month ago images 9 years ago jquery-ui.dialog.extended 3 weeks ago jquery.serializeJSON 5 years ago jstree 1 year ago labelauty 3 weeks ago pcloud 3 weeks ago select2 1 year ago tether 6 years ago tether-shepherd 7 years ago updraftclone 3 weeks ago S3.php 3 weeks ago S3compat.php 3 weeks ago cacert.pem 2 years ago class-backup-history.php 1 month ago class-commands.php 3 weeks ago class-database-utility.php 1 month ago class-filesystem-functions.php 1 month ago class-http-error-descriptions.php 2 years ago class-job-scheduler.php 3 years ago class-manipulation-functions.php 1 month ago class-partialfileservlet.php 3 weeks ago class-remote-send.php 3 weeks ago class-search-replace.php 1 month ago class-semaphore.php 3 weeks ago class-storage-methods-interface.php 1 month ago class-updraft-dashboard-news.php 1 month ago class-updraft-semaphore.php 4 years ago class-updraftcentral-updraftplus-commands.php 3 years ago class-updraftplus-deactivation.php 1 month ago class-updraftplus-encryption.php 1 month ago class-wpadmin-commands.php 1 month ago class-zip.php 1 month ago ftp.class.php 2 months ago get-cpanel-quota-usage.pl 12 years ago google-extensions.php 1 month ago jquery-ui.custom-v1.11.4-1-26-4.min.css 3 weeks ago jquery-ui.custom-v1.11.4-1-26-4.min.css.map 3 weeks ago jquery-ui.custom-v1.11.4.css 3 years ago jquery-ui.custom-v1.12.1-1-26-4.min.css 3 weeks ago jquery-ui.custom-v1.12.1-1-26-4.min.css.map 3 weeks ago jquery-ui.custom-v1.12.1.css 3 years ago migrator-lite.php 1 month ago updraft-admin-common-1-26-4.min.js 3 weeks ago updraft-admin-common.js 3 weeks ago updraft-restorer-skin-compatibility.php 6 years ago updraft-restorer-skin.php 3 years ago updraftcentral.php 1 year ago updraftplus-clone.php 1 year ago updraftplus-login.php 7 months ago updraftplus-notices.php 1 month ago updraftplus-tour.php 1 month ago updraftvault.php 3 years ago
class-updraft-semaphore.php
214 lines
1 <?php
2
3 if (!defined('ABSPATH')) die('No direct access.');
4
5 /**
6 * Class Updraft_Semaphore_3_0
7 *
8 * This class is much simpler to use than the the previous series, as it has dropped support for complicated cases that were not being used. It also now only uses a single row in the options database, and takes care of creating it itself internally.
9 *
10 * Logging, though, may be noisier, unless your loggers are taking note of the log level and only registering what is required.
11 *
12 * Example of use (a lock that will expire if not released within 300 seconds)
13 *
14 * See test.php for a longer example (including logging).
15 *
16 * $my_lock = new Updraft_Semaphore_3_0('my_lock_name', 300);
17 * // If getting the lock does not succeed first time, try again up to twice
18 * if ($my_lock->lock(2)) {
19 * try {
20 * // do stuff ...
21 * } catch (Exception $e) {
22 * // We are making sure we release the lock in case of an error
23 * } catch (Error $e) {
24 * // We are making sure we release the lock in case of an error
25 * }
26 * $my_lock->release();
27 * } else {
28 * error_log("Sorry, could not get the lock");
29 * }
30 */
31 class Updraft_Semaphore_3_0 {
32
33 // Time after which the lock will expire (in seconds)
34 protected $locked_for;
35
36 // Name for the lock in the WP options table
37 protected $option_name;
38
39 // Lock status - a boolean
40 protected $acquired = false;
41
42 // An array of loggers
43 protected $loggers = array();
44
45 /**
46 * Constructor. Instantiating does not lock anything, but sets up the details for future operations.
47 *
48 * @param String $name - a unique (across the WP site) name for the lock. Should be no more than 51 characters in length (because of the use of the WP options table, with some further characters used internally)
49 * @param Integer $locked_for - time (in seconds) after which the lock will expire if not released. This needs to be positive if you don't want bad things to happen.
50 * @param Array $loggers - an array of loggers
51 */
52 public function __construct($name, $locked_for = 300, $loggers = array()) {
53 $this->option_name = 'updraft_lock_'.$name;
54 $this->locked_for = $locked_for;
55 $this->loggers = $loggers;
56 }
57
58 /**
59 * Internal function to make sure that the lock is set up in the database
60 *
61 * @return Integer - 0 means 'failed' (which could include that someone else concurrently created it); 1 means 'already existed'; 2 means 'exists, because we created it). The intention is that non-zero results mean that the lock exists.
62 */
63 private function ensure_database_initialised() {
64
65 global $wpdb;
66
67 $sql = $wpdb->prepare("SELECT COUNT(*) FROM {$wpdb->options} WHERE option_name = %s", $this->option_name);
68
69 if (1 === (int) $wpdb->get_var($sql)) {
70 $this->log('Lock option ('.$this->option_name.', '.$wpdb->options.') already existed in the database', 'debug');
71 return 1;
72 }
73
74 $sql = $wpdb->prepare("INSERT INTO {$wpdb->options} (option_name, option_value, autoload) VALUES(%s, '0', 'no');", $this->option_name);
75
76 $rows_affected = $wpdb->query($sql);
77
78 if ($rows_affected > 0) {
79 $this->log('Lock option ('.$this->option_name.', '.$wpdb->options.') was created in the database', 'debug');
80 } else {
81 $this->log('Lock option ('.$this->option_name.', '.$wpdb->options.') failed to be created in the database (could already exist)', 'notice');
82 }
83
84 return ($rows_affected > 0) ? 2 : 0;
85 }
86
87 /**
88 * Attempt to acquire the lock. If it was already acquired, then nothing extra will be done (the method will be a no-op).
89 *
90 * @param Integer $retries - how many times to retry (after a 1 second sleep each time)
91 *
92 * @return Boolean - whether the lock was successfully acquired or not
93 */
94 public function lock($retries = 0) {
95
96 if ($this->acquired) return true;
97
98 global $wpdb;
99
100 $time_now = time();
101 $acquire_until = $time_now + $this->locked_for;
102
103 $sql = $wpdb->prepare("UPDATE {$wpdb->options} SET option_value = %s WHERE option_name = %s AND option_value < %d", $acquire_until, $this->option_name, $time_now);
104
105 if (1 === $wpdb->query($sql)) {
106 $this->log('Lock ('.$this->option_name.', '.$wpdb->options.') acquired', 'info');
107 $this->acquired = true;
108 return true;
109 }
110
111 // See if the failure was caused by the row not existing (we check this only after failure, because it should only occur once on the site)
112 if (!$this->ensure_database_initialised()) return false;
113
114 do {
115 // Now that the row has been created, try again
116 if (1 === $wpdb->query($sql)) {
117 $this->log('Lock ('.$this->option_name.', '.$wpdb->options.') acquired after initialising the database', 'info');
118 $this->acquired = true;
119 return true;
120 }
121 $retries--;
122 if ($retries >=0) {
123 $this->log('Lock ('.$this->option_name.', '.$wpdb->options.') not yet acquired; sleeping', 'debug');
124 sleep(1);
125 // As a second has passed, update the time we are aiming for
126 $time_now = time();
127 $acquire_until = $time_now + $this->locked_for;
128 $sql = $wpdb->prepare("UPDATE {$wpdb->options} SET option_value = %s WHERE option_name = %s AND option_value < %d", $acquire_until, $this->option_name, $time_now);
129 }
130 } while ($retries >= 0);
131
132 $this->log('Lock ('.$this->option_name.', '.$wpdb->options.') could not be acquired (it is locked)', 'info');
133
134 return false;
135 }
136
137 /**
138 * Release the lock
139 *
140 * N.B. We don't attempt to unlock it unless we locked it. i.e. Lost locks are left to expire rather than being forced. (If we want to force them, we'll need to introduce a new parameter).
141 *
142 * @return Boolean - if it returns false, then the lock was apparently not locked by us (and the caller will most likely therefore ignore the result, whatever it is).
143 */
144 public function release() {
145 if (!$this->acquired) return false;
146 global $wpdb;
147 $sql = $wpdb->prepare("UPDATE {$wpdb->options} SET option_value = '0' WHERE option_name = %s", $this->option_name);
148
149 $this->log('Lock option ('.$this->option_name.', '.$wpdb->options.') released', 'info');
150
151 $result = (int) $wpdb->query($sql) === 1;
152
153 $this->acquired = false;
154
155 return $result;
156 }
157
158 /**
159 * Cleans up the DB of any residual data. This should not be used as part of ordinary unlocking; only as part of deinstalling, or if you otherwise know that the lock will not be used again. If calling this, it's redundant to first unlock (and a no-op to attempt to do so afterwards).
160 */
161 public function delete() {
162 $this->acquired = false;
163
164 global $wpdb;
165 $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->options} WHERE option_name = %s", $this->option_name));
166
167 $this->log('Lock option ('.$this->option_name.', '.$wpdb->options.') was deleted from the database');
168 }
169
170 /**
171 * Captures and logs any given messages
172 *
173 * @param String $message - the error message
174 * @param String $level - the message level (debug, notice, info, warning, error)
175 */
176 public function log($message, $level = 'info') {
177 if (isset($this->loggers)) {
178 foreach ($this->loggers as $logger) {
179 $logger->log($message, $level);
180 }
181 }
182 }
183
184 /**
185 * Sets the list of loggers for this instance (removing any others).
186 *
187 * @param Array $loggers - the loggers for this task
188 */
189 public function set_loggers($loggers) {
190 $this->loggers = array();
191 foreach ($loggers as $logger) {
192 $this->add_logger($logger);
193 }
194 }
195
196 /**
197 * Add a logger to loggers list
198 *
199 * @param Callable $logger - a logger (a method with a callable function 'log', taking string parameters $level $message)
200 */
201 public function add_logger($logger) {
202 $this->loggers[] = $logger;
203 }
204
205 /**
206 * Return the current list of loggers
207 *
208 * @return Array
209 */
210 public function get_loggers() {
211 return $this->loggers;
212 }
213 }
214