PHP脚本到Python3(Django)的翻译

PHP脚本到Python3(Django)的翻译,python,php,python-3.x,django,Python,Php,Python 3.x,Django,我正在尝试为我的Django项目从零开始将以下PHP脚本转换为Python: 注意,我的理解是,这个脚本应该处理从表单发送的值,使用Secret_密钥对数据进行签名,在SHA256中加密数据,并在Base64中编码 <?php define ('HMAC_SHA256', 'sha256'); define ('SECRET_KEY', '<REPLACE WITH SECRET KEY>'); function sign ($params) { return sign

我正在尝试为我的Django项目从零开始将以下PHP脚本转换为Python:

注意,我的理解是,这个脚本应该处理从表单发送的值,使用Secret_密钥对数据进行签名,在SHA256中加密数据,并在Base64中编码

<?php

define ('HMAC_SHA256', 'sha256');
define ('SECRET_KEY', '<REPLACE WITH SECRET KEY>');

function sign ($params) {
  return signData(buildDataToSign($params), SECRET_KEY);
}

function signData($data, $secretKey) {
    return base64_encode(hash_hmac('sha256', $data, $secretKey, true));
}

function buildDataToSign($params) {
        $signedFieldNames = explode(",",$params["signed_field_names"]);
        foreach ($signedFieldNames as $field) {
           $dataToSign[] = $field . "=" . $params[$field];
        }
        return commaSeparate($dataToSign);
}

function commaSeparate ($dataToSign) {
    return implode(",",$dataToSign);
}

?>
在打印变量时,我得到以下信息:

VALUES :  ['afc10315b6aa3b2a8cfc91253812b94c', 'E25C4FE4-4622-47E9-9941-1003B7910B3B', '0b59b0ae-bd25-4421-a231-bb83dcfc91fa', 'access_key,profile_id,transaction_uuid,signed_field_names,unsigned_field_names,signed_date_time,locale,transaction_type,reference_number,amount,currency', '', '2021-03-06T22:07:30Z', 'en', 'authorization', '1615068450109', '100', 'USD']
DATATOSIGN :  ['access_key=afc10315b6aa3b2a8cfc91253812b94c', 'profile_id=E25C4FE4-4622-47E9-9941-1003B7910B3B', 'transaction_uuid=0b59b0ae-bd25-4421-a231-bb83dcfc91fa', 'signed_field_names=access_key,profile_id,transaction_uuid,signed_field_names,unsigned_field_names,signed_date_time,locale,transaction_type,reference_number,amount,currency', 'unsigned_field_names=', 'signed_date_time=2021-03-06T22:07:30Z', 'locale=en', 'transaction_type=authorization', 'reference_number=1615068450109', 'amount=100', 'currency=USD']
SIGNATURE :  953C786EB9884CEC13C24118B00125BDCFE23AFF8AB02E7BEF29A83156C55C16
BASE64STRING :  b'OTUzQzc4NkVCOTg4NENFQzEzQzI0MTE4QjAwMTI1QkRDRkUyM0FGRjhBQjAyRTdCRUYyOUE4MzE1NkM1NUMxNg=='
我想我离我想要达到的最终结果已经很近了,因为我只需要将Base64String发布到一个特定的URL

然而,我不确定有几件事情看起来有点不对劲:

  • 我将PHP代码“翻译”成Python是否正确?我是否打算将我的列表合并为“DATATOSIGN”?我不精通PHP,因此可能误解了如何显示数据

  • Base64中的签名应始终为44个字符,如使用PHP示例代码时的“WrXOhTzhBjYMZROwiCug2My3jiZHOqATimcz5EBA07M=”但我的方式超过了此限制

  • 如果您需要任何其他信息,请随时询问


    希望你能给我指点

    要解决这个问题,最好了解给定参数的最终PHP结果

    以下是我在给定PHP代码中使用的参数:

    $params = [
        'access_key' => 'afc10315b6aaxxxxxcfc912xx812b94c',
        'profile_id' => 'E25C4XXX-4622-47E9-9941-1003B7910B3B',
        'transaction_uuid' => '12345',
        'signed_field_names' => 'access_key,profile_id,transaction_uuid,signed_field_names,unsigned_field_names,signed_date_time,locale,transaction_type,reference_number,amount,currency',
        'unsigned_field_names' => '',
        'signed_date_time' => '2021-03-06 16:14:00',
        'locale' => 'en',
        'transaction_type' => 'credit',
        'reference_number' => '12345',
        'amount' => '50',
        'currency' => 'usd'
    ];
    
    当我使用这些参数运行原始PHP代码时,以及这些用于输出代码的行:

    <?php
    echo "build data to sign:\n";
    print_r(buildDataToSign($params));
    echo "\n";
    
    echo "sign data:\n";
    echo signData(buildDataToSign($params), 'secret');
    ?>
    
    因此,对于这个PHP代码的新Python版本,您可能希望在这些参数的末尾有一个类似的符号数据值
    6v0iiqu3smgmagmadpk4kvruhm1nnkuivlbpblg7vka7m8=

    因为您的Python示例似乎没有得到与现在相同的结果,在Python
    def
    的末尾添加了一个
    return base64string
    之后,我得到了以下输出:

    build data to sign:
    access_key=afc10315b6aaxxxxxcfc912xx812b94c,profile_id=E25C4XXX-4622-47E9-9941-1003B7910B3B,transaction_uuid=12345,signed_field_names=access_key,profile_id,transaction_uuid,signed_field_names,unsigned_field_names,signed_date_time,locale,transaction_type,reference_number,amount,currency,unsigned_field_names=,signed_date_time=2021-03-06 16:14:00,locale=en,transaction_type=credit,reference_number=12345,amount=50,currency=usd
    sign data:
    6V0iIqu3smGmadPK4KvRuHm1nNkuIVLBPbLg7VkA7M8=
    
    sign_data:
    b'NThFMjU4QTQyRjU2MkVDRDgzM0RCOEIwM0VDODczQTExNjc3MUNDMEM2OURGMDFGMjdFQkU3MEMzMDAyNjA3RQ=='
    
    为了匹配代码的PHP版本,我想尝试找出PHP和Python方法在
    hmac
    base64
    部分上的区别

    当我将您的PHP代码示例分解为与
    hmac
    值相关的步骤,然后是
    base64
    值相关的步骤时,我发现了以下内容(使用
    'hello'
    的数据消息和
    'secret'
    键保持简单):

    PHP代码示例:

    <?php
    $hash_value = hash_hmac('sha256', 'hello', 'secret', true);
    $base64_value = base64_encode($hash_value);
    
    echo "hash value:\n";
    echo $hash_value;
    echo "\n";
    echo "base64 value:\n";
    echo $base64_value;
    echo "\n";
    ?>
    
    ;▒▒▒▒▒C▒|
    
    base64 value:
    iKqz7ejTrflNJquQ07r9SiCDBww7zOnAFO4EpEOEfAs=
    
    import base64
    import hashlib
    import hmac
    
    # Based on your Python code example
    hash_value = hmac.new(bytes('secret' , 'latin-1'), msg = bytes('hello', 'latin-1'), digestmod = hashlib.sha256).hexdigest().upper()
    base64_value = base64.b64encode(bytes(hash_value, 'utf-8'))
    
    print("hash value:")
    print(hash_value)
    print("base64 value:")
    print(base64_value)
    
    hash value:
    88AAB3EDE8D3ADF94D26AB90D3BAFD4A2083070C3BCCE9C014EE04A443847C0B
    base64 value:
    b'ODhBQUIzRURFOEQzQURGOTREMjZBQjkwRDNCQUZENEEyMDgzMDcwQzNCQ0NFOUMwMTRFRTA0QTQ0Mzg0N0MwQg=='
    
    import base64
    import hashlib
    import hmac
    
    # Based on your Python code example
    hash_value = hmac.new(bytes('secret' , 'latin-1'), msg = bytes('hello', 'latin-1'), digestmod = hashlib.sha256).digest()
    base64_value = base64.b64encode(bytes(hash_value))
    
    print("hash value:")
    print(hash_value)
    print("base64 value:")
    print(base64_value)
    
    hash value:
    b'\x88\xaa\xb3\xed\xe8\xd3\xad\xf9M&\xab\x90\xd3\xba\xfdJ \x83\x07\x0c;\xcc\xe9\xc0\x14\xee\x04\xa4C\x84|\x0b'
    base64 value:
    b'iKqz7ejTrflNJquQ07r9SiCDBww7zOnAFO4EpEOEfAs='
    
    这看起来像是一些疯狂的二进制类型数据!然后,我想尝试确保
    base64
    值可以在Python中重现。为此,我在Python中使用了一种简单的方法,使用了与前面相同的值

    Python代码示例:

    <?php
    $hash_value = hash_hmac('sha256', 'hello', 'secret', true);
    $base64_value = base64_encode($hash_value);
    
    echo "hash value:\n";
    echo $hash_value;
    echo "\n";
    echo "base64 value:\n";
    echo $base64_value;
    echo "\n";
    ?>
    
    ;▒▒▒▒▒C▒|
    
    base64 value:
    iKqz7ejTrflNJquQ07r9SiCDBww7zOnAFO4EpEOEfAs=
    
    import base64
    import hashlib
    import hmac
    
    # Based on your Python code example
    hash_value = hmac.new(bytes('secret' , 'latin-1'), msg = bytes('hello', 'latin-1'), digestmod = hashlib.sha256).hexdigest().upper()
    base64_value = base64.b64encode(bytes(hash_value, 'utf-8'))
    
    print("hash value:")
    print(hash_value)
    print("base64 value:")
    print(base64_value)
    
    hash value:
    88AAB3EDE8D3ADF94D26AB90D3BAFD4A2083070C3BCCE9C014EE04A443847C0B
    base64 value:
    b'ODhBQUIzRURFOEQzQURGOTREMjZBQjkwRDNCQUZENEEyMDgzMDcwQzNCQ0NFOUMwMTRFRTA0QTQ0Mzg0N0MwQg=='
    
    import base64
    import hashlib
    import hmac
    
    # Based on your Python code example
    hash_value = hmac.new(bytes('secret' , 'latin-1'), msg = bytes('hello', 'latin-1'), digestmod = hashlib.sha256).digest()
    base64_value = base64.b64encode(bytes(hash_value))
    
    print("hash value:")
    print(hash_value)
    print("base64 value:")
    print(base64_value)
    
    hash value:
    b'\x88\xaa\xb3\xed\xe8\xd3\xad\xf9M&\xab\x90\xd3\xba\xfdJ \x83\x07\x0c;\xcc\xe9\xc0\x14\xee\x04\xa4C\x84|\x0b'
    base64 value:
    b'iKqz7ejTrflNJquQ07r9SiCDBww7zOnAFO4EpEOEfAs='
    
    Python代码输出示例:

    <?php
    $hash_value = hash_hmac('sha256', 'hello', 'secret', true);
    $base64_value = base64_encode($hash_value);
    
    echo "hash value:\n";
    echo $hash_value;
    echo "\n";
    echo "base64 value:\n";
    echo $base64_value;
    echo "\n";
    ?>
    
    ;▒▒▒▒▒C▒|
    
    base64 value:
    iKqz7ejTrflNJquQ07r9SiCDBww7zOnAFO4EpEOEfAs=
    
    import base64
    import hashlib
    import hmac
    
    # Based on your Python code example
    hash_value = hmac.new(bytes('secret' , 'latin-1'), msg = bytes('hello', 'latin-1'), digestmod = hashlib.sha256).hexdigest().upper()
    base64_value = base64.b64encode(bytes(hash_value, 'utf-8'))
    
    print("hash value:")
    print(hash_value)
    print("base64 value:")
    print(base64_value)
    
    hash value:
    88AAB3EDE8D3ADF94D26AB90D3BAFD4A2083070C3BCCE9C014EE04A443847C0B
    base64 value:
    b'ODhBQUIzRURFOEQzQURGOTREMjZBQjkwRDNCQUZENEEyMDgzMDcwQzNCQ0NFOUMwMTRFRTA0QTQ0Mzg0N0MwQg=='
    
    import base64
    import hashlib
    import hmac
    
    # Based on your Python code example
    hash_value = hmac.new(bytes('secret' , 'latin-1'), msg = bytes('hello', 'latin-1'), digestmod = hashlib.sha256).digest()
    base64_value = base64.b64encode(bytes(hash_value))
    
    print("hash value:")
    print(hash_value)
    print("base64 value:")
    print(base64_value)
    
    hash value:
    b'\x88\xaa\xb3\xed\xe8\xd3\xad\xf9M&\xab\x90\xd3\xba\xfdJ \x83\x07\x0c;\xcc\xe9\xc0\x14\xee\x04\xa4C\x84|\x0b'
    base64 value:
    b'iKqz7ejTrflNJquQ07r9SiCDBww7zOnAFO4EpEOEfAs='
    
    因此,正如您之前发现的,Python端的
    base64
    值结果比PHP版本长

    在进一步研究之后(特别是在上面的PHP测试代码中看到奇怪的数据结果),我发现in-PHP可以选择以二进制形式返回结果(在PHP代码示例中,
    true
    值位于
    hash_hmac()
    的末尾)。在Python方面,看起来您决定使用
    hmac.hexdigest()
    ,我想我以前在需要类似字符串的值时使用过它。但是,对于这种情况,我认为您可能希望将该值作为二进制值返回。要做到这一点,您可能需要使用

    修改的示例Python代码:

    <?php
    $hash_value = hash_hmac('sha256', 'hello', 'secret', true);
    $base64_value = base64_encode($hash_value);
    
    echo "hash value:\n";
    echo $hash_value;
    echo "\n";
    echo "base64 value:\n";
    echo $base64_value;
    echo "\n";
    ?>
    
    ;▒▒▒▒▒C▒|
    
    base64 value:
    iKqz7ejTrflNJquQ07r9SiCDBww7zOnAFO4EpEOEfAs=
    
    import base64
    import hashlib
    import hmac
    
    # Based on your Python code example
    hash_value = hmac.new(bytes('secret' , 'latin-1'), msg = bytes('hello', 'latin-1'), digestmod = hashlib.sha256).hexdigest().upper()
    base64_value = base64.b64encode(bytes(hash_value, 'utf-8'))
    
    print("hash value:")
    print(hash_value)
    print("base64 value:")
    print(base64_value)
    
    hash value:
    88AAB3EDE8D3ADF94D26AB90D3BAFD4A2083070C3BCCE9C014EE04A443847C0B
    base64 value:
    b'ODhBQUIzRURFOEQzQURGOTREMjZBQjkwRDNCQUZENEEyMDgzMDcwQzNCQ0NFOUMwMTRFRTA0QTQ0Mzg0N0MwQg=='
    
    import base64
    import hashlib
    import hmac
    
    # Based on your Python code example
    hash_value = hmac.new(bytes('secret' , 'latin-1'), msg = bytes('hello', 'latin-1'), digestmod = hashlib.sha256).digest()
    base64_value = base64.b64encode(bytes(hash_value))
    
    print("hash value:")
    print(hash_value)
    print("base64 value:")
    print(base64_value)
    
    hash value:
    b'\x88\xaa\xb3\xed\xe8\xd3\xad\xf9M&\xab\x90\xd3\xba\xfdJ \x83\x07\x0c;\xcc\xe9\xc0\x14\xee\x04\xa4C\x84|\x0b'
    base64 value:
    b'iKqz7ejTrflNJquQ07r9SiCDBww7zOnAFO4EpEOEfAs='
    
    修改的示例Python代码输出:

    <?php
    $hash_value = hash_hmac('sha256', 'hello', 'secret', true);
    $base64_value = base64_encode($hash_value);
    
    echo "hash value:\n";
    echo $hash_value;
    echo "\n";
    echo "base64 value:\n";
    echo $base64_value;
    echo "\n";
    ?>
    
    ;▒▒▒▒▒C▒|
    
    base64 value:
    iKqz7ejTrflNJquQ07r9SiCDBww7zOnAFO4EpEOEfAs=
    
    import base64
    import hashlib
    import hmac
    
    # Based on your Python code example
    hash_value = hmac.new(bytes('secret' , 'latin-1'), msg = bytes('hello', 'latin-1'), digestmod = hashlib.sha256).hexdigest().upper()
    base64_value = base64.b64encode(bytes(hash_value, 'utf-8'))
    
    print("hash value:")
    print(hash_value)
    print("base64 value:")
    print(base64_value)
    
    hash value:
    88AAB3EDE8D3ADF94D26AB90D3BAFD4A2083070C3BCCE9C014EE04A443847C0B
    base64 value:
    b'ODhBQUIzRURFOEQzQURGOTREMjZBQjkwRDNCQUZENEEyMDgzMDcwQzNCQ0NFOUMwMTRFRTA0QTQ0Mzg0N0MwQg=='
    
    import base64
    import hashlib
    import hmac
    
    # Based on your Python code example
    hash_value = hmac.new(bytes('secret' , 'latin-1'), msg = bytes('hello', 'latin-1'), digestmod = hashlib.sha256).digest()
    base64_value = base64.b64encode(bytes(hash_value))
    
    print("hash value:")
    print(hash_value)
    print("base64 value:")
    print(base64_value)
    
    hash value:
    b'\x88\xaa\xb3\xed\xe8\xd3\xad\xf9M&\xab\x90\xd3\xba\xfdJ \x83\x07\x0c;\xcc\xe9\xc0\x14\xee\x04\xa4C\x84|\x0b'
    base64 value:
    b'iKqz7ejTrflNJquQ07r9SiCDBww7zOnAFO4EpEOEfAs='
    
    现在,最后的
    base64
    结果似乎与示例PHP和Python代码之间的匹配

    为了更好地理解PHP和Python代码之间的区别,我最后将PHP代码简单地翻译成Python(部分基于Python代码)

    以下是我这边的相关Python代码(示例
    params
    ):

    当我使用我的代码翻译检查Python代码时,我检查了代码中变量
    signed_field_names
    DataToSign
    的值,得到了以下结果:

    signed_field_names:
    ['access_key', 'profile_id', 'transaction_uuid', 'signed_field_names', 'unsigned_field_names', 'signed_date_time', 'locale', 'transaction_type', 'reference_number', 'amount', 'currency']
    DataToSign:
    ['access_key=afc10315b6aaxxxxxcfc912xx812b94c', 'profile_id=E25C4XXX-4622-47E9-9941-1003B7910B3B', 'transaction_uuid=12345', 'signed_field_names=access_key,profile_id,transaction_uuid,signed_field_names,unsigned_field_names,signed_date_time,locale,transaction_type,reference_number,amount,currency', 'unsigned_field_names=', 'signed_date_time=2021-03-06 16:14:00', 'locale=en', 'transaction_type=credit', 'reference_number=12345', 'amount=50', 'currency=usd']
    
    当我用代码翻译尝试检查这些值时,我得到以下值:

    signed_field_names:
    ['access_key', 'profile_id', 'transaction_uuid', 'signed_field_names', 'unsigned_field_names', 'signed_date_time', 'locale', 'transaction_type', 'reference_number', 'amount', 'currency']
    DataToSign:
    access_key=afc10315b6aaxxxxxcfc912xx812b94c,profile_id=E25C4XXX-4622-47E9-9941-1003B7910B3B,transaction_uuid=12345,signed_field_names=access_key,profile_id,transaction_uuid,signed_field_names,unsigned_field_names,signed_date_time,locale,transaction_type,reference_number,amount,currency,unsigned_field_names=,signed_date_time=2021-03-06 16:14:00,locale=en,transaction_type=credit,reference_number=12345,amount=50,currency=usd
    
    因此,看起来您的
    DataToSign=list(map('='.join,zip(signed_field_name,values))
    行正在指定一个
    list
    ,而我的代码尝试是基于您的原始PHP示例指定一个
    字符串

    因此,我认为您需要将结果转换回类似这样的
    字符串
    (尽管如果您选择的话,变量名也可以写得不同):

    为了节省在这篇长文章中的时间,我还发现您的
    message
    变量与我翻译的PHP代码不同。为了解决这个问题,我将Python代码中的
    message
    变量设置为前面提到的
    DataToSignString

    # Commenting out previous message line for now
    # message = '{} {}'.format(DataToSignString, API_SECRET)
    message = DataToSignString
    
    此外,Python示例似乎需要进行以下更改:

    signature = hmac.new(bytes(API_SECRET , 'latin-1'), msg = bytes(message , 'latin-1'), digestmod = hashlib.sha256).digest()
    base64string = base64.b64encode(bytes(signature))
    
    这样,您就拥有了
    hmac
    对象的二进制版本。另外,在
    base64encode
    部分中,现在可能不需要
    utf-8
    部分

    最后,在返回
    base64string
    之前,我添加了一个
    return
    来返回计算的
    base64string

    return str(base64string, 'utf-8')
    
    综合起来,下面是Python示例中修改后的代码:

    import base64
    import datetime
    import hashlib
    import hmac
    import pprint
    import uuid
    
    def sign():
        access_key = 'afc10315b6aaxxxxxcfc912xx812b94c'
        profile_id = 'E25C4XXX-4622-47E9-9941-1003B7910B3B'
        transaction_uuid = "12345"
        signed_field_names = 'access_key,profile_id,transaction_uuid,signed_field_names,unsigned_field_names,signed_date_time,locale,transaction_type,reference_number,amount,currency'
        signed_date_time = "2021-03-06 16:14:00"
        locale = 'en'
        transaction_type = "credit"
        reference_number = "12345"
        amount = "50"
        currency = "usd"
    
        # Transform the String into a List
        signed_field_names = [x.strip() for x in signed_field_names.split(',')]
    
        # Get Values for each of the fields in the form
        values = [access_key, profile_id, transaction_uuid,signed_field_names,'',signed_date_time,locale,transaction_type,reference_number,amount,currency]
    
        # Insert the signedfieldnames in their place in the list (MUST BE KEPT)
        values[3] = 'access_key,profile_id,transaction_uuid,signed_field_names,unsigned_field_names,signed_date_time,locale,transaction_type,reference_number,amount,currency'
    
        # Merge the two lists as one
        DataToSign = list(map('='.join, zip(signed_field_names, values)))
        DataToSignString = ','.join(DataToSign)
    
        # Hash Sha-256
        API_SECRET = 'secret'
        message = DataToSignString
    
        signature = hmac.new(bytes(API_SECRET , 'latin-1'), msg = bytes(message , 'latin-1'), digestmod = hashlib.sha256).digest()
    
        base64string = base64.b64encode(bytes(signature))
        return str(base64string, 'utf-8')
    
    result = sign()
    print("sign_data:")
    print(result)
    
    此代码(具有给定参数)的输出为:


    这个输出的值部分应该与本文前面的PHP输出相同。早期的值是
    6v0iiqu3smgmagmadpk4kvruhm1nnkuivlbpblg7vka7m8=
    ,最新的输出显示了
    6v0iqu3smgmagpk4kvruhm1nnkuivlbpblg7vka7m8=

    @summea your was god sent!非常感谢!我不敢相信你做出了多大的努力,我是巴