我使用这个cmd成功下载了Result.csv

curl.exe https://example.com/rest -u "xx:yy" -F xmlRequest=@file.xml > result.csv

我想使用PHP来完成这项工作.但无济于事. 请帮帮忙.

这是我的PHP:

$url = 'https://example.com/rest';
$xml = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<request xmlns="http://example.com"><search path="report_date" value="2023-07-01T00:00:00+0000"/>'; //and so on..
$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);

$data = curl_exec($ch);
var_dump($data); //just to check if it has requested data (will save to file later)
if(curl_errno($ch))
    print curl_error($ch);
else
    curl_close($ch);

它没有请求的数据.但它给了我们这个

字符串(346)" 500人 出现错误. 请重试,如果问题仍然存在,请与我们联系. "

推荐答案

根据经验,您可以说,您可以查找每个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
  1. https://example.com/rest(URL)

    URL语法依赖于协议.您可以在RFC 3986中找到详细说明.(ref)

  2. -u "xx:yy"(<user:password>)

    指定用于服务器身份验证的用户名和密码.(ref)

  3. -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);
  1. curl_setopt($ch, CURLOPT_USERPWD, 'xx:yy');-OK,匹配2.)上图.
  2. curl_setopt($ch, CURLOPT_URL,$url);-OK,匹配1.)上图.
  3. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);-好的,您的配置.(正如您所写的,您希望在以后执行此操作.)
  4. curl_setopt($ch, CURLOPT_TIMEOUT, 10);-好的,您的配置.(这也有利于更快的测试.)
  5. curl_setopt($ch, CURLOPT_POST, true);-OK,与上面匹配3的POST方法相同.)
  6. 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.xmlcurl(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 phpcurl_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  
]);

参见CURLFileCURLFile从PHP5.5开始可用.

让我们继续下面的几行:

  1. curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: text/xml'));-不太好,原来的cURL命令行not有这个功能.把它拿掉.

  2. curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);-不太好,原来的cURL命令行not有这个功能.把它拿掉.

  3. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);-不太好,原来的cURL命令行not有这个功能.把它拿掉.

  4. 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
...

一百零二

Php相关问答推荐

用户信息更新期间Laravel邮箱验证问题

如何使用PHP停止foreach循环中的重复项?

在保留唯一键值对的情况下高效合并嵌套数组

msgraph-sdk-php v2如何传递skiptoken到request?

将变体设置字段添加到WooCommerce中的特定变量产品

模式 bootstrap 未显示

Laravel Http::get not working on controller

从WooCommerce订单项目获取Dokan卖家详细信息

将可编辑的计费自定义字段添加到 WooCommerce 管理单个订单

如何用十进制和字母数字减go 和添加 id

对产品/库存结果集进行分组和计数,形成多维分层数组

为什么从一个页面到另一个页面都找不到 JQuery,因为它们使用相同的 twig 模板?

无法读取某些 WordPress 主机上的 cookie

根据WooCommerce中的产品重量更改简单产品的输入数量步值

在这个 Laravel 应用中,如何仅显示已批准的 comments 回复?

Laravel使用另一张表进行关联查询

Xdebug 不会在断点处停止

yii2 sql迁移覆盖新更改的记录

为什么非贪婪匹配会消耗整个模式,即使后面跟着另一个非贪婪匹配

在管理表单字段中