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

关于PDFGeneratorAPI签名密钥生成及PHP示例转C#的技术问题

Fixing PDFGeneratorAPI Signature Key & Sorting Mismatch in C#

Hey there, I’ve dealt with exactly this pain point when adapting PDFGeneratorAPI from PHP to C#—the ksort behavior difference and signature generation got me stuck for a bit too. Let’s walk through how to resolve both issues properly.

Why PHP’s ksort Doesn’t Match C# Default Sorting

The core problem here is that PHP’s ksort() uses strict ASCII-value ordering by default. That means uppercase letters (ASCII 65-90) come before lowercase letters (97-122) because their ASCII values are smaller.

In contrast, C#’s default string sorting (like using OrderBy() without a comparer) relies on your system’s current culture settings, which usually ignores case and sorts alphabetically (not strictly by ASCII). This is why you’re seeing lowercase "t" show up before uppercase "O"—the culture-aware sort doesn’t care about ASCII values, while PHP does.

Replicate PHP’s ksort in C#

To get identical sorting behavior, you need to use StringComparer.Ordinal in C#. This comparer strictly compares characters by their ASCII values, just like PHP’s ksort.

Here’s how to sort your parameter keys correctly:

// Your request parameters stored in a Dictionary
var requestParams = new Dictionary<string, string>
{
    {"title", "Sample Document"},
    {"OrderId", "45678"},
    // Add other required params here
};

// Sort keys using ASCII ordinal order (matches PHP ksort)
var sortedKeys = requestParams.Keys.OrderBy(key => key, StringComparer.Ordinal).ToList();

Test this with your problematic keys—you’ll see uppercase "O" now comes before lowercase "t", just like in PHP.

Generating a Valid Signature in C#

Once your keys are sorted correctly, follow these steps to generate a signature that PDFGeneratorAPI will accept:

  1. Collect all request parameters: Exclude the signature itself from this list.
  2. Sort keys with ordinal comparison: Use the method above.
  3. Encode and concatenate key-value pairs: URL-encode both keys and values (match PHP’s urlencode behavior—note that Uri.EscapeDataString uses %20 for spaces instead of +, so replace if the API expects +).
  4. Generate HMAC hash: Use your API secret to create an HMAC-SHA256 hash of the concatenated string, then convert it to Base64 (or hex, depending on the API’s requirements).

Here’s a complete reusable method:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;

public static class PdfGeneratorSignatureHelper
{
    public static string CreateSignature(Dictionary<string, string> parameters, string apiSecret)
    {
        // Step 1: Sort keys using ASCII ordinal order
        var sortedKeys = parameters.Keys.OrderBy(k => k, StringComparer.Ordinal).ToList();
        
        // Step 2: Build the payload string
        var payloadBuilder = new StringBuilder();
        foreach (var key in sortedKeys)
        {
            if (payloadBuilder.Length > 0)
                payloadBuilder.Append("&");
            
            // Encode key and value (match PHP's urlencode)
            var encodedKey = Uri.EscapeDataString(key);
            var encodedValue = Uri.EscapeDataString(parameters[key])
                                .Replace("%20", "+"); // Swap %20 to + if API expects PHP-style urlencode
            
            payloadBuilder.Append($"{encodedKey}={encodedValue}");
        }
        var payload = payloadBuilder.ToString();
        
        // Step 3: Generate HMAC-SHA256 signature
        using (var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(apiSecret)))
        {
            var hashBytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(payload));
            return Convert.ToBase64String(hashBytes); // Or use BitConverter.ToString(hashBytes).Replace("-", "").ToLower() for hex
        }
    }
}

Verify Consistency

To make sure your sorting and signature match PHP’s output, run quick tests:

PHP Test Code:

$params = ["title" => "test", "OrderId" => "123"];
ksort($params);
print_r($params);
// Output: Array ( [OrderId] => 123 [title] => test )

// Generate signature (match your API's logic)
$payload = http_build_query($params);
$signature = base64_encode(hash_hmac('sha256', $payload, 'YOUR_API_SECRET', true));
echo $signature;

C# Test Code:

var paramsDict = new Dictionary<string, string> { {"title", "test"}, {"OrderId", "123"} };
var signature = PdfGeneratorSignatureHelper.CreateSignature(paramsDict, "YOUR_API_SECRET");
Console.WriteLine(signature);

The signatures should be identical if everything is set up correctly.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 10:14:31