PluginProbe
Import WP – CSV & XML Import Export for WordPress / 2.14.23
Import WP – CSV & XML Import Export for WordPress v2.14.23
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.14.23, at class/Common/Runner/RunnerState.php

358 lines 8.9 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", 'jc-importer'));
48 }
49
50 $this->populate($state);
51
52 if (!$this->validate($session)) {
53 throw new \Exception(__("Session has changed", 'jc-importer'));
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", 'jc-importer'));
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 $query = $wpdb->prepare(
267 "UPDATE {$wpdb->options} SET option_value=%s WHERE option_name=%s AND option_value=''",
268 $user,
269 $lock_option_id
270 );
271 } else {
272 return self::update_option($lock_option_id, '');
273 }
274
275 $result = $wpdb->query($query);
276
277 if ($result) {
278
279 self::touch_lock($id);
280 } else {
281
282 // Clear lock if timestamp is greater than timeout.
283 $last_locked_time = (int)self::get_option('iwp_' . static::$object_type . '_lock_timestamp_' . $id, 0);
284 if (current_time('timestamp') > $last_locked_time + $timeout_in_seconds) {
285 self::reset_lock($id);
286 }
287 }
288
289 return $result;
290 }
291
292 public static function reset_lock($id)
293 {
294 self::update_option('iwp_' . static::$object_type . '_lock_' . $id);
295 self::touch_lock($id);
296 }
297
298 public static function touch_lock($id)
299 {
300 self::update_option('iwp_' . static::$object_type . '_lock_timestamp_' . $id, current_time('timestamp'));
301 }
302
303 public static function get_option($key, $default = false)
304 {
305 /**
306 * @var \WPDB $wpdb
307 */
308 global $wpdb;
309
310 $query = $wpdb->prepare("SELECT option_id as id, option_value as data FROM {$wpdb->options} WHERE option_name=%s LIMIT 1", [$key]);
311
312 $result = $wpdb->get_row($query, ARRAY_A);
313 if (!$result) {
314 return $default;
315 }
316
317 if (is_serialized($result['data'])) {
318 return unserialize($result['data']);
319 }
320
321 return $result['data'];
322 }
323
324 public static function update_option($key, $value = '')
325 {
326 /**
327 * @var \WPDB $wpdb
328 */
329 global $wpdb;
330
331 $result = self::get_option($key);
332
333 if ($result !== false) {
334 $result = $wpdb->update($wpdb->options, ['option_value' => $value], ['option_name' => $key], ['%s'], ['%s']);
335 } else {
336 $result = $wpdb->insert($wpdb->options, ['option_value' => $value, 'option_name' => $key], ['%s', '%s']);
337 }
338
339 return $result;
340 }
341
342 public static function clear_options($id)
343 {
344
345 // clear existing
346 delete_site_option('iwp_' . static::$object_type . '_config_' . $id);
347 delete_site_option('iwp_' . static::$object_type . '_state_' . $id);
348 delete_site_option('iwp_' . static::$object_type . '_lock_' . $id);
349 delete_site_option('iwp_' . static::$object_type . '_lock_timestamp_' . $id);
350
351 /**
352 * @var \WPDB $wpdb
353 */
354 global $wpdb;
355 $wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE 'iwp\_" . static::$object_type . "\_state\_" . $id . "\_%'");
356 }
357 }
358