Stripe支付成功后无法结合PHPMailer发送QR码求助
我使用Stripe、PHPMailer、phpqrcode和MySQL处理支付业务,目标是在支付成功时生成QR码并以邮件附件形式发送。目前单独生成QR码、发送邮件都能正常实现,也能在支付成功时将数据存入数据库并生成保存QR码图片,但无法在支付成功事件中结合PHPMailer完成发送操作。我使用的是Stripe测试模式,请问问题出在哪?
相关代码
<?php require_once './stripe-php-9.0.0/init.php'; include 'db.php'; // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.stripe.com/apikeys \Stripe\Stripe::setApiKey('xxxxx'); // If you are testing your webhook locally with the Stripe CLI you // can find the endpoint's secret by running `stripe listen` // Otherwise, find your endpoint's secret in your webhook settings in the Developer Dashboard $endpoint_secret = 'xxxxx'; $payload = @file_get_contents('php://input'); $sig_header = $_SERVER['HTTP_STRIPE_SIGNATURE']; $event = null; try { $event = \Stripe\Webhook::constructEvent( $payload, $sig_header, $endpoint_secret ); } catch(\UnexpectedValueException $e) { // Invalid payload http_response_code(400); exit(); } catch(\Stripe\Exception\SignatureVerificationException $e) { // Invalid signature http_response_code(400); exit(); } $id = $event->data->object->id; $amount = $event->data->object->amount_captured; $currency = $event->data->object->currency; $customer_email = $event->data->object->billing_details->email; $customer_name = $event->data->object->billing_details->name; // Handle the event switch ($event->type) { case 'payment_intent.succeeded': $paymentIntent = $event->data->object; // contains a \Stripe\PaymentIntent handlePaymentIntentSucceeded($paymentIntent); break; case 'charge.succeeded': $stmt = $conn->prepare("INSERT INTO Tynnsuppe (txid, Amount, Currency, Customer_email, Customer_name) VALUES (?, ?, ?, ?, ?)"); $stmt->bind_param("sdsss", $id, $amount, $currency, $customer_email, $customer_name); $stmt->execute(); if (!$stmt) { echo "Error"; } $stmt->close(); $conn->close(); // QR-code include 'phpqrcode/qrlib.php'; //The payment-id is the qr-code $text = $id; //Save the qr-code as an image and the name is the payment-id. $folder="bilder/qr/"; $file_name= $text.'.png'; $file_name=$folder.$file_name; QRcode::png($text,$file_name); //SEND MAIL require_once('PHPMailer/src/PHPMailer.php'); use PHPMailer\PHPMailer\PHPMailer; use PHPMailer\PHPMailer\Exception; $bodytext = "Hei"; $mail = new PHPMailer(); $mail->SetFrom('you@example.com', 'Your Name'); //Name is optional $mail->Subject = 'Din billett'; $mail->Body = $bodytext; $mail->AddAddress( 'reciver@hotmail.com' ); $file_to_attach = 'bilder/qr/' . $text . '.png'; $mail->AddAttachment( $file_to_attach , 'KlubbkveldBillett.pdf' ); return $mail->Send(); break; // ... handle other event types default: echo 'Received unknown event type ' . $event->type; } http_response_code(200); ?>
问题排查与解决方案
PHPMailer依赖不全
你只引入了PHPMailer.php,但PHPMailer运行需要Exception.php,如果用SMTP发送还需要SMTP.php。建议直接引入完整的必要文件:require_once('PHPMailer/src/PHPMailer.php'); require_once('PHPMailer/src/Exception.php'); require_once('PHPMailer/src/SMTP.php');未配置邮件发送驱动
默认PHPMailer可能使用PHP内置的mail()函数,但Webhook运行环境中该函数可能被禁用,或者服务器邮件配置不正确。建议配置SMTP方式发送,稳定性更高:$mail->isSMTP(); $mail->Host = 'smtp.example.com'; // 替换为你的SMTP服务器地址 $mail->SMTPAuth = true; $mail->Username = 'your_email@example.com'; // 你的邮箱账号 $mail->Password = 'your_email_password'; // 邮箱密码或授权码 $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; $mail->Port = 587; // 对应SMTP端口附件路径错误
你使用的是相对路径bilder/qr/,Webhook脚本的执行目录可能和预期不一致,导致找不到生成的QR码文件。改用绝对路径确保能正确定位文件:$folder = __DIR__ . '/bilder/qr/'; // __DIR__表示当前脚本所在目录 if (!is_dir($folder)) { mkdir($folder, 0755, true); // 确保目录存在 } $file_name = $folder . $text . '.png';Webhook响应超时与异常未处理
Stripe要求Webhook在10秒内返回响应,邮件发送操作可能耗时较长导致超时。另外,$mail->Send()可能抛出异常,未捕获会导致脚本中断,无法返回200响应给Stripe,进而触发重试。修改邮件发送逻辑:try { // 邮件配置代码... if (!$mail->send()) { error_log('邮件发送失败: ' . $mail->ErrorInfo); // 记录错误日志 } else { error_log('邮件发送成功'); } } catch (Exception $e) { error_log('邮件发送异常: ' . $e->getMessage()); } // 不要用return,确保脚本执行到最后返回200响应未定义函数导致脚本中断
在payment_intent.succeeded事件中调用了未定义的handlePaymentIntentSucceeded函数,会直接导致脚本报错终止。如果不需要处理该事件,直接注释这段代码;如果需要,实现该函数。数据库连接关闭过早
虽然这不会直接影响邮件发送,但建议把$conn->close();移到邮件发送完成之后,避免后续操作(如果有的话)出现数据库连接问题。
内容的提问来源于stack exchange,提问作者Soreng

