7fd3cde4f6
Один невалидный UTF-8-байт в выгрузке лидов crm.bp-gr.ru ронял весь импорт на INSERT (PG: invalid byte sequence for encoding UTF8, SQLSTATE 22021). str_getcsv пропускает любые байты, и невалидная последовательность доходила до БД. CsvLeadsParser::parse теперь чистит невалидный UTF-8 через mb_convert_encoding до парсинга — битый байт заменяется, строка импортируется, очередь не падает. TDD CsvLeadsParserUtf8Test, проверено руками на PG. Также зафиксирован вывод по FN-RLS-CTX: no-action — путь projects уже под tenant-middleware, старый no-auth endpoint заменён, не воспроизводится. Прод не трогался. Накат — позже вместе с остальным. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
28 lines
1.6 KiB
PHP
28 lines
1.6 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Services\Import\CsvLeadsParser;
|
|
|
|
// FN-ENC (приёмка 22.06.2026): один битый UTF-8-байт в CSV-выгрузке лидов ронял
|
|
// весь импорт на INSERT (PG: «invalid byte sequence for encoding UTF8»). str_getcsv
|
|
// пропускает любые байты, и невалидная последовательность доходила до БД. Контракт:
|
|
// парсер чистит невалидный UTF-8 — строка импортируется, очередь не падает.
|
|
test('parse чистит битый UTF-8 в текстовых полях — результат валидный UTF-8', function () {
|
|
// Имя содержит одиночный байт 0xFF (невалидный UTF-8).
|
|
$badName = "Имя\xFF";
|
|
$csv = "id,Проект,Тег,Телефон,Создано,Напоминание,Комментарий,Состояние,Имя\n"
|
|
."1,Проект A,t1,79991234567,2026/01/01 10:00:00,,ок,Новый,{$badName}\n";
|
|
|
|
$result = (new CsvLeadsParser)->parse($csv);
|
|
|
|
expect($result->rows)->toHaveCount(1);
|
|
$row = $result->rows[0];
|
|
|
|
// Главное: всё, что уйдёт в INSERT, — валидный UTF-8 (иначе PG роняет джобу).
|
|
expect(mb_check_encoding($row->contactName, 'UTF-8'))->toBeTrue();
|
|
expect(mb_check_encoding($row->projectName, 'UTF-8'))->toBeTrue();
|
|
// Кириллица-основа сохранена (битый байт убран, не вся строка).
|
|
expect($row->contactName)->toContain('Имя');
|
|
});
|