Files
portal/app/tests/Unit/Import/CsvLeadsParserUtf8Test.php
T
Дмитрий 7fd3cde4f6
Accessibility (Pa11y live) / a11y (push) Has been cancelled
SAST — Semgrep / Semgrep SAST scan (push) Has been cancelled
fix(приёмка): FN-ENC — битый UTF-8 в CSV-импорте ронял очередь
Один невалидный 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>
2026-06-22 09:43:02 +03:00

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('Имя');
});