* @copyright 2015 PrestaShow.pl * @license http://PrestaShow.pl/license */ class PShow_File { /** * Update file from URL * (convert to XML if CSV downloaded) * * @param string $filepath * @param string $url * @return boolean */ public static function updateFileFromURL($filepath, $url) { if (empty($filepath)) { return false; } $filename = pathinfo($filepath, PATHINFO_FILENAME); if (empty($url) || filter_var($url, FILTER_VALIDATE_URL) === false) { PShow_Log::add($filename . '.log', "url is empty or invalid " . $url); return false; } PShow_Log::add($filename . '.log', sprintf("downloading file from %s to %s", $url, $filepath)); $config = PShow_Config::getFileConfig($filename); $login = (isset($config['file']) && isset($config['file']['login'])) ? $config['file']['login'] : null; $password = (isset($config['file']) && isset($config['file']['password'])) ? $config['file']['password'] : null; if (!isset($config['file']) || !isset($config['file']['auth_req']) || !$config['file']['auth_req']) { $login = $password = null; } PShow_File::download($url, $filepath, $login, $password); if (file_exists(_IMPORT_CONFIG_PATH_ . $filename . '/csv_delimiter')) { // this method is deprecated $delimiter = file_get_contents(_IMPORT_CONFIG_PATH_ . $filename . '/csv_delimiter'); if (empty($delimiter)) { PShow_Log::add($filename . '.log', "delimiter not found"); return false; } $headers_in_the_file = 1; if (file_exists(_IMPORT_CONFIG_PATH_ . $filename . '/headers_in_the_file')) { $headers_in_the_file = (int) file_get_contents(_IMPORT_CONFIG_PATH_ . $filename . '/headers_in_the_file'); } PShow_Log::add($filename . '.log', "converting csv to xml document"); PShow_Csv::convertToXml($filepath, $delimiter, true, $headers_in_the_file); $new_config = array( 'file' => array( 'format' => 'csv', 'csv' => array( 'headers_in_the_file' => $headers_in_the_file, 'separator' => $delimiter, ), ) ); PShow_Config::saveFileConfig($filename, $new_config); @unlink(_IMPORT_CONFIG_PATH_ . $filename . '/csv_delimiter'); @unlink(_IMPORT_CONFIG_PATH_ . $filename . '/headers_in_the_file'); } elseif (isset($config['file']) && isset($config['file']['format']) && $config['file']['format'] == 'csv') { $delimiter = $config['file']['csv']['separator']; if (empty($delimiter)) { PShow_Log::add($filename . '.log', "delimiter not found"); return false; } $headers_in_the_file = $config['file']['csv']['headers_in_the_file']; PShow_Log::add($filename . '.log', "converting csv to xml document"); PShow_Csv::convertToXml($filepath, $delimiter, true, $headers_in_the_file, (isset($config['file']['encoding']) ? $config['file']['encoding'] : 'UTF-8')); } PShow_File::minifyXmlFile($filepath); return true; } /** * Re-encode file with UTF8 * * @param string $dest_filepath */ public static function re_encode_utf8_file($dest_filepath) { $source_filepath = $dest_filepath . '.encoding'; rename($dest_filepath, $source_filepath); $r = fopen($source_filepath, 'r'); $w = fopen($dest_filepath, 'w'); while ($str = fread($r, 255)) { fwrite($w, utf8_encode(utf8_decode($str))); } fclose($r); fclose($w); @unlink($source_filepath); } /** * Find free filename in upload directory * * @param string $name_ * @param int $append * @return string */ public static function findFreeNameToUpload($name_, $append = 0) { $name = $name_; if ($append) { $name .= '_' . $append; } if (count(glob(_MODULE_UPLOAD_PATH_ . '*-' . $name . '.*'))) { return self::findFreeNameToUpload($name_, ++$append); } return $name; } public static function unlink($filepath) { if (!file_exists($filepath)) { return false; } return unlink($filepath); } /** * * @param string $path */ public static function minifyXmlFile($path) { if (strtolower(pathinfo($path, PATHINFO_EXTENSION)) == "xml") { $content = file_get_contents($path); $newcontent = preg_replace('~ xmlns:([^=]+)="([^"]+)"~', "", $content); $newcontent = preg_replace('~ xmlns="([^"]+)"~', "", $newcontent); $newcontent = preg_replace('~ xsi:([^=]+)="([^"]+)"~', "", $newcontent); $newcontent = preg_replace('~ xsi="([^"]+)"~', "", $newcontent); $newcontent = preg_replace('~iaiext:~', "", $newcontent); file_put_contents($path, $newcontent); } } /** * * @param string $url * @return boolean|array */ public static function isImage(&$url) { $url = str_replace('\n', '', $url); $url = preg_replace('~(.*)(http|ftp)~', '$2', $url); $url = chop($url); $url = str_replace(' ', '%20', $url); if (strpos($url, 'ftp://') !== false) { return array('url' => $url); } $headers = self::get_headers($url); if (!$headers) { return false; } if (stripos($headers['Content-Type'], 'image') === false) { return false; } return $headers; } public static function getLogFile($filepath) { return PShow_Log::getLogFile($filepath); } public static function _getHeaders($url) { if (function_exists('curl_init')) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_HEADER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_NOBODY, false); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_VERBOSE, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_exec($ch); $responseCode = curl_getinfo($ch, CURLINFO_RESPONSE_CODE); $contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE); curl_close($ch); if ($responseCode != null) { return array( $responseCode, 'Content-Type: ' . $contentType ); } } else { PShow_Log::addImportLog('curl extension not available'); } return get_headers($url); } public static function get_headers($url) { $headers = self::_getHeaders($url); while (stripos($headers[0], "301") !== false) { foreach ($headers as $h) { if (stripos($h, 'Location: ') !== false) { $url = str_replace('Location: ', null, $h); break; } } $headers = self::_getHeaders($url); } if (!$headers || stripos($headers[0], "200") === false) { $url = urldecode($url); $headers = self::_getHeaders($url); } if (!$headers || stripos($headers[0], "200") === false) { $url = urlencode($url); $headers = self::_getHeaders($url); } if (!$headers || stripos($headers[0], "200") === false) { return false; } $content_type = null; foreach ($headers as $h) { if (stripos($h, 'Content-Type: ') !== false) { $content_type = str_replace('Content-Type: ', null, $h); break; } } if (stripos($content_type, 'image') === false && in_array($content_type, array('png', 'jpg', 'jpeg', 'gif'))) { $content_type = "image/" . $content_type; } return array( 'url' => $url, 'Content-Type' => $content_type ); } public static function file_get_contents($path) { $contents = Tools::file_get_contents($path, false, null, (60 * 10)); if (!$contents && filter_var($path, FILTER_VALIDATE_URL)) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $path); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); $contents = curl_exec($ch); curl_close($ch); } return $contents; } /** * download() * * @param $url address to file * @param $save_as download file to... */ public static function download($url, $save_as, $login = null, $password = null) { $opts = array( "ssl" => array( "verify_peer" => false, "verify_peer_name" => false, ), 'http' => array( 'method' => 'GET', 'timeout' => 60 * 10 ) ); if (!empty($login) && !empty($password)) { $url = str_replace('https://', sprintf('https://%s:%s@', $login, $password), $url); $url = str_replace('http://', sprintf('http://%s:%s@', $login, $password), $url); $url = str_replace('ftp://', sprintf('ftp://%s:%s@', $login, $password), $url); } $file = @fopen($url, "rb", false, stream_context_create($opts)); //stream_set_timeout($file, 300); if ($file) { $newf = fopen($save_as, "wb"); if ($newf) { while (!feof($file)) { fwrite($newf, fread($file, 1024 * 8), 1024 * 8); } fclose($newf); } fclose($file); } else { $data = self::file_get_contents($url); file_put_contents($save_as, $data); } } /** * getFileFromURL() * * @param $url address to file * @return bool downloaded or not */ public static function getFileFromURL($url, $auth_req, $login, $password) { $ext = strtolower(Tools::getValue('fileext')); $filename = Tools::getValue('saveas'); $filename = str_replace(' ', '_', $filename); $time = time(); $freeFilename = self::findFreeNameToUpload($filename); $info_file = _MODULE_UPLOAD_PATH_ . $time . '-' . $freeFilename . '.txt'; $data_file = _MODULE_UPLOAD_PATH_ . $time . '-' . $freeFilename . '.' . $ext; $encoding = Tools::getValue('file_encoding'); PShow_Config::saveFileConfig($time . '-' . $freeFilename, array( 'file' => array( 'auth_req' => (int) $auth_req, 'login' => $login, 'password' => $password, 'format' => 'xml', 'encoding' => $encoding, ), )); file_put_contents($info_file, $url); if (!file_exists($info_file)) { return false; } self::download($url, $data_file, $login, $password); @chmod($data_file, 0664); if (!file_exists($data_file)) { unlink($info_file); return false; } $delimiter = Tools::getValue('csvdelim'); $headers_in_the_file = (int) Tools::getValue('headers_in_the_file'); self::minifyXmlFile($data_file); if ($ext == 'csv' && $delimiter) { // create xml file PShow_Csv::convertToXml($data_file, $delimiter, true, $headers_in_the_file, $encoding, ($encoding ? $encoding : 'UTF-8')); $conf_dir = _IMPORT_CONFIG_PATH_ . pathinfo($data_file, PATHINFO_FILENAME); if (!is_dir($conf_dir)) { mkdir($conf_dir, 0777); } PShow_Config::saveFileConfig($time . '-' . $freeFilename, array( 'file' => array( 'csv' => array( 'separator' => $delimiter, 'headers_in_the_file' => $headers_in_the_file, ), 'format' => 'csv', ), )); } Cache::getInstance()->delete('pshowimporter_files_list'); return true; } /** * getFileFromLocalDisk() * * @return string */ public static function getFileFromLocalDisk() { $filename_ = Tools::getValue('saveas'); $filename_ = str_replace(' ', '_', $filename_); $dirname = self::findFreeNameToUpload($filename_); $filename = $dirname . '.' . strtolower(pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION)); $upload_path = time() . '-' . $filename; PShow_Config::saveFileConfig($dirname, array( 'file' => array( 'auth_req' => 0, 'format' => 'xml', ), )); $return = null; if (!preg_match('/.*\.(' . str_replace(',', '|', _IMPORT_FILE_EXTENSIONS_) . ')$/i', $_FILES['file']['name'])) { $return = 'The extension of your file should be .csv or .xml'; } elseif (!@move_uploaded_file($_FILES['file']['tmp_name'], _MODULE_UPLOAD_PATH_ . $upload_path)) { $return = 'An error occurred while uploading / copying the file.'; } else { @chmod(_MODULE_UPLOAD_PATH_ . $upload_path, 0664); $_FILES['file']['filename'] = $upload_path; $return = 'File successfully uploaded.'; self::minifyXmlFile(_MODULE_UPLOAD_PATH_ . $upload_path); $delimiter = Tools::getValue('csvdelim'); $headers_in_the_file = (int) Tools::getValue('headers_in_the_file'); $encoding = Tools::getValue('file_encoding'); PShow_Config::saveFileConfig($dirname, array( 'file' => array( 'csv' => array( 'separator' => $delimiter, 'headers_in_the_file' => $headers_in_the_file, ), 'format' => 'csv', 'encoding' => $encoding, ), )); if ($delimiter) { // create xml file PShow_Csv::convertToXml(_MODULE_UPLOAD_PATH_ . $upload_path, $delimiter, true, $headers_in_the_file, ($encoding ? $encoding : 'UTF-8')); $conf_dir = _IMPORT_CONFIG_PATH_ . pathinfo($upload_path, PATHINFO_FILENAME); if (!is_dir($conf_dir)) { mkdir($conf_dir, 0777); } } Cache::getInstance()->delete('pshowimporter_files_list'); } return $return; } /** * getFilesList() * * @return array list of the files */ public static function getFilesList() { if (_PS_CACHE_ENABLED_ && Cache::getInstance()->exists('pshowimporter_files_list')) { return Cache::getInstance()->get('pshowimporter_files_list'); } $files = glob(_MODULE_UPLOAD_PATH_ . '*.*'); $data = array(); $i = 0; foreach ($files as $path) { if (!in_array(pathinfo($path, PATHINFO_EXTENSION), explode(',', _IMPORT_FILE_EXTENSIONS_))) { continue; } $data[$i] = pathinfo($path); $data[$i]['path'] = $path; // chmods $data[$i]['chmod'] = "" . substr(sprintf('%o', fileperms($path)), -4) . ""; $data[$i]['writable'] = is_writable($path); $data[$i]['readable'] = is_readable($path); if ($data[$i]['writable'] && $data[$i]['readable']) { $data[$i]['chmod'] = "OK"; } else { $data[$i]['chmod'] = "Error"; } $data[$i]['writable'] = $data[$i]['writable'] ? 'OK' : 'No access!'; $data[$i]['readable'] = $data[$i]['readable'] ? 'OK' : 'No access!'; // source $txt_file = $data[$i]['dirname'] . '/' . $data[$i]['filename'] . '.txt'; if (file_exists($txt_file)) { $data[$i]['from_url'] = self::file_get_contents($txt_file); } else { $data[$i]['from_url'] = false; } // time $filename_data = explode('-', $data[$i]['filename']); $data[$i]['time'] = $filename_data[0]; $lastimport_file = _IMPORT_CONFIG_PATH_ . $data[$i]['filename'] . '/lastimport'; if (file_exists($lastimport_file)) { $data[$i]['lastimport'] = filemtime($lastimport_file); } else { $data[$i]['lastimport'] = false; } $config = PShow_Config::getFileConfig($data[$i]['filename']); $data[$i]['rowsCount'] = (array_key_exists('primary', $config) && array_key_exists('rowsCount', $config['primary'])) ? $config['primary']['rowsCount'] : '-'; $data[$i]['configured'] = array_key_exists('primary', $config); $data[$i]['matched'] = array_key_exists('matched', $config); $data[$i]['match_cats'] = ($data[$i]['configured'] && $data[$i]['matched']); $data[$i]['filename'] = str_replace($data[$i]['time'] . '-', '', $data[$i]['filename']); $filesizetypes = array('B', 'KB', 'MB', 'GB', 'TB'); $data[$i]['filesizetype'] = 'B'; // required memory $data[$i]['reqMoreMemory'] = (bool) (intval(filesize($path)) * 2.2 > intval(ini_get('memory_limit')) * 1000 * 1000); if ($data[$i]['reqMoreMemory']) { $data[$i]['reqMoreMemory'] = (string) ($data[$i]['filesize'] * 2) . $data[$i]['filesizetype']; } $data[$i]['filesize'] = round(filesize($path), 2); while ($data[$i]['filesize'] > 1000) { $data[$i]['filesize'] = round($data[$i]['filesize'] / 1000, 2); $act = array_search($data[$i]['filesizetype'], $filesizetypes); $data[$i]['filesizetype'] = $filesizetypes[($act + 1)]; } // get display filename $data[$i]['data'] = array( 'displayFileName' => array_key_exists('displayFileName', $config) ? $config['displayFileName'] : $data[$i]['filename'] ); $mime_encoding = "utf-8"; $disabled = ini_get("disable_functions"); if (stripos($disabled, 'exec') === false) { @exec("file --mime-encoding " . escapeshellarg($path), $mime_encoding); if (is_array($mime_encoding)) { $mime_encoding = reset($mime_encoding); $mime_encoding = substr($mime_encoding, (stripos($mime_encoding, ': ')) + 2); } } // file encoding $data[$i]['correct_encoding'] = ($mime_encoding == "utf-8" || $mime_encoding == "us-ascii") ? true : $mime_encoding; if ($data[$i]['correct_encoding'] === true) { $data[$i]['encoding'] = "OK"; } else { $data[$i]['encoding'] = "ERROR"; } $data[$i]['id'] = $i + 1; $data[$i]['reconfigRequired'] = false; $data[$i]['wrong_xml_format'] = false; $data[$i]['log_dir'] = _IMPORT_LOG_PATH_ . $data[$i]['time'] . '-' . $data[$i]['filename']; ++$i; } if (_PS_CACHE_ENABLED_) { Cache::getInstance()->set('pshowimporter_files_list', $data); } return $data; } /** * sortFiles() * * @param array list of the files * @param string sort type * @param string sorting order * @return array sorted list of the files */ public static function sortFiles($files, $sort_by, $order) { $files_count = count($files); for ($y = 0; $y < $files_count; ++$y) { for ($x = 0; $x < ($files_count - 1); ++$x) { $tmp = array(); switch ($sort_by) { case 'time': if ($files[$x]['time'] > $files[$x + 1]['time'] && $order == 'desc') { $tmp = $files[$x]; $files[$x] = $files[$x + 1]; $files[$x + 1] = $tmp; } if ($files[$x]['time'] < $files[$x + 1]['time'] && $order == 'asc') { $tmp = $files[$x]; $files[$x] = $files[$x + 1]; $files[$x + 1] = $tmp; } break; case 'filesize': if ($files[$x]['filesize'] < $files[$x + 1]['filesize'] && $order == 'desc') { $tmp = $files[$x]; $files[$x] = $files[$x + 1]; $files[$x + 1] = $tmp; } if ($files[$x]['filesize'] > $files[$x + 1]['filesize'] && $order == 'asc') { $tmp = $files[$x]; $files[$x] = $files[$x + 1]; $files[$x + 1] = $tmp; } break; } } } return $files; } /** * Import image as attribute texture * * @param string $url * @param integer $id_attribute */ public static function importAttributeTexture($url, $id_attribute) { $images_path = _PS_COL_IMG_DIR_ . $id_attribute; PShow_Log::addImportLog("import attribute texture from: " . $url); $img = self::file_get_contents($url); file_put_contents($images_path . '.temp', $img); list($width, $height, $type) = self::getimagesize($images_path . '.temp'); unlink($images_path . '.temp'); if ($type === null) { PShow_Log::addImportLog("attribute texture not imported because type not found for url: " . $url); return false; } $_ext = (($type == IMAGETYPE_JPEG) ? '.jpg' : '.png'); $ext = '.jpg'; if ($type == IMAGETYPE_JPEG) { file_put_contents($images_path . $ext, $img); } else { file_put_contents($images_path . $_ext, $img); $input_file = $images_path . $_ext; $output_file = $images_path . $ext; $input = imagecreatefrompng($input_file); list($width, $height) = getimagesize($input_file); $output = imagecreatetruecolor($width, $height); $white = imagecolorallocate($output, 255, 255, 255); imagefilledrectangle($output, 0, 0, $width, $height, $white); imagecopy($output, $input, 0, 0, 0, 0, $width, $height); imagejpeg($output, $output_file); unlink($images_path . $_ext); } PShow_Log::addImportLog("attribute texture imported to: " . $images_path . $ext); } private static $imagesize = array(); public static function getimagesize($url) { $md5 = md5($url); if (!array_key_exists($md5, self::$imagesize) || self::$imagesize[$md5] === null) { self::$imagesize[$md5] = getimagesize($url); } return self::$imagesize[$md5]; } /** * * @param string $url * @param string $images_path * @param integer $quality * @param boolean $generate_thumbnails * @param string $log_path */ public static function import_image($url, $images_path, $quality, $generate_thumbnails, $log_path = null) { $img = self::file_get_contents($url); file_put_contents($images_path . '.temp', $img); list($width, $height, $type) = self::getimagesize($images_path . '.temp'); unlink($images_path . '.temp'); if ($type === null) { if ($log_path !== null) { PShow_Log::addImportLog("Image type not found for url: " . $url); } $type = IMAGETYPE_JPEG; } $_ext = (($type == IMAGETYPE_JPEG) ? '.jpg' : '.png'); $ext = '.jpg'; if ($type == IMAGETYPE_JPEG) { file_put_contents($images_path . $ext, $img); } else { file_put_contents($images_path . $_ext, $img); $input_file = $images_path . $_ext; $output_file = $images_path . $ext; $input = imagecreatefrompng($input_file); list($width, $height) = getimagesize($input_file); $output = imagecreatetruecolor($width, $height); $white = imagecolorallocate($output, 255, 255, 255); imagefilledrectangle($output, 0, 0, $width, $height, $white); imagecopy($output, $input, 0, 0, 0, 0, $width, $height); imagejpeg($output, $output_file); unlink($images_path . $_ext); } $tmpZero = 0; $tmpNull = null; if ($generate_thumbnails) { PShow_Log::addImportLog("generate thumbnails for image: " . $url); $images_types = ImageType::getImagesTypes('products'); $quality = ($quality < 3 ? 3 : ($quality > 10 ? 10 : $quality)); foreach ($images_types as $image_type) { $result = ImageManager::resize( $images_path . $ext, $images_path . '-' . $image_type['name'] . $ext, (int) $image_type['width'], (int) $image_type['height'], false, $tmpZero, $tmpNull, $tmpNull, $quality ); if (!$result) { PShow_Log::addImportLog("unable to create thumbnail: " . $image_type['name']); } else { $expl = explode('/img/', $images_path . '-' . $image_type['name'] . $ext); PShow_Log::addImportLog("created thumbnail " . $image_type['name'] . " in " . __PS_BASE_URI__ . 'img/' . $expl[1]); } } } } }