我使用PHP和curl与我的geth服务器进行json交互。
除了一个问题,我能够实现我想要的所有功能:根据以太坊钱包格式检查用户输入的地址是否有效。
我看到了一个javascript函数在这里,但我主要使用PHP,对JS不熟悉。
有任何想法如何在PHP中验证以太坊地址吗?
这是一个基于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;
}
}
为了验证校验和地址,我们需要一个现成的keccak-256实现,该实现不受内置的hash()
函数支持。您需要将greensea/keccak composer包作为依赖项导入。
感谢@WebSpanner指出SHA3散列的问题。
return strtolower($value) === $value || strtoupper($value) === $value;
- SameOldNick基本上,您可以完全将JavaScript转换为PHP。 在这里,我已经成功将验证以太坊地址的JavaScript代码转换并测试为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;
}
与此同时,对于希望查验以太坊地址是否有效的人(例如将其用作HTML字段的模式属性),这个非常简单的正则表达式可能就足够了。
^(0x)?[0-9a-fA-F]{40}$
hash()
不支持SHA3的情况下如何“使用”代码,而第二组preg_match
调用实际上是错误地被否定了。 - sepehrsha3
哈希算法。请使用sha3-256
代替,该算法从PHP 7.1.0开始可用。 - Paul Basenko