以太坊作为全球领先的智能合约平台,其节点接口(通常通过 JSON-RPC 协议暴露)是与区块链进行交互的核心通道,开发者常常需要在后端应用中获取以太坊数据、发送交易或与智能合约交互,ThinkPHP 5 (TP5) 作为一款流行的 PHP 开发框架,可以方便地实现与以太坊节点的通信,本文将详细介绍如何在 TP5 中请求以太坊接口,涵盖环境准备、代码实现及常见注意事项。
环境准备
在开始之前,请确保您的开发环境满足以下条件:
- PHP 环境:已安装 PHP 7.1 或更高版本(TP5 官方推荐)。
- Composer:用于管理 PHP 依赖包。
- TP5 项目:已创建并成功运行的 ThinkPHP 5 项目。
- 以太坊节点:
- 本地节点:运行您自己的以太坊全节点(如 Geth 或 Parity),这需要较好的硬件配置和同步时间。
- 第三方服务:使用 Infura、Alchemy 等提供的以太坊节点服务,这是更便捷的方式,只需注册获取一个 HTTP 或 WebSocket 接口 URL。
- 测试网络:强烈建议在 Goerli(以前是 Ropsten)等测试网络上进行开发和测试,避免消耗真实的 ETH。
核心思路:发送 HTTP POST 请求
以太坊的 JSON-RPC 接口通过 HTTP POST 请求进行通信,TP5 中可以通过其内置的 HttpClient 或者结合第三方 HTTP 客户端库(如 Guzzle)来实现,这里我们主要介绍 TP5 自带的 HttpClient,它轻量且足够使用。
请求的核心要素包括:
- URL:以太坊节点的 JSON-RPC 接口地址(
https://mainnet.infura.io/v3/YOUR_PROJECT_ID或http://localhost:8545)。 - Method:
POST。 - Headers:
Content-Type: application/json。 - Body:一个 JSON 对象,包含以下字段:
jsonrpc: 版本,通常为"2.0"。method: 要调用的以太坊方法名(如eth_blockNumber,eth_getBalance,eth_sendRawTransaction)。params: 方法所需的参数数组,顺序很重要。id: 请求 ID,可以是任意唯一值,用于响应匹配。
TP5 中实现以太坊接口请求
创建服务类(推荐)
为了代码的复用和可维护性,我们建议创建一个专门的服务类来处理以太坊相关的请求,在 application/common/service 目录下创建 EthereumService.php:
// application/common/service/EthereumService.php
namespace app\common\service;
use think\facade\Log;
class EthereumService
{
private $rpcUrl;
private $httpClient;
public function __construct($rpcUrl)
{
$this->rpcUrl = $rpcUrl;
// 初始化 HttpClient
$this->httpClient = \think\facade\Http::create([
'timeout' => 30, // 设置超时时间
]);
}
/**
* 发送 JSON-RPC 请求到以太坊节点
* @param string $method 方法名
* @param array $params 参数数组
* @param int $id 请求ID
* @return array|bool 响应数据或false
*/
public function sendRequest($method, array $params = [], $id = 1)
{
$payload = [
'jsonrpc' => '2.0',
'method' => $method,
'params' => $params,
'id' => $id,
];
try {
// 发送 POST 请求
$response = $this->httpClient
->post($this->rpcUrl, $payload)
->header(['Content-Type' => 'application/json'])
->json();
// 检查响应是否有错误
if (isset($response['error']) && $response['error'] !== null) {
Log::error('以太坊节点请求错误: ' . json_encode($response['error']));
return false;
}
return $response['result'] ?? false;
} catch (\Exception $e) {
Log::error('以太坊节点请求异常: ' . $e->getMessage());
return false;
}
}
}
在控制器中调用服务
假设我们有一个 Index 控制器,想要获取最新区块号:
// application/index/controller/Index.php
namespace app\index\controller;
use app\common\service\EthereumService;
use think\facade\View;
class Index
{
public function index()
{
// 替换为您的以太坊节点 RPC URL
// Infura 的 Goerli 测试网 URL
$rpcUrl = 'https://goerli.infura.io/v3/YOUR_PROJECT_ID';
$ethService = new EthereumService($rpcUrl);
// 获取最新区块号
$latestBlockNumber = $ethService->sendRequest('eth_blockNumber');
if ($latestBlockNumber !== false) {
// 以太坊返回的十六进制数,转换为十进制
$blockNumberDec = hexdec($latestBlockNumber);
View::assign('blockNumber', $blockNumberDec);
return View::fetch('index', ['message' => '最新区块号: ' . $blockNumberDec]);
} else {
return View::fetch('index', ['message' => '获取最新区块号失败,请检查日志']);
}
}
// 其他方法示例:获取账户余额
public function getBalance($address = '0x742d35Cc6634C0532925a3b844Bc454e4438f44e')
{
$rpcUrl = 'https://goerli.infura.io/v3/YOUR_PROJECT_ID';
$ethService = new EthereumService($rpcUrl);
// eth_getBalance 需要地址和区块参数('latest' 表示最新区块)
$balance = $ethService->sendRequest('eth_getBalance', [$address, 'latest']);
if ($balance !== false) {
// 余额是十六进制,单位是 Wei,转换为 Ether
$balanceInEther = hexdec($balance) / pow(10, 18);
return json(['address' => $address, 'balance_ether' => $balanceInEther]);
} else {
return json(['error' => '获取余额失败'], 500);
}
}
}
创建视图文件 (可选)
在 application/index/view/index.html 中:
<!DOCTYPE html>
<html>
<head>TP5 以太坊接口示例</title>
</head>
<body>
<h1>以太坊节点交互示例</h1>
<p>{$message|default='请访问相关方法'}</p>
<!-- 可以添加一个链接或按钮来触发 getBalance 方法 -->
<a href="{:url('index/getBalance', ['address' => '0x742d35Cc6634C0532925a
3b844Bc454e4438f44e'])}">获取示例地址余额</a>
</body>
</html>
常见以太坊接口调用示例
在 EthereumService 中,我们可以轻松调用各种以太坊方法:
- 获取账户余额:
$ethService->sendRequest('eth_getBalance', ['0x...', 'latest']); - 获取交易详情:
$ethService->sendRequest('eth_getTransactionByHash', ['0x...']); - 发送交易:
这通常需要构造一个原始交易(rawTransaction),并使用账户的私钥进行签名,发送交易本身不直接在服务中做签名(不安全),而是接收已签名的交易数据。
$signedRawTransaction = '0x...'; // 已签名的原始交易字符串 $ethService->sendRequest('eth_sendRawTransaction', [$signedRawTransaction]); - 调用智能合约:
需要使用
eth_call来读取合约状态,或eth_sendTransaction来写入合约,这通常需要构造 ABI(应用程序二进制接口)编码的数据,可以使用web3.php等库辅助构造。
注意事项与最佳实践
- 安全性:
- 绝对不要将私钥或敏感信息硬编码在代码中或提交到版本控制,应使用环境变量(如 TP5 的
.env文件)或安全的配置管理服务来存储。 - 如果涉及发送交易,签名过程应在安全的环境
- 绝对不要将私钥或敏感信息硬编码在代码中或提交到版本控制,应使用环境变量(如 TP5 的