我想使用 cURL 不仅可以在 HTTP POST 中发送数据参数,还可以上传具有特定表单名称的文件。我该怎么做?
HTTP Post 参数:
用户ID = 12345 filecomment = 这是一个图像文件
HTTP 文件上传: 文件位置 = /home/user1/Desktop/test.jpg file = image 的表单名称(对应 PHP 端的 $_FILES['image'])
我认为 cURL 命令的一部分如下:
curl -d "userid=1&filecomment=This is an image file" --data-binary @"/home/user1/Desktop/test.jpg" localhost/uploader.php
我遇到的问题如下:
Notice: Undefined index: image in /var/www/uploader.php
问题是我正在使用 $_FILES['image'] 来获取 PHP 脚本中的文件。
如何相应地调整我的 cURL 命令?
您需要使用
-F
选项:-F/--form <name=content> Specify HTTP multipart POST data (H)
试试这个:
curl \
-F "userid=1" \
-F "filecomment=This is an image file" \
-F "image=@/home/user1/Desktop/test.jpg" \
localhost/uploader.php
捕获用户 ID 作为路径变量(推荐):
curl -i -X POST -H "Content-Type: multipart/form-data"
-F "[email protected]" http://mysuperserver/media/1234/upload/
捕获用户 ID 作为表单的一部分:
curl -i -X POST -H "Content-Type: multipart/form-data"
-F "[email protected];userid=1234" http://mysuperserver/media/upload/
或:
curl -i -X POST -H "Content-Type: multipart/form-data"
-F "[email protected]" -F "userid=1234" http://mysuperserver/media/upload/
如果您要上传二进制文件,例如 csv,请使用以下格式上传文件
curl -X POST \
'http://localhost:8080/workers' \
-H 'authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6ImFjY2VzcyIsInR5cGUiOiJhY2Nlc3MifQ.eyJ1c2VySWQiOjEsImFjY291bnRJZCI6MSwiaWF0IjoxNTExMzMwMzg5LCJleHAiOjE1MTM5MjIzODksImF1ZCI6Imh0dHBzOi8veW91cmRvbWFpbi5jb20iLCJpc3MiOiJmZWF0aGVycyIsInN1YiI6ImFub255bW91cyJ9.HWk7qJ0uK6SEi8qSeeB6-TGslDlZOTpG51U6kVi8nYc' \
-H 'content-type: application/x-www-form-urlencoded' \
--data-binary '@/home/limitless/Downloads/iRoute Masters - Workers.csv'
这是我的解决方案,我读了很多帖子,它们真的很有帮助。最后我用 cURL 和 PHP 写了一些小文件的代码,我认为它真的很有用。
public function postFile()
{
$file_url = "test.txt"; //here is the file route, in this case is on same directory but you can set URL too like "http://examplewebsite.com/test.txt"
$eol = "\r\n"; //default line-break for mime type
$BOUNDARY = md5(time()); //random boundaryid, is a separator for each param on my post curl function
$BODY=""; //init my curl body
$BODY.= '--'.$BOUNDARY. $eol; //start param header
$BODY .= 'Content-Disposition: form-data; name="sometext"' . $eol . $eol; // last Content with 2 $eol, in this case is only 1 content.
$BODY .= "Some Data" . $eol;//param data in this case is a simple post data and 1 $eol for the end of the data
$BODY.= '--'.$BOUNDARY. $eol; // start 2nd param,
$BODY.= 'Content-Disposition: form-data; name="somefile"; filename="test.txt"'. $eol ; //first Content data for post file, remember you only put 1 when you are going to add more Contents, and 2 on the last, to close the Content Instance
$BODY.= 'Content-Type: application/octet-stream' . $eol; //Same before row
$BODY.= 'Content-Transfer-Encoding: base64' . $eol . $eol; // we put the last Content and 2 $eol,
$BODY.= chunk_split(base64_encode(file_get_contents($file_url))) . $eol; // we write the Base64 File Content and the $eol to finish the data,
$BODY.= '--'.$BOUNDARY .'--' . $eol. $eol; // we close the param and the post width "--" and 2 $eol at the end of our boundary header.
$ch = curl_init(); //init curl
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'X_PARAM_TOKEN : 71e2cb8b-42b7-4bf0-b2e8-53fbd2f578f9' //custom header for my api validation you can get it from $_SERVER["HTTP_X_PARAM_TOKEN"] variable
,"Content-Type: multipart/form-data; boundary=".$BOUNDARY) //setting our mime type for make it work on $_FILE variable
);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/1.0 (Windows NT 6.1; WOW64; rv:28.0) Gecko/20100101 Firefox/28.0'); //setting our user agent
curl_setopt($ch, CURLOPT_URL, "api.endpoint.post"); //setting our api post url
curl_setopt($ch, CURLOPT_COOKIEJAR, $BOUNDARY.'.txt'); //saving cookies just in case we want
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1); // call return content
curl_setopt ($ch, CURLOPT_FOLLOWLOCATION, 1); navigate the endpoint
curl_setopt($ch, CURLOPT_POST, true); //set as post
curl_setopt($ch, CURLOPT_POSTFIELDS, $BODY); // set our $BODY
$response = curl_exec($ch); // start curl navigation
print_r($response); //print response
}
有了这个,我们应该可以在“api.endpoint.post”上获取发布的以下变量。您可以轻松地使用此脚本进行测试,并且您应该会在最后一行的函数
postFile()
上收到此调试信息。
print_r($response); //print response
public function getPostFile()
{
echo "\n\n_SERVER\n";
echo "<pre>";
print_r($_SERVER['HTTP_X_PARAM_TOKEN']);
echo "/<pre>";
echo "_POST\n";
echo "<pre>";
print_r($_POST['sometext']);
echo "/<pre>";
echo "_FILES\n";
echo "<pre>";
print_r($_FILEST['somefile']);
echo "/<pre>";
}
它应该工作得很好,它们可能是更好的解决方案,但这确实有效,并且对于理解 Boundary 和 multipart/from-data mime 如何在 PHP 和 cURL 库上工作非常有帮助。
经过多次尝试,这个命令对我有用:
curl -v -F filename=image.jpg -F [email protected] http://localhost:8080/api/upload
导致我出现这里的问题原来是一个基本的用户错误 - 我没有在文件路径中包含
@
符号,因此curl 发布的是文件的路径/名称而不是内容。因此,考虑到测试文件的长度,Content-Length
值是 8,而不是我预期看到的 479。
curl 读取并发布文件时,会自动计算
Content-Length
标头。
curl -i -H "Content-Type: application/xml" --data "@test.xml" -v -X POST https://<url>/<uri/
... < Content-Length: 479 ...
在此发布此内容是为了将来帮助其他新手。
作为
curl
的替代方案,您可以使用 HTTPie,它是一个面向人类的 CLI、类似 cURL 的工具。
然后,运行:
http -f POST http://localhost:4040/api/users username=johnsnow photo@images/avatar.jpg
HTTP/1.1 200 OK
Access-Control-Expose-Headers: X-Frontend
Cache-control: no-store
Connection: keep-alive
Content-Encoding: gzip
Content-Length: 89
Content-Type: text/html; charset=windows-1251
Date: Tue, 26 Jun 2018 11:11:55 GMT
Pragma: no-cache
Server: Apache
Vary: Accept-Encoding
X-Frontend: front623311
...
cat test.txt
文件 test.txt 内容。
curl -v -F "hello=word" -F "[email protected]" https://httpbin.org/post
> POST /post HTTP/2
> Host: httpbin.org
> user-agent: curl/7.68.0
> accept: */*
> content-length: 307
> content-type: multipart/form-data; boundary=------------------------78a9f655d8c87a53
>
* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
* We are completely uploaded and fine
< HTTP/2 200
< date: Mon, 15 Nov 2021 06:18:47 GMT
< content-type: application/json
< content-length: 510
< server: gunicorn/19.9.0
< access-control-allow-origin: *
< access-control-allow-credentials: true
<
{
"args": {},
"data": "",
"files": {
"file": "file test.txt content.\n"
},
"form": {
"hello": "word"
},
"headers": {
"Accept": "*/*",
"Content-Length": "307",
"Content-Type": "multipart/form-data; boundary=------------------------78a9f655d8c87a53",
"Host": "httpbin.org",
"User-Agent": "curl/7.68.0",
"X-Amzn-Trace-Id": "Root=1-6191fbc7-6c68fead194d943d07148860"
},
"json": null,
"origin": "43.129.xx.xxx",
"url": "https://httpbin.org/post"
}
我用这个命令就可以工作了
curl -F 'filename=@/home/yourhomedirextory/file.txt' http://yourserver/upload
以下是如何使用
bash
正确转义上传文件的任意文件名:
#!/bin/bash
set -eu
f="$1"
f=${f//\\/\\\\}
f=${f//\"/\\\"}
f=${f//;/\\;}
curl --silent --form "uploaded=@\"$f\"" "$2"
将所有发送的文件保存到文件夹: 主机上的 php 文件。 u.php:
<?php
$uploaddir = 'C:/VALID_DIR/';
echo '<pre>';
foreach ($_FILES as $key => $file) {
if(!isset($file) || !isset($file['name'])) continue;
$uploadfile = $uploaddir . basename($file['name']);
if (move_uploaded_file($file['tmp_name'], $uploadfile)) {
echo "$key file > $uploadfile .\n";
} else {
echo " Error $key file.\n";
}
}
print_r($_FILES);
print "</pre>";?>
客户使用情况:
curl -v -F filename=ff.xml -F [email protected] https://myhost.com/u.php
这对我有用。
我的虚拟机崩溃了,它只有互联网连接。 我用这种方法恢复了一些文件。
curl -X POST -F 'key1=value1' -F 'key2=value2' -F 'file1=@/path/to/file1.txt' -F 'file2=@/path/to/file2.txt' http://example.com/upload 让我为您分解这个命令:
-X POST:指定HTTP请求方式为POST。 -F 'key1=value1' -F 'key2=value2': 添加表单字段 key1 和 key2 以及对应的值 value1 和 value2。 -F 'file1=@/path/to/file1.txt' -F 'file2=@/path/to/file2.txt': 上传位于 /path/to/ 目录的文件 file1.txt 和 file2.txt。 http://example.com/upload:指定将发布数据的 URL。 确保将 http://example.com/upload 替换为您要将数据上传到的实际端点,并替换 key1, value1, key2, value2, file1.txt, file2.txt, /path/to/分别使用适当的字段名称、值、文件名和路径。