Stripe支付报错Invalid source object,请求排查代码问题
嘿,我来帮你拆解这个错误并修复代码里的问题。首先看你遇到的错误:
错误信息: [16-May-2018 22:16:06 UTC] PHP致命错误:未捕获异常 'Stripe\Error\InvalidRequest',消息为 'Invalid source object: must be a dictionary or a non-empty string. 请查看API文档',位于/home/autravelservice/public_html/wp-content/plugins/ats/libraries/stripe-php-6.0.0/lib/ApiRequestor.php:120,来自API请求 'req_6uGybuHR3adjqW'
这个错误的核心是你传递给Stripe的支付凭证(token)格式不对,或者代码用了过时的API参数。结合你的代码,主要有这几个问题:
1. 过时的API参数:card 已被废弃,改用 source
你用的是Stripe PHP库v6.0.0,这个版本里创建Customer的card参数已经被淘汰了,官方要求用source来传递支付token。继续用card会导致Stripe无法正确解析你传入的凭证,直接触发InvalidRequest错误。
2. 没做$token的有效性校验
你直接拿$payment_details['token']来用,但没检查这个值是不是存在、是不是非空字符串。如果前端没传对token,或者token是空的,Stripe肯定会报错。
3. 冗余的foreach循环逻辑
你在foreach里只处理第一个申请人($i++ == 0),完全没必要写循环,直接取第一个申请人的数据就行,避免代码啰嗦。
4. shuffle的使用错误
你写了$counter= shuffle($counter);,但shuffle是直接修改原数组的,不需要赋值;而且直接把数组拼到orderid里会输出Array字样,得把数组转成字符串。
修复后的完整代码
// Set your secret key: remember to change this to your live secret key in production \Stripe\Stripe::setApiKey($sk); // 先校验支付token是否有效 $token = isset($payment_details['token']) ? trim($payment_details['token']) : ''; if (empty($token)) { die('Invalid payment token received. Please try again.'); } // 获取第一个申请人的信息(去掉冗余的foreach) $applicants = get_field('applicant', $post_id); if (empty($applicants)) { die('No applicant information found.'); } $applicant = $applicants[0]; $applicant_details = $applicant['applicant_details']; $contact_details = $applicant['contact_details']; $name_first = $applicant_details['first_name']; $name_last = $applicant_details['last_name']; $email = $contact_details['email']; $user_info = [ "First Name" => $name_first, "Last Name" => $name_last ]; try { // 创建Customer:用source替代废弃的card参数 $customer = \Stripe\Customer::create([ "email" => $email, "source" => $token, "metadata" => $user_info ]); // 发起支付请求 $charge = \Stripe\Charge::create([ "customer" => $customer->id, "amount" => $pay_amount, "currency" => "usd", "description" => "Australian Travel Service" ]); if ($charge->status === 'succeeded') { $counter = range(1, 5); shuffle($counter); // 直接修改原数组,不需要赋值 $orderid = 'AUS-CU-' . date('Ymd') . $post_id . implode('', $counter); // 把数组转成字符串 echo '<input type="hidden" name="orderid" id="app_order_id" value="'.$orderid.'">'; echo '<input type="hidden" id="applicant_count" value="'.$applicant_count.'">'; echo '<input type="hidden" id="processing_type" value="'.$processing_fee_type[0].'">'; echo '<input type="hidden" id="order_total" value="'.$pay_amount.'">'; appFormAdminMail($post_id, $orderid); acf_form([ 'id' => 'survey-form', 'post_id' => $post_id, 'field_groups' => [158], 'return' => './survey-thank-you/?record=%post_id%', 'submit_value' => 'SUBMIT SURVEY', 'html_submit_button' => '<button type="submit" class="acf-btn red-btn rounded-btn">%s</button>' ]); } else { echo 'Payment failed: Charge was not successful.'; } } catch (\Stripe\Error\InvalidRequest $e) { // 捕获Stripe的请求错误,给用户友好提示 echo 'Payment error: ' . $e->getMessage(); } catch (\Exception $e) { // 捕获其他所有异常 echo 'Unexpected error occurred: ' . $e->getMessage(); }
额外提醒
- 一定要确保前端通过Stripe Checkout/Elements生成的token是有效的(格式类似
tok_xxxxxx),如果前端没正确传递,后端肯定会报错。 - 把所有Stripe API调用放到
try-catch块里,这样可以优雅处理错误,而不是直接抛出致命错误让用户看到一堆代码路径。
内容的提问来源于stack exchange,提问作者Dean Junior

