PluginProbe
Import WP – CSV & XML Import Export for WordPress / 2.8.0
Import WP – CSV & XML Import Export for WordPress v2.8.0
2.15.1 2.15.0 2.14.24 2.14.23 2.7.0 2.7.1 2.7.10 2.7.11 2.7.12 2.7.13 2.7.14 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 2.7.8 2.7.9 2.8.0 2.8.1 2.8.2 2.8.3 2.9.0 2.9.1 All 144 releases
jc-importer / class / Common / Runner / RunnerState.php

RunnerState.php in Import WP – CSV & XML Import Export for WordPress 2.8.0, at class/Common/Runner/RunnerState.php

385 lines 10.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace ImportWP\Common\Runner;
4
5 use ImportWP\Common\Util\Logger;
6
7 abstract class RunnerState
8 {
9 private $id;
10 private $user;
11 protected $data;
12 protected static $object_type = '';
13
14 public function __construct($id, $user)
15 {
16 $this->id = $id;
17 $this->user = $user;
18 }
19
20 public function is_running()
21 {
22 return false;
23 }
24
25 public function is_resumable()
26 {
27 return false;
28 }
29
30 protected function default($session)
31 {
32 return [
33 'id' => $session,
34 'status' => 'init',
35 'version' => 2,
36 'message' => '',
37 'timestamp' => time(),
38 'duration' => 0
39 ];
40 }
41
42 public function init($session)
43 {
44 $state = self::wait_for_lock_and_get_state($this->id, $this->user, $this->default($session));
45
46 if (!$state || !isset($state['status'])) {
47 throw new \Exception("Invalid state");
48 }
49
50 $this->populate($state);
51
52 if (!$this->validate($session)) {
53 throw new \Exception("Session has changed");
54 }
55 }
56
57
58 public function populate($state)
59 {
60 foreach ($state as $name => $value) {
61 $this->data[$name] = $value;
62 }
63 }
64
65 public function has_section($section)
66 {
67 if (!isset($this->data['section'])) {
68 return false;
69 }
70
71 if (is_array($section)) {
72 return in_array($this->data['section'], $section);
73 }
74
75 return $this->data['section'] == $section;
76 }
77
78 public function has_status($status)
79 {
80 if (!isset($this->data['status'])) {
81 return false;
82 }
83
84 if (is_array($status)) {
85 return in_array($this->data['status'], $status);
86 }
87
88 return $this->data['status'] == $status;
89 }
90
91 public function get_session()
92 {
93 return isset($this->data['id']) ? $this->data['id'] : false;
94 }
95
96 public function get_section()
97 {
98 if (!isset($this->data['section'])) {
99 return false;
100 }
101
102 return $this->data['section'];
103 }
104
105 public function get_progress($section = null)
106 {
107 if (is_null($section)) {
108 $section = $this->get_section();
109 }
110
111 return $this->data['progress'][$section];
112 }
113
114 public function validate($session_id)
115 {
116 $valid = $this->has_status('init') || $this->get_session() == $session_id;
117 if (!$valid) {
118 Logger::write("state -invalid -check={$session_id} -current={$this->get_session()}");
119 }
120 return $valid;
121 }
122
123 public function get_raw()
124 {
125 return $this->data;
126 }
127
128 /**
129 * Update live state data using callback
130 *
131 * @param Closure[array]:array $state
132 *
133 * @return $this
134 */
135 public function update($callback)
136 {
137 $raw = self::wait_for_lock($this->id, $this->user, function () use ($callback) {
138 $state = self::get_state($this->id);
139
140 if (is_callable($callback)) {
141 $state = call_user_func($callback, $state);
142 }
143
144 self::set_state($this->id, $state);
145 do_action('iwp/' . static::$object_type . '/status/save', $state);
146 return $state;
147 });
148
149 $this->populate($raw);
150
151 return $this;
152 }
153
154 /**
155 * Log fatal error
156 *
157 * @param \Exception $error
158 * @return $this
159 */
160 public function error($error)
161 {
162 return $this->update(function ($data) use ($error) {
163
164 $data['status'] = 'error';
165 $data['message'] = $error->getMessage();
166 $data['duration'] = floatval($data['duration']) + Logger::timer();
167
168 return $data;
169 });
170 }
171
172 public static function wait_for_lock($id, $user, $callback)
173 {
174
175 $start = microtime(true);
176
177 do {
178 list($has_lock, $result) = self::try_get_lock($id, $user, $callback);
179 } while (!$has_lock && (microtime(true) - $start < 30));
180
181 if (!$has_lock) {
182 throw new \Exception("Unable to get lock");
183 }
184
185 return $result;
186 }
187
188 public static function wait_for_lock_and_get_state($id, $user, $default = false)
189 {
190 return self::wait_for_lock($id, $user, function () use ($id, $default) {
191 return self::get_state($id, $default);
192 });
193 }
194
195 /**
196 * Get importer lock to update state
197 *
198 * @param mixed $user current id
199 * @param mixed $callback Callback triggered when we have a lock.
200 * @param int $wait_in_microseconds Time to wait in microseconds before retrying
201 *
202 * @return false|array
203 */
204 public static function try_get_lock($id, $user, $callback)
205 {
206 $has_lock = self::get_lock($id, $user);
207 if ($has_lock) {
208
209 $result = $has_lock;
210
211 if (is_callable($callback)) {
212 $result = call_user_func($callback);
213 }
214
215 self::reset_lock($id);
216
217 return [true, $result];
218 } else {
219
220 return [false, null];
221 }
222 }
223
224 /**
225 * Update importer state
226 *
227 * @param mixed $state State to overwrite
228 *
229 * @return void
230 */
231 public static function set_state($id, $state)
232 {
233 $state['updated'] = time();
234 self::update_option('iwp_' . static::$object_type . '_state_' . $id, maybe_serialize($state));
235 }
236
237 /**
238 * Get last importer state
239 *
240 * @return array Importer state
241 */
242 public static function get_state($id, $default = false)
243 {
244 $state = self::get_option('iwp_' . static::$object_type . '_state_' . $id);
245 if (!$state) {
246 $state = $default;
247 if ($state !== false) {
248 self::set_state($id, $state);
249 }
250 }
251
252 return $state;
253 }
254
255 public static function get_lock($id, $user, $timeout_in_seconds = 10)
256 {
257 /**
258 * @var \WPDB $wpdb
259 */
260 global $wpdb;
261
262 $lock_option_id = sprintf('iwp_' . static::$object_type . '_lock_%d', $id);
263 $existing = self::get_option($lock_option_id, false);
264
265 if ($existing !== false) {
266 if (is_multisite()) {
267 $query = $wpdb->prepare(
268 "UPDATE {$wpdb->sitemeta} SET meta_value=%s WHERE site_id=%d AND meta_key=%s AND meta_value=''",
269 $user,
270 $wpdb->siteid,
271 $lock_option_id
272 );
273 } else {
274 $query = $wpdb->prepare(
275 "UPDATE {$wpdb->options} SET option_value=%s WHERE option_name=%s AND option_value=''",
276 $user,
277 $lock_option_id
278 );
279 }
280 } else {
281 return self::update_option($lock_option_id, '');
282 }
283
284 $result = $wpdb->query($query);
285
286 if ($result) {
287
288 self::touch_lock($id);
289 } else {
290
291 // Clear lock if timestamp is greater than timeout.
292 $last_locked_time = (int)self::get_option('iwp_' . static::$object_type . '_lock_timestamp_' . $id, 0);
293 if (current_time('timestamp') > $last_locked_time + $timeout_in_seconds) {
294 self::reset_lock($id);
295 }
296 }
297
298 return $result;
299 }
300
301 public static function reset_lock($id)
302 {
303 self::update_option('iwp_' . static::$object_type . '_lock_' . $id);
304 self::touch_lock($id);
305 }
306
307 public static function touch_lock($id)
308 {
309 self::update_option('iwp_' . static::$object_type . '_lock_timestamp_' . $id, current_time('timestamp'));
310 }
311
312 public static function get_option($key, $default = false)
313 {
314 /**
315 * @var \WPDB $wpdb
316 */
317 global $wpdb;
318
319 if (is_multisite()) {
320 $query = $wpdb->prepare("SELECT meta_id as id, meta_value as data FROM {$wpdb->sitemeta} WHERE site_id=%s AND meta_key=%s LIMIT 1", [$wpdb->siteid, $key]);
321 } else {
322 $query = $wpdb->prepare("SELECT option_id as id, option_value as data FROM {$wpdb->options} WHERE option_name=%s LIMIT 1", [$key]);
323 }
324
325 $result = $wpdb->get_row($query, ARRAY_A);
326 if (!$result) {
327 return $default;
328 }
329
330 if (is_serialized($result['data'])) {
331 return unserialize($result['data']);
332 }
333
334 return $result['data'];
335 }
336
337 public static function update_option($key, $value = '')
338 {
339 /**
340 * @var \WPDB $wpdb
341 */
342 global $wpdb;
343
344 $result = self::get_option($key);
345
346 if (is_multisite()) {
347
348 if ($result !== false) {
349 $result = $wpdb->update($wpdb->sitemeta, ['meta_value' => $value], ['meta_key' => $key, 'site_id' => $wpdb->siteid], ['%s'], ['%s', '%s']);
350 } else {
351 $result = $wpdb->insert($wpdb->sitemeta, ['meta_value' => $value, 'meta_key' => $key, 'site_id' => $wpdb->siteid], ['%s', '%s', '%s']);
352 }
353 } else {
354 if ($result !== false) {
355 $result = $wpdb->update($wpdb->options, ['option_value' => $value], ['option_name' => $key], ['%s'], ['%s']);
356 } else {
357 $result = $wpdb->insert($wpdb->options, ['option_value' => $value, 'option_name' => $key], ['%s', '%s']);
358 }
359 }
360
361 return $result;
362 }
363
364 public static function clear_options($id)
365 {
366
367 // clear existing
368 delete_site_option('iwp_' . static::$object_type . '_config_' . $id);
369 delete_site_option('iwp_' . static::$object_type . '_state_' . $id);
370 delete_site_option('iwp_' . static::$object_type . '_lock_' . $id);
371 delete_site_option('iwp_' . static::$object_type . '_lock_timestamp_' . $id);
372
373 /**
374 * @var \WPDB $wpdb
375 */
376 global $wpdb;
377
378 if (is_multisite()) {
379 $wpdb->query("DELETE FROM {$wpdb->sitemeta} WHERE meta_key LIKE 'iwp\_" . static::$object_type . "\_state\_" . $id . "\_%'");
380 } else {
381 $wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE 'iwp\_" . static::$object_type . "\_state\_" . $id . "\_%'");
382 }
383 }
384 }
385