vikkyshostak
@vikkyshostak
< This head full of dreams.

Парсинг CSV файла в MySQL базу с помощью PHP (mysqli). Как задать кодировку и условие выборки элементов перед внесением в БД?

Доброго времени года!

Вводные данные. Итак, в определённую папку на хостинге (обычный shared, не VDS) каждый день из 1С: Альфа-Авто (спец. редакция 1С: Предприятие 8.3 для СТО и прочих авто-организаций) выгружается файл в формате CSV следующего содержания:

"Параметр 1","Параметр 2","Параметр 3","Параметр 4","Параметр 5"
"Параметр N","Параметр N","Параметр N","Параметр N","Параметр N"
...


Это база запчастей/деталей в наличии (кол-во > 0). Для парсинга файла и преобразования его значений в массив (для последующего использования), я использую вот такой код:

$file = file_get_contents('/home/user/site.ru/public_html/upload/catalog.csv');
$lines = explode(PHP_EOL, $file);
$array = array();
foreach ($lines as $line) {
  $array[] = str_getcsv($line);
}


Вот тут появляется первый затык. По старой доброй традиции, 1С всё фигачит в кодировке CP1251 (или KOI8-R), и, вместо кириллицы, одни крякозябры в массиве $array. Так же, при последующих попытках сделать INSERT этих значений в БД, их не понимает mysqli и выдаёт ошибки.

Можно ли как-то пересохранять этот CSV файл или преобразовывать его «на лету» в формат UTF-8 (без BOM, например) перед парсингом? Да, есть Notepad++, но делать это каждый день вручную — просто физически нет человекоресурсов, да и не по фей-шую это, всё же.

Хорошо. Двигаемся дальше!

Для внесения значений в БД, пишу вот так:

// Init MySQLi.
$mysqli = mysqli_init();
// Connect to DB.
if (!$mysqli->real_connect('localhost', $login, $password, $table)) die('Ошибка подключения (' . mysqli_connect_errno() . ') ' . mysqli_connect_error());
// Loop INSERT.
foreach ($array as $row) {
  if (!$mysqli->query("INSERT INTO catalog(id, name, brand, stock, price) VALUES ('$row[0]', '$row[1]', '$row[2]', '$row[3]', '$row[4]')")) echo "Ошибка (" . $mysqli->errno . ") " . $mysqli->error;
}    
// Close MySQLi connection.
$mysqli->close();


(Ячейка таблицы ID имеет значения UNIQUE и PRIMARY)

В удачные дни этот файл весит около 500 Кб (~4000 наименований номенклатуры). Это второй затык, ибо грузить каждый раз заново такое кол-во, пусть даже и глубокой ночью по Cron, в MySQL — не есть хорошо (ИМХО). Следовательно, вопрос: как лучше сравнивать каждую строчку (элемент массива) из CSV файла с существующими строками в БД и вносить только те значения, которые были изменены (главный, логично, файл CSV)?

При этом, нужно как-то указать опции:
1. Если такой ID есть в БД, но его нет в файле CSV, то делать DELETE элемента;
2. Если такого ID нет в БД, но есть в файле CSV, то делать INSERT, иначе — пропустить элемент;
3. Если такой ID есть и в БД и в файле CSV, то делать UPDATE, иначе — пропустить элемент.

Надеюсь на вашу помощь. Заранее, спасибо!
  • Вопрос задан
  • 1010 просмотров
Решения вопроса 1
@balamyt92
; select * from users; --
По кодировке php.net/manual/ru/function.iconv.php

500 Кб

грузить каждый раз заново такое кол-во, пусть даже и глубокой ночью по Cron, в MySQL — не есть хорошо


Это мизерное количество, почему не хорошо? Тем более если всего раз в день.

И да используй хотя бы PDO
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
sotland
@sotland
Ordinary man
>Можно ли как-то пересохранять этот CSV файл или преобразовывать его «на лету» в формат UTF-8
Про php ничего не скажу, его не знаю, но при желании распознавать кодировку 866 или 1251 легко, посмотрите сюда https://github.com/softlandia/change-code-page
Это код на go
Там есть определение и конвертация в кодировку. Если что пишите там, я допилю
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы