Laravel:无法对​​有效负载进行 JSON 编码。错误代码:5

Per*_*ika 6 php csv mongodb-php laravel laravel-queue

我正在开发 Laravel (v5.7) 应用程序,该应用程序将上传的 CSV(带有联系人)转换为数组,然后在调度作业类时将其作为参数传递。

以下是 CSV 文件的示例(支持的格式):

123456,Richard,Smith
654321,John,Doe
Run Code Online (Sandbox Code Playgroud)

上传 (CSV) 文件的处理方式如下:

123456,Richard,Smith
654321,John,Doe
Run Code Online (Sandbox Code Playgroud)
$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
Run Code Online (Sandbox Code Playgroud)

最后,$contacts数组被传递给一个被分派的作业:

ImportContacts::dispatch($contacts);
Run Code Online (Sandbox Code Playgroud)

这个作业类看起来像这样:

    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]) : '',
            ];
        }
    }
Run Code Online (Sandbox Code Playgroud)

...在我尝试使用此 CSV 之前,一切正常(没有错误):

123456,Richardÿ,Smith
654321,John,Doe
Run Code Online (Sandbox Code Playgroud)

请注意ÿ。因此,当我尝试使用此 CSV 时 - 我收到此错误异常:

/code_smsto/vendor/laravel/framework/src/Illuminate/Queue/Queue.php | 91 | Unable to JSON encode payload. Error code: 5 
Run Code Online (Sandbox Code Playgroud)

...我的日志文件如下所示:

  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 
Run Code Online (Sandbox Code Playgroud)

如您所见 -handle方法从未执行过。如果我删除ÿ- 没有错误并被handle执行。

我试图解决这个问题,但没有成功:

  1. 申请utf8_encode
ImportContacts::dispatch($contacts);
Run Code Online (Sandbox Code Playgroud)

...它有效(没有错误,无论是否有错误ÿ),但是希腊和西里尔字母变成了问号。例如,这个:???????将变成???????.

我也试过mb_convert_encoding($row[1], 'utf-8')- 它不会把希腊或西里尔字母变成问号,但这个ÿ字符会变成?.

  1. 将上传的 CSV 文件的“处理”(转换为数组)移动到@handle工作类的方法中,但随后我无法将该数组中的数据存储到数据库(MongoDB)中。请参阅下面的更新。

调试:

这是我得到的dd($contacts);

在此处输入图片说明

所以,它有“b”在哪里ÿ。并且,经过一番“谷歌搜索”后,我发现这个“b”的意思是“二进制字符串”,即一个非 unicode 字符串,函数在字节级别上操作(字符串文字前面的 b 有什么作用?)。

我的理解是:在调度 Job 类时,Laravel 尝试对其进行“JSON 编码”(传递的参数/数据),但由于存在二进制数据(非 unicode 字符串)而失败。无论如何,我找不到解决方案(能够使用 处理此类 CSV 文件ÿ)。

我在用:

  • Laravel 5.7
  • PHP 7.1.31-1+ubuntu16.04.1+deb.sury.org+1 (cli) (build: Aug 7 2019 10:22:48) ( NTS )
  • Redis 驱动的队列

更新

当我将上传的 CSV 文件的“处理”(转换为数组)移动到@handleJob 类的方法中时 - 我没有收到此错误 ( Unable to JSON encode payload. Error code: 5),但是当我尝试使用ÿ( b"Richardÿ")将有问题的二进制数据存储到 MongoDB 中时 - 它失败了. 奇怪的是,我在日志文件中没有收到任何错误异常消息,所以我把所有内容都放在 try-catch 中,如下所示:

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

    public function handle()
    {
        Log::info('ImportContacts@handle');
    }
Run Code Online (Sandbox Code Playgroud)

......这是结果:

在此处输入图片说明

无论如何,我相信它失败的原因是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

Vla*_*dan 9

您有多种方法来处理它,但我建议您使用以下两种方法。在这两种情况下,想法都是存储一个 UTF-8 字符串。

一种更简单的方法,从(您的)预定义列表中找出它是什么编码并将其转换为 UTF8。

$encoding = mb_detect_encoding($content, 'UTF-8, ISO-8859-1, WINDOWS-1252, WINDOWS-1251', true);
if ($encoding != 'UTF-8') {
    $string = iconv($encoding, 'UTF-8//IGNORE', $row[1]);
}
Run Code Online (Sandbox Code Playgroud)

第二种方法是使用此答案中概述的第三方库