PluginProbe
Import WP – CSV & XML Import Export for WordPress / 2.7.10
Import WP – CSV & XML Import Export for WordPress v2.7.10
2.15.2 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 All 145 releases
jc-importer / class / Common / Runner / RunnerState.php

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

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