如何用PHP Curl向CrossRef上传文件?遇405及401错误求助
CrossRef Deposit API 上传问题排查与解决
让我们一步步拆解你的问题,找到根本原因和对应的解决方案:
第一个错误:405 Method Not Allowed
你最初的代码犯了两个核心错误,导致服务器拒绝你的请求:
- 请求格式不符合要求:CrossRef的Deposit API只接受
multipart/form-data格式的表单提交,而你直接通过CURLOPT_INFILE上传XML内容,还手动设置了application/vnd.crossref.deposit+xml的Content-Type,这完全不符合API的预期。 - 登录方式错误:你用
CURLOPT_USERPWD做HTTP Basic认证,但CrossRef要求把登录信息作为表单字段(login_id和login_passwd)传递,而不是放在HTTP头里。
第二个错误:401 Unauthorized
修改后的表单上传代码依然没踩对API的要求:
- 没有添加必填的表单字段:官方curl示例里的
operation=doQueryUpload、login_id、login_passwd你都没放到POST参数里,服务器自然识别不到你的登录信息。 - 旧版文件上传语法问题:PHP 5.5+已经弃用了
@$filedata这种写法,应该用CURLFile类来处理文件上传,否则可能导致文件无法正确传递。 - 手动设置Content-Type画蛇添足:curl会自动生成带正确boundary的
multipart/form-data头,你手动设置反而会破坏这个格式,导致服务器解析表单失败。
正确的PHP CURL实现代码
下面是完全符合CrossRef官方要求的代码,包含所有必填项和正确的上传逻辑:
<?php ini_set('display_errors', E_ALL); define('CROSSREF_TEST_URL', 'https://test.crossref.org/servlet/deposit'); function depositToCrossRef($xmlFilePath) { // 先验证文件是否存在且可读 if (!is_readable($xmlFilePath)) { return "错误:文件不存在或无法读取,请检查路径"; } $curlCh = curl_init(); // 配置基础CURL选项 curl_setopt_array($curlCh, [ CURLOPT_URL => CROSSREF_TEST_URL, CURLOPT_RETURNTRANSFER => true, CURLOPT_HEADER => true, // 保留响应头方便调试 CURLOPT_POST => true, // 不要手动设置Content-Type!curl会自动生成正确的multipart/form-data头 ]); // 严格按照官方示例准备表单字段,字段名必须完全一致 $postFields = [ 'operation' => 'doQueryUpload', // 必填操作标识 'login_id' => '你的CrossRef用户名', 'login_passwd' => '你的CrossRef密码', 'fname' => new CURLFile( $xmlFilePath, 'application/xml', basename($xmlFilePath) ) // CURLFile自动处理文件类型和文件名,替代旧的@语法 ]; curl_setopt($curlCh, CURLOPT_POSTFIELDS, $postFields); // 执行请求并处理结果 $response = curl_exec($curlCh); if ($response === false) { $errorMsg = curl_error($curlCh); curl_close($curlCh); return "CURL请求失败:" . $errorMsg; } // 获取HTTP状态码,CrossRef成功接收的状态码是303 $httpCode = curl_getinfo($curlCh, CURLINFO_HTTP_CODE); curl_close($curlCh); if ($httpCode === 303) { return "Deposit提交成功!响应详情:\n" . $response; } else { return "提交失败,HTTP状态码:{$httpCode}\n响应详情:\n" . $response; } } // 调用函数,传入你的XML文件路径 echo depositToCrossRef(realpath('test.xml')); ?>
关键注意事项
- 字段名严格匹配:
operation、login_id、login_passwd、fname这四个字段是必填项,字段名必须和官方示例完全一致,大小写敏感。 - 环境切换:测试用
https://test.crossref.org/servlet/deposit,正式上线要换成https://doi.crossref.org/servlet/deposit。 - 调试技巧:开启
CURLOPT_HEADER => true可以查看完整的响应头和内容,方便你排查后续可能出现的问题。 - PHP版本兼容:确保你的PHP版本在5.5及以上,
CURLFile类才会生效。
内容的提问来源于stack exchange,提问作者Camargo
相关产品推荐
相关产品推荐

