Laravel: Невозможно JSON кодировать полезную нагрузку. Код ошибки: 5 - PullRequest
0 голосов
/ 11 ноября 2019

Я работаю над приложением Laravel (v5.7), которое преобразует загруженный CSV (с контактами) в массив, который затем передается в качестве аргумента при отправке класса задания.

Вот пример файла CSV (поддерживаемый формат):

123456,Richard,Smith
654321,John,Doe

Загруженный (CSV) файл обрабатывается следующим образом:

$file_path = $request->file_name->store('contacts');
$file = storage_path('app/' . $file_path);

$contactsIterator = $this->getContacts($file);

$contacts = iterator_to_array($contactsIterator); // Array of contacts from uploaded CSV file
    protected function getContacts($file)
    {
        $f = fopen($file, 'r');

        while ($line = fgets($f))
        {
            $row = explode(",", $line);

            yield [
                'phone'     => !empty($row[0]) ? trim($row[0]) : '',
                'firstname' => !empty($row[1]) ? trim($row[1]) : '',
                'lastname'  => !empty($row[2]) ? trim($row[2]) : '',
            ];
        }
    }

Наконец, массив $contacts передается отправляемому заданию:

ImportContacts::dispatch($contacts);

Этот класс задания выглядит следующим образом:

    public function __construct($contacts)
    {
        Log::info('ImportContacts@__construct START');
        $this->contacts = $contacts;
        Log::info('ImportContacts@__construct END');
    }

    public function handle()
    {
        Log::info('ImportContacts@handle');
    }

... и все работает нормально (нетошибки), пока я не попробовал с этим CSV:

123456,Richardÿ,Smith
654321,John,Doe

Пожалуйста, обратите внимание ÿ. Итак, когда я пытаюсь с этим CSV - я получаю это исключение ошибки:

/code_smsto/vendor/laravel/framework/src/Illuminate/Queue/Queue.php | 91 | Unable to JSON encode payload. Error code: 5 

... и мой файл журнала выглядит так:

  error local   2019-11-11 17:17:18     /code_smsto/vendor/laravel/framework/src/Illuminate/Queue/Queue.php | 91 | Unable to JSON encode payload. Error code: 5
  info  local   2019-11-11 17:17:18     ImportContacts@__construct END
  info  local   2019-11-11 17:17:18     ImportContacts@__construct START 

Как вы можете видеть - *Метод 1027 * никогда не выполнялся. Если я удалю ÿ - без ошибок и handle выполняется.

Я пытался решить эту проблему, но безуспешно:

  1. Применить utf8_encode:
    protected function getContacts($file, $listId)
    {
        $f = fopen($file, 'r');

        while ($line = fgets($f))
        {
            $row = explode(",", $line);

            yield [
                'phone'     => !empty($row[0]) ? utf8_encode($row[0]) : '',
                'firstname' => !empty($row[1]) ? utf8_encode($row[1]) : '',
                'lastname'  => !empty($row[2]) ? utf8_encode($row[2]) : '',
            ];
        }
    }

... и это работает (без ошибок, независимо от того, есть ли ÿ), но тогда греческие и кириллические буквы превращаются в вопросительные знаки. Например, это: Εθνικής станет ???????.

Я также пытался с mb_convert_encoding($row[1], 'utf-8') - и это не превращает греческую или кириллическую букву в вопросительные знаки, но этот символ ÿ станет?.

Переместить «обработку» (преобразование в массив) загруженного файла CSV в @handle метод класса Job сработал, но тогда я не смог сохранить данные из этого массива в БД (MongoDB). Пожалуйста, смотрите обновление ниже.

ОТЛАДКА:

Вот что я получаю от dd($contacts);:

enter image description here

Итак, у него есть то "b", где ÿ. И после некоторого «прибегания к поиску» я обнаружил, что это «b» означает «двоичную строку», то есть строку, не являющуюся юникодом, в которой функции работают на уровне байтов ( Что делает b перед строковыми литералами? ).

Что я понимаю, так это то, что: при отправке класса Job, Laravel пытается "JSON-кодировать" его (передаваемые аргументы / данные), но он терпит неудачу из-за наличия двоичных данных (не-Unicode строк). Во всяком случае, я не смог найти решение (чтобы иметь возможность обрабатывать такой файл CSV с ÿ).

Я использую:

  • Laravel 5.7
  • PHP 7.1.31-1 + ubuntu16.04.1 + deb.sury.org + 1 (cli) (построено: 7 августа 2019 10:22:48) (NTS)
  • Очереди с поддержкой Redis

ОБНОВЛЕНИЕ

Когда я перемещаю "обработку" (преобразование в массив) загруженного файла CSV в @handle метод класса Job - я не получаю эту ошибку (Unable to JSON encode payload. Error code: 5), но когда я пытаюсь сохранить эти проблемные двоичные данные с ÿ (b"Richardÿ") в MongoDB - происходит сбой. Странно то, что я не получаю никаких исключений ошибок сообщение в файле журнала, поэтому я помещаю все в try-catch следующим образом:

        try {
            // Insert data into MongoDB
        } catch (Exception $e) {
            Log::info($e->getFile());
            Log::info($e->getLine());
            Log::info($e->getMessage());
        }

... и этоэто результат:

enter image description here

В любом случае, я считаю, что это не удалось из-за b"Richardÿ", и я предполагаю, что решение заключается в кодировании строки, нокак я уже упоминал - я не смог найти решение, которое работает:

  • utf8_encode работает (без ошибок, независимо от того, есть ли ÿ), но затем греческие и кириллические буквыпревращаются в вопросительные знаки. Например, это: Εθνικής станет ???????
  • mb_convert_encoding($row[1], 'utf-8') - это не превращает греческую или кириллическую букву в вопросительные знаки, но этот символ ÿ станет ?.
  • iconv('windows-1252', 'UTF-8', $row[1]) - работает (без ошибок, независимо от того, есть ли ÿ), но при наличии букв греческого или кириллического алфавита - происходит сбой (я получаю это исключение ошибки: iconv(): Detected an illegal character in input string)
...