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

如何在CodeIgniter4中实现与Node.js/Express一致的JSON.stringify以完成Delyva Webhook的SHA256验签?

How to Match JSON.stringify Behavior in CodeIgniter4 for Delyva Webhook Signature Validation

Problem Analysis

Your core issue is that you're first parsing the JSON request body in CodeIgniter4 and then re-serializing it—a process that changes the string from the raw payload Delyva sends. While the Node.js example uses express.json() followed by JSON.stringify, this works only because Express's parsing combined with JSON.stringify happens to match the original payload (not a reliable best practice). PHP's json_encode has subtle differences from Node's JSON.stringify (like key ordering, whitespace handling, and empty value representation) that break the signature match.

Solution

To pass the SHA256 signature validation, you need to use the raw, unmodified POST request body string sent by Delyva to compute the HMAC, not a parsed-and-re-serialized version. Here's the corrected CodeIgniter4 code:

public function postTracking(): ResponseInterface {
    // Set your API secret
    $apiSecret = 'dx6ed8365ad507451595c151b6b61e3dbdcfbb987f';
    
    // Get the raw POST request body (critical: skip parsing/serializing)
    $payload = file_get_contents('php://input');
    // Alternatively, use CodeIgniter4's built-in method:
    // $payload = $this->request->getRawInput();
    
    // Retrieve the signature from request headers
    $signature = $this->request->getHeaderLine('X-Delyvax-Hmac-Sha256');
    
    // Calculate expected signature (matches Node.js logic exactly)
    $expected = base64_encode(hash_hmac('sha256', $payload, $apiSecret, true));
    
    // Validate the signature
    if ($signature !== $expected) {
        return $this->respond([
            'status' => 'error',
            'message' => 'Invalid signature',
            'received_signature' => $signature,
            'computed_signature' => $expected
        ], 401);
    }
    
    // Parse the payload only if you need to process the event data
    $eventData = json_decode($payload, true);
    
    return $this->respond([
        'status' => 'success',
        'event_data' => $eventData
    ]);
}

Key Details to Note

  1. Use the Raw Request Body
    Delyva computes the signature based on the exact string they send in the HTTP request body. Any parsing and re-serializing can alter whitespace, key order, or value formatting—even in unnoticeable ways—and break the signature match. Reading php://input or using getRawInput() ensures you work with the exact same string Delyva used.

  2. Match Node.js HMAC Logic

    • Node.js's crypto.createHmac('sha256', secret).update(payload).digest('base64') is equivalent to PHP's base64_encode(hash_hmac('sha256', $payload, $apiSecret, true))
    • The true parameter in hash_hmac tells PHP to return raw binary data, which we then encode to base64—matching Node.js's digest('base64') behavior perfectly.
  3. Why Parsing/Re-Serializing Fails
    Even if you tried to force json_encode to mimic JSON.stringify, you'd run into edge cases:

    • PHP 7.3 and below sorts object keys alphabetically, while Node.js preserves insertion order
    • Floating-point precision handling can differ
    • Whitespace and formatting (like trailing commas in arrays) are handled differently

Test the Fix

To verify, use your provided test data:

  • Plug the exact payload string into $payload
  • Compute $expected—it should match f8vncFdUbn+STSRVnS3oa6Rr+50tEGevZaYc7LrRncw=
  • If the values match, your signature logic is correct.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 06:42:40