如何用PHP项目实现物流跟踪?

wen java案例 3

本文目录导读:

如何用PHP项目实现物流跟踪?

  1. 集成第三方物流API(推荐)
  2. 数据库设计方案
  3. 物流跟踪功能实现
  4. 前端展示示例
  5. 定时任务自动更新
  6. 注意事项

我来详细介绍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);
}

注意事项

  1. API选择:根据业务量选择合适的API服务商,注意API调用次数限制
  2. 缓存策略:避免频繁调用API,设置合理的缓存时间
  3. 错误处理:处理API调用失败、快递单号错误等情况
  4. 数据安全:保护API密钥,不要在客户端暴露

建议先用免费API(如快递100免费版)测试,业务量大了再考虑付费方案。

抱歉,评论功能暂时关闭!