随着区块链技术的飞速发展,以太坊作为领先的智能合约平台,其应用日益广泛,对于许多基于 PHP 开发的 Web 应用而言,能够与以太坊网络进行交互(如查询余额、发送交易、调用智能合约等)已成为一项重要需求,本文将详细介绍如何使用 PHP 与以太坊 Web3 接口进行通信,并提供核心代码示例,帮助开发者快速上手。

理解 Web3 接口与 PHP 交互方式

以太坊本身没有直接为 PHP 设计的原生 API,PHP 与以太坊的交互通常通过以下几种方式实现:

  1. JSON-RPC 接口:这是最常用和推荐的方式,以太坊节点(如 Geth, Parity)或第三方服务(如 Infura, Alchemy)提供 JSON-RPC API,PHP 作为客户端,通过 HTTP 请求向这些端点发送符合 JSON-RPC 2.0 规范的请求,并接收响应。
  2. Web3.js 的 PHP 封装库:社区存在一些将 JavaScript 的 Web3.js 库功能封装成 PHP 可用库的尝试,但不如直接调用 JSON-RPC 流行和稳定。
  3. 以太坊 PHP 客户端库:一些专门为 PHP 开发的库,如 web3php(原 php-ethereum),它们内部也是通过调用 JSON-RPC 接口来简化操作,提供了更友好的 PHP 风格 API。

我们将重点介绍使用 JSON-RPC 直接调用 和使用成熟的 PHP Web3 库(如 web3p/web3.php 这两种主流方法。

环境准备

在开始编码之前,确保你的开发环境满足以下条件:

  1. PHP 环境:PHP 7.4 或更高版本。
  2. Composer:PHP 的依赖管理工具,用于安装第三方库。
  3. 以太坊节点访问
    • 本地节点:运行自己的以太坊节点(如 Geth),并开启 JSON-RPC 服务(默认端口 8545)。
    • 第三方服务:注册 Infura、Alchemy 等服务,获取一个 HTTP 或 WebSocket URL,对于初学者,第三方服务更为便捷,无需同步整个区块链。
  4. 以太坊钱包:用于测试的账户,包含私钥(注意:私钥需妥善保管,切勿泄露)。

方法一:直接通过 cURL 调用 JSON-RPC 接口

这种方式不依赖额外库,适合理解底层交互原理。

示例代码:获取以太坊最新区块号

<?php
$rpcUrl = 'https://mainnet.infura.io/v3/YOUR_INFURA_PROJECT_ID'; // 替换为你的 Infura URL 或本地节点地址
$data = [
    'jsonrpc' => '2.0',
    'method' => 'eth_blockNumber',
    'params' => [],
    'id' => 1
];
$ch = curl_init($rpcUrl);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    'Content-Length: ' . strlen(json_encode($data))
]);
$response = curl_exec($ch);
if (curl_errno($ch)) {
    echo 'cURL Error: ' . curl_error($ch);
    curl_close($ch);
    exit;
}
curl_close($ch);
$result = json_decode($response, true);
if (isset($result['result'])) {
    $blockNumberHex = $result['result'];
    $blockNumber = hexdec($blockNumberHex);
    echo "Latest Block Number: " . $blockNumber . PHP_EOL;
} else {
    echo "Error: " . ($result['error']['message'] ?? 'Unknown error') . PHP_EOL;
}
?>

代码说明:

  • $rpcUrl:替换为你的以太坊节点 JSON-RPC 端点。
  • $data:构建 JSON-RPC 请求体,包含 jsonrpc 版本、method(要调用的方法,如 eth_blockNumber, eth_getBalance 等)、params(方法参数,若无则为空数组)和 id(请求标识符)。
  • 使用 cURL 发送 POST 请求,并设置请求头和请求体。
  • 解析响应 JSON,获取结果或错误信息。

方法二:使用 web3p/web3.php 库(推荐)

为了简化开发,我们可以使用成熟的 PHP Web3 库,如 web3p/web3.php,它提供了更面向对象的接口,封装了底层 JSON-RPC 的细节。

安装库

composer require web3p/web3.php

示例代码:获取账户余额并发送交易

<?php
require 'vendor/autoload.php';
use Web3\Web3;
use Web3\Providers\HttpProvider;
use Web3\RequestManagers\HttpRequestManager;
use Web3\Utils;
use Web3\Eth;
$rpcUrl = 'https://mainnet.infura.io/v3/YOUR_INFURA_PROJECT_ID'; // 替换为你的 Infura URL
$privateKey = 'YOUR_ACCOUNT_PRIVATE_KEY'; // 替换为你的账户私钥(仅用于测试,生产环境务必安全存储)
$toAddress = '0xRecipientAddressHere'; // 接收地址
// 创建 Web3 实例
$web3 = new Web3(new HttpProvider(new HttpRequestManager($rpcUrl, 5)));
$eth = $eth = new Eth($web3->provider);
// 1. 获取发送方账户余额
$fromAddress = '0xYourSenderAddressHere'; // 发送方地址
$eth->getBalance($fromAddress, function ($err, $balance) {
    if ($err !== null) {
        echo "Error getting balance: " . $err->getMessage() . PHP_EOL;
        return;
    }
    $balanceInEth = Utils::fromWei($balance, 'ether');
    echo "Sender Balance: " . $balanceInEth . " ETH" . PHP_EOL;
});
// 2. 发送交易 (注意:这需要 gas,并且私钥会暴露在代码中,仅用于演示)
$value = Utils::toWei('0.01', 'ether'); // 发送 0.01 ETH
$gasLimit = '21000'; // 转账默认 gas limit
$gasPrice = '20000000000'; // gas price, 20 Gwei
$eth->sendTransaction([
    'from' => $fromAddress,
    'to' => $toAddress,
    'value' => $value,
    'gas' => $gasLimit,
    'gasPrice' => $gasPrice,
], $privateKey, function ($err, $transactionHash) {
    if ($err !== null) {
        echo "Error sending transaction: " . $err->getMessage() . PHP_EOL;
        return;
    }
    echo "Transaction sent! Hash: " . $transactionHash . PHP_EOL;
});
?>

代码说明:

  • 引入自动加载器require 'vendor/autoload.php';
  • 创建 Web3 实例:通过 HttpProvider 指定 JSON-RPC 端点。
  • 获取余额
    • $eth->getBalance($address, $callback):获取指定地址的余额,返回的是 Wei 单位,使用 Utils::fromWei() 转换为 ETH。
  • 发送交易
    • $eth->sendTransaction($transactionParams, $privateKey, $callback):发送交易。
    • $transactionParams 包含 from, to, value(Wei 单位), gas, gasPrice 等参数。
    • $privateKey:发送方账户的私钥,用于签名交易。生产环境中切勿将私钥硬编码在代码中,应使用环境变量或密钥管理服务。
    • 成功后返回交易哈希。

调用智能合约

调用智能合约是 Web3 交互的重要部分,使用 web3p/web3.php 库,你需要先加载合约的 ABI(Application Binary Interface)和字节码(Bytecode,通常部署后不需要)。

简化的智能合约调用示例(假设已部署一个简单的存储合约):

// 假设 $web3 和 $eth 实例已创建如上
$contractAddress = '0xYourDeployedContractAddress';
$contractAbi = '[...你的合约 ABI JSON 数组...]'; // [{"constant":false,"inputs":[...],"name":"set","outputs":[...],"type":"function"}, ...]
$contract = new Contract($web3->provider, $contractAbi);
$contract->at($contractAddress); // 绑定到已部署的合约