PHP 里 curl POST 提交文件到底应该怎么写呀

2019-11-14 13:51:23 +08:00
 mashirozx

想用 PHP 上传文件到图床(只接受 form data ),普通的 curl 是这样的,正常:

curl \
  -F "smfile=@favicon-original.png" \
  -H "Content-Type: multipart/form-data" \
  https://sm.ms/api/v2/upload

但是用 PHP 一写,返回的都是 bool(false)string(0) ""

<?php

$url = "https://sm.ms/api/v2/upload";
$headers = array();
array_push($headers, "Content-Type: multipart/form-data");
array_push($headers, "User-Agent: ".$_SERVER['HTTP_USER_AGENT']);

// $fields = array('smfile' => curl_file_create('test.png', 'image/png', 'test.png'));
$fields = array('smfile' => new CURLFile('test.png', 'image/png', 'tset.png'));

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);

var_dump(curl_exec($ch));
var_dump(curl_error($ch));

求助ヽ(*。>Д<)o゜

5313 次点击
所在节点    PHP
15 条回复
pota
2019-11-14 14:04:39 +08:00
$fields = array('smfile' => "@favicon-original.png");
mashirozx
2019-11-14 14:54:04 +08:00
@pota #1 试了这样的写法,但是接口返回的是资源无效。检查了 curl 的 request header,发现 ["content_type"]=> string(24) "text/html; charset=UTF-8",header 里面的 size_upload 大小好像也太小了,不像是图片,所以看起来好像图片并没有被上传,只是上传了 @favicon-original.png 几个字?萌新我不是太懂,请耐心~
young
2019-11-14 15:05:08 +08:00
mashirozx
2019-11-14 15:13:05 +08:00
@young 我要是在 Google 查到解决方法就不会在这里问了
pota
2019-11-14 15:20:41 +08:00
royantar
2019-11-14 15:28:00 +08:00
User-Agent 随便填一些字符试试,别用$_SERVER['HTTP_USER_AGENT']。
justfindu
2019-11-14 15:28:02 +08:00
试试文件使用绝对地址
pota
2019-11-14 15:29:56 +08:00
```
<?php

$url = "https://sm.ms/api/v2/upload";
$headers = array();
array_push($headers, "Content-Type: multipart/form-data");
//agent 我复制的我浏览器的 你换乘你对应的就行了
array_push($headers, "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36");
$file_path = 'your file path';
if (function_exists('curl_file_create')) {
$cFile = curl_file_create($file_path);
} else { //
$cFile = '@' . realpath($file_path);
}
$fields = array('smfile' => $cFile);

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_POST,1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);

$result=curl_exec ($ch);
curl_close($ch);

var_dump(curl_exec($ch));
```
liuxu
2019-11-14 16:04:37 +08:00
google: sm.ms 403

https://www.v2ex.com/t/369007

```bash
liuxu:/tmp$ cat post.php
<?php

$ch = curl_init();
$fd = curl_file_create('/home/liuxu/Downloads/1.png', 'image/png', '1.png');
$file = array('smfile' => $fd);

curl_setopt($ch, CURLOPT_URL, "https://sm.ms/api/v2/upload");
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: multipart/form-data', 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36'));
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $file);
$rs = curl_exec($ch);
curl_close($ch);
var_dump($rs);
?>
liuxu:/tmp$ php post.php
* Trying 47.88.229.110...
* TCP_NODELAY set
* Connected to sm.ms (47.88.229.110) port 443 (#0)
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
CApath: /etc/ssl/certs
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use http/1.1
* Server certificate:
* subject: OU=Domain Control Validated; OU=ShinoSaki MDV; CN=sm.ms
* start date: Jan 2 00:00:00 2017 GMT
* expire date: Jan 2 23:59:59 2020 GMT
* subjectAltName: host "sm.ms" matched cert's "sm.ms"
* issuer: C=GB; ST=Greater Manchester; L=Salford; O=COMODO CA Limited; CN=COMODO RSA Domain Validation Secure Server CA
* SSL certificate verify ok.
> POST /api/v2/upload HTTP/1.1
Host: sm.ms
Accept: */*
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36
Content-Length: 59028
Content-Type: multipart/form-data; boundary=------------------------0dc5337c392dd914
Expect: 100-continue

< HTTP/1.1 100 Continue
< HTTP/1.1 200 OK
< Server: nginx
< Date: Thu, 14 Nov 2019 08:02:36 GMT
< Content-Type: text/html; charset=UTF-8
< Transfer-Encoding: chunked
< Connection: keep-alive
< Vary: Accept-Encoding
< Set-Cookie: PHPSESSID=1qsrkiqn676norodn0qnl3peln; path=/
< Expires: Thu, 19 Nov 1981 08:52:00 GMT
< Cache-Control: no-store, no-cache, must-revalidate
< Pragma: no-cache
< Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
< X-Frame-Options: SAMEORIGIN
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< X-Custom-Job: If you see this, please contact hello@cat.net for a job
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Methods: OPTIONS, HEAD, GET, POST
< Allow: GET, POST, HEAD
< Set-Cookie: cid=rBWawl3NChysdVkoQsGLAg==; expires=Thu, 31-Dec-37 23:55:55 GMT; domain=sm.ms; path=/
<
* Connection #0 to host sm.ms left intact
string(481) "{"success":true,"code":"success","message":"Upload success.","data":{"file_id":0,"width":715,"height":645,"filename":"1.png","storename":"rng9GNzEhBCMUQA.png","size":58844,"path":"\/2019\/11\/14\/rng9GNzEhBCMUQA.png","hash":"QChs79nUXbdZW6ygYDVOBvjGNe","url":"https:\/\/i.loli.net\/2019\/11\/14\/rng9GNzEhBCMUQA.png","delete":"https:\/\/sm.ms\/delete\/QChs79nUXbdZW6ygYDVOBvjGNe","page":"https:\/\/sm.ms\/image\/rng9GNzEhBCMUQA"},"RequestId":"3985A52B-A6C8-4F22-A96A-749E3C77D35E"}"

```
liuxu
2019-11-14 16:08:47 +08:00
实际上 CURLOPT_POSTFIELDS 不需要设置 content-type 为 multipart-data

https://www.php.net/manual/zh/function.curl-setopt.php

CURLOPT_POSTFIELDS 全部数据使用 HTTP 协议中的 "POST" 操作来发送。 要发送文件,在文件名前面加上 @前缀并使用完整路径。 文件类型可在文件名后以 ';type=mimetype' 的格式指定。 这个参数可以是 urlencoded 后的字符串,类似'para1=val1&para2=val2&...',也可以使用一个以字段名为键值,字段数据为值的数组。 如果 value 是一个数组,Content-Type 头将会被设置成 multipart/form-data。 从 PHP 5.2.0 开始,使用 @ 前缀传递文件时,value 必须是个数组。 从 PHP 5.5.0 开始, @ 前缀已被废弃,文件可通过 CURLFile 发送。 设置 CURLOPT_SAFE_UPLOAD 为 TRUE 可禁用 @ 前缀发送文件,以增加安全性。
Rekkles
2019-11-14 16:52:24 +08:00
如果你用了 composer 那么请 google guzzle 的 document,
如果没有,请使用 postman 模拟请求,成功之后 postman 可以导出代码
完。
mashirozx
2019-11-14 17:19:47 +08:00
@liuxu #10 中午折腾了半天 @ 前缀,原来是和 PHP 版本有关!按您说的换了一个 UA 就成功了😂👍
mashirozx
2019-11-14 17:23:10 +08:00
@pota #5 中午我也看到这个帖子了,我这边是 PHP 7.2,按照 @liuxu #10 说的,不能直接那样写~ 不过还是很感谢你啦 o(* ̄▽ ̄*)o
mashirozx
2019-11-14 17:25:19 +08:00
@Rekkles #11 没用 composer~ 以后用到会注意的~
micookie
2019-11-20 18:14:21 +08:00
file_get_contens 也可以实现 post 请求,比起来变态的 curl 好多了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/619504

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX