PluginProbe
Import WP – CSV & XML Import Export for WordPress / 2.8.3
Import WP – CSV & XML Import Export for WordPress v2.8.3
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 / ImporterManager.php

ImporterManager.php in Import WP – CSV & XML Import Export for WordPress 2.8.3, at class/Common/Importer/ImporterManager.php

981 lines 33.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;
4
5 use ImportWP\Common\Filesystem\Filesystem;
6 use ImportWP\Common\Importer\Config\Config;
7 use ImportWP\Common\Importer\File\CSVFile;
8 use ImportWP\Common\Importer\File\XMLFile;
9 use ImportWP\Common\Importer\Mapper\AttachmentMapper;
10 use ImportWP\Common\Importer\Mapper\CommentMapper;
11 use ImportWP\Common\Importer\Mapper\PostMapper;
12 use ImportWP\Common\Importer\Mapper\TermMapper;
13 use ImportWP\Common\Importer\Mapper\UserMapper;
14 use ImportWP\Common\Importer\Parser\CSVParser;
15 use ImportWP\Common\Importer\Parser\XMLParser;
16 use ImportWP\Common\Importer\Permission\Permission;
17 use ImportWP\Common\Importer\State\ImporterState;
18 use ImportWP\Common\Importer\Template\AttachmentTemplate;
19 use ImportWP\Common\Importer\Template\CommentTemplate;
20 use ImportWP\Common\Importer\Template\CustomPostTypeTemplate;
21 use ImportWP\Common\Importer\Template\PageTemplate;
22 use ImportWP\Common\Importer\Template\PostTemplate;
23 use ImportWP\Common\Importer\Template\Template;
24 use ImportWP\Common\Importer\Template\TemplateManager;
25 use ImportWP\Common\Importer\Template\TermTemplate;
26 use ImportWP\Common\Importer\Template\UserTemplate;
27 use ImportWP\Common\Model\ImporterModel;
28 use ImportWP\Common\Properties\Properties;
29 use ImportWP\Common\Runner\ImporterRunnerState;
30 use ImportWP\Common\Util\Logger;
31 use ImportWP\Common\Util\Util;
32 use ImportWP\Container;
33 use ImportWP\EventHandler;
34
35 class ImporterManager
36 {
37
38 /**
39 * @var Filesystem
40 */
41 private $filesystem;
42
43 /**
44 * @var TemplateManager $template_manager
45 */
46 private $template_manager;
47
48 /**
49 * @var EventHandler $event_handler
50 */
51 protected $event_handler;
52
53 public function __construct(Filesystem $filesystem, TemplateManager $template_manager, EventHandler $event_handler)
54 {
55 $this->filesystem = $filesystem;
56 $this->template_manager = $template_manager;
57 $this->event_handler = $event_handler;
58 }
59
60 /**
61 * Get Importers
62 *
63 * @return ImporterModel[]
64 */
65 public function get_importers()
66 {
67
68 $result = array();
69 $query = new \WP_Query(array(
70 'post_type' => IWP_POST_TYPE,
71 'posts_per_page' => -1,
72 ));
73
74 foreach ($query->posts as $post) {
75 $result[] = $this->get_importer($post);
76 }
77 return $result;
78 }
79
80 /**
81 * Get Importer
82 *
83 * @param int $id
84 * @return ImporterModel
85 */
86 public function get_importer($id)
87 {
88 if ($id instanceof ImporterModel) {
89 return $id;
90 }
91
92 if (IWP_POST_TYPE !== get_post_type($id)) {
93 return false;
94 }
95
96 return new ImporterModel($id, $this->is_debug());
97 }
98
99 public function is_debug()
100 {
101
102 if (defined('IWP_DEBUG') && true === IWP_DEBUG) {
103 return true;
104 }
105
106 $uninstall_enabled = get_option('iwp_settings');
107 if (isset($uninstall_enabled['debug']) && true === $uninstall_enabled['debug']) {
108 return true;
109 }
110
111 return false;
112 }
113
114 public function set_current_user($id)
115 {
116 $importer_model = $this->get_importer($id);
117 $user_id = $importer_model->getUserId();
118
119 Logger::write('set_current_user -user=' . $user_id, $importer_model->getId());
120
121 if ($user_id) {
122 return wp_set_current_user($user_id);
123 }
124
125 return false;
126 }
127
128 /**
129 * Delete Importer
130 *
131 * @param int $id
132 * @return void
133 */
134 public function delete_importer($id)
135 {
136 $importer = $this->get_importer($id);
137 $importer->delete();
138 }
139
140 public function get_file($id)
141 {
142 $importer = $this->get_importer($id);
143 $config = $this->get_config($importer);
144 $parser = $importer->getParser();
145
146 if ('xml' === $parser) {
147 return $this->get_xml_file($importer, $config);
148 } elseif ('csv' === $parser) {
149 return $this->get_csv_file($importer, $config);
150 }
151
152 return false;
153 }
154
155 public function get_csv_file($id, $config)
156 {
157 $importer = $this->get_importer($id);
158 $file = new CSVFile($importer->getFile(), $config);
159 $file->setDelimiter($importer->getFileSetting('delimiter'));
160 $file->setEnclosure($importer->getFileSetting('enclosure'));
161 return $file;
162 }
163
164 public function get_xml_file($id, $config)
165 {
166 $importer = $this->get_importer($id);
167 $file = new XMLFile($importer->getFile(), $config);
168 $file->setRecordPath($importer->getFileSetting('base_path'));
169 return $file;
170 }
171
172 public function preview_csv_file($id, $fields = [], $row = 0)
173 {
174 $importer = $this->get_importer($id);
175 $config = $this->get_config($importer, true);
176
177 $file = $this->get_csv_file($importer, $config);
178 $parser = new CSVParser($file);
179
180 $record = $parser->getRecord($row);
181
182 return $record->queryGroup(['fields' => $fields]);
183 }
184
185 public function preview_xml_file($id, $fields = [], $row = 0)
186 {
187 $importer = $this->get_importer($id);
188 $config = $this->get_config($importer, true);
189
190 $file = $this->get_xml_file($importer, $config);
191 $parser = new XMLParser($file);
192
193 $record = $parser->getRecord($row);
194 return $record->queryGroup(['fields' => $fields]);
195 }
196
197 public function process_csv_file($id, $delimiter, $enclosure, $tmp = false)
198 {
199 $importer = $this->get_importer($id);
200 $config = $this->get_config($importer->getId(), $tmp);
201
202 $file = $this->get_csv_file($importer, $config);
203 $file->setDelimiter($delimiter);
204 $file->setEnclosure($enclosure);
205 $file->processing(true);
206
207 if (empty($importer->getMap())) {
208
209 // we are on first file import
210 $headings = str_getcsv($file->getRecord(0), $file->getDelimiter(), $file->getEnclosure());
211 $headings = array_map('trim', $headings);
212
213 $template = $this->get_importer_template($id);
214 $field_map = $template->generate_field_map($headings, $importer);
215 $field_map = apply_filters('iwp/importer/generate_field_map', $field_map, $headings, $importer);
216
217 $map = $field_map['map'];
218 foreach ($map as $key => $value) {
219 $importer->setMap($key, $value);
220 }
221
222 $enabled = $field_map['enabled'];
223 foreach ($enabled as $enabled_field) {
224 $importer->setEnabled($enabled_field);
225 }
226
227 // Disabled due to testing:
228 // https://localdev/wp-admin/tools.php?page=importwp&edit=29&step=1
229 //
230 // a:9:{s:8:"template";s:19:"woocommerce-product";s:13:"template_type";s:0:"";s:4:"file";a:2:{s:2:"id";i:9;s:8:"settings";a:6:{s:9:"enclosure";s:1:""";s:9:"delimiter";s:1:",";s:13:"show_headings";b:1;s:5:"setup";b:0;s:5:"count";i:2;s:9:"processed";b:1;}}s:10:"datasource";a:2:{s:4:"type";s:5:"local";s:8:"settings";a:2:{s:10:"remote_url";s:0:"";s:9:"local_url";s:48:"/var/www/html/wp-content/uploads/exportwp/30.csv";}}s:6:"parser";s:3:"csv";s:3:"map";a:0:{}s:7:"enabled";a:0:{}s:11:"permissions";a:0:{}s:8:"settings";a:4:{s:9:"post_type";a:2:{i:0;s:7:"product";i:1;s:17:"product_variation";}s:12:"unique_field";a:3:{i:0;s:2:"ID";i:1;s:4:"_sku";i:2;s:9:"post_name";}s:9:"start_row";N;s:7:"max_row";N;}}
231 //
232 $importer->save();
233 }
234
235 return $file->getRecordCount();
236 }
237
238 public function process_xml_file($id, $tmp = false)
239 {
240
241 $importer = $this->get_importer($id);
242 $config = $this->get_config($importer->getId(), $tmp);
243
244 $filePath = $importer->getFile();
245 $file = new XMLFile($filePath, $config);
246 $file->processing(true);
247 $nodes = $file->get_node_list();
248 $results = [];
249
250 foreach ($nodes as $node) {
251 $config = $this->get_config($importer->getId(), $tmp);
252 $file = new XMLFile($filePath, $config);
253 $file->setRecordPath($node);
254 // TODO: Seperate record count, to when a node has been selected.
255 $results[$node] = 0; //$file->getRecordCount();
256 }
257
258 return $results;
259 }
260
261 /**
262 * Link import file to importer via post meta
263 *
264 * @param ImporterModel $id
265 * @param string $file_path
266 * @return integer Id of inserted file
267 */
268 public function link_importer_file($id, $file_path)
269 {
270 $importer = $this->get_importer($id);
271 $index = get_post_meta($importer->getId(), '_importer_files', true);
272 if (!$index) {
273 $index = 1;
274 }
275
276 $index++;
277
278 update_post_meta($importer->getId(), '_importer_files', $index);
279 update_post_meta($importer->getId(), '_importer_file_' . $index, $file_path);
280 return $index;
281 }
282
283 public function get_importer_file_prefix($importer)
284 {
285 $importer = $this->get_importer($importer);
286
287 $file_index = get_post_meta($importer->getId(), '_importer_files', true);
288 if (!$file_index) {
289 $file_index = 1;
290 }
291 $file_index++;
292
293 return $importer->getId() . '-' . intval($file_index) . '-';
294 }
295
296 public function upload_file($id, $file)
297 {
298 $importer = $this->get_importer($id);
299 Logger::setId($importer->getId());
300
301 $allowed_file_types = $this->event_handler->run('importer.allowed_file_types', [$importer->getAllowedFileTypes()]);
302 $result = $this->filesystem->upload_file($file, $allowed_file_types);
303
304 if (is_wp_error($result)) {
305 return $result;
306 }
307
308 $attachment_id = $this->insert_file_attachment($importer, $result['dest'], $result['type']);
309 if (is_wp_error($attachment_id)) {
310 return $attachment_id;
311 }
312
313 return $attachment_id;
314 }
315
316 public function remote_file($id, $source, $filetype = null)
317 {
318 $importer = $this->get_importer($id);
319 Logger::setId($importer->getId());
320
321 $allowed_file_types = $this->event_handler->run('importer.allowed_file_types', [$importer->getAllowedFileTypes()]);
322 $prefix = $this->get_importer_file_prefix($importer);
323
324 try {
325
326 if (preg_match('/^s?ftp?:\/\//', $source) === 1) {
327
328 if (preg_match('/^(?<protocol>s?ftp):\/\/(?:(?<user>[^\:@]+)(?:\:(?<pass>[^@]+))?@)?(?<host>[^\:\/]+)(?:\:(?<port>[0-9]+))?(?:\/(?<path>.*))$/', $source, $matches) !== 1) {
329
330 return new \WP_Error("IM_RM_FTP_PARSE", "Unable to parse FTP connection string");
331 }
332
333 $user = isset($matches['user']) ? urldecode($matches['user']) : '';
334 $pass = isset($matches['pass']) ? urldecode($matches['pass']) : '';
335 $host = isset($matches['host']) ? $matches['host'] : false;
336 $port = isset($matches['port']) && !empty($matches['port']) ? $matches['port'] : intval(21);
337 $path = isset($matches['path']) ? $matches['path'] : false;
338
339 if (!$host) {
340 return new \WP_Error("IM_RM_FTP_HOST", "Unable to parse ftp host from connection string");
341 }
342
343 if (!$path) {
344 return new \WP_Error("IM_RM_FTP_HOST", "Unable to parse ftp host from connection string");
345 }
346
347 /**
348 * @var \ImportWP\Common\Ftp\Ftp $ftp
349 */
350 $ftp = Container::getInstance()->get('ftp');
351
352 $path = apply_filters('iwp/importer/remote_file', $path, $importer);
353 $path = apply_filters(sprintf('iwp/importer=%d/remote_file', $importer->getId()), $path, $importer);
354
355 $filter_connection_args = [
356 'user' => $user,
357 'pass' => $pass,
358 'host' => $host,
359 'port' => $port,
360 'path' => $path,
361 ];
362 $path = apply_filters(sprintf('iwp/importer/remote_file/source=%s', 'ftp'), $path, $importer, $filter_connection_args);
363 $path = apply_filters(sprintf('iwp/importer=%d/remote_file/source=ftp', $importer->getId(), 'ftp'), $path, $importer, $filter_connection_args);
364
365 $result = $ftp->download_file($path, $host, $user, $pass, false, $port);
366 } else {
367
368 $result = $this->filesystem->download_file($source, $filetype, $allowed_file_types, null, $prefix);
369 }
370 } catch (\Exception $e) {
371 return new \WP_Error($e->getCode(), $e->getMessage());
372 }
373
374 if (is_wp_error($result)) {
375 return $result;
376 }
377
378 $attachment_id = $this->insert_file_attachment($importer, $result['dest'], $result['type']);
379 if (is_wp_error($attachment_id)) {
380 return $attachment_id;
381 }
382
383 return $attachment_id;
384 }
385
386 public function local_file($id, $source)
387 {
388 $importer = $this->get_importer($id);
389 Logger::setId($importer->getId());
390
391 $allowed_file_types = $this->event_handler->run('importer.allowed_file_types', [$importer->getAllowedFileTypes()]);
392 $prefix = $this->get_importer_file_prefix($importer);
393 $result = $this->filesystem->copy_file($source, $allowed_file_types, null, $prefix);
394
395 if (is_wp_error($result)) {
396 return $result;
397 }
398
399 $attachment_id = $this->insert_file_attachment($importer, $result['dest'], $result['type']);
400 if (is_wp_error($attachment_id)) {
401 return $attachment_id;
402 }
403
404 return $attachment_id;
405 }
406
407 /**
408 * Add uploaded file to importer
409 *
410 * Insert file record in database, set as current import file.
411 *
412 * @param integer|ImporterModel $id Importer to attach file
413 * @param string $file_path File location on server
414 * @param string $file_type Type of file
415 *
416 * @return \WP_Error|int Id of file
417 */
418 private function insert_file_attachment($id, $file_path, $file_type)
419 {
420 $importer_model = $this->get_importer($id);
421 Logger::setId($importer_model->getId());
422
423 // Allow the modification of file path
424 $file_path = wp_normalize_path($file_path);
425 $file_path = apply_filters('iwp/importer/file_uploaded/file_path', $file_path, $importer_model);
426
427 $file_id = $this->link_importer_file($id, $file_path);
428 if (!$file_id) {
429 return new \WP_Error('IWP_IM_01', 'Unable to link importer file');
430 }
431
432 if (is_null($importer_model->getParser())) {
433 $importer_model->setParser($file_type);
434 }
435
436 $importer_model->setFileId($file_id);
437 $importer_model->save();
438
439 do_action('iwp/importer/file_uploaded', $file_path, $importer_model);
440
441 return $file_id;
442 }
443
444 /**
445 * Clear config files
446 *
447 * @param int $id
448 * @return void
449 */
450 public function clear_config_files($id, $tmp = false, $all = true)
451 {
452 $config_path = $this->get_config_path($id, $tmp);
453 if (file_exists($config_path)) {
454
455 unlink($config_path);
456 if (true === $all) {
457 foreach (glob($config_path . '*') as $file) {
458
459 // don't remove status file
460 if (basename($file) === basename($config_path) . '.status') {
461 continue;
462 }
463
464 unlink($file);
465 }
466 }
467 }
468 }
469
470 public function get_config($importer, $tmp = false)
471 {
472 $config_path = $this->get_config_path($importer, $tmp);
473 $config = new Config($config_path);
474
475
476 $importer = $this->get_importer($importer);
477 $file_encoding = $importer->getFileSetting('file_encoding');
478
479 // file encoding
480 $config->set('file_encoding', apply_filters('iwp/importer/file_encoding', $file_encoding, $importer));
481
482 return $config;
483 }
484
485 public function get_session_path($id, $session, $max_depth = 4)
486 {
487 $base = $this->filesystem->get_temp_directory() . DIRECTORY_SEPARATOR;
488
489 $base .= str_pad($id, 2, STR_PAD_LEFT) . DIRECTORY_SEPARATOR;
490 if (!file_exists($base)) {
491 if (!is_writable(dirname($base)) || !mkdir($base)) {
492 throw new \Exception("Unable to create directory: " . $base);
493 }
494 }
495
496 for ($i = 0; $i < ceil(strlen($session) / 2); $i++) {
497 $base .= substr($session, $i * 2, 2) . DIRECTORY_SEPARATOR;
498 if (!file_exists($base)) {
499
500 if (!is_writable(dirname($base)) || !mkdir($base)) {
501 throw new \Exception("Unable to create directory: " . $base);
502 }
503 }
504
505 if ($i >= $max_depth - 2) {
506 break;
507 }
508 }
509 return $base;
510 }
511
512 public function get_config_path($id, $tmp = false, $session_id = null)
513 {
514 $importer = $this->get_importer($id);
515
516 $key = 'config-%d.json';
517 if ($tmp) {
518 $key = 'temp-config-%d.json';
519 }
520
521 $base = !is_null($session_id) ? $this->get_session_path($id, $session_id) : $this->filesystem->get_temp_directory() . DIRECTORY_SEPARATOR;
522
523 return $base . sprintf($key, $importer->getId());
524 }
525
526 public function import($id, $user, $session = null)
527 {
528 Logger::timer();
529
530 $importer_data = $this->get_importer($id);
531 $importer_id = $importer_data->getId();
532
533 // store current importer
534 iwp()->importer = $importer_data;
535
536 $config_data = get_site_option('iwp_importer_config_' . $importer_id, []);
537
538 $this->event_handler->run('importer_manager.import', [$importer_data]);
539
540 $state = new ImporterState($importer_id, $user);
541
542 try {
543
544 Logger::debug('IM -init_state');
545 $state->init($session);
546
547 if ($state->has_status('init')) {
548 Logger::debug('IM -clear_config_files');
549 $this->clear_config_files($importer_id, false, true);
550 $config_data['features'] = [
551 'session_table' => true
552 ];
553 }
554
555 Logger::debug('IM -get_config');
556 $config = $this->get_config($importer_data);
557
558 // template
559 Logger::debug('IM -get_importer_template');
560 $template = $this->get_importer_template($importer_data);
561
562 Logger::debug('IM -register_hooks');
563 $template->register_hooks($importer_data);
564
565 // permission
566 Logger::debug('IM -permissions');
567 $permission = new Permission($importer_data);
568
569 // mapper
570 Logger::debug('IM -get_importer_mapper');
571 $mapper = $this->get_importer_mapper($importer_data, $template, $permission);
572
573 if ($state->has_status('init')) {
574
575 Logger::debug('IM -generate_config');
576
577 $config_data['data'] = $template->config_field_map($importer_data->getMap());
578 $config->set('data', $config_data['data']);
579
580 $config_data['id'] = $state->get_session();
581
582 // This is used for storing version on imported records
583 update_post_meta($importer_id, '_iwp_session', $config_data['id']);
584
585 // Increase Version
586 $version = get_post_meta($importer_id, '_iwp_version', true);
587 if ($version !== false) {
588 $version++;
589 } else {
590 $version = 0;
591 }
592 update_post_meta($importer_id, '_iwp_version', $version);
593 $config_data['version'] = $version;
594
595 /**
596 * Fetch new file if setting is checked
597 * @since 2.7.15
598 */
599 $run_fetch_file = $importer_data->getSetting('run_fetch') || false;
600 $run_fetch_file = apply_filters('iwp/importer/run_fetch_file', $run_fetch_file);
601 if ($run_fetch_file) {
602
603 $datasource = $importer_data->getDatasource();
604 switch ($datasource) {
605 case 'remote':
606 $raw_source = $importer_data->getDatasourceSetting('remote_url');
607 $source = apply_filters('iwp/importer/datasource', $raw_source, $raw_source, $importer_data);
608 $source = apply_filters('iwp/importer/datasource/remote', $source, $raw_source, $importer_data);
609 $attachment_id = $this->remote_file($importer_data, $source, $importer_data->getParser());
610 break;
611 case 'local':
612 $raw_source = $importer_data->getDatasourceSetting('local_url');
613 $source = apply_filters('iwp/importer/datasource', $raw_source, $raw_source, $importer_data);
614 $source = apply_filters('iwp/importer/datasource/local', $source, $raw_source, $importer_data);
615 $attachment_id = $this->local_file($importer_data, $source);
616 break;
617 default:
618 // TODO: record error
619 $attachment_id = new \WP_Error('IWP_CRON_1', 'Unable to get new file using datasource: ' . $datasource);
620 break;
621 }
622
623 if (is_wp_error($attachment_id)) {
624 throw new \Exception('Importer Datasource: ' . $attachment_id->get_error_message());
625 }
626 }
627 }
628
629 $start = 0;
630
631 // get parser
632 if ($importer_data->getParser() === 'csv') {
633 Logger::debug('IM -get_csv_file');
634 $file = $this->get_csv_file($importer_data, $config);
635 Logger::debug('IM -load_parser');
636 $parser = new CSVParser($file);
637 if (true === $importer_data->getFileSetting('show_headings')) {
638 $start = 1;
639 }
640 } elseif ($importer_data->getParser() === 'xml') {
641 Logger::debug('IM -get_xml_file');
642 $file = $this->get_xml_file($importer_data, $config);
643 Logger::debug('IM -load_parser');
644 $parser = new XMLParser($file);
645 } else {
646 $parser = apply_filters('iwp/importer/init_parser', false, $importer_data, $config);
647 }
648
649 if ($state->has_status('init')) {
650
651 Logger::debug('IM -get_record_count');
652 $end = $parser->file()->getRecordCount();
653
654 // Capture cancelled status from file processor
655 $raw_state = ImporterState::get_state($importer_data->getId());
656 if ($raw_state['status'] === 'cancelled') {
657 return $raw_state;
658 }
659
660 $config_data['start'] = $this->get_start($importer_data, $start);
661 $config_data['end'] = $this->get_end($importer_data, $config_data['start'], $end);
662
663 update_site_option('iwp_importer_config_' . $importer_id, $config_data);
664
665 Logger::debug('IM -update_state');
666 $state->update(function ($state) use ($config_data) {
667
668 Logger::debug('IM -update_state=running');
669
670 $state['id'] = $config_data['id'];
671 $state['status'] = 'running';
672 $state['progress']['import']['start'] = $config_data['start'];
673 $state['progress']['import']['end'] = $config_data['end'];
674 return $state;
675 });
676
677 Logger::debug('IM -write_status_session_to_file');
678 Util::write_status_session_to_file($id, $state);
679
680 do_action('iwp/importer/init', $importer_data);
681 }
682
683 Logger::debug('IM -import');
684 $importer = new \ImportWP\Common\Importer\Importer($config);
685 $importer->parser($parser);
686 $importer->mapper($mapper);
687 $importer->from($config_data['start']);
688 $importer->to($config_data['end']);
689 $importer->filter($importer_data->getFilters());
690 $importer->import($importer_id, $user, $state);
691 Logger::debug('IM -import_complete');
692 } catch (\Exception $e) {
693
694 // TODO: Missing template errors are currently not being logged to history, possibly others?
695 Logger::error('import -error=' . $e->getMessage(), $importer_id);
696 return $state->error($e)->get_raw();
697 }
698
699 /**
700 * @var Properties $properties
701 */
702 $properties = Container::getInstance()->get('properties');
703
704 // rotate files to not fill up server
705 $importer_data->limit_importer_files($properties->file_rotation);
706 $this->prune_importer_logs($importer_data, $properties->log_rotation);
707
708 $template->unregister_hooks();
709
710 $this->event_handler->run('importer_manager.import_shutdown', [$importer_data]);
711
712 return $state->update(function ($data) {
713 $data['duration'] = floatval($data['duration']) + Logger::timer();
714 return $data;
715 })->get_raw();
716 }
717
718 public function get_start($importer_data, $start)
719 {
720 $tmp_start = $importer_data->getStartRow();
721 if (!is_null($tmp_start) && "" !== $tmp_start) {
722 $tmp_start = intval($tmp_start);
723
724 if ($tmp_start > $start) {
725 $start = $tmp_start;
726 }
727 }
728
729 return $start;
730 }
731
732 public function get_end($importer_data, $start, $end)
733 {
734 $tmp_max_row = $importer_data->getMaxRow();
735 if (!is_null($tmp_max_row) && $tmp_max_row !== '') {
736 $tmp_end = $start + intval($tmp_max_row);
737 if ($tmp_end < $end) {
738 $end = $tmp_end;
739 }
740 }
741
742 return $end;
743 }
744
745 public function get_importer_template($id)
746 {
747 $importer_model = $this->get_importer($id);
748 $templates = $this->get_templates();
749 $template_name = $importer_model->getTemplate();
750
751 if (!isset($templates[$template_name])) {
752 $exception_msg = "Unable to locate importer template: " . $template_name;
753 Logger::error('import -get_importer_template=' . $exception_msg, $importer_model->getId());
754 throw new \Exception($exception_msg);
755 }
756
757 return $this->template_manager->load_template($templates[$template_name]);
758 }
759
760 /**
761 * Get importer mapper
762 *
763 * @param int $id
764 * @param Template $template
765 * @param Permission $permission
766 * @return MapperInterface
767 */
768 public function get_importer_mapper($id, $template, $permission = null)
769 {
770 $importer = $this->get_importer($id);
771 $mapper_name = $template->get_mapper();
772
773 $mappers = $this->get_mappers();
774 return isset($mappers[$mapper_name]) ? new $mappers[$mapper_name]($importer, $template, $permission) : false;
775 }
776
777 public function get_mappers()
778 {
779 $mappers = $this->event_handler->run('mappers.register', [[]]); // apply_filters('iwp/mappers/register', []);
780 $mappers = array_merge($mappers, [
781 'post' => PostMapper::class,
782 'user' => UserMapper::class,
783 'term' => TermMapper::class,
784 'attachment' => AttachmentMapper::class,
785 'comment' => CommentMapper::class,
786 ]);
787 return $mappers;
788 }
789
790 public function get_mapper($key)
791 {
792 $mappers = $this->get_mappers();
793 if (!isset($mappers[$key])) {
794 return new \WP_Error('IWP_IM_1', 'Unable to locate mapper: ' . $key);
795 }
796
797 return $mappers[$key];
798 }
799
800 public function get_templates()
801 {
802 $templates = $this->event_handler->run('templates.register', [[]]);
803 $templates = array_merge($templates, [
804 'post' => PostTemplate::class,
805 'page' => PageTemplate::class,
806 'user' => UserTemplate::class,
807 'term' => TermTemplate::class,
808 'attachment' => AttachmentTemplate::class,
809 'comment' => CommentTemplate::class,
810 'custom-post-type' => CustomPostTypeTemplate::class,
811 ]);
812 return $templates;
813 }
814
815 public function get_template($key)
816 {
817 $templates = $this->get_templates();
818 if (!isset($templates[$key])) {
819 return new \WP_Error('IWP_IM_1', 'Unable to locate template: ' . $key);
820 }
821
822 return $templates[$key];
823 }
824
825 public function get_importer_debug_log(ImporterModel $importer_data, $page = 0, $per_page = -1)
826 {
827 $file_path = Logger::getLogFile($importer_data->getId());
828
829 $line_counter = 0;
830 $lines = [];
831 $start = $end = -1;
832
833 if ($per_page > 0) {
834 $start = ($page - 1) * $per_page;
835 $end = $start + $per_page;
836 }
837
838 if (file_exists($file_path)) {
839 $fh = fopen($file_path, 'r');
840 if ($fh !== false) {
841 while (($data = fgetcsv($fh)) !== false) {
842 if ($line_counter === $end) {
843 return $lines;
844 } elseif ($per_page === -1 || $line_counter >= $start) {
845 $lines[] = $data;
846 }
847
848 $line_counter++;
849 }
850 fclose($fh);
851 }
852 }
853 return $lines;
854 }
855
856 public function prune_importer_logs($importer_model, $limit)
857 {
858 $limit = intval($limit);
859 if ($limit <= -1) {
860 return;
861 }
862
863 $file_path = Util::get_importer_status_file_path($importer_model->getId());
864 $tmp_file_path = Util::get_importer_status_file_path($importer_model->getId()) . '.tmp';
865 $lines = $this->get_importer_logs($importer_model);
866
867 if (count($lines) > $limit) {
868
869 require_once(ABSPATH . 'wp-admin/includes/class-wp-filesystem-base.php');
870 require_once(ABSPATH . 'wp-admin/includes/class-wp-filesystem-direct.php');
871 $fileSystemDirect = new \WP_Filesystem_Direct(false);
872
873 $fh = fopen($tmp_file_path, 'w');
874 for ($i = 0; $i < count($lines); $i++) {
875
876 if ($i < count($lines) - $limit) {
877 $log_file_path = Util::get_importer_log_file_path($importer_model->getId(), $lines[$i]['id']);
878 if ($fileSystemDirect->exists($log_file_path)) {
879
880 $fileSystemDirect->delete($log_file_path);
881
882 $tmp = $log_file_path;
883 for ($j = 0; $j < 3; $j++) {
884 $tmp = dirname($tmp);
885 $sub_files = $fileSystemDirect->dirlist($log_file_path);
886 if (empty($sub_files)) {
887 $fileSystemDirect->rmdir($tmp);
888 }
889 }
890 }
891 } else {
892 fputs($fh, json_encode($lines[$i]) . "\n");
893 }
894 }
895 fclose($fh);
896
897 if ($fileSystemDirect->move($tmp_file_path, $file_path, true)) {
898 $fileSystemDirect->delete($tmp_file_path);
899 }
900 }
901 }
902
903 public function get_importer_logs(ImporterModel $importer_data, $page = 0, $per_page = -1)
904 {
905 $file_path = Util::get_importer_status_file_path($importer_data->getId());
906
907 $line_counter = 0;
908 $lines = [];
909
910 $start = $end = -1;
911
912 if ($per_page > 0) {
913 $start = ($page - 1) * $per_page;
914 $end = $start + $per_page;
915 }
916
917 if (file_exists($file_path)) {
918 $fh = fopen($file_path, 'r');
919 if ($fh !== false) {
920 while (($data = fgets($fh)) !== false) {
921 if ($data[strlen($data) - 1] === "\n") {
922 $data = substr($data, 0, strlen($data) - 1);
923 }
924
925 if ($line_counter === $end) {
926 return $lines;
927 } elseif ($per_page === -1 || $line_counter >= $start) {
928 $lines[] = json_decode($data, true);
929 }
930
931 $line_counter++;
932 }
933 fclose($fh);
934 }
935 }
936 return $lines;
937 }
938
939 public function get_importer_log(ImporterModel $importer_data, $session_id, $page = 0, $per_page = -1)
940 {
941 $file_path = Util::get_importer_log_file_path($importer_data->getId(), $session_id);
942
943 $line_counter = 0;
944 $lines = [];
945 $start = $end = -1;
946
947 if ($per_page > 0) {
948 $start = ($page - 1) * $per_page;
949 $end = $start + $per_page;
950 }
951
952 if (file_exists($file_path)) {
953 $fh = fopen($file_path, 'r');
954 if ($fh !== false) {
955 while (($data = fgetcsv($fh)) !== false) {
956 if ($line_counter === $end) {
957 return $lines;
958 } elseif ($per_page === -1 || $line_counter >= $start) {
959 $lines[] = $data;
960 }
961
962 $line_counter++;
963 }
964 fclose($fh);
965 }
966 }
967 return $lines;
968 }
969
970 public function get_importer_status_report(ImporterModel $immpoter_data, $session)
971 {
972 $logs = $this->get_importer_logs($immpoter_data);
973 foreach ($logs as $log) {
974 if ($log && isset($log['id']) && $log['id'] === $session) {
975 return $log;
976 }
977 }
978 return false;
979 }
980 }
981