You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Symfony 5.4.12集成mnastalski/przelewy24-php的交易验证问题

问题分析与修复方案

你的核心问题是积分添加逻辑未与交易成功验证绑定,且错误地在发起交易的流程中调用了handleWebhook()——该方法用于接收Przelewy24的异步回调,发起交易时并无回调请求,导致当前代码跳过验证直接执行了积分添加。

修复步骤

1. 拆分发起交易与回调处理逻辑

将交易发起和Webhook回调验证拆分为两个独立的控制器方法:

发起交易的myAccount方法修改

namespace App\Controller;
...
use Przelewy24\Przelewy24;
use Przelewy24\Exceptions\Przelewy24Exception;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
...
public function myAccount(
   $partnerId = XXXXXX;
   $crc = 'XXXXXXXXXXXXXXXXXX';
   $live = false;
   UrlGeneratorInterface $urlGenerator
...
if ($buyPointsForm->isSubmitted() && $buyPointsForm->isValid()) {
    $session_id = session_id();
    $przelewy24 = new Przelewy24([
        'merchant_id' => $partnerId,
        'crc' => $crc,
        'live' => $live,
    ]);
    try {
        $transaction = $przelewy24->transaction([
            'session_id' => $session_id,
            // 跳转至支付结果页面,不直接处理积分
            'url_return' => $urlGenerator->generate('app_payment_return', ['itemId' => $item->getId()], UrlGeneratorInterface::ABSOLUTE_URL),
            // 指向专门的Webhook处理路由
            'url_status' => $urlGenerator->generate('app_przelewy24_webhook', [], UrlGeneratorInterface::ABSOLUTE_URL),
            'amount' => 1000, // 注意:Przelewy24金额单位为分,1000代表10PLN,按需调整
            'description' => 'Test',
            'email' =>  'sample@sample.pl',
            // 传递自定义参数,用于后续Webhook验证后处理积分
            'additional' => json_encode([
                'userId' => $this->getUser()->getId(),
                'points' => intVal($item->getPoints()),
                'itemId' => $item->getId()
            ])
        ]);
        
        // 获取支付跳转URL并跳转
        $redirectUrl = $transaction->redirectUrl();
        return $this->redirect($redirectUrl);
    } catch (Przelewy24Exception $e) {
        dd($e);
    }
}

新增Webhook处理控制器方法

创建专门方法接收Przelewy24异步回调,此处才是验证交易并添加积分的核心逻辑:

use Symfony\Component\HttpFoundation\Response;
use Psr\Log\LoggerInterface;
use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
...
/**
 * @Route("/przelewy24/webhook", name="app_przelewy24_webhook", methods={"POST"})
 */
public function handlePrzelewy24Webhook(
    $partnerId = XXXXXX,
    $crc = 'XXXXXXXXXXXXXXXXXX',
    $live = false,
    LoggerInterface $logger,
    EntityManagerInterface $em
): Response {
    $przelewy24 = new Przelewy24([
        'merchant_id' => $partnerId,
        'crc' => $crc,
        'live' => $live,
    ]);

    try {
        // 解析Webhook请求数据
        $webhookData = $przelewy24->handleWebhook();
        
        // 1. 验证交易真实性(必须执行,防止伪造请求)
        $verifyResponse = $przelewy24->verifyTransaction([
            'session_id' => $webhookData['sessionId'],
            'order_id' => $webhookData['orderId'],
            'amount' => $webhookData['amount'],
        ]);

        // 2. 检查交易状态是否成功
        if ($verifyResponse['status'] === 'success' && $webhookData['status'] === 'success') {
            // 解析自定义参数
            $additionalData = json_decode($webhookData['additional'], true);
            $userId = $additionalData['userId'];
            $pointsToAdd = $additionalData['points'];
            
            // 3. 执行添加积分逻辑
            $user = $em->getRepository(User::class)->find($userId);
            if ($user) {
                $user->setPoints($user->getPoints() + $pointsToAdd); // 假设存在对应属性方法
                $em->persist($user);
                $em->flush();
            }
        }

        // 返回200确认接收回调,Przelewy24会停止重试
        return new Response('OK', Response::HTTP_OK);
    } catch (Przelewy24Exception $e) {
        // 记录错误日志,不返回具体错误信息给外部
        $logger->error('Przelewy24 Webhook Error: ' . $e->getMessage());
        return new Response('Error', Response::HTTP_BAD_REQUEST);
    }
}

2. 调整支付结果页面逻辑

原assign_points路由改为仅展示支付结果,不再处理积分添加:

/**
 * @Route("/payment/return/{itemId}", name="app_payment_return")
 */
public function paymentReturn(int $itemId): Response {
    $item = $this->getDoctrine()->getRepository(Item::class)->find($itemId);
    return $this->render('payment/return.html.twig', [
        'item' => $item,
    ]);
}

关键注意事项

  • 金额单位:Przelewy24的amount参数单位为分,需根据实际支付金额换算。
  • Webhook路由权限:确保app_przelewy24_webhook路由未被Symfony防火墙拦截,回调请求为匿名访问。
  • 参数安全性:避免将敏感参数(如积分数量、用户ID)暴露在URL中,使用additional字段传递序列化参数更安全。
  • 日志记录:在Webhook中添加日志,便于后续排查交易问题。

内容的提问来源于stack exchange,提问作者PKDEVELOP

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 08:18:34