## Signature calculation script example
- Below is a complete calculation script example of the signature (**JAVA, Python and PHP**). You can refer to it to implement the signature calculation script of your development language.

<details>
<summary>Click to expand/collapse <b>Java code</b></summary>

```Java
import org.apache.commons.lang.StringUtils;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.Map;
import java.util.TreeMap;

public class SignatureUtils {

    /**
    * generate signature
    * @param url: request url
    * @param queryParamMap: request query parameters Map Structure
    * @param bodyJSONString: request body JSON String
    * @param clientSecret: client secret
    * @return
    */
    public String generateSignature(String url, Map<String, Object> queryParamMap, String bodyJSONString, String clientSecret) {
        StringBuilder sb = new StringBuilder();
        // step 1: concat url
        sb.append(url);
        // step 2: concat query parameters
        if (!queryParamMap.isEmpty()) {
            // 2.1: sort by alphabetical order
            TreeMap<String, Object> sortedParams = new TreeMap<>(queryParamMap);
            // 2.2: concat key and value
            for (Map.Entry<String, Object> entry : sortedParams.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue() != null ? entry.getValue().toString() : null;
                sb.append("&");
                sb.append(key + "=" + value);
            }
        }
        // step 3: concat body
        if (StringUtils.isNotBlank(bodyJSONString)) {
            sb.append("&");
            sb.append(bodyJSONString);
        }
        // step 4: got a complete string waiting to generate a signature
        String signatureString = sb.toString();
        try {
            // step 5: initialize the HmacSHA256 algorithm with the clientSecret
            Mac mac = Mac.getInstance("HmacSHA256");
            mac.init(new SecretKeySpec(clientSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
            // step 6: calculate signature
            byte[] bytes = mac.doFinal(signatureString.getBytes(StandardCharsets.UTF_8));
            // step 7: encode the signature in Base64 format
            String signature = new String(Base64.getEncoder().encode(bytes), StandardCharsets.UTF_8);
            return signature;
        }catch (NoSuchAlgorithmException e){
            throw new IllegalStateException("Algorithm HmacSHA256 does not exist.", e);
        }catch (InvalidKeyException e){
            throw new RuntimeException("Key is invalid.", e);
        }
    }
}
```
</details>
<details>
<summary>Click to expand/collapse <b>Python code</b></summary>

```Python
import hashlib
import hmac
import base64
from typing import Dict, Any


class SignatureUtils:
    """
    Generate signature utility class
    """

    @staticmethod
    def generate_signature(url: str,
                          query_param_map: Dict[str, Any],
                          body_json_string: str,
                          client_secret: str) -> str:
        """
        Generate signature

        Args:
            url: request url
            query_param_map: request query parameters dict
            body_json_string: request body JSON string
            client_secret: client secret

        Returns:
            Generated signature string
        """
        sb = []

        # Step 1: concat url
        sb.append(url)

        # Step 2: concat query parameters
        if query_param_map:
            # 2.1: sort by alphabetical order
            sorted_params = dict(sorted(query_param_map.items()))
            # 2.2: concat key and value
            for key, value in sorted_params.items():
                value_str = str(value) if value is not None else ""
                sb.append(f"&{key}={value_str}")

        # Step 3: concat body
        if body_json_string and body_json_string.strip():
            sb.append(f"&{body_json_string}")

        # Step 4: got complete string for signature generation
        signature_string = "".join(sb)

        try:
            # Step 5 & 6: calculate HMAC-SHA256 signature
            signature_bytes = hmac.new(
                client_secret.encode('utf-8'),
                signature_string.encode('utf-8'),
                hashlib.sha256
            ).digest()

            # Step 7: encode in Base64
            signature = base64.b64encode(signature_bytes).decode('utf-8')
            return signature

        except Exception as e:
            raise RuntimeError(f"Failed to generate signature: {str(e)}")
```
</details>
<details>
<summary>Click to expand/collapse <b>PHP code</b></summary>

```PHP
<?php

    class SignatureUtils
    {
        /**
        * Generate signature
        *
        * @param string $url Request URL
        * @param array $queryParamMap Request query parameters associative array
        * @param string $bodyJSONString Request body JSON string
        * @param string $clientSecret Client secret
        * @return string Generated signature string
        * @throws RuntimeException If signature generation fails
        */
        public static function generateSignature(
            string $url,
            array $queryParamMap,
            string $bodyJSONString,
            string $clientSecret
        ): string {
            $sb = '';
            
            // Step 1: concat url
            $sb .= $url;
            
            // Step 2: concat query parameters
            if (!empty($queryParamMap)) {
                // 2.1: sort by alphabetical order (PHP's ksort sorts in-place)
                ksort($queryParamMap);
                
                // 2.2: concat key and value
                foreach ($queryParamMap as $key => $value) {
                    // String value = entry.getValue() != null ? entry.getValue().toString() : null;
                    // In PHP, null becomes empty string when concatenated, but we need "null" string
                    $valueStr = $value !== null ? (string)$value : '';
                    $sb .= '&' . $key . '=' . $valueStr;
                }
            }
            
            // Step 3: concat body
            if (trim($bodyJSONString) !== '') {
                $sb .= '&' . $bodyJSONString;
            }
            
            // Step 4: got a complete string waiting to generate a signature
            $signatureString = $sb;

            try {
                // Step 5 & 6: calculate HMAC-SHA256 signature
                // Note: hash_hmac returns raw binary data by default
                $signatureBytes = hash_hmac('sha256', $signatureString, $clientSecret, true);
                
                if ($signatureBytes === false) {
                    throw new RuntimeException('Failed to calculate HMAC signature');
                }
                
                // Step 7: encode the signature in Base64 format
                $signature = base64_encode($signatureBytes);
                
                return $signature;
                
            } catch (Exception $e) {
                // Re-throw with appropriate message
                throw new RuntimeException('Failed to generate signature: ' . $e->getMessage(), 0, $e);
            }
        }
    }
```
</details>
