Безопасный импорт данных

StalkerClasses

Новичок
Есть файл csv. В нем 1000 строк.
Как правильно реализовать безопасный импорт. Если скрипт прервется по каким-либо причином, то допустим будет импортировано только 325 строк.

Есть идея разбить например на шаги по 100 записей и в файле отмечать галочкой - строка импортирована.
Можно ли для импорта использовать транзакции? Если в строке есть связи - то при импорте может затрагиваться не 1 таблица.
 
Последнее редактирование:

jonjonson

Охренеть
Насколько уникальны строки в csv?
Есть ли в них идентификатор уникальный или несколько значений разных полей могут дать уникальный ключ?
Если строки уникальны, то для каждой можно посчитать хэш и сохранять его при импорте.
В случае сбоя или повторной загрузки можно получать и сверять хэш с хранимым.
 

StalkerClasses

Новичок
Это пример файла. Может быть 30 колонок. Но я импортирую например только 2 колонки. ID=0 - будет создана новая запись. ID=5 - обновится запись если такой ID существует, если нет проигнорируется.

Мне нужно понимать был ли успешен запрос на обновление 1 строки, и если нет вернуть все как было. В случае если есть колонка со связьями (many many) то трогается также еще 1 таблица. И ее тоже нужно откатить если строка не обработана.
 

ksnk

прохожий
К примеру - можно импортировать csv в базу данных в специальную временную таблицу. В ней должны присутствовать все поля исходного файла и пара полей - дата импорта и флаг "импортировано". При чтении csv файла всегда добавляется новое поле с датой и "не импортировано". Обычно - такая операция делается быстро и не тормозит, хотя зависит от размера файла....
Дальше - не торопясь, по одному товары переносить в базу куда надо. Уже импортированные и недоимпортированные старые строки импорта можно выкинуть сразу после чтения файла
 

AnrDaemon

Продвинутый новичок
Надо прочесть первые три байта и проверить, что это BOM.
Если BOM, то просто читать дальше, если нет, то $file->reset();
А импортировать, да, весь файл сразу во временную таблицу, и уже из неё раскидывать, а не морочить себе голову неизвестно чем.
 

StalkerClasses

Новичок
При экспорте в CSV-файл я добавляю в начало файла: "\xEF\xBB\xBF";
При импорте я вырезаю из первой строки где содержатся id,title "\xEF\xBB\xBF".

Что здесь не правильного?
 

ksnk

прохожий
Чтобы запутать еще больше - попробуй сохранить csv из Excel в формате "text Unicode". Получишь немного другой бом и несколько другой головняк при чтении файлов. Хотя, в общем смысле, это тоже csv...
 

AnrDaemon

Продвинутый новичок
Что здесь не правильного?
Что будет, если в строке окажется не только BOM, но и любой другой символ из блока https://www.fileformat.info/info/unicode/block/arabic_presentation_forms_b/utf8test.htm ?
Я тебе скажу, что - повреждение уникодной строки.
Иди читай, как именно работает trim() и сам объясни, почему ты написал глупость.
Дважды глупость, потому что добавляешь BOM к файлу, а удаляешь из строки.
 

StalkerClasses

Новичок
Понимаю что это бред.
Но как тогда быть?

PHP:
        if (($handle = @fopen("csv-import/".$fileName, "r")) !== FALSE) {
            while (($data = fgetcsv($handle, 1000, ';')) !== FALSE) {
                $num = count($data);
                // Первая строка с названием полей
                if($row == 1){
                    foreach($data as $kD => $vD){
                        $csv_rows_field[] = trim($vD, "\xEF\xBB\xBF"); // ставим без BOM trim($vD);
                    }
                // Содержимое импорта начиная со 2 строки файла
                } else {
                    $temp = [];
                    for($i = 0; $i<count($csv_rows_field);$i++){
                        $temp[$csv_rows_field[$i]] = $data[$i];
                    }
                    $csv_rows[] = $temp;
                }
                #echo "<p> $num полей в строке $row: <br /></p>\n";
                #$row++;
                #for ($c=0; $c < $num; $c++) {
                #    echo $data[$c] . "<br />\n";
                #}
                $row++;
            }
            fclose($handle);
        }
 

ksnk

прохожий
PHP:
if (($handle = @fopen("csv-import/".$fileName, "r")) !== FALSE) {
  # читаем первые 3 байта
  $bom = fread($handle, 3);
  $convert='cp1251';
  # если это не BOM
  if ("\xEF\xBB\xBF" !== $bom) {
    # то отматываем обратно
    fseek($handle, 0);
    $convert = false;
  }
  while (($data = fgetcsv($handle, 1000, ';')) !== FALSE) {
 ...
 

StalkerClasses

Новичок
PHP:
if (($handle = @fopen("csv-import/".$fileName, "r")) !== FALSE) {
  # читаем первые 3 байта
  $bom = fread($handle, 3);
  $convert='cp1251';
  # если это не BOM
  if ("\xEF\xBB\xBF" !== $bom) {
    # то отматываем обратно
    fseek($handle, 0);
    $convert = false;
  }
  while (($data = fgetcsv($handle, 1000, ';')) !== FALSE) {
...
Не совсем пойму а переменная $convert для чего нужна?
 

StalkerClasses

Новичок
Да это очень даже подходит.
и UTF-8 с BOM
и UTF-8 без BOM
загружается.
PHP:
        if (($handle = @fopen("fileadmin/csv-import/".$fileName, "r")) !== FALSE) {
            // "\xEF\xBB\xBF" смотрим BOM
            // читаем первые 3 байта, если это не BOM
            $bom = fread($handle, 3);
            if ("\xEF\xBB\xBF" !== $bom) {
                fseek($handle, 0);
            }
            while (($data = fgetcsv($handle, 1000, ';')) !== FALSE) {
                $num = count($data);
                if($row == 1){
                    foreach($data as $kD => $vD){
                        $csv_rows_field[] = trim($vD);
                    }
                } else {
                    $temp = [];
                    for($i = 0; $i<count($csv_rows_field);$i++){
                        $temp[$csv_rows_field[$i]] = $data[$i];
                    }
                    $csv_rows[] = $temp;
                }
                #echo "<p> $num полей в строке $row: <br /></p>\n";
                #$row++;
                #for ($c=0; $c < $num; $c++) {
                #    echo $data[$c] . "<br />\n";
                #}
                $row++;
            }
            fclose($handle);
        }
 
Сверху