| @@ -4,8 +4,9 @@ | ||
| 4 | 4 | |
| 5 | 5 | use ImportWP\Common\Filesystem\Filesystem; |
| 6 | 6 | use ImportWP\Common\Importer\Config\Config; |
| 7 | 7 | use ImportWP\Common\Importer\File\CSVFile; |
| 8 | +use ImportWP\Common\Importer\File\JSONFile; | |
| 8 | 9 | use ImportWP\Common\Importer\File\XMLFile; |
| 9 | 10 | use ImportWP\Common\Importer\Mapper\AttachmentMapper; |
| 10 | 11 | use ImportWP\Common\Importer\Mapper\CommentMapper; |
| 11 | 12 | use ImportWP\Common\Importer\Mapper\PostMapper; |
| @@ -11,8 +12,9 @@ | ||
| 11 | 12 | use ImportWP\Common\Importer\Mapper\PostMapper; |
| 12 | 13 | use ImportWP\Common\Importer\Mapper\TermMapper; |
| 13 | 14 | use ImportWP\Common\Importer\Mapper\UserMapper; |
| 14 | 15 | use ImportWP\Common\Importer\Parser\CSVParser; |
| 16 | +use ImportWP\Common\Importer\Parser\JSONParser; | |
| 15 | 17 | use ImportWP\Common\Importer\Parser\XMLParser; |
| 16 | 18 | use ImportWP\Common\Importer\Permission\Permission; |
| 17 | 19 | use ImportWP\Common\Importer\State\ImporterState; |
| 18 | 20 | use ImportWP\Common\Importer\Template\AttachmentTemplate; |
| @@ -54,11 +56,57 @@ | ||
| 54 | 56 | { |
| 55 | 57 | $this->filesystem = $filesystem; |
| 56 | 58 | $this->template_manager = $template_manager; |
| 57 | 59 | $this->event_handler = $event_handler; |
| 60 | + | |
| 61 | + add_action('admin_init', [$this, 'download_debug_log']); | |
| 58 | 62 | } |
| 59 | 63 | |
| 60 | 64 | /** |
| 65 | + * Stream an importer debug log through an authenticated admin request. | |
| 66 | + * | |
| 67 | + * Direct public URLs under uploads/importwp are blocked by .htaccess (CVE-2025-12894). | |
| 68 | + * | |
| 69 | + * @return void | |
| 70 | + */ | |
| 71 | + public function download_debug_log() | |
| 72 | + { | |
| 73 | + if (!isset($_GET['page'], $_GET['import'], $_GET['download_debug']) || $_GET['page'] !== 'importwp') { | |
| 74 | + return; | |
| 75 | + } | |
| 76 | + | |
| 77 | + if (!is_user_logged_in() || !current_user_can('manage_options')) { | |
| 78 | + wp_die(esc_html__('You do not have permission to download this file.', 'jc-importer'), '', array('response' => 403)); | |
| 79 | + } | |
| 80 | + | |
| 81 | + if (!isset($_GET['_wpnonce']) || !wp_verify_nonce(sanitize_key(wp_unslash($_GET['_wpnonce'])), 'iwp_debug_log_download')) { | |
| 82 | + wp_die(esc_html__('Invalid download request.', 'jc-importer'), '', array('response' => 403)); | |
| 83 | + } | |
| 84 | + | |
| 85 | + $importer_id = intval($_GET['import']); | |
| 86 | + $importer_data = $this->get_importer($importer_id); | |
| 87 | + if (!$importer_data) { | |
| 88 | + wp_die(esc_html__('Invalid download request.', 'jc-importer'), '', array('response' => 403)); | |
| 89 | + } | |
| 90 | + | |
| 91 | + if (!$this->is_debug()) { | |
| 92 | + wp_die(esc_html__('Debug mode is not enabled.', 'jc-importer'), '', array('response' => 403)); | |
| 93 | + } | |
| 94 | + | |
| 95 | + $file_path = Logger::getLogFile($importer_id); | |
| 96 | + if (!is_string($file_path) || !file_exists($file_path)) { | |
| 97 | + wp_die(esc_html__('Debug log file not found.', 'jc-importer'), '', array('response' => 404)); | |
| 98 | + } | |
| 99 | + | |
| 100 | + nocache_headers(); | |
| 101 | + header('Content-Type: text/plain; charset=utf-8'); | |
| 102 | + header('Content-Disposition: attachment; filename="' . basename($file_path) . '"'); | |
| 103 | + header('Content-Length: ' . (string) filesize($file_path)); | |
| 104 | + readfile($file_path); | |
| 105 | + exit; | |
| 106 | + } | |
| 107 | + | |
| 108 | + /** | |
| 61 | 109 | * Get Importers |
| 62 | 110 | * |
| 63 | 111 | * @return ImporterModel[] |
| 64 | 112 | */ |
| @@ -146,8 +194,10 @@ | ||
| 146 | 194 | if ('xml' === $parser) { |
| 147 | 195 | return $this->get_xml_file($importer, $config); |
| 148 | 196 | } elseif ('csv' === $parser) { |
| 149 | 197 | return $this->get_csv_file($importer, $config); |
| 198 | + } elseif ('json' === $parser) { | |
| 199 | + return $this->get_json_file($importer, $config); | |
| 150 | 200 | } |
| 151 | 201 | |
| 152 | 202 | return false; |
| 153 | 203 | } |
| @@ -169,8 +219,16 @@ | ||
| 169 | 219 | $file->setRecordPath($importer->getFileSetting('base_path')); |
| 170 | 220 | return $file; |
| 171 | 221 | } |
| 172 | 222 | |
| 223 | + public function get_json_file($id, $config) | |
| 224 | + { | |
| 225 | + $importer = $this->get_importer($id); | |
| 226 | + $file = new JSONFile($importer->getFile(), $config); | |
| 227 | + $file->setRecordPath($importer->getFileSetting('base_path')); | |
| 228 | + return $file; | |
| 229 | + } | |
| 230 | + | |
| 173 | 231 | public function preview_csv_file($id, $fields = [], $row = 0) |
| 174 | 232 | { |
| 175 | 233 | $importer = $this->get_importer($id); |
| 176 | 234 | $config = $this->get_config($importer, true); |
| @@ -194,8 +252,20 @@ | ||
| 194 | 252 | $record = $parser->getRecord($row); |
| 195 | 253 | return $record->queryGroup(['fields' => $fields]); |
| 196 | 254 | } |
| 197 | 255 | |
| 256 | + public function preview_json_file($id, $fields = [], $row = 0) | |
| 257 | + { | |
| 258 | + $importer = $this->get_importer($id); | |
| 259 | + $config = $this->get_config($importer, true); | |
| 260 | + | |
| 261 | + $file = $this->get_json_file($importer, $config); | |
| 262 | + $parser = new JSONParser($file); | |
| 263 | + | |
| 264 | + $record = $parser->getRecord($row); | |
| 265 | + return $record->queryGroup(['fields' => $fields]); | |
| 266 | + } | |
| 267 | + | |
| 198 | 268 | public function process_csv_file($id, $delimiter, $enclosure, $tmp = false) |
| 199 | 269 | { |
| 200 | 270 | $importer = $this->get_importer($id); |
| 201 | 271 | $config = $this->get_config($importer->getId(), $tmp); |
| @@ -230,8 +300,19 @@ | ||
| 230 | 300 | |
| 231 | 301 | return $results; |
| 232 | 302 | } |
| 233 | 303 | |
| 304 | + public function process_json_file($id, $tmp = false) | |
| 305 | + { | |
| 306 | + $importer = $this->get_importer($id); | |
| 307 | + $config = $this->get_config($importer->getId(), $tmp); | |
| 308 | + | |
| 309 | + $file = new JSONFile($importer->getFile(), $config); | |
| 310 | + $file->processing(true); | |
| 311 | + | |
| 312 | + return $file->get_path_list(); | |
| 313 | + } | |
| 314 | + | |
| 234 | 315 | /** |
| 235 | 316 | * Link import file to importer via post meta |
| 236 | 317 | * |
| 237 | 318 | * @param ImporterModel $id |
| @@ -727,10 +808,25 @@ | ||
| 727 | 808 | Logger::debug('IM -get_xml_file'); |
| 728 | 809 | $file = $this->get_xml_file($importer_data, $config); |
| 729 | 810 | Logger::debug('IM -load_parser'); |
| 730 | 811 | $parser = new XMLParser($file); |
| 812 | + } elseif ($importer_data->getParser() === 'json') { | |
| 813 | + Logger::debug('IM -get_json_file'); | |
| 814 | + $file = $this->get_json_file($importer_data, $config); | |
| 815 | + Logger::debug('IM -load_parser'); | |
| 816 | + $parser = new JSONParser($file); | |
| 731 | 817 | } else { |
| 732 | 818 | $parser = apply_filters('iwp/importer/init_parser', false, $importer_data, $config); |
| 819 | + } | |
| 820 | + | |
| 821 | + if (!$parser || !is_object($parser) || !method_exists($parser, 'file')) { | |
| 822 | + $parser_type = $importer_data->getParser(); | |
| 823 | + throw new \Exception( | |
| 824 | + sprintf( | |
| 825 | + __('Unable to load importer parser for type: %s', 'jc-importer'), | |
| 826 | + $parser_type ? $parser_type : __('unknown', 'jc-importer') | |
| 827 | + ) | |
| 828 | + ); | |
| 733 | 829 | } |
| 734 | 830 | |
| 735 | 831 | // if this is a new session, set start / end rows to state |
| 736 | 832 | if ($state->has_status('init')) { |