PluginProbe
Import WP – CSV & XML Import Export for WordPress / 2.7.9
Import WP – CSV & XML Import Export for WordPress v2.7.9
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 / Importer / State / ImporterState.php

ImporterState.php in Import WP – CSV & XML Import Export for WordPress 2.7.9, at class/Common/Importer/State/ImporterState.php

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