$data = str_replace("\xEF\xBB\xBF", '', $data); } $data = array_map(function ($item) { return trim($item, ' \'"'); }, $data); if (!$fields) { $fields = $data; continue; } if (count($fields) != count($data)) { continue; } $data = array_combine($fields, $data); try { $product = $this->feedProductPrepare($data); } catch (\Exception $e) { if ($i > 0) { continue; } $this->setLastImportError($e->getMessage()); fclose($handle); return; } if (!$product) { continue; } if (!empty($product['ean'])) { $product['ean'] = TextHelper::fixEan($product['ean']); } if ($in_stock_only && $product['stock_status'] == ContentProduct::STOCK_STATUS_OUT_OF_STOCK) { continue; } $products[] = $product; $i++; if ($i % static::MULTIPLE_INSERT_ROWS == 0) { $this->product_model->multipleInsert($products, static::MULTIPLE_INSERT_ROWS); $products = array(); } } if ($products) { $this->product_model->multipleInsert($products, static::MULTIPLE_INSERT_ROWS); } } protected function processFeedXml($file) { $uniqueNode = $this->getProductNode(); if (!$uniqueNode) { $uniqueNode = 'offer'; } $streamer = \ContentEgg\application\vendor\XmlStringStreamer\XmlStringStreamer::createUniqueNodeParser($file, array('uniqueNode' => $uniqueNode)); $in_stock_only = $this->config('in_stock', false); $i = 0; $products = array(); libxml_use_internal_errors(true); $encoding = $this->config('encoding', 'UTF-8'); while ($node_string = $streamer->getNode()) { if ($encoding != 'UTF-8') { $node_string = iconv($encoding, 'UTF-8//TRANSLIT//IGNORE', $node_string); } $node = simplexml_load_string($node_string); if ($node === false) { $err_mess = 'Cannot load xml source.'; if ($error = libxml_get_last_error()) { $err_mess .= $error->message; } $this->setLastImportError($err_mess); return; } $data = $this->mapXmlData($node); try { $product = $this->feedProductPrepare($data); } catch (\Exception $e) { if ($i > 0) { continue; } $this->setLastImportError($e->getMessage()); return; } if (!$product) { continue; } if (!empty($product['ean'])) { $product['ean'] = TextHelper::fixEan($product['ean']); } if ($in_stock_only && $product['stock_status'] == ContentProduct::STOCK_STATUS_OUT_OF_STOCK) { continue; } $products[] = $product; $i++; if ($i % static::MULTIPLE_INSERT_ROWS == 0) { $this->product_model->multipleInsert($products, static::MULTIPLE_INSERT_ROWS); $products = array(); } } if ($i == 0) { $this->setLastImportError('Product node not found.'); } if ($products) { $this->product_model->multipleInsert($products, static::MULTIPLE_INSERT_ROWS); } } protected function processFeedJson($file) { $encoding = $this->config('encoding', 'UTF-8'); $in_stock_only = $this->config('in_stock', false); $json = file_get_contents($file); $json_arr = json_decode($json, true); if (!$json_arr) { $this->setLastImportError(trim('Cannot decode JSON source. ' . json_last_error_msg())); return; } $node = $this->getProductNode(); if (!$node && is_array($json_arr)) { $node = 'offer'; $json_arr = array($node => $json_arr); } if (!isset($json_arr[$node]) || !is_array($json_arr[$node])) { $this->setLastImportError('The product node "' . \esc_html($node) . '" does not exist.'); return; } $i = 0; foreach ($json_arr[$node] as $data) { if ($encoding == 'ISO-8859-1') { $data = array_map('utf8_encode', $data); } try { $product = $this->feedProductPrepare($data); } catch (\Exception $e) { if ($i > 0) { continue; } $this->setLastImportError($e->getMessage()); return; } if (!$product) { continue; } if (!empty($product['ean'])) { $product['ean'] = TextHelper::fixEan($product['ean']); } if ($in_stock_only && $product['stock_status'] == ContentProduct::STOCK_STATUS_OUT_OF_STOCK) { continue; } $products[] = $product; $i++; if ($i % static::MULTIPLE_INSERT_ROWS == 0) { $this->product_model->multipleInsert($products, static::MULTIPLE_INSERT_ROWS); $products = array(); } $i++; } if ($products) { $this->product_model->multipleInsert($products, static::MULTIPLE_INSERT_ROWS); } } protected function mapXmlData($node) { $data = array(); $mapping = $this->config('mapping'); $fields = array_values($mapping); $attributes = $node->attributes(); foreach ($fields as $field) { if (isset($attributes[$field])) $data[$field] = (string) $attributes[$field]; elseif (isset($node->{$field})) $data[$field] = (string) $node->{$field}; elseif ($res = $node->xpath($field)) $data[$field] = trim(\wp_strip_all_tags((string) $res[0])); else continue; } return $data; } public function getLastImportDateReadable() { $last_import = $this->getLastImportDate(); if (empty($last_import)) { return ''; } if ($last_import < 0) { return __('Product import is in progress', 'content-egg'); } if (time() - $last_import <= 43200) { return sprintf(__('%s ago', '%s = human-readable time difference', 'content-egg'), \human_time_diff($last_import, time())); } return TemplateHelper::dateFormatFromGmt($last_import, true); } public function getProductCount() { return $this->product_model->count(); } protected function getDatafeedDir() { $upload_dir = \wp_upload_dir(); $datafeed_dir = $upload_dir['basedir'] . '/' . static::DATAFEED_DIR_NAME; if (is_dir($datafeed_dir)) { return $datafeed_dir; } $files = array( array( 'file' => 'index.html', 'content' => '', ), array( 'file' => '.htaccess', 'content' => 'deny from all', ), ); foreach ($files as $file) { if (\wp_mkdir_p($datafeed_dir) && !file_exists(trailingslashit($datafeed_dir) . $file['file'])) { if ($file_handle = @fopen(trailingslashit($datafeed_dir) . $file['file'], 'w')) { fwrite($file_handle, $file['content']); fclose($file_handle); } } } if (!is_dir($datafeed_dir)) { throw new \Exception('Can not create temporary directory for datafeed.'); } return $datafeed_dir; } protected function detectCsvDelimiter($file) { $delimiters = array( ';' => 0, ',' => 0, "\t" => 0, "|" => 0 ); $handle = fopen($file, "r"); $firstLine = fgets($handle); fclose($handle); foreach ($delimiters as $delimiter => &$count) { $count = count(str_getcsv($firstLine, $delimiter)); } return array_search(max($delimiters), $delimiters); } public function fatalHandler() { if (!$error = error_get_last()) { return; } if (!isset($error['file']) || !strpos($error['file'], 'AffiliateFeedParserModule.php')) { return; } $message = $error['message']; if (strstr($message, 'Allowed memory size')) { $message .= '. ' . sprintf(__('Your data feed is too large and cannot be imported. Use a smaller feed or increase WP_MAX_MEMORY_LIMIT.', 'content-egg'), 'https://wordpress.org/support/article/editing-wp-config-php/#increasing-memory-allocated-to-php'); } $this->setLastImportError($message); } public function deleteTemporaryFiles() { $dir = trailingslashit($this->getDatafeedDir()); $parts = explode('/', $dir); if ($parts[count($parts) - 2] !== self::DATAFEED_DIR_NAME) { throw new \Exception('Unexpected error while cleaning temporary directory.'); return; } $scanned = array_values(array_diff(scandir($dir), array('..', '.', 'index.html', '.htaccess'))); if (!$scanned) { return; } global $wp_filesystem; if (!$wp_filesystem) { require_once(ABSPATH . '/wp-admin/includes/file.php'); \WP_Filesystem(); } foreach ($scanned as $s) { $path = $dir . $s; if (is_dir($path) && !preg_match('/-unzipped-dir$/', $path)) { continue; } if (is_file($path) && pathinfo($path, PATHINFO_EXTENSION) !== 'csv') { continue; } if ($wp_filesystem->exists($path) && time() - filemtime($path) > 3600) { $wp_filesystem->delete($path, true); } } } public function getProductNode() { $mapping = $this->config('mapping'); if (!empty($mapping['product node'])) { return $mapping['product node']; } else { return false; } } }