使用Try/Catch PHP方法捕获Stripe错误

50

在我对网站中的Stripe进行测试时,我编写了如下代码:

   try {
        $charge = Stripe_Charge::create(array(
          "amount" => $clientPriceStripe, // amount in cents
          "currency" => "usd",
          "customer" => $customer->id,
          "description" => $description));
          $success = 1;
          $paymentProcessor="Credit card (www.stripe.com)";
    } 
    catch (Stripe_InvalidRequestError $a) {
        // Since it's a decline, Stripe_CardError will be caught
        $error3 = $a->getMessage();
    }

    catch (Stripe_Error $e) {
        // Since it's a decline, Stripe_CardError will be caught
        $error2 = $e->getMessage();
        $error = 1;
    }
if ($success!=1)
{
    $_SESSION['error3'] = $error3;
    $_SESSION['error2'] = $error2;
    header('Location: checkout.php');
    exit();
}

问题在于有时候卡片存在错误(未被"catch"参数捕获),"try"失败并且页面立即在屏幕上显示错误信息,而不是进入"if"语句并重定向回checkout.php。

我应该如何构建错误处理结构以便获取错误并立即重定向回checkout.php并在那里显示错误?

谢谢!


抛出的错误:

Fatal error: Uncaught exception 'Stripe_CardError' with message 'Your card was declined.' in ............
/lib/Stripe/ApiRequestor.php on line 92

只有这个解决方案对我有帮助。 - PokatilovArt
8个回答

104

如果您正在使用命名空间的Stripe PHP库(例如通过Composer安装),则可以使用以下代码捕获所有Stripe异常:

<?php 
try {
  // Use a Stripe PHP library method that may throw an exception....
  \Stripe\Customer::create($args);
} catch (\Stripe\Error\Base $e) {
  // Code to do something with the $e exception object when an error occurs
  echo($e->getMessage());
} catch (Exception $e) {
  // Catch any other non-Stripe exceptions
}

2
请参考另一个答案(https://dev59.com/7mMm5IYBdhLWcg3wRdMz#17750537),该答案引用了Stripe文档(https://stripe.com/docs/api?lang=php#errors),其中显示了不同的错误对象可供捕获。`Stripe\Error\Base`是不够的。 - Ryan
4
所有的Stripe错误类都继承自Stripe\Error\Base,第一个catch块将匹配所有这些子类。我添加了第二个更健壮的catch块,处理Stripe API调用未返回Stripe异常的情况。 - leepowers
根据文档,我确实需要在第一个catch库调用之前加上\,所以它是这样的: } catch (\Stripe\Error\Base $e) { 如果其他人也会出现错误,您可能需要进行更改。 - Jeremy L.
这是正确的答案。Base 可以解决大多数错误,而 Stripe 的其余 Exception 类可以用于记录特定问题。 - Ali Gajani
尝试过这个,但无法捕获错误。请看这个链接:https://stackoverflow.com/questions/52695268/can-not-catch-errors-in-stripe-payment-gateway-in-codeigniter-3 - Rahat Islam Khan
经过尝试,我喜欢这个方法:} catch (\Stripe\Error\Base $e) { 这样可以捕获任何错误,然后将其重定向到一个失败的付款页面,在那里他们可以使用PayPal链接支付,或者联系我们以便我们调查并帮助他们。 - Joe's Ideas

69

我认为需要捕获的异常不止这些(Stripe_InvalidRequestErrorStripe_Error)。

下面的代码来自于Stripe的网站。可能会发生你没有考虑到的其他异常,导致你的代码有时候运行失败。

try {
  // Use Stripe's bindings...
} catch(Stripe_CardError $e) {
  // Since it's a decline, Stripe_CardError will be caught
  $body = $e->getJsonBody();
  $err  = $body['error'];

  print('Status is:' . $e->getHttpStatus() . "\n");
  print('Type is:' . $err['type'] . "\n");
  print('Code is:' . $err['code'] . "\n");
  // param is '' in this case
  print('Param is:' . $err['param'] . "\n");
  print('Message is:' . $err['message'] . "\n");
} catch (Stripe_InvalidRequestError $e) {
  // Invalid parameters were supplied to Stripe's API
} catch (Stripe_AuthenticationError $e) {
  // Authentication with Stripe's API failed
  // (maybe you changed API keys recently)
} catch (Stripe_ApiConnectionError $e) {
  // Network communication with Stripe failed
} catch (Stripe_Error $e) {
  // Display a very generic error to the user, and maybe send
  // yourself an email
} catch (Exception $e) {
  // Something else happened, completely unrelated to Stripe
}

编辑:

try {
    $charge = Stripe_Charge::create(array(
    "amount" => $clientPriceStripe, // amount in cents
    "currency" => "usd",
    "customer" => $customer->id,
    "description" => $description));
    $success = 1;
    $paymentProcessor="Credit card (www.stripe.com)";
} catch(Stripe_CardError $e) {
  $error1 = $e->getMessage();
} catch (Stripe_InvalidRequestError $e) {
  // Invalid parameters were supplied to Stripe's API
  $error2 = $e->getMessage();
} catch (Stripe_AuthenticationError $e) {
  // Authentication with Stripe's API failed
  $error3 = $e->getMessage();
} catch (Stripe_ApiConnectionError $e) {
  // Network communication with Stripe failed
  $error4 = $e->getMessage();
} catch (Stripe_Error $e) {
  // Display a very generic error to the user, and maybe send
  // yourself an email
  $error5 = $e->getMessage();
} catch (Exception $e) {
  // Something else happened, completely unrelated to Stripe
  $error6 = $e->getMessage();
}

if ($success!=1)
{
    $_SESSION['error1'] = $error1;
    $_SESSION['error2'] = $error2;
    $_SESSION['error3'] = $error3;
    $_SESSION['error4'] = $error4;
    $_SESSION['error5'] = $error5;
    $_SESSION['error6'] = $error6;
    header('Location: checkout.php');
    exit();
}

现在,您将捕获所有可能的异常,并且可以按照您的意愿显示错误消息。还有$error6用于不相关的异常。


1
我在屏幕上添加了错误提示。它来自处理错误的Stripe文件之一。问题是,我如何捕获错误并进行重定向,而不是抛出Stripe的消息... - samyb8
我已经编辑了代码。你没有考虑所有的异常(例如Stripe_CarError),因此你不能捕获它们并显示自己的错误信息。 - Oguzhan Ozel
2
问题在于代码经过ApiRequestor.php(Stripe的文件),它在那里出现了一些问题并且没有继续通过我的“catches”。 - samyb8
那么也许尝试在ApiRequestor.php中捕获异常会有帮助? - Oguzhan Ozel
2
你的技巧是先设置$success,然后根据结果进行重定向,这对我在另一种情况下非常有帮助。谢谢! - David Taiaroa
我喜欢它,但是$paymentProcessor="Credit card (www.stripe.com)";是什么意思? - Jonathon Philip Chambers

14

这是对另一个答案的更新,但文档略有更改,因此我成功地使用了以下方法:

try {
  // Use Stripe's library to make requests...
} catch(\Stripe\Exception\CardException $e) {
  // Since it's a decline, \Stripe\Exception\CardException will be caught
  echo 'Status is:' . $e->getHttpStatus() . '\n';
  echo 'Type is:' . $e->getError()->type . '\n';
  echo 'Code is:' . $e->getError()->code . '\n';
  // param is '' in this case
  echo 'Param is:' . $e->getError()->param . '\n';
  echo 'Message is:' . $e->getError()->message . '\n';
} catch (\Stripe\Exception\RateLimitException $e) {
  // Too many requests made to the API too quickly
} catch (\Stripe\Exception\InvalidRequestException $e) {
  // Invalid parameters were supplied to Stripe's API
} catch (\Stripe\Exception\AuthenticationException $e) {
  // Authentication with Stripe's API failed
  // (maybe you changed API keys recently)
} catch (\Stripe\Exception\ApiConnectionException $e) {
  // Network communication with Stripe failed
} catch (\Stripe\Exception\ApiErrorException $e) {
  // Display a very generic error to the user, and maybe send
  // yourself an email
} catch (Exception $e) {
  // Something else happened, completely unrelated to Stripe
}
你可以在这里找到这个的源代码Stripe文档:
https://stripe.com/docs/api/errors/handling?lang=php

我认为这应该是正确的答案(特别是因为我宁愿使用Stripe自己推荐的方法!)值得注意的是,如果您的API版本过时,文档页面顶部会有一个蓝色的条形提示。 - William Turrell
这在我的Laravel 8上运行正常。 - STA

12

我可能对这个问题有所耽搁,但我遇到了同样的问题并找到了解决方法。

你只需要使用 "Stripe_Error" 类即可。

use Stripe_Error;

声明之后,我成功地捕获了错误。


我不得不使用"use \Stripe_CardError和use \Stripe_Error"。 - Eric Cope

8
这是Stripe如何捕捉错误的方式:文档
try {
    // make Stripe API calls
} catch(\Stripe\Exception\ApiErrorException $e) {
    $return_array = [
        "status" => $e->getHttpStatus(),
        "type" => $e->getError()->type,
        "code" => $e->getError()->code,
        "param" => $e->getError()->param,
        "message" => $e->getError()->message,
    ];
    $return_str = json_encode($return_array);          
    http_response_code($e->getHttpStatus());
    echo $return_str;
}

您可以使用以下代码在 ajax 中捕获错误:
$(document).ajaxError(function ajaxError(event, jqXHR, ajaxSettings, thrownError) {
    try {
        var url = ajaxSettings.url;
        var http_status_code = jqXHR.status;
        var response = jqXHR.responseText;
        var message = "";
        if (isJson(response)) {     // see here for function: https://dev59.com/_nA65IYBdhLWcg3wogOe#32278428
            message = "  " + (JSON.parse(response)).message;
        }
        var error_str = "";

        // 1. handle HTTP status code
        switch (http_status_code) {
            case 0: {
                error_str = "No Connection.  Cannot connect to " + new URL(url).hostname + ".";
                break;
            }   // No Connection
            case 400: {
                error_str = "Bad Request." + message + "  Please see help.";
                break;
            }   // Bad Request
            case 401: {
                error_str = "Unauthorized." + message + "  Please see help.";
                break;
            }   // Unauthorized
            case 402: {
                error_str = "Request Failed." + message;
                break;
            }   // Request Failed
            case 404: {
                error_str = "Not Found." + message + "  Please see help.";
                break;
            }   // Not Found
            case 405: {
                error_str = "Method Not Allowed." + message + "  Please see help.";
                break;
            }   // Method Not Allowed
            case 409: {
                error_str = "Conflict." + message + "  Please see help.";
                break;
            }   // Conflict
            case 429: {
                error_str = "Too Many Requests." + message + "  Please try again later.";
                break;
            }   // Too Many Requests
            case 500: {
                error_str = "Internal Server Error." + message + "  Please see help.";
                break;
            }   // Internal Server Error
            case 502: {
                error_str = "Bad Gateway." + message + "  Please see help.";
                break;
            }   // Bad Gateway
            case 503: {
                error_str = "Service Unavailable." + message + "  Please see help.";
                break;
            }   // Service Unavailable
            case 504: {
                error_str = "Gateway Timeout." + message + "  Please see help.";
                break;
            }   // Gateway Timeout
            default: {
                console.error(loc + "http_status_code unhandled >> http_status_code = " + http_status_code);
                error_str = "Unknown Error." + message + "  Please see help.";
                break;
            }
        }

        // 2. show popup
        alert(error_str);
        console.error(arguments.callee.name + " >> http_status_code = " + http_status_code.toString() + "; thrownError = " + thrownError + "; URL = " + url + "; Response = " + response);

    }
    catch (e) {
        console.error(arguments.callee.name + " >> ERROR >> " + e.toString());
        alert("Internal Error.  Please see help.");
    }
});

1
你能否只捕获 \Stripe\Error\Base 而不是捕获每个 Stripe 异常类呢? - Jasir
@Jasir 我认为你可能是对的。谢谢。我会更新我的回答。 - xinthose

3

我认为你只需要检查Stripe的基础错误类和如果与Stripe无关的异常。以下是我的处理方式:

/**
 * Config.
 */
require_once( dirname( __FILE__ ) . '/config.php' );

// Hit Stripe API.
try {
  // Register a Customer.
  $customer = \Stripe\Customer::create(array(
    'email'    => 'AA@TESTING.com',
    'source'   => $token,
    'metadata' => array( // Note: You can specify up to 20 keys, with key names up to 40 characters long and values up to 500 characters long.
        'NAME'          => 'AA',
        'EMAIL'         => 'a@a.c.o',
        'ORDER DETAILS' => $order_details,
    )
  ));

  // Charge a customer.
  $charge = \Stripe\Charge::create(array(
    'customer' => $customer->id,
    'amount'   => 5000, // In cents.
    'currency' => 'usd'
  ));



  // If there is an error from Stripe.
} catch ( Stripe\Error\Base $e ) {
  // Code to do something with the $e exception object when an error occurs.
  echo $e->getMessage();

  // DEBUG.
  $body = $e->getJsonBody();
  $err  = $body['error'];
  echo '<br> ——— <br>';
  echo '<br>THE ERROR DEFINED — <br>';
  echo '— Status is: ' . $e->getHttpStatus() . '<br>';
  echo '— Message is: ' . $err['message'] . '<br>';
  echo '— Type is: ' . $err['type'] . '<br>';
  echo '— Param is: ' . $err['param'] . '<br>';
  echo '— Code is: ' . $err['code'] . '<br>';
  echo '<br> ——— <br>';

// Catch any other non-Stripe exceptions.
} catch ( Exception $e ) {
    $body = $e->getJsonBody();
    $err  = $body['error'];
    echo '<br> ——— <br>';
    echo '<br>THE ERROR DEFINED — <br>';
    echo '— Status is: ' . $e->getHttpStatus() . '<br>';
    echo '— Message is: ' . $err['message'] . '<br>';
    echo '— Type is: ' . $err['type'] . '<br>';
    echo '— Param is: ' . $err['param'] . '<br>';
    echo '— Code is: ' . $err['code'] . '<br>';
    echo '<br> ——— <br>';
}

getJsonBody()getHttpStatus()是 Stripe 函数,并且在捕获标准异常时不适用。 - xinthose

0

如何在提供的令牌无效时获取错误消息。在 Laravel 中,它会中断并显示一些异常。因此,我使用了 try 和 catch 来使用 Stripe 异常。这将正常工作。尝试使用此代码。您可以显示自己的自定义消息而不是 Stripe 消息。

try{
    \Stripe\Stripe::setApiKey ("your stripe secret key");
    $charge =   \Stripe\Charge::create ( array (
                "amount" => 100,
                "currency" => "USD",
                "source" => 'sdf', // obtained with Stripe.js
                "description" => "Test payment."
        ) );
      $order_information = array(
                            'paid'=>'true',
                            'transaction_id'=>$charge->id,
                            'type'=>$charge->outcome->type,
                            'balance_transaction'=>$charge->balance_transaction,
                            'status'=>$charge->status,
                            'currency'=>$charge->currency,
                            'amount'=>$charge->amount,
                            'created'=>date('d M,Y', $charge->created),
                            'dispute'=>$charge->dispute,
                            'customer'=>$charge->customer,
                            'address_zip'=>$charge->source->address_zip,
                            'seller_message'=>$charge->outcome->seller_message,
                            'network_status'=>$charge->outcome->network_status,
                            'expirationMonth'=>$charge->outcome->type
                        );

        $result['status'] = 1;
        $result['message'] = 'success';
        $result['transactions'] = $order_information;

      }
      catch(\Stripe\Exception\InvalidRequestException $e){
        $result['message'] = $e->getMessage();
        $result['status'] = 0;

      }

0

这里是一个功能演示,包含所有可能的错误的 try / catch,只需在每个 catch 中添加自己的功能即可

try {
  // Use Stripe's library to make requests...
  $charge = \Stripe\Charge::create([
    'amount' => $amount,
    'currency' => "usd",
    'description' => $description,
    "receipt_email" => $mail,
   ]);
} catch(\Stripe\Exception\CardException $e) {
  // Since it's a decline, \Stripe\Exception\CardException will be caught
  echo 'Status is:' . $e->getHttpStatus() . '\n';
  echo 'Type is:' . $e->getError()->type . '\n';
  echo 'Code is:' . $e->getError()->code . '\n';
  // param is '' in this case
  echo 'Param is:' . $e->getError()->param . '\n';
  echo 'Message is:' . $e->getError()->message . '\n';
} catch (\Stripe\Exception\RateLimitException $e) {
  // Too many requests made to the API too quickly
} catch (\Stripe\Exception\InvalidRequestException $e) {
  // Invalid parameters were supplied to Stripe's API
} catch (\Stripe\Exception\AuthenticationException $e) {
  // Authentication with Stripe's API failed
  // (maybe you changed API keys recently)
} catch (\Stripe\Exception\ApiConnectionException $e) {
  // Network communication with Stripe failed
} catch (\Stripe\Exception\ApiErrorException $e) {
  // Display a very generic error to the user, and maybe send
  // yourself an email
} catch (Exception $e) {
  // Something else happened, completely unrelated to Stripe
}

您可以从这里获取官方代码


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接