PHP парсер CSV

PHP парсер CSV. Импорт из CSV или экспорт в CSV

Разберём ещё несколько практических задач из области разработки PHP парсеров, связанных с импортом, сортировкой и экспортом CSV данных. Часто требуется представить результаты парсинга в виде CSV файла, далее такой файл можно импортировать в базу данных сайта. Средства импорта CSV данных часто поддерживаются стандартными средствами различных CMS.

CSV (Comma-Separated Values) — текстовый формат, предназначенный для представления табличных данных. Из названия следует, что данные разделены запятыми, но могут использоваться и другие разделители, например, точка с запятой (DSV формат).

CSV файлы можно открывать разными текстовыми редакторами, а также программой EXCEL. Но бывают проблемы с кодировкой. Например, EXCEL плохо переваривает UTF-8 без BOM. Под EXCEL нужно данные просто в UTF-8 сохранять.

В тестовой задаче нам нужно отсортировать ряд CSV файлов по столбцу email. Файлы содержат списки организаций с различными контактными данными, при этом не у всех фирм есть электронная почта. Так, чтобы облегчить работу со списками удобно скриптом отсортировать списки и наверх поставить компании с известными почтовыми ящиками.

Скрипт index.php и каталог с входными данными следует разместитьть в папке csv-sorter.

Экспорт, импорт, сортировка CSV файловОбработанные файлы будут записываться в директорию output.

Импорт и экспорт CSV данных на PHP

Листинг файла index.php

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Сортировка CSV файлов по заполненности полей</title>
</head>
<body>
<h1>Сортировка CSV файлов</h1>
<!--p>Файлы на выходе программы преобразуются в кодировку UTF-8.</p-->
<?php
/**
 * Функция преобразования строки в CSV формате в массив
 *
 * @param string $filename, int $file_size, string $delimiter
 *
 * @return string
*/
function csv2array($filename='', $file_size, $delimiter=';') {
	ini_set('auto_detect_line_endings', true);
	if(!file_exists($filename) || !is_readable($filename)) {
		return false;
	}
	$header = null;
	$data = array();
	if(($handle = fopen($filename, 'r')) !== false) {
		while(($row = fgetcsv($handle, $file_size, $delimiter)) !== false) {
			if(!$header) {
				if($row[0] != 'sep=') {
					$header = $row;
				}
			} else {
				if (count($header) > count($row)) {
					$difference = count($header) - count($row);
					for ($i = 1; $i <= $difference; $i++) {
						$row[count($row) + 1] = '';
					}
				}
			}
			if($row[0] != 'sep=') {
				$data[] = $row;
			}
		}
		fclose($handle);
	}
	return $data;
}

/**
 * Функция сортировки массива по 1-му полю или N полей
 *
 * @param string|array $keys, string $order [ASC|DESC]
 *
 * @return int
*/
function sort_arr_ncol($keys, $order = 'ASC') {
	$order = ($order == 'DESC') ? -1 : 1;
	if(is_array($keys)) { //если сортировка по нескольким полям
		return function($a, $b) use ($keys, $order) {
			foreach($keys as $k) {
				if($a[$k] != $b[$k]) {
					return $order * (($a[$k] < $b[$k]) ? 1 : -1);
				}
			}
			return 0;
		};
	} else { //если сортировка по одному полю
		return function($a, $b) use ($keys, $order) {
			if ($a[$keys] == $b[$keys]) {
				return 0;
			}
			return $order * (($a[$keys] < $b[$keys]) ? 1 : -1);
		};
	}
}
	
/**
 * Функция преобразования массива в строку в CSV формате
 *
 * @param @param string $input, int $file_size, string $delimiter, string $enclosure
 *
 * @return string
*/
function str_putcsv($input, $file_size, $delimiter = ';', $enclosure = '"') {
	// Open a memory "file" for read/write...
	$fp = fopen('php://temp', 'r+');
	// ... write the $input array to the "file" using fputcsv()...
	fputcsv($fp, $input, $delimiter, $enclosure);
	// ... rewind the "file" so we can read what we just wrote...
	rewind($fp);
	// ... read the entire line into a variable...
	$data = stream_get_contents($fp);
	// ... close the "file"...
	fclose($fp);
	// ... and return the $data to the caller, with the trailing newline from fgets() removed.
	return $data; //rtrim($data, "\r");
}
	
// Параметры сортировщика	
$data_dir_name = "input";	// Каталог с исходными файлами
$res_dir_name = "output";	// Каталог с отсортированными файлами
$key_list_str = 'email';		// Название столбца для сортировки (с нуля)
if(!empty($_REQUEST['action']) && $_REQUEST['action'] = 'run') {
	if(!isset($_REQUEST['charset'])) {
		$charset =  'no';
	} else {
		$charset =  $_REQUEST['charset'];
	}
	$k = 0;
	$er = 0;
	$error_file_names = array();
	$all_file_count = 0;
	$entries =  scandir($data_dir_name);
	foreach($entries as $entry) {
		if(mb_strpos($entry, '.csv') !== false) { // Обрабатываем только CSV файлы
			$filepath_in = $data_dir_name . "/" . $entry;
			$file_size = filesize($filepath_in);
			$csv_data_arr = csv2array($filepath_in, $file_size);
			$header_arr[0] = array_shift($csv_data_arr);
			$key_list = array_keys($header_arr[0], $key_list_str);
			usort($csv_data_arr, sort_arr_ncol($key_list, 'ASC'));
			$csv_data_arr = array_merge($header_arr, $csv_data_arr);
// Формируем строку для CSV файла
			$res_csv_file = '';
			foreach($csv_data_arr as $key_row => $csv_data_arr_row) {
				$res_csv_file .=  str_putcsv($csv_data_arr_row, $file_size);
			}
			if($charset == 'yes') {
				$res_csv_file = iconv("WINDOWS-1251", "UTF-8", $res_csv_file);
				if($res_csv_file == false) {
					$res_csv_file = iconv("WINDOWS-1251", "UTF-8//IGNORE", $res_csv_file);
					$error_file_names[] = $entry;
				}
			}
			$filepath_out = $res_dir_name . "/" . $entry;
			file_put_contents($filepath_out, $res_csv_file) ? $k++ : $er++;
			$all_file_count++;
		}
	}
	echo "<div id=\"stat_block\">Обработано файлов: <span>" . $k . "</span> из <span>" . $all_file_count . "</span>. Ошибок: <span>" . $er . "</span></div>";
	echo "<div id=\"error_files\"><p>" . implode("</p><p>", $error_file_names) . "</p></div>";
}
?>
<div><a href="/csv-sorter/">Перезагрузка</a> :: <a href="/csv-sorter/?action=run">Запуск</a>...</div>
</body>
</html>

Алгоритм работы следующий. Считываются файлы из заданного каталога. Далее данные преобразуются из CSV формата в PHP массив — это по сути импорт CSV.

Функция csv2array($filepath_in, $file_size) считывает CSV данные из файла и преобразует их в массив с помощью стандартной функции PHP fgetcsv().

Далее массив сортируется по заданному полю с помощью функции sort_arr_ncol(). Полезная штука в разных задачах для сортировки многомерных массивов по столбцам.

Далее обработанные данные экспортируются обратно в файл. Вначале преобразуем PHP массив в строку в формате CSV при помощи функции str_putcsv() и записываем результат в файл.

Список компаний до сортировки:

Пример файла в CSV формате

Пример файла после сортировки по столбцу email:

Сортировка по email списка компаний

Теперь мы с вами умеем сохранять результаты парсинга не только в JSON формате, но и в CSV. А уже с CSV могут работать много разных программ и движков сайтов. Например, часто с помощью CSV файлов экспортируются и импортируются товары в интернет-магазинах.

 

4 thoughts on “PHP парсер CSV. Импорт из CSV или экспорт в CSV”
  1. Это работает, отлично! Но, как это запустить из консоли?

    /usr/bin/php /home/public_html/csv-sorter/?action=run

    Не получается, с амерсандом вместо знака вопроса, тоже…

    1. Для запуска из консоли этот скрипт не приспособлен. Вам интерфейс получается совсем не нужен. Самый простой вариант дописать в начало скрипта .
      Либо разобраться с передачей переменных в консоли и сделать замену переменных в скрипте:
      /usr/bin/php/home/public_html/csv-sorter/ run no
      То в скрипте нужно определить переменные
      $params[‘action’] = $argv[1]; // =run
      $paras[‘charset’] = $argv[2]; // =no
      Массив $params[] будет вместо $_REQUEST[] в данном случае.

  2. Здравствуйте.

    А, возможно ли спарсить с удаленного сервера (по FTP) нужные для преобразования CSV/XML файлы, чтобы в итоге получить на выходе один CSV?

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *