【问题标题】:Uploaded file opened using fopen error in guzzle json_encode error: Type is not supported上传的文件在 guzzle json_encode 错误中使用 fopen 错误打开:不支持类型
【发布时间】:2021-03-07 23:21:48
【问题描述】:

我无法附加上传的文件。我看到 fopen($image->getPathname(),'r') 返回不可转换的 json 数据类型,使 guzzle 返回错误 json_encode 错误:不支持类型。我在这里做错了什么?谢谢。

stream resource @586 ▼
    timed_out: false
    blocked: true
    eof: false
    wrapper_type: "plainfile"
    stream_type: "STDIO"
    mode: "r"
    unread_bytes: 0
    seekable: true
    uri: "\Temp\php2D41.tmp"
    options: []


//use Illuminate\Support\Facades\Http;
//use Illuminate\Support\Facades\File;

if($request->hasFile('imgInp1'))
   {
    foreach(request('imgInp1') as $image)
    {
      $message = Http::post('https://graph.facebook.com/v9.0/me/message_attachments?access_token='.$access_token, 
                                [
                                    'headers' => [
                                        'Content-Type' => 'multipart/form-data',
                                    ],
                                    'multipart' => [
                                        'name'         => 'image',
                                        'image_path'   => $image->getPathname(),
                                        'image_mime'   => $image->getmimeType(),
                                        'image_org'    => $image->getClientOriginalName(),
                                        'contents'     => fopen($image->getPathname(), 'r'),
                                    ],
                                    'message'=>[
                                        'attachment' => [
                                            'type' => 'image',
                                            'payload' => [
                                                "is_reusable"=> true,
                                            ],
                                        ],
                                    ],
                                ]);
    }
  }

【问题讨论】:

  • 您确定在多部分帖子中需要attachment 数组吗?
  • multipart中使用的key也只有4个,name,contents,header,filename
  • 我猜你正在使用本网站developers.facebook.com/docs/messenger-platform/reference/… 上列出的 api,你正在使用 multipart 它会将数据作为 multipart/form-data 发送,** 错误** 你正在将包装器 httpclient 的语法与直接使用 guzzle,** 错误** 如果您使用的是 multipart,则应用程序数据进入 multipart 您使用消息键将其分隔
  • 是的,我正在尝试翻译从文件上传的 curl -F 'message={"attachment":{"type":"image", "payload":{"is_reusable":true}}}' -F 'filedata=@/tmp/shirt.png;type=image/png' 到 http 客户端/guzzle。我的错误是上传的文件数量不正确。我想我没有正确附加图像文件...我似乎无法让 fopen 为 json 编码工作...我已经将 content-type 更改为 'application/json'
  • 是什么让您认为通过 guzzle 上传文件可以通过传递文件 pointer 作为参数来工作?我猜这应该是此时传递的实际文件 content,因此此时读取该文件的快速方法是file_get_contents

标签: php laravel facebook-graph-api guzzle


【解决方案1】:

从您使用的网址来看,这是 facebook api_guide 中提供的 curl 请求

curl  \
  -F 'message={"attachment":{"type":"image", "payload":{"is_reusable":true}}}' \
  -F 'filedata=@/tmp/shirt.png;type=image/png' \
  "https://graph.facebook.com/v9.0/me/message_attachments?access_token=<PAGE_ACCESS_TOKEN>"

这就是 curl 中 -F 的意思

-F, --form

(HTTP SMTP IMAP) 对于 HTTP 协议族,这让 curl emu‐ 迟到用户按下提交的填写表格 按钮。这会导致 curl 使用 Content-Type POST 数据 多部分/表单数据,符合 RFC 2388。

(来源:man curl

通过解释 curl 的第二行,

你也可以通过使用来告诉 curl 使用什么 Content-Type 'type=',方式类似于:
curl -F "web=@index.html;type=text/html" example.com

curl -F "name=daniel;type=text/foo" example.com

所以它告诉你需要 multipart/form-data。

我直接使用 guzzle 代替使用 HttpClient(在 laravel 中默认提供,来自 composer.json 的确认)。另外我建议使用 try catch 块,因为它不一定总是 200 响应。

$message["attachment"] = [
        "type" => "image",
        "payload"=> ["is_reusable"=>true]
    ];

try{
    $client = new \GuzzleHttp\Client();
    if(file_exists($image)){ // or can use \Illuminate\Support\Facades\File::exists($image)
        $request = $client->post( 'https://graph.facebook.com/v9.0/me/message_attachments?access_token='.$access_token, [
            // 'headers' => [],  //if you want to add some
            'multipart' => [
                [
                    'name' => 'message',
                    'contents' => json_encode($message),
                ],
                [
                    'Content-type' => $image->getmimeType(),
                    'name'     => 'filedata',
                    'contents' => fopen($image->getPathname(), 'r'),
                ]
            ]
        ]);
        if ($request->getStatusCode() == 200) {
             $response = json_decode($request->getBody(),true);
             //perform your action with $response 
        } 
    }else{
        throw new \Illuminate\Contracts\Filesystem\FileNotFoundException();
    }
}catch(\GuzzleHttp\Exception\RequestException $e){
    // see this answer for https://stackoverflow.com/questions/17658283/catching-exceptions-from-guzzle/64603614#64603614 
    // you can catch here 400 response errors and 500 response errors
    // see this https://stackoverflow.com/questions/25040436/guzzle-handle-400-bad-request/25040600
}catch(Exception $e){
    //catch other errors
}

【讨论】:

  • 你也可以用 HTTP 类来做到这一点(它基本上是 guzzlehttp 的包装类),但我更习惯使用 guzzle,我也可以发布 HTTP 类答案,但如果你愿意,我会更喜欢先用它
  • 在理解代码数小时后设法使其工作。我对 http 客户端和 guzzle 感到很困惑。将首先使用 guzzle 并学习如何更多地使用它。感谢您的帮助!
  • 我真的同意 guzzle 只有一个简短的文档,并且对于使用它的新人来说看起来很难,所以它是否有效,我认为上述解决方案应该有效,它类似于他们的 curl 请求文档
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-19
  • 2012-05-23
  • 2015-12-18
  • 2019-04-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多