根据经验,您可以说,您可以查找每个cURL(1)命令行选项(+参数)和操作数,并找到适当的curl_setopt($OPTION,$VALUE).
因此,您可以将命令行与PHP代码进行比较,以定位可能导致500错误的潜在问题(100).否则,当命令行工作时,您无法发现PHP代码中的错误所在.
在下面的回答中,我将一步一步地说明这是如何完成的.它还提供了如何从文件系统和包含文件内容的字符串上传文件的PHP代码示例.
那么让我们来看看我们在该命令行中得到了什么:
curl.exe https://example.com/rest -u "xx:yy" -F xmlRequest=@file.xml > result.csv
https://example.com/rest
(URL
)
URL语法依赖于协议.您可以在RFC 3986中找到详细说明.(ref)
-u "xx:yy"
(<user:password>
)
指定用于服务器身份验证的用户名和密码.(ref)
-F xmlRequest=@file.xml
(<name=content>
)
对于HTTP协议族,这让cURL模拟用户按下提交按钮后填写的表单.这导致CURL使用根据RFC 2388的内容类型多部分/表单数据来发布数据.
这允许上传二进制文件等.要强制"内容"部分为文件,请在文件名前加上@符号.要仅从文件中获取内容部分,请在文件名前加上符号<;.@和<;之间的区别在于,@使文件作为文件上传附加到帖子中,而<;创建文本字段并从文件(ref)中仅获取该文本字段的内容
然后让我们看看PHP代码中有哪些curl_setopt()操作:
$ch = curl_init();
curl_setopt($ch, CURLOPT_USERPWD, 'xx:yy');
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, "xmlRequest=$xml");
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: text/xml'));
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_USERPWD, 'xx:yy');
-OK,匹配2.)上图.
curl_setopt($ch, CURLOPT_URL,$url);
-OK,匹配1.)上图.
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
-好的,您的配置.(正如您所写的,您希望在以后执行此操作.)
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
-好的,您的配置.(这也有利于更快的测试.)
curl_setopt($ch, CURLOPT_POST, true);
-OK,与上面匹配3的POST方法相同.)
curl_setopt($ch, CURLOPT_POSTFIELDS, "xmlRequest=$xml");
-不好,not与3匹配吗?)3.)上面上传了一个文件,这里您正在设置一个表单字符串值.这从来不是文件上传.有意思,让我们来看看这个.
我可以想象这可能会在遥远的一侧引发500级地震,
因为它们可能只有很少的错误处理,并且该过程只是崩溃,
因此,给出了500 Internal Server Error分,并且没有提供请求本身的详细错误信息
(400-499 HTTP状态代码范围).
让我们看看如何将其转换为文件上传.有两种变体:From字符串或From路径名.
PHP cURL文件从字符串上载
您可能希望从字符串创建一个文件上传,这样文件上传的数据就是字符串内容.
如果是这种情况,则它在PHP Curl中的工作方式是根据您的-F xmlRequest=@file.xml
curl(1)选项和参数示例定制的:
curl_setopt($ch, CURLOPT_POSTFIELDS, [
'xmlRequest' => new CURLStringFile($xml, 'file.xml'),
# ^ ^ ^
# | | `-- upload filename
# name of the form-field |
# |
# string contents of the file (plain binary data)
]);
参见CURLStringFile个;
answer to Send string as a file using curl and php和curl_setopt(CURLOPT_POSTFIELDS)(已经提到CURLStringFile);CURLStringFile从PHP8.1开始可用.
从路径名上传PHP cURL文件
如果不是这样的话,
并且您想要从文件系统(而不是字符串数据)上载文件,
这就是它在PHP Curl中的工作方式,根据您的-F xmlRequest=@file.xml
Curl量身定做(1)
选项和参数示例:
curl_setopt($ch, CURLOPT_POSTFIELDS, [
'xmlRequest' => new CURLFile('file.xml'),
# ^ ^
# | `-- upload filename
# name of the form-field
]);
参见CURLFile;CURLFile从PHP5.5开始可用.
让我们继续下面的几行:
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: text/xml'));
-不太好,原来的cURL命令行not有这个功能.把它拿掉.
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
-不太好,原来的cURL命令行not有这个功能.把它拿掉.
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
-不太好,原来的cURL命令行not有这个功能.把它拿掉.
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
-不太好,原来的cURL命令行not有这个功能.把它拿掉.
正如您已经写过的,您对将重定向转换为文件(命令行末尾的> result.csv
)不感兴趣,因此对于您面临的500错误,这should已经足够了.
讨论
比较Curl命令行和PHP Curl代码的技术是一个很好的过程
因为它允许一种直接的故障排除方法,并且总是可以完成的.
这并不意味着它能解决all个问题;
但是,如果完成后错误仍然存在,则可以更容易地将其本地化,并找出命令行上的cURL和PHP Curl扩展之间的配置差异.对于这类问题,通常需要判断所有的curl_setopt()调用(以及它们的顺序),这已经是过程的一部分,因此也使您能够处理更高级别的问题.
给出的答案还可能显示如何将Curl命令行移植(转换)为PHP Curl,但是,它没有详细说明如何找到正确的PHP Curl选项(curl_setopt()包含所有选项的列表)及其适当的顺序(设置some选项影响或重置其他选项).你还可以在网站上找到一些关于这个主题的问答,无论是在命令行上还是在PHP Curl中都是如此.
例如,PHP - Debugging Curl显示了如何获取PHP Curl的详细信息和连接信息.
此外,存在从cURL命令行(例如Curl-to-PHP)生成样板PHP代码的工具,但请注意,这样的工具可能是有限的(这个工具来自2017年,在PHP中,日期是11月30日PHP7.2发布的年份,并且PHP Curl扩展需要libcurl版本7.10.5,这是相当过时的).
Extra:如果您的工具带中有Composer,您可以运行composer diagnose
,它会在命令行上显示您手头的PHP版本以及PHP Curl扩展的Curl版本(ext-curl
是它的名称platform package in Composer):
> composer diagnose
...
PHP version: 8.2.8
...
cURL version: 7.81.0 libz 1.2.11 ssl OpenSSL/3.0.2
...
一百零二