# 各语言签名示例

# PHP

<?php
    const APPFLAG = 'test_appflag';
    const APPSECRET = 'test_appsecret';
    
    $param = [
        'appflag' => APPFLAG,           // 通用参数appflag必传
        'timestamp' => strval(time()),  // 通用参数timestamp实时获取
        'xxx' => 'xxx',                 // 业务参数,根据接口文档传入
    ];
    // 通用参数sign计算生成
    $param['sign'] = sign($param);
    var_dump($param);
    function sign($param = []) {
        // 1. 对参数key做ASCII升序排序
        ksort($param);
        $str = '';
        foreach ($param as $key => $value) {
            if ($key == 'sign') {
                // 签名串中不包含sign字段
                continue;
            }
            // 2. 拼接key和value,不添加任何字符
            $str .= $key . $value;
        }
        // 3. 在头部拼接appsecret
        $str = APPSECRET . $str;
        // 4. 计算md5值并转换为大写
        $sign = strtoupper(md5($str));
        return $sign;
    }
?>

# Golang

package main

import (
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"sort"
	"strconv"
	"strings"
	"time"
)

const (
	AppFlag   = "test_appflag"
	AppSecret = "test_appsecret"
)

func main() {
	timestamp := strconv.FormatInt(time.Now().Unix(), 10)
	params := map[string]string{
		"appflag":   AppFlag,   // 通用参数appflag必传
		"timestamp": timestamp, // 通用参数timestamp实时获取
		"xxx":       "xxx",     // 业务参数,根据接口文档传入
	}
	// 通用参数sign计算生成
	params["sign"] = sign(params)
	fmt.Println(params)
}

func sign(params map[string]string) string {
	// 1. 对参数key做ASCII升序排序
	keys := make([]string, 0, len(params))
	for k := range params {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	var strBuilder strings.Builder
	for _, k := range keys {
		if k == "sign" {
			// 签名串中不包含sign字段
			continue
		}
		// 2. 拼接key和value,不添加任何字符
		strBuilder.WriteString(k)
		strBuilder.WriteString(params[k])
	}
	// 3. 在头部拼接appsecret
	str := AppSecret + strBuilder.String()
	// 4. 计算md5值并转换为大写
	s := md5.Sum([]byte(str))
	return strings.ToUpper(hex.EncodeToString(s[:]))
}

# Java

import java.util.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.nio.charset.StandardCharsets;

public class Main {
private static final String APPFLAG = "test_appflag";
private static final String APPSECRET = "test_appsecret";

    public static void main(String[] args) throws NoSuchAlgorithmException {
        Map<String, String> params = new HashMap<>();
        params.put("appflag", APPFLAG); // 通用参数appflag必传
        params.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000L)); // 通用参数timestamp实时获取
        params.put("xxx", "xxx");   // 业务参数,根据接口文档传入
        String sign = sign(params); // 通用参数sign计算生成
        params.put("sign", sign);
        System.out.println(params);
    }

    public static String sign(Map<String, String> params) throws NoSuchAlgorithmException {
        // 1. 对参数key做ASCII升序排序
        List<String> keys = new ArrayList<>(params.keySet());
        Collections.sort(keys);

        StringBuilder strBuilder = new StringBuilder();
        for (String key : keys) {
            if (key.equals("sign")) {
                // 签名串中不包含sign字段
                continue;
            }
            // 2. 拼接key和value,不添加任何字符
            strBuilder.append(key);
            strBuilder.append(params.get(key));
        }
        // 3. 在头部拼接appsecret
        String str = APPSECRET + strBuilder.toString();
        // 4. 计算md5值并转换为大写
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] hashInBytes = md.digest(str.getBytes(StandardCharsets.UTF_8));
        StringBuilder sb = new StringBuilder();
        for (byte b : hashInBytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString().toUpperCase();
    }
}

# Python

#!/usr/bin/python
import hashlib
import time

APPFLAG = 'test_appflag'
APPSECRET = 'test_appsecret'

def sign(params):
    # 1. 对参数key做ASCII升序排序
    sorted_keys = sorted(params.keys())
    string = ''
    for key in sorted_keys:
        if key == 'sign':
            # 签名串中不包含sign字段
            continue
        # 2. 拼接key和value,不添加任何字符
        string += key + str(params[key])
    # 3. 在头部拼接appsecret
    string = APPSECRET + string
    # 4. 计算md5值并转换为大写
    sign = hashlib.md5(string.encode()).hexdigest().upper()
    return sign

params = {
    'appflag': APPFLAG,           # 通用参数appflag必传
    'timestamp': str(int(time.time())),  # 通用参数timestamp实时获取
    'xxx': 'xxx',                 # 业务参数,根据接口文档传入
}
# 通用参数sign计算生成
params['sign'] = sign(params)
print(params)

# Javascript

const crypto = require('crypto');

const APPFLAG = 'test_appflag';
const APPSECRET = 'test_appsecret';

function sign(params) {
    // 1. 对参数key做ASCII升序排序
    const sortedKeys = Object.keys(params).sort();

    let str = '';
    for (let key of sortedKeys) {
        if (key === 'sign') {
            // 签名串中不包含sign字段
            continue;
        }
        // 2. 拼接key和value,不添加任何字符
        str += key + params[key];
    }

    // 3. 在头部拼接appsecret
    str = APPSECRET + str;

    // 4. 计算md5值并转换为大写
    const hash = crypto.createHash('md5').update(str, 'utf8').digest('hex');
    return hash.toUpperCase();
}

let params = {
    'appflag': APPFLAG,           // 通用参数appflag必传
    'timestamp': String(Math.floor(Date.now() / 1000)),  // 通用参数timestamp实时获取
    'xxx': 'xxx',                 // 业务参数,根据接口文档传入
};

// 通用参数sign计算生成
params['sign'] = sign(params);
console.log(params);