我该如何检查Laravel输入的以太坊地址格式是否有效?
<?php
namespace App\Rules;
use kornrunner\Keccak; // composer require greensea/keccak
use Illuminate\Contracts\Validation\Rule;
class ValidEthereumAddress implements Rule
{
/**
* @var Keccak
*/
protected $hasher;
public function __construct(Keccak $hasher)
{
$this->keccak = $hasher;
}
public function passes($attribute, $value)
{
// See: https://github.com/ethereum/web3.js/blob/7935e5f/lib/utils/utils.js#L415
if ($this->matchesPattern($value)) {
return $this->isAllSameCaps($value) ?: $this->isValidChecksum($value);
}
return false;
}
public function message()
{
return 'The :attribute must be a valid Ethereum address.';
}
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 = $this->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;
}
}
为了验证校验和地址,我们需要一个Keccac实现,而内置的hash()
函数不支持该实现。您需要引入这个纯PHP实现以使上述规则生效。
任何以0x开头,后跟0-9、A-F、a-f(有效的十六进制字符)的42个字符字符串都代表一个有效的以太坊地址。
您可以在这里找到有关小写和部分大写(用于添加校验和)以太坊地址格式的更多信息。
从 Laravel 9 开始,如果您正在使用请求类进行验证,请将此内容添加到验证规则中:
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'address' => 'regex:/^(0x)?(?i:[0-9a-f]){40}$/'
];
}
注释:
(?i: ... )
对正则表达式的部分内容进行了大小写不敏感处理
0x7614e80bE7E0C1e5aFce4E8e35627dEEc461d2bD
。 - Dhaval Bharadva