随着区块链技术的飞速发展,以太坊作为最智能合约平台之一,其上的代币(尤其是遵循 ERC-20 标准的代币)数量激增,对于许多基于 Web 的应用而言,实现与以太坊代币的对接(如代币转账、余额查询、代币转账记录查询等)成为了一项常见需求,PHP 作为一种广泛使用的服务器端脚本语言,同样可以与以太坊网络进行交互,实现代币对接,本文将详细介绍如何使用 PHP 进行以太坊代币对接的基本步骤和核心要点。
在开始之前,你需要准备以下几样东西:
web3.php 库,这是以太坊官方 JavaScript 库 web3.js 的 PHP 移植版,功能强大且文档相对完善,可以通过 Composer 安装:composer require sc0vu/web3.php
我们需要使用 PHP 连接到以太坊网络,这通常通过 RPC 接口实现。
<?php
require 'vendor/autoload.php';
use Web3\Web3;
use Web3\Providers\HttpProvider;
use Web3\RequestManagers\HttpRequestManager;
// 替换为你的以太坊节点 RPC URL
$rpcUrl = 'https://mainnet.infura.io/v3/YOUR_INFURA_PROJECT_ID';
// 创建 HTTP Provider
$provider = new HttpProvider(new HttpRequestManager($rpcUrl, 5000)); // 5000 是超时时间(毫秒)
// 创建 Web3 实例
$web3 = new Web3($provider);
// 测试连接
$web3->eth->blockNumber(function ($err, $blockNumber) {
if ($err !== null) {
echo "Error: " . $err->getMessage();
return;
}
echo "Current Ethereum Block Number: " . $blockNumber->toString() . "\n";
});
?>
将 YOUR_INFURA_PROJECT_ID 替换为你在 Infura 上创建的项目 ID,运行上述代码,如果能正确返回当前区块号,说明连接成功。

ERC-20 代币的核心功能是通过智能合约实现的,要与代币交互,我们需要两个关键信息:

0xdAC17F958D2ee523a2206206994597C13D831ec7。balanceOf(), transfer(), transferFrom(), approve(), allowance(), totalSupply(), decimals(), symbol(), name() 等函数。你可以从 Etherscan、合约官方文档或代币项目方获取这些信息,在 Etherscan 上代币页面点击 "Contract" -> "Contract ABI" 即可复制。

要查询某个地址的代币余额,我们需要使用代币合约的 balanceOf(address) 函数。
<?php
// 假设已连接 $web3
// 代币合约地址 (USDT)
$tokenContractAddress = '0xdAC17F958D2ee523a2206206994597C13D831ec7';
// 要查询余额的地址
$queryAddress = '0x742d35Cc6634C0532925a3b844Bc454e4438f44e';
// 代币合约 ABI (简化版,实际使用需要完整的 ERC20 ABI)
$erc20Abi = json_decode('[{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}]', true);
// 创建合约实例
$contract = $web3->eth->contract($erc20Abi, $tokenContractAddress);
// 调用 balanceOf 函数
$contract->call('balanceOf', $queryAddress, function ($err, $balance) {
if ($err !== null) {
echo "Error: " . $err->getMessage();
return;
}
// 余额是 uint256 类型,通常需要根据代币的 decimals 进行转换
// USDT 的 decimals 是 6
$decimals = 6; // 这里需要根据具体代币设置
$formattedBalance = bcdiv($balance->toString(), bcpow(10, $decimals), $decimals);
echo "Token Balance: " . $formattedBalance . "\n";
});
?>
注意:balanceOf 返回的是最小单位(如 wei 对于 ETH,satoshi 对于 BTC),代币也有自己的 decimals(小数位数),通常需要将结果除以 10^decimals 才是我们常见的显示单位,你需要先调用 decimals() 函数获取代币的小数位数。
<?php
// 假设已连接 $web3 和 $contract 实例
// 获取名称
$contract->call('name', function ($err, $name) {
if ($err === null) {
echo "Token Name: " . $name . "\n";
}
});
// 获取符号
$contract->call('symbol', function ($err, $symbol) {
if ($err === null) {
echo "Token Symbol: " . $symbol . "\n";
}
});
// 获取小数位数
$contract->call('decimals', function ($err, $decimals) {
if ($err === null) {
echo "Token Decimals: " . $decimals->toString() . "\n";
}
});
?>
代币转账需要构建一个交易并发送到以太坊网络,这需要发送者的私钥进行签名。
<?php
// 假设已连接 $web3 和 $contract 实例
// 发送者私钥 (极度敏感,实际应用中务必安全处理!)
$privateKey = 'YOUR_PRIVATE_KEY_WITHOUT_0X';
// 接收者地址
$toAddress = '0x742d35Cc6634C0532925a3b844Bc454e4438f44e';
// 转账数量 (假设代币 decimals 是 6,要转 100 个代币)
$amount = bcmul('100', bcpow(10, 6), 0); // 转换为最小单位
// 构建交易参数
$transaction = [
'from' => 'YOUR_SENDER_ADDRESS_WITHOUT_0X', // 发送者地址,从私钥推导或提供
'to' => $tokenContractAddress, // 代币合约地址
'value' => '0x0', // 对于代币转账,value 通常为 0
'gas' => '0x100000', // Gas 限制,根据实际情况调整
'gasPrice' => $web3->eth->gasPrice, // 获取当前建议的 Gas Price
'nonce' => $web3->eth->getTransactionCount('YOUR_SENDER_ADDRESS', 'latest'), // 获取 nonce
'data' => $contract->at('transfer')->encodeABI($toAddress, $amount) // 编码 transfer 函数调用数据
];
// 使用私钥签名交易
$web3->eth->sendRawTransaction($transaction, $privateKey, function ($err, $txHash