当前位置: 首页 > 知识库问答 >
问题:

对PayPal的订阅 API 进行 HTTPS 调用时出现“无法读取 x509 证书”

笪欣嘉
2023-03-14

我正在将PayPal的订阅API实现到我的项目中,但是,我收到以下curl错误:

array:2 [▼
  "error" => "error_in_reading_cert"
  "error_description" => "Unable to read x509 certificate"
]

注意我用的是Laravel。这是我的卷曲类:

<?php

namespace App\Logic\Curl;

class Curl {

    /**
     * Perform new POST request and return decoded JSON response
     *
     * @param $url
     * @param $data
     * @return array
     */
    public function newRequest($url, $data)
    {
        $connection = curl_init($url);

        $clientId = env('services.paypal.client-id');
        $secret = env('services.paypal.secret');

        curl_setopt($connection, CURLOPT_HTTPHEADER, [
                "Content-Type: application/json",
                "Authorization: Basic $clientId:$secret",
            ]
        );

        $options = array(
            CURLOPT_RETURNTRANSFER => true,   // return web page
            CURLOPT_HEADER         => false,  // don't return headers
            CURLOPT_FOLLOWLOCATION => true,   // follow redirects
            CURLOPT_MAXREDIRS      => 10,     // stop after 10 redirects
            CURLOPT_ENCODING       => "",     // handle compressed
            CURLOPT_USERAGENT      => "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36", // name of client
            CURLOPT_AUTOREFERER    => true,   // set referrer on redirect
            CURLOPT_CONNECTTIMEOUT => 120,    // time-out on connect
            CURLOPT_TIMEOUT        => 120,    // time-out on response
        );

        curl_setopt_array($connection, $options);

        curl_setopt($connection, CURLOPT_POSTFIELDS, $data);

        $response = curl_exec($connection);

        if(curl_error($connection)) {
            return curl_error($connection);
        }

        curl_close($connection);

        return $this->decodeResponse($response);
    }

    /**
     * JSON decode the response
     *
     * @param $response
     * @return mixed
     */
    public function decodeResponse($response)
    {
        return json_decode($response, true);
    }

}

这是我的PayPal课程:

<?php

namespace App\Logic\Paypal;

use App\Logic\Curl\Curl;
use Exception;

class Paypal {

    public function createProduct()
    {
        $productDetails = [
            "name" => "Feedback Form",
            "description" => "Feedback form as a service.",
            "type" => "SERVICE",
            "category" => "SOFTWARE",
            "home_url" => "https://www.feedback.com/"
        ];

        $url = $this->getApiUrl('createProduct');

        $curl = new Curl();

        return $curl->newRequest($url, $productDetails);
    }

    public function getApiUrl($endpointName) {
        $mode = config('services.paypal.mode');

        $urls = [
            'createProduct' => [
                'live' => 'https://api.paypal.com/v1/catalogs/products',
                'sandbox' => 'https://api.sandbox.paypal.com/v1/catalogs/products'
            ]
        ];

        return $urls[$endpointName][$mode];
    }
}

这是我的PayPal控制器,它接收请求:

<?php

namespace App\Http\Controllers;

use App\Logic\Paypal\Paypal;
use App\Setting;

class PaypalController extends Controller
{
    public function bootstrap()
    {
        $setting = Setting::where('name', '=', 'active_plan_id')->first();

        if ($setting) {
            return 'plan already activated';
        }

        $paypal = new Paypal();
        $product = $paypal->createProduct();

        dd($product);
    }
}

上面的代码只是尝试根据PayPal的订阅文档创建产品。

在网上搜索解决方案时,我在StackOverflow上遇到了各种问题——其中最有希望的是这个问题。首先,我尝试了投票最多的解决方案,但它对我不起作用,尽管这有点奇怪。我跟随它,进入我的/etc/php/7.2/apache2/php.ini,取消注释< code>curl.cainfo并用下载的证书的绝对路径填充它,并重新启动apache,这没有帮助。然后,我创建了一个php info文件并查看了选项,在那里我找不到< code>curl.cainfo,尽管加载的配置文件正是我编辑的文件——根据这个curl.cainfo从PHP7.2开始就不会在phpinfo中显示,这就解决了这个问题。

根据同一个StackOverflow问题,我还尝试了:

sudo apt-get install ca-certificates

和:

sudo update-ca-certificates

但这无济于事。

非常感谢任何帮助。

编辑1:刚刚注意到在PayPal的文档中,curl是用选项< code>-k调用的,它甚至允许不安全的连接,我想知道这是为什么,PayPal在其沙箱API中使用自签名证书吗?

编辑2:我尝试从这里下载证书并将curl.cainfo指向它,但它不起作用。

编辑3:我尝试通过添加以下行$options[CURLOPT_SSL_VERIFYPEER]=false来禁用对等证书验证但我仍然得到相同的错误

编辑4:我还尝试添加curl_setopt($connection,CURLOPT_CAINFO,'/path/to/cacert.pem')但没有帮助

编辑5:我也尝试从命令行运行相同的请求,但是我得到了相同的错误,下面是输出:

Note: Unnecessary use of -X or --request, POST is already inferred.
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:01 --:--:--     0*   Trying 173.0.82.78...
* TCP_NODELAY set

  0     0    0     0    0     0      0      0 --:--:--  0:00:02 --:--:--     0* Connected to api.sandbox.paypal.com (173.0.82.78) port 443 (#0)

  0     0    0     0    0     0      0      0 --:--:--  0:00:03 --:--:--     0* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: /etc/ca-certificates
} [5 bytes data]
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
} [512 bytes data]
* TLSv1.3 (IN), TLS handshake, Server hello (2):
{ [85 bytes data]

  0     0    0     0    0     0      0      0 --:--:--  0:00:04 --:--:--     0* TLSv1.2 (IN), TLS handshake, Certificate (11):
{ [4162 bytes data]
* TLSv1.2 (IN), TLS handshake, Request CERT (13):
{ [944 bytes data]
* TLSv1.2 (IN), TLS handshake, Server finished (14):
{ [4 bytes data]
* TLSv1.2 (OUT), TLS handshake, Certificate (11):
} [7 bytes data]
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
} [262 bytes data]
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
} [1 bytes data]
* TLSv1.2 (OUT), TLS handshake, Finished (20):
} [16 bytes data]
* TLSv1.2 (IN), TLS handshake, Finished (20):
{ [16 bytes data]
* SSL connection using TLSv1.2 / AES256-SHA256
* ALPN, server did not agree to a protocol
* Server certificate:
*  subject: C=US; ST=California; L=San Jose; O=PayPal, Inc.; OU=PayPal Production; CN=api.sandbox.paypal.com
*  start date: Aug 21 00:00:00 2018 GMT
*  expire date: Aug 20 12:00:00 2020 GMT
*  subjectAltName: host "api.sandbox.paypal.com" matched cert's "api.sandbox.paypal.com"
*  issuer: C=US; O=DigiCert Inc; CN=DigiCert Global CA G2
*  SSL certificate verify ok.

  0     0    0     0    0     0      0      0 --:--:--  0:00:05 --:--:--     0} [5 bytes data]
> POST /v1/catalogs/products HTTP/1.1
> Host: api.sandbox.paypal.com
> User-Agent: curl/7.58.0
> Accept: */*
> Content-Type: application/json
> Authorization: Basic client-id:secret
> Content-Length: 205
> 
} [205 bytes data]
* upload completely sent off: 205 out of 205 bytes
{ [5 bytes data]
< HTTP/1.1 401 Unauthorized
< Cache-Control: max-age=0, no-cache, no-store, must-revalidate
< Content-Length: 87
< Content-Type: application/json
< Date: Wed, 25 Mar 2020 09:45:30 GMT
< Paypal-Debug-Id: f3411e0e1c2ab
< 
{ [87 bytes data]

100   292  100    87  100   205     12     30  0:00:07  0:00:06  0:00:01    55
100   292  100    87  100   205     12     30  0:00:07  0:00:06  0:00:01    68
* Connection #0 to host api.sandbox.paypal.com left intact
{"error":"error_in_reading_cert","error_description":"Unable to read x509 certificate"}

编辑6:这是我尝试的全卷曲命令和输出:

curl -v -k POST https://api.sandbox.paypal.com/v1/catalogs/products -H "Content-Type: application/json" -H "Authorization: Basic AW09uZVO_1NUVZXEzlYp1xgiVjweOwnIBl0rMltEK7X1zMhe9fxcPPr_IgwGplL0xSPHQo4lO3cdP27p:EB351ARk-HkEd5OmkV7NGXrUT5V2AU_zN8ZRJ55cWowGUKr845Do0MM5zrqfpCxJECqL59rwcXueQUW2" -d '{"name": "Video Streaming Service","description": "Video streaming service","type": "SERVICE","category": "SOFTWARE","image_url": "https://example.com/streaming.jpg","home_url": "https://example.com/home"}' --cacert /opt/ssl/curl.pem 2>&1 | tee curl.txt

输出:

* Rebuilt URL to: POST/
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:01 --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:02 --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:03 --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:04 --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:05 --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:06 --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:07 --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:08 --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:09 --:--:--     0* Could not resolve host: POST
* Closing connection 0
curl: (6) Could not resolve host: POST

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:01 --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:02 --:--:--     0*   Trying 173.0.82.78...
* TCP_NODELAY set

  0     0    0     0    0     0      0      0 --:--:--  0:00:03 --:--:--     0* Connected to api.sandbox.paypal.com (173.0.82.78) port 443 (#1)

  0     0    0     0    0     0      0      0 --:--:--  0:00:03 --:--:--     0* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /opt/ssl/curl.pem
  CApath: /etc/ssl/certs
} [5 bytes data]
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
} [512 bytes data]
* TLSv1.3 (IN), TLS handshake, Server hello (2):
{ [85 bytes data]
* TLSv1.2 (IN), TLS handshake, Certificate (11):
{ [4162 bytes data]
* TLSv1.2 (IN), TLS handshake, Request CERT (13):
{ [944 bytes data]
* TLSv1.2 (IN), TLS handshake, Server finished (14):
{ [4 bytes data]
* TLSv1.2 (OUT), TLS handshake, Certificate (11):
} [7 bytes data]
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
} [262 bytes data]
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
} [1 bytes data]
* TLSv1.2 (OUT), TLS handshake, Finished (20):
} [16 bytes data]
* TLSv1.2 (IN), TLS handshake, Finished (20):
{ [16 bytes data]
* SSL connection using TLSv1.2 / AES256-SHA256
* ALPN, server did not agree to a protocol
* Server certificate:
*  subject: C=US; ST=California; L=San Jose; O=PayPal, Inc.; OU=PayPal Production; CN=api.sandbox.paypal.com
*  start date: Aug 21 00:00:00 2018 GMT
*  expire date: Aug 20 12:00:00 2020 GMT
*  issuer: C=US; O=DigiCert Inc; CN=DigiCert Global CA G2
*  SSL certificate verify ok.

  0     0    0     0    0     0      0      0 --:--:--  0:00:04 --:--:--     0} [5 bytes data]
> POST /v1/catalogs/products HTTP/1.1
> Host: api.sandbox.paypal.com
> User-Agent: curl/7.58.0
> Accept: */*
> Content-Type: application/json
> Authorization: Basic AW09uZVO_1NUVZXEzlYp1xgiVjweOwnIBl0rMltEK7X1zMhe9fxcPPr_IgwGplL0xSPHQo4lO3cdP27p:EB351ARk-HkEd5OmkV7NGXrUT5V2AU_zN8ZRJ55cWowGUKr845Do0MM5zrqfpCxJECqL59rwcXueQUW2
> Content-Length: 205
> 
} [205 bytes data]
* upload completely sent off: 205 out of 205 bytes
{ [5 bytes data]
< HTTP/1.1 401 Unauthorized
< Cache-Control: max-age=0, no-cache, no-store, must-revalidate
< Content-Length: 87
< Content-Type: application/json
< Date: Wed, 25 Mar 2020 15:54:35 GMT
< Paypal-Debug-Id: ae0a3de96fdf5
< 
{ [87 bytes data]

100   292  100    87  100   205     16     39  0:00:05  0:00:05 --:--:--    79
* Connection #1 to host api.sandbox.paypal.com left intact
{"error":"error_in_reading_cert","error_description":"Unable to read x509 certificate"}

编辑7:我运行相同的curl命令,但是使用不同的商业帐户的不同凭证,下面是命令和输出:

curl -v -k POST https://api.sandbox.paypal.com/v1/catalogs/products -H "Content-Type: application/json" -H "Authorization: Basic AVx9AFnHHdAvjsRA_t5AXJEdu_XIqC4RgxOvJ_a49r3QZj9eNlSy1gRGRmLIBS52wh1LWi27adQgvwSc:EPCcwShbEMG4O9uoPvoMtbwFc02RT2vo8FayHqU3StskKR3bxx7sxXACEG7Sf-Mwx_taRFhRfp0s79Ox" -d '{"name": "Video Streaming Service","description": "Video streaming service","type": "SERVICE","category": "SOFTWARE","image_url": "https://example.com/streaming.jpg","home_url": "https://example.com/home"}' --cacert /opt/ssl/curl.pem 2>&1 | tee curl.txt

输出:

* Rebuilt URL to: POST/
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:01 --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:02 --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:03 --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:04 --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:05 --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:06 --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:07 --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:08 --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:09 --:--:--     0* Could not resolve host: POST
* Closing connection 0
curl: (6) Could not resolve host: POST

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:01 --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:02 --:--:--     0*   Trying 173.0.82.78...
* TCP_NODELAY set

  0     0    0     0    0     0      0      0 --:--:--  0:00:03 --:--:--     0* Connected to api.sandbox.paypal.com (173.0.82.78) port 443 (#1)

  0     0    0     0    0     0      0      0 --:--:--  0:00:03 --:--:--     0* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /opt/ssl/curl.pem
  CApath: /etc/ssl/certs
} [5 bytes data]
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
} [512 bytes data]
* TLSv1.3 (IN), TLS handshake, Server hello (2):
{ [85 bytes data]
* TLSv1.2 (IN), TLS handshake, Certificate (11):
{ [4162 bytes data]
* TLSv1.2 (IN), TLS handshake, Request CERT (13):
{ [944 bytes data]
* TLSv1.2 (IN), TLS handshake, Server finished (14):
{ [4 bytes data]
* TLSv1.2 (OUT), TLS handshake, Certificate (11):
} [7 bytes data]
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
} [262 bytes data]
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
} [1 bytes data]
* TLSv1.2 (OUT), TLS handshake, Finished (20):
} [16 bytes data]
* TLSv1.2 (IN), TLS handshake, Finished (20):
{ [16 bytes data]
* SSL connection using TLSv1.2 / AES256-SHA256
* ALPN, server did not agree to a protocol
* Server certificate:
*  subject: C=US; ST=California; L=San Jose; O=PayPal, Inc.; OU=PayPal Production; CN=api.sandbox.paypal.com
*  start date: Aug 21 00:00:00 2018 GMT
*  expire date: Aug 20 12:00:00 2020 GMT
*  issuer: C=US; O=DigiCert Inc; CN=DigiCert Global CA G2
*  SSL certificate verify ok.

  0     0    0     0    0     0      0      0 --:--:--  0:00:04 --:--:--     0} [5 bytes data]
> POST /v1/catalogs/products HTTP/1.1
> Host: api.sandbox.paypal.com
> User-Agent: curl/7.58.0
> Accept: */*
> Content-Type: application/json
> Authorization: Basic AW09uZVO_1NUVZXEzlYp1xgiVjweOwnIBl0rMltEK7X1zMhe9fxcPPr_IgwGplL0xSPHQo4lO3cdP27p:EB351ARk-HkEd5OmkV7NGXrUT5V2AU_zN8ZRJ55cWowGUKr845Do0MM5zrqfpCxJECqL59rwcXueQUW2
> Content-Length: 205
> 
} [205 bytes data]
* upload completely sent off: 205 out of 205 bytes
{ [5 bytes data]
< HTTP/1.1 401 Unauthorized
< Cache-Control: max-age=0, no-cache, no-store, must-revalidate
< Content-Length: 87
< Content-Type: application/json
< Date: Wed, 25 Mar 2020 15:54:35 GMT
< Paypal-Debug-Id: ae0a3de96fdf5
< 
{ [87 bytes data]

100   292  100    87  100   205     16     39  0:00:05  0:00:05 --:--:--    79
* Connection #1 to host api.sandbox.paypal.com left intact
{"error":"error_in_reading_cert","error_description":"Unable to read x509 certificate"}

共有3个答案

顾昌翰
2023-03-14

您可以从 https://curl.haxx.se/docs/caextract.html 下载更新的证书颁发机构捆绑包

在其他可能的配置位置中。pem文件可以通过将此添加到您的curl选项中来传递:

curl_setopt($connection, CURLOPT_CAINFO, '/path/to/cacert.pem');

或者因为你有一系列的选择:

CURLOPT_CAINFO => '/path/to/cacert.pem',

PayPal在沙箱中不使用自签名证书,但由于某些环境没有配置适当的证书颁发机构,因此在命令行示例中使用curl-k(不安全/无验证对等),因为在开发过程中无需验证对等证书。

狄誉
2023-03-14

问题在于使用了错误的授权头,如下所示:

Authorization: Basic <client-id>:<secret>

尽管出于某种原因这在文档中出现了,但它不起作用,请使用以下代码:

Authorization: Bearer <access-token>

感谢普雷斯顿PHX帮助我解决这个问题。

胡霖
2023-03-14

在客户端使用base64:secret。

如果您有:

clientId: "clientId"
secret: "mySecret"

Than do base64(“clientId:mySecret”)

所以正确的标题是

Authorization: Basic Y2xpZW50SWQ6bXlTZWNyZXQ=
 类似资料:
  • 我正在尝试升级贝宝订阅使用Rest API的计划。 https://developer.paypal.com/docs/api/subscriptions/v1/#subscriptions_remission

  • 我一直在与一个团队合作,为我们的应用程序提供PayPal集成,我们使用REST API设置订阅的实现进展顺利。然而,我遇到了一些问题,试图测试一些负面的场景,如用户有一张过期的卡。我注意到在沙箱环境中可以启用负面测试,但我相信这只适用于经典API(我们使用的是REST API)。 是否有任何方法我可以建立一个测试用户与过期的卡,或测试用户没有钱在他们的银行(不是贝宝)帐户等。我想了解的行为,批准和

  • 我读到过,通常您不必明确地取消对或的订阅,因为: ActivatedRoute及其可观察到的内容与路由器本身绝缘。当不再需要路由组件时,路由器会销毁该组件,并且注入的ActivatedRoute也会随之死亡。 每当有人导航到另一个组件/页面时,就会被再次订阅。只有当事件是的实例时,我才必须在路由器订阅中执行此操作,因为在此之前,url参数还不可用。 我的问题是,那些订阅会发生什么?他们是自动退订还

  • 我已经为spring boot应用程序和spring security设置了CRO,如下所示。带有Spring security和jwt令牌的Spring Boot应用程序。 我与其他域一起使用api,所以我在所有控制器上使用交叉源。 所有不需要auth-token(JWT)的api调用在以下配置中都可以正常工作。但是使用所需jwt令牌的api调用失败,错误如下。 我正在尝试添加过滤器,但它没有按

  • 例: 注意:是非Android 运行环境, 使用的是RxJava2.x

  • 在ngOnDestory中,我取消了两个订阅,但仍然得到前面的错误。 现在我几乎可以肯定问题出在这行:即使我在注销之前取消了proposalSubscription和chatSubscription的订阅,但仍然会出现错误。有没有解决这个问题的方法?而且,我对RXJ和操作符没有太多的经验。有没有操作符可以用来避免这种嵌套订阅? 提前道谢。