首页 > 解决方案 > 使用 CURL 上传给定的文件和 POST-Date

问题描述

也许有人可以帮助我?我没有解决这个问题

我有一个来自公式的 POST 数组和一个已经存在于服务器上的文件。任务是通过 CURL PUT 将 POST 数据和文件发送到 URL。

我已经尝试解决这个问题几个小时/几天了

我已经设置了标题Content-type: application/octet-stream和字段$ch->setOption(CURLOPT_POSTFIELDS, http_build_query($data)

POST 数据如下所示:

$data = array (
  'field1' => 'lorem',
  'field2' => 'ipsum',
  'field3' => 'dolor'
);

使用说明(php.net、stackoverflow 等)

https://kb.detlus.com/articles/php/upload-files-using-curl/

https://www.php.net/manual/de/curlfile.construct.php

是否可以使用 cURL 通过 POST 流式上传文件?

我尝试发送文件

不工作

$data = array (
  'field1' => 'lorem',
  'field2' => 'ipsum',
  'field3' => 'dolor'
  'file' => '@'.realpath('/abs/path/file.xlsx');
);

两者都不

$data = array (
  'field1' => 'lorem',
  'field2' => 'ipsum',
  'field3' => 'dolor'
);

$data['file'] = curl_file_create('/abs/path/file.xlsx'], mime_content_type('/abs/path/file.xlsx'), 'file.xlsx');

这导致以下数组

$data = array (
  'field1' => 'lorem',
  'field2' => 'ipsum',
  'field3' => 'dolor',
  'file' => 
  array (
    'file' => 
    CURLFile::__set_state(array(
       'name' => '/abs/path/file.xlsx',
       'mime' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
       'postname' => '/abs/path/file.xlsx',
    )),
  )
);

根据我尝试的版本,我会收到 400 或 500 错误。

有没有人有可以帮助我的提示?我究竟做错了什么?

标签: phpcurlpostupload

解决方案


I think the main problem here is that you're using the wrong content type.

For file uploads you should be using "Content-Type: multipart/form-data". Taken from Wikipedia (in the multipart subtypes) MIME

The MIME type multipart/form-data is used to express values submitted through a form. Originally defined as part of HTML 4.0, it is most commonly used for submitting files with HTTP. It is specified in RFC 7578, superseding RFC 2388.

I wrote this snippet, hope this can help you (sorry for the non-OOP version of the code, I don't have a PHP 8 install, I'm using PHP 7.4, but you can "translate" it easily :D):

<?php
//This is a dummy data array, will contain your form fields (Advice: never trust user input, always check the values given before submitting)
$data = [
    'field1' => 'value',
    'field2' => 'value2',
    'field3' => 123
];

//The path to the file you want to upload
$fileName = 'somefile.xlsx';
$filePath = './../files/'.$fileName;

//Security check
if (file_exists($filePath))
{
    //Adding the file to the $data array
    $data['file'] = curl_file_create($filePath, mime_content_type($filePath), $fileName);

    //Initialize the cURL handle
    $ch = curl_init('https://some-random-site.com/api/some/random/endpoint');

    //Set the request method (HTTP verb)
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');

    //This will make curl "return" the response as string when we call curl_exec()
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

    //This SHALL NOT be used in production, unless you know the implications!!! But, if you have an HTTPS endpoint with a self-signed certificate you can skip checks
    //curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    //curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    //======

    //We set the data we want to send (curl will "transform" this for us
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);

    //Here the important part, setting the right content-type
    curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: multipart/form-data']);

    //Execute the call and get the response as string
    $res = curl_exec($ch);
    if ($res === false)
    {
        //An error occurred, print out
        echo 'ERROR: '.curl_error($ch);
    }
    else
    {
        //Execution succeeded, do whatever with the response
        //Hint: this does not mean that the server answered with a success status but rather, it indicates that the curl execution has succeeded

        //If you want to check the HTTP status of the request you can get it like this:
        //$info = curl_getinfo($curl);
        //echo $info['http_code'];

        //Do whatever with the response (I'm just printing it).
        echo $res;
    }

    curl_close($ch);
}
else
{
    echo 'File not found.';
}

I really hope this can help, unfortunately I don't know the URL/API you're submitting the request to so I can't test it on your endpoint. I made an endpoint myself:

<?php
if ($_SERVER['REQUEST_METHOD'] === 'PUT')
{
    $c = file_get_contents('php://input');
    die(var_dump($c));
}

The output I got showed me all the fields and the file upload.

--------------------------05a7619c906d94df Content-Disposition: form-data; name="field1" value

 --------------------------05a7619c906d94df Content-Disposition: form-data; name="field2" value2

 --------------------------05a7619c906d94df Content-Disposition: form-data; name="field3" 123

 --------------------------05a7619c906d94df Content-Disposition: form-data; name="file"; filename="./../conf/test.xlsx" Content-Type:
 application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
 ........LOTS_OF_BYTES_OF_THE_XLSX_FILE_:P......
 --------------------------05a7619c906d94df--

推荐阅读