如何在PHP中验证以太坊地址

btc*_*ash 6 php curl json-rpc ethereum

我正在使用PHP和curl与json与我的geth服务器进行交互.

除了一件事,我能够做我想要的一切:根据以太坊钱包格式检查用户的输入地址是否有效.

我在这里看到了一个javascript函数,但我主要使用的是PHP,我根本不会使用JS.

任何想法如何验证PHP中的以太坊地址?

sep*_*ehr 8

这是一个针对EIP 55规范的以太坊地址验证的PHP实现。有关其工作方式的详细信息,请仔细阅读注释。

<?php

use kornrunner\Keccak; // composer require greensea/keccak

class EthereumValidator
{
    public function isAddress(string $address): bool
    {
        // See: https://github.com/ethereum/web3.js/blob/7935e5f/lib/utils/utils.js#L415
        if ($this->matchesPattern($address)) {
            return $this->isAllSameCaps($address) ?: $this->isValidChecksum($address);
        }

        return false;
    }

    protected function matchesPattern(string $address): int
    {
        return preg_match('/^(0x)?[0-9a-f]{40}$/i', $address);
    }

    protected function isAllSameCaps(string $address): bool
    {
        return preg_match('/^(0x)?[0-9a-f]{40}$/', $address) || preg_match('/^(0x)?[0-9A-F]{40}$/', $address);
    }

    protected function isValidChecksum($address)
    {
        $address = str_replace('0x', '', $address);
        $hash = Keccak::hash(strtolower($address), 256);

        // See: https://github.com/web3j/web3j/pull/134/files#diff-db8702981afff54d3de6a913f13b7be4R42
        for ($i = 0; $i < 40; $i++ ) {
            if (ctype_alpha($address{$i})) {
                // Each uppercase letter should correlate with a first bit of 1 in the hash char with the same index,
                // and each lowercase letter with a 0 bit.
                $charInt = intval($hash{$i}, 16);

                if ((ctype_upper($address{$i}) && $charInt <= 7) || (ctype_lower($address{$i}) && $charInt > 7)) {
                    return false;
                }
            }
        }

        return true;
    }
}
Run Code Online (Sandbox Code Playgroud)

依存关系

为了验证校验和地址,我们需要适当的keccak-256实现,而内置hash()函数不支持该实现。您需要将greensea / keccak作曲家软件包作为依赖项。


@WebSpanner指出SHA3哈希问题。

  • @sepehr 这个实现在算法上是正确的,但是根据规范使用的散列算法(sha3-256)是不正确的。正确的散列算法是 keccack-256,它本质上是相同的散列算法,只是填充常量不同,因此会产生不同的结果。将此处的 Sha3 类替换为 greensea/keccak 包中的 Keccak 类以获得所需的结果。我没有添加新答案,因为我认为 sepehr 应该编辑这个答案,因为除了这个小改动之外,我只会使用他的代码。 (2认同)

tor*_*uto 6

基本上,您可以将javascript完全转换为PHP.在这里,我已经能够转换和测试用于在PHP中验证以太坊地址的代码.

/**
 * Checks if the given string is an address
 *
 * @method isAddress
 * @param {String} $address the given HEX adress
 * @return {Boolean}
*/
function isAddress($address) {
    if (!preg_match('/^(0x)?[0-9a-f]{40}$/i',$address)) {
        // check if it has the basic requirements of an address
        return false;
    } elseif (!preg_match('/^(0x)?[0-9a-f]{40}$/',$address) || preg_match('/^(0x)?[0-9A-F]{40}$/',$address)) {
        // If it's all small caps or all all caps, return true
        return true;
    } else {
        // Otherwise check each case
        return isChecksumAddress($address);
    }
}

/**
 * Checks if the given string is a checksummed address
 *
 * @method isChecksumAddress
 * @param {String} $address the given HEX adress
 * @return {Boolean}
*/
function isChecksumAddress($address) {
    // Check each case
    $address = str_replace('0x','',$address);
    $addressHash = hash('sha3',strtolower($address));
    $addressArray=str_split($address);
    $addressHashArray=str_split($addressHash);

    for($i = 0; $i < 40; $i++ ) {
        // the nth letter should be uppercase if the nth digit of casemap is 1
        if ((intval($addressHashArray[$i], 16) > 7 && strtoupper($addressArray[$i]) !== $addressArray[$i]) || (intval($addressHashArray[$i], 16) <= 7 && strtolower($addressArray[$i]) !== $addressArray[$i])) {
            return false;
        }
    }
    return true;
}
Run Code Online (Sandbox Code Playgroud)

同时,对于寻找用于检查以太坊地址有效性的非常简单的正则表达式的人(例如,使用是作为HTML字段的模式属性),这个正则表达式可能就足够了.

^(0x)?[0-9a-fA-F]{40}$
Run Code Online (Sandbox Code Playgroud)

  • 未知的哈希算法:sha3 (2认同)
  • @tormuto 我不认为我需要帮助,谢谢 :) 我想知道当 `hash()` 不支持 SHA3 并且第二组 `preg_match` 调用实际上被错误地否定时,你怎么能“使用”代码。 (2认同)