本文目录导读:

针对PHP项目链上数据的解析、查询与展示,我为你整理了一套完整的技术方案:
链上数据获取方式
通过区块链节点RPC接口
// 以太坊节点RPC调用示例
function getEthBalance($address) {
$data = [
'jsonrpc' => '2.0',
'method' => 'eth_getBalance',
'params' => [$address, 'latest'],
'id' => 1
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://mainnet.infura.io/v3/YOUR_API_KEY');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}
使用区块链数据索引服务
// 使用The Graph API查询
$query = '
{
transfers(first: 10, orderBy: timestamp, orderDirection: desc) {
from
to
value
timestamp
}
}';
$response = file_get_contents('https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v2', false, stream_context_create([
'http' => [
'method' => 'POST',
'header' => 'Content-Type: application/json',
'content' => json_encode(['query' => $query])
]
]));
数据解析处理
ABI解码工具类
class BlockchainDataParser {
// 解析ERC20交易数据
public function parseERC20Transfer($inputData) {
$methodId = substr($inputData, 0, 10);
$params = substr($inputData, 10);
// Transfer方法ID: 0xa9059cbb
if ($methodId === '0xa9059cbb') {
$to = '0x' . substr($params, 24, 40);
$value = hexdec(substr($params, 64, 64));
return [
'to' => $to,
'value' => $this->fromWei($value)
];
}
return null;
}
// Wei转ETH
public function fromWei($wei, $decimals = 18) {
return bcdiv($wei, bcpow('10', $decimals), $decimals);
}
}
事件日志解析
class EventLogParser {
public function parseEventLogs($logs) {
$events = [];
foreach ($logs as $log) {
// 解析主题
$topics = $log['topics'];
// 解析数据
$data = $this->hexToString($log['data']);
$events[] = [
'address' => $log['address'],
'topics' => $topics,
'data' => $data,
'blockNumber' => $log['blockNumber']
];
}
return $events;
}
private function hexToString($hex) {
$string = '';
for ($i = 0; $i < strlen($hex) - 1; $i += 2) {
$string .= chr(hexdec($hex[$i] . $hex[$i + 1]));
}
return $string;
}
}
数据存储与查询
数据库结构设计
CREATE TABLE block_transactions (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
tx_hash VARCHAR(66) UNIQUE NOT NULL,
block_number INT NOT NULL,
from_address VARCHAR(42) NOT NULL,
to_address VARCHAR(42),
value DECIMAL(65, 18),
gas_used BIGINT,
gas_price BIGINT,
input_data TEXT,
status TINYINT DEFAULT 1,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_block_number (block_number),
INDEX idx_from_address (from_address),
INDEX idx_to_address (to_address)
);
数据同步脚本
class BlockchainSync {
private $db;
private $web3;
public function syncLatestBlocks($fromBlock, $toBlock) {
for ($block = $fromBlock; $block <= $toBlock; $block++) {
$blockData = $this->web3->eth_getBlockByNumber($block, true);
if ($blockData) {
$this->processBlockTransactions($blockData);
}
}
}
private function processBlockTransactions($blockData) {
foreach ($blockData['transactions'] as $tx) {
$this->saveTransaction([
'tx_hash' => $tx['hash'],
'block_number' => hexdec($blockData['number']),
'from_address' => $tx['from'],
'to_address' => $tx['to'] ?? null,
'value' => hexdec($tx['value']),
'gas_used' => hexdec($tx['gas']),
'gas_price' => hexdec($tx['gasPrice']),
'input_data' => $tx['input']
]);
}
}
}
数据展示实现
API接口设计
// 交易查询API
Route::get('/transactions/{address}', function($address) {
$transactions = DB::table('block_transactions')
->where('from_address', $address)
->orWhere('to_address', $address)
->orderBy('block_number', 'desc')
->paginate(20);
return response()->json([
'code' => 200,
'data' => $transactions,
'total' => $transactions->total()
]);
});
链上数据可视化
// 使用Highcharts展示交易趋势
class TransactionChartService {
public function getTransactionTrend($days = 30) {
$trendData = [];
for ($i = $days - 1; $i >= 0; $i--) {
$date = date('Y-m-d', strtotime("-$i days"));
$count = DB::table('block_transactions')
->whereDate('created_at', $date)
->count();
$trendData[] = [
'date' => $date,
'count' => $count
];
}
return $trendData;
}
}
前端展示组件
<!-- 区块链交易列表 -->
<div class="transactions-table">
<table>
<thead>
<tr>
<th>交易哈希</th>
<th>区块高度</th>
<th>发送地址</th>
<th>接收地址</th>
<th>金额</th>
<th>时间</th>
</tr>
</thead>
<tbody>
<?php foreach ($transactions as $tx): ?>
<tr>
<td class="tx-hash" title="<?= $tx['tx_hash'] ?>">
<?= substr($tx['tx_hash'], 0, 10) . '...' ?>
</td>
<td><?= $tx['block_number'] ?></td>
<td class="address"><?= substr($tx['from_address'], 0, 6) . '...' ?></td>
<td class="address"><?= substr($tx['to_address'], 0, 6) . '...' ?></td>
<td class="amount">
<?= number_format($tx['value'], 4) ?> ETH
</td>
<td><?= $tx['created_at'] ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<script>
// 实时更新交易数据
function updateTransactions() {
$.ajax({
url: '/api/transactions/latest',
success: function(data) {
// 更新表格数据
updateTable(data.transactions);
}
});
}
setInterval(updateTransactions, 5000);
</script>
性能优化建议
缓存策略
class BlockchainCache {
public function getCachedData($key, $callback, $ttl = 300) {
$cacheKey = "blockchain:{$key}";
// 尝试从缓存获取
$data = Redis::get($cacheKey);
if (!$data) {
// 从区块链获取数据
$data = $callback();
// 存入缓存
Redis::setex($cacheKey, $ttl, json_encode($data));
}
return json_decode($data, true);
}
}
数据索引优化
- 对常用查询字段建立索引
- 使用分区表管理历史数据
- 定期清理过期数据
异步处理
// 使用队列处理区块链数据同步
class ProcessBlockchainData implements ShouldQueue {
public function handle() {
$sync = new BlockchainSync();
// 处理数据同步
}
}
安全注意事项
-
输入验证
// 地址验证 function validateAddress($address) { return preg_match('/^0x[a-fA-F0-9]{40}$/', $address); } -
防SQL注入
// 使用预处理语句 $stmt = $db->prepare("SELECT * FROM transactions WHERE tx_hash = ?"); $stmt->execute([$txHash]); -
速率限制
// API请求限制 Route::middleware('throttle:60,1')->group(function () { Route::get('/api/blockchain/*', 'BlockchainController@index'); });
这套方案涵盖了PHP项目处理链上数据的完整流程,你可以根据具体需求选择合适的组件和实现方式。