本文目录导读:

我来详细介绍PHP项目中实现物流跟踪的几种方案:
集成第三方物流API(推荐)
主流物流API服务商
// 1. 快递100 API
$apiKey = 'your_api_key';
$customer = 'your_customer_id';
$trackingNumber = 'SF1234567890';
$company = 'shunfeng'; // 快递公司编码
$url = "https://api.kuaidi100.com/api?id={$apiKey}&com={$company}&nu={$trackingNumber}&show=0&muti=1&order=desc";
$response = file_get_contents($url);
$data = json_decode($response, true);
// 2. 菜鸟物流API
// 需要注册成为菜鸟开发者,获取appKey和appSecret
封装物流查询类
<?php
class LogisticsTracker {
private $apiKey;
private $apiSecret;
public function __construct($apiKey, $apiSecret) {
$this->apiKey = $apiKey;
$this->apiSecret = $apiSecret;
}
// 快递100查询示例
public function trackByExpress100($companyCode, $trackingNumber) {
$url = "https://api.kuaidi100.com/api";
$postData = [
'customer' => $this->apiKey,
'sign' => md5($postData['param'] . $this->apiSecret . $this->apiKey),
'param' => json_encode([
'com' => $companyCode,
'num' => $trackingNumber
])
];
return $this->curlPost($url, $postData);
}
private function curlPost($url, $data) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}
}
数据库设计方案
-- 物流信息表
CREATE TABLE logistics_tracking (
id INT PRIMARY KEY AUTO_INCREMENT,
order_id INT NOT NULL,
tracking_number VARCHAR(50) UNIQUE,
company_code VARCHAR(20), -- 快递公司编码
company_name VARCHAR(50), -- 快递公司名称
status ENUM('pending','shipped','in_transit','delivered','failed') DEFAULT 'pending',
current_location VARCHAR(200),
estimated_delivery DATETIME,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_order (order_id),
INDEX idx_tracking (tracking_number)
);
-- 物流轨迹明细表
CREATE TABLE logistics_tracks (
id INT PRIMARY KEY AUTO_INCREMENT,
tracking_id INT,
status VARCHAR(50),
location VARCHAR(200),
description TEXT,
operator VARCHAR(50),
track_time DATETIME,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (tracking_id) REFERENCES logistics_tracking(id)
);
物流跟踪功能实现
查询物流信息
<?php
class LogisticsService {
private $db;
private $tracker;
public function __construct($db, $tracker) {
$this->db = $db;
$this->tracker = $tracker;
}
// 创建物流记录
public function createTracking($orderId, $trackingNumber, $companyCode) {
$sql = "INSERT INTO logistics_tracking (order_id, tracking_number, company_code, company_name)
VALUES (?, ?, ?, ?)";
$stmt = $this->db->prepare($sql);
$companyName = $this->getCompanyName($companyCode);
$stmt->execute([$orderId, $trackingNumber, $companyCode, $companyName]);
return $this->db->lastInsertId();
}
// 查询物流信息
public function getTrackingInfo($trackingId) {
// 先从数据库获取缓存
$sql = "SELECT * FROM logistics_tracking WHERE id = ?";
$stmt = $this->db->prepare($sql);
$stmt->execute([$trackingId]);
$tracking = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$tracking) {
return null;
}
// 检查是否需要更新(缓存策略:30分钟更新一次)
if ($this->needUpdate($tracking)) {
$this->updateTrackingInfo($tracking);
}
// 获取轨迹详情
$tracks = $this->getTracks($trackingId);
$tracking['tracks'] = $tracks;
return $tracking;
}
// 更新物流信息
private function updateTrackingInfo(&$tracking) {
$result = $this->tracker->trackByExpress100(
$tracking['company_code'],
$tracking['tracking_number']
);
if (isset($result['data']) && !empty($result['data'])) {
// 更新主表
$latest = $result['data'][0];
$sql = "UPDATE logistics_tracking SET
current_location = ?,
status = ?,
updated_at = NOW()
WHERE id = ?";
$stmt = $this->db->prepare($sql);
$stmt->execute([
$latest['context'],
$this->mapStatus($result['state']),
$tracking['id']
]);
// 更新轨迹明细
$this->updateTracks($tracking['id'], $result['data']);
}
}
// 更新轨迹明细
private function updateTracks($trackingId, $tracks) {
foreach ($tracks as $track) {
$sql = "INSERT IGNORE INTO logistics_tracks
(tracking_id, status, location, description, track_time)
VALUES (?, ?, ?, ?, ?)";
$stmt = $this->db->prepare($sql);
$stmt->execute([
$trackingId,
$track['status'] ?? '',
$track['context'],
$track['desc'] ?? '',
$track['time']
]);
}
}
}
前端展示示例
<!-- 物流跟踪页面 -->
<div class="logistics-tracking">
<h3>物流跟踪</h3>
<div class="tracking-header">
<span class="company">快递公司:<?php echo htmlspecialchars($tracking['company_name']); ?></span>
<span class="number">运单号:<?php echo htmlspecialchars($tracking['tracking_number']); ?></span>
<span class="status">状态:<?php echo $this->getStatusText($tracking['status']); ?></span>
</div>
<div class="tracking-timeline">
<?php foreach ($tracking['tracks'] as $track): ?>
<div class="track-item">
<div class="track-time"><?php echo date('Y-m-d H:i:s', strtotime($track['track_time'])); ?></div>
<div class="track-content">
<p class="location"><?php echo htmlspecialchars($track['location']); ?></p>
<p class="desc"><?php echo htmlspecialchars($track['description']); ?></p>
<p class="operator">操作人:<?php echo htmlspecialchars($track['operator']); ?></p>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
<style>
.tracking-timeline {
position: relative;
padding: 20px 0;
}
.track-item {
position: relative;
padding-left: 30px;
margin-bottom: 20px;
border-left: 2px solid #e0e0e0;
}
.track-item:last-child {
border-left-color: #4CAF50;
}
.track-time {
color: #666;
font-size: 14px;
margin-bottom: 5px;
}
.track-content {
background: #f5f5f5;
padding: 10px;
border-radius: 4px;
}
.track-content .location {
font-weight: bold;
color: #333;
}
</style>
定时任务自动更新
// cron.php - 定时更新物流信息
<?php
// 每30分钟执行一次
require_once 'config.php';
$db = new PDO("mysql:host=localhost;dbname=your_db", "user", "password");
$tracker = new LogisticsTracker($apiKey, $apiSecret);
$service = new LogisticsService($db, $tracker);
// 获取需要更新的物流记录
$sql = "SELECT * FROM logistics_tracking
WHERE status NOT IN ('delivered', 'failed')
AND updated_at < DATE_SUB(NOW(), INTERVAL 30 MINUTE)";
$stmt = $db->query($sql);
while ($tracking = $stmt->fetch(PDO::FETCH_ASSOC)) {
$service->updateTrackingInfo($tracking);
// 防止API限制,每次请求间隔1秒
sleep(1);
}
注意事项
- API选择:根据业务量选择合适的API服务商,注意API调用次数限制
- 缓存策略:避免频繁调用API,设置合理的缓存时间
- 错误处理:处理API调用失败、快递单号错误等情况
- 数据安全:保护API密钥,不要在客户端暴露
建议先用免费API(如快递100免费版)测试,业务量大了再考虑付费方案。