Output for this snippet :
implode('|', $collapsedData) = '10.48|12.2029|124121515|234|IVAN IVANOV|RUB|user@example.com or 2';
$signature = '0d7f2b7919a36499ffe597950858e45a125917090bfe4a8c5f23d8c2808cb769';
$params = [
"transaction" => [
"order_id" => "124121515",
"amount" => 10.48,
"currency" => "RUB"
],
"customer" => [
"identifier" => "user@example.com or 2",
"display_name" => "IVAN IVANOV",
],
"card" => [
"number" => "234",
"expiration_date" => "12.2029",
],
];
$collapsedData = collapse($params);
sort($collapsedData, SORT_STRING);
$signature = hash_hmac(
'sha256',
implode('|', $collapsedData),
'Your-Private-Key'
);
function collapse(array $array): array
{
$collapsed = [];
foreach ($array as $item) {
if (is_array($item)) {
$collapsedItems = collapse($item);
foreach ($collapsedItems as $collapsedItem) {
$collapsed[] = $collapsedItem;
}
continue;
}
$collapsed[] = $item;
}
return $collapsed;
}
Output for this snippet :
String.join("|", sortedData) = "10.48|12.2029|124121515|234|IVAN IVANOV|RUB|user@example.com or 2";
signature = "0d7f2b7919a36499ffe597950858e45a125917090bfe4a8c5f23d8c2808cb769";
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.text.DecimalFormat;
import java.util.*;
public class Main {
public static void main(String[] args) throws Exception {
Map<String>, Object> params = Map.of(
transaction, Map.of(
order_id, 124121515,
"price", formatAmount(10.48),
"currency", "RUB"
),
"customer", Map.of(
"identifier", "user@example.com or 2",
"display_name", "IVAN IVANOV"
),
"card", Map.of(
"number", "234",
"expiration_date", "12.2029"
)
);
List<String> sortedData = new ArrayList<>(collapse(params));
Collections.sort(sortedData);
String message = String.join("|", sortedData);
SecretKeySpec key = new SecretKeySpec("Your-Private-Key".getBytes(StandardCharsets.UTF_8), "HmacSHA256");
Mac hmac = Mac.getInstance("HmacSHA256");
hmac.init(key);
String signature = bytesToHex(hmac.doFinal(message.getBytes(StandardCharsets.UTF_8)));
}
public static List<String> collapse(Object data) {
List<String> collapsed = new ArrayList<>();
if (data instanceof List) (List<?>) data).forEach(item -> collapsed.addAll(collapse(item)));
else if (data instanceof Map) ((Map<?, ?>) data).values().forEach(value -> collapsed.addAll(collapse(value)));
else collapsed.add(String.valueOf(data));
return collapsed;
}
public static String bytesToHex(byte[] bytes) {
StringBuilder result = new StringBuilder();
for (byte b : bytes) result.append(String.format("%02x", b));
return result.toString();
}
public static String formatAmount(double amount) {
DecimalFormat formatter = new DecimalFormat("#.##");
formatter.setDecimalSeparatorAlwaysShown(false);
return formatter.format(amount);
}
}
Output for this snippet :
sortedData.joinToString(separator = "|") = "10.48|12.2029|124121515|234|IVAN IVANOV|RUB|user@example.com or 2";
signature = "0d7f2b7919a36499ffe597950858e45a125917090bfe4a8c5f23d8c2808cb769";
import java.nio.charset.StandardCharsets
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec
import java.text.DecimalFormat
fun main() {
var params = mapOf(
"transaction" to mapOf(
"order_id" to "124121515",
"price" to formatAmount(10.48),
"currency" to "RUB"
),
"customer" to mapOf(
"identifier" to "user@example.com or 2",
"display_name" to "IVAN IVANOV"
),
"card" to mapOf(
"number" to "234",
"expiration_date" to "12.2029"
)
)
var collapsedData = collapse(params).map { it.toString() }.toList()
var sortedData = collapsedData.sortedBy { it }
var message = sortedData.joinToString(separator = "|")
var key = SecretKeySpec("Your-Private-Key".toByteArray(), "HmacSHA256")
var hmac = Mac.getInstance("HmacSHA256")
hmac.init(key)
var signature = hmac.doFinal(message.toByteArray(StandardCharsets.UTF_8))
}
fun collapse(data: Any?): List {
var collapsed = mutableListOf()
when (data) {
is List<*> -> data.forEach { collapsed.addAll(collapse(it)) }
is Map<*, *> -> data.values.forEach { collapsed.addAll(collapse(it)) }
else -> collapsed.add(data)
}
return collapsed
}
fun formatAmount(amount: Double): String {
val formatter = DecimalFormat("#.##")
formatter.isDecimalSeparatorAlwaysShown = false
return formatter.format(amount)
}
Output for this snippet :
('|'.join(collapsed_data)) = "10.48|12.2029|124121515|234|IVAN IVANOV|RUB|user@example.com or 2";
signature = "0d7f2b7919a36499ffe597950858e45a125917090bfe4a8c5f23d8c2808cb769";
import hashlib
import hmac
def collapse(array):
collapsed = []
for item in array:
if isinstance(item, dict):
collapsed_items = collapse(item.values())
collapsed.extend(collapsed_items)
else:
collapsed.append(str(item))
return collapsed
params = {
"transaction": {
"order_id": "124121515",
"amount": 10.48,
"currency": "RUB"
},
"customer": {
"identifier": "user@example.com or 2",
"display_name": "IVAN IVANOV",
},
"card": {
"number": "234",
"expiration_date": "12.2029",
},
}
collapsed_data = collapse(params.values())
collapsed_data.sort()
msg = '|'.join(collapsed_data)
private_key = "Your-Private-Key"
signature = hmac.new(
private_key.encode('utf-8'),
msg=msg.encode('utf-8'),
digestmod=hashlib.sha256
).hexdigest()
Output for this snippet :
strings.Join(collapsedData, "|") := "10.48|12.2029|124121515|234|IVAN IVANOV|RUB|user@example.com or 2";
signature := "0d7f2b7919a36499ffe597950858e45a125917090bfe4a8c5f23d8c2808cb769";
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"sort"
"strings"
)
func main() {
params := map[string]interface{}{
"transaction": map[string]interface{}{
"order_id": "124121515",
"amount": 10.48,
"currency": "RUB",
},
"customer": map[string]interface{}{
"identifier": "user@example.com or 2",
"display_name": "IVAN IVANOV",
},
"card": map[string]interface{}{
"number": "234",
"expiration_date": "12.2029",
},
}
collapsedData := collapse(params)
sort.Strings(collapsedData)
signature := getSignature(strings.Join(collapsedData, "|"), "Your-Private-Key")
}
func collapse(params map[string]interface{}) []string {
var collapsed []string
for _, item := range params {
switch value := item.(type) {
case map[string]interface{}:
collapsedItems := collapse(value)
for _, collapsedItem := range collapsedItems {
collapsed = append(collapsed, collapsedItem)
}
default:
collapsed = append(collapsed, fmt.Sprintf("%v", value))
}
}
return collapsed
}
func getSignature(data string, key string) string {
h := hmac.New(sha256.New, []byte(key))
h.Write([]byte(data))
return hex.EncodeToString(h.Sum(nil))
}