怎样在PHP项目中实现询价比价?

wen java案例 9

本文目录导读:

怎样在PHP项目中实现询价比价?

  1. 核心功能模块设计
  2. 数据库表结构设计(MySQL)
  3. 基础代码实现
  4. 进阶功能实现
  5. 注意事项
  6. 完整示例:小项目快速实现

在PHP项目中实现询价比价功能,需要处理数据采集价格比较用户交互等环节,下面提供一个从简单到复杂的实现思路和代码示例。

核心功能模块设计

一个完整的询价比价系统通常包含三部分:

  1. 询价管理(用户发起询价请求)
  2. 报价管理(供应商/系统返回报价)
  3. 比价展示(对比显示最低/最优价格)

数据库表结构设计(MySQL)

-- 询价表
CREATE TABLE inquiries (
    id INT AUTO_INCREMENT PRIMARY KEY,
    user_id INT NOT NULL,
    product_name VARCHAR(255) NOT NULL,
    product_description TEXT,
    quantity INT DEFAULT 1,
    status ENUM('pending', 'quoted', 'completed') DEFAULT 'pending',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 报价表
CREATE TABLE quotes (
    id INT AUTO_INCREMENT PRIMARY KEY,
    inquiry_id INT NOT NULL,
    supplier_name VARCHAR(255) NOT NULL,
    price DECIMAL(10,2) NOT NULL,
    currency VARCHAR(10) DEFAULT 'CNY',
    delivery_time VARCHAR(100),
    remarks TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (inquiry_id) REFERENCES inquiries(id) ON DELETE CASCADE
);

基础代码实现

用户发起询价

<?php
// InquiryController.php
class InquiryController {
    private $db;
    public function __construct($db) {
        $this->db = $db;
    }
    // 用户提交询价
    public function createInquiry($userId, $productName, $description, $quantity) {
        $stmt = $this->db->prepare("INSERT INTO inquiries (user_id, product_name, product_description, quantity) VALUES (?, ?, ?, ?)");
        $stmt->execute([$userId, $productName, $description, $quantity]);
        return $this->db->lastInsertId();
    }
    // 供应商提交报价
    public function submitQuote($inquiryId, $supplierName, $price, $currency, $deliveryTime) {
        $stmt = $this->db->prepare("INSERT INTO quotes (inquiry_id, supplier_name, price, currency, delivery_time) VALUES (?, ?, ?, ?, ?)");
        $stmt->execute([$inquiryId, $supplierName, $price, $currency, $deliveryTime]);
        // 更新询价状态
        $this->updateInquiryStatus($inquiryId, 'quoted');
        return true;
    }
    // 获取某次询价的所有报价(比价用)
    public function getQuotesForComparison($inquiryId) {
        $stmt = $this->db->prepare("
            SELECT q.*, i.product_name 
            FROM quotes q 
            JOIN inquiries i ON q.inquiry_id = i.id 
            WHERE q.inquiry_id = ? 
            ORDER BY q.price ASC
        ");
        $stmt->execute([$inquiryId]);
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }
    private function updateInquiryStatus($inquiryId, $status) {
        $stmt = $this->db->prepare("UPDATE inquiries SET status = ? WHERE id = ?");
        $stmt->execute([$status, $inquiryId]);
    }
}

比价展示页面

<?php
// compare.php - 比价显示页面
require_once 'InquiryController.php';
$controller = new InquiryController($db);
$inquiryId = $_GET['id'] ?? 0;
$quotes = $controller->getQuotesForComparison($inquiryId);
// 获取最低价和最高价
$minPrice = min(array_column($quotes, 'price'));
$maxPrice = max(array_column($quotes, 'price'));
?>
<!DOCTYPE html>
<html>
<head>比价结果</title>
    <style>
        .comparison-table { width: 100%; border-collapse: collapse; }
        .comparison-table th, .comparison-table td { padding: 12px; text-align: left; border-bottom: 1px solid #ddd; }
        .best-price { background-color: #d4edda; font-weight: bold; }
        .worst-price { background-color: #f8d7da; }
    </style>
</head>
<body>
    <h2>产品: <?= htmlspecialchars($quotes[0]['product_name'] ?? 'N/A') ?></h2>
    <table class="comparison-table">
        <thead>
            <tr>
                <th>供应商</th>
                <th>价格 (<?= htmlspecialchars($quotes[0]['currency'] ?? 'CNY') ?>)</th>
                <th>交货时间</th>
                <th>备注</th>
            </tr>
        </thead>
        <tbody>
            <?php foreach ($quotes as $quote): ?>
            <tr class="<?= $quote['price'] == $minPrice ? 'best-price' : ($quote['price'] == $maxPrice ? 'worst-price' : '') ?>">
                <td><?= htmlspecialchars($quote['supplier_name']) ?></td>
                <td>¥<?= number_format($quote['price'], 2) ?></td>
                <td><?= htmlspecialchars($quote['delivery_time'] ?? 'N/A') ?></td>
                <td><?= htmlspecialchars($quote['remarks'] ?? '') ?></td>
            </tr>
            <?php endforeach; ?>
        </tbody>
    </table>
</body>
</html>

进阶功能实现

自动化数据采集(爬虫比价)

如果需要从外部网站自动采集价格,可以使用 GuzzlecURL

<?php
// PriceCrawler.php
use GuzzleHttp\Client;
class PriceCrawler {
    private $client;
    public function __construct() {
        $this->client = new Client([
            'timeout'  => 10.0,
            'headers' => [
                'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
            ]
        ]);
    }
    // 爬取某电商平台价格(示例:京东)
    public function scrapeJDPrice($productUrl) {
        try {
            $response = $this->client->get($productUrl);
            $html = (string) $response->getBody();
            // 使用正则或DomDocument提取价格
            preg_match('/"price"[^"]*"?[^"]*"?\s*:\s*"?([\d.]+)"/', $html, $matches);
            return $matches[1] ?? null;
        } catch (Exception $e) {
            error_log("Failed to scrape: " . $e->getMessage());
            return null;
        }
    }
    // 批量比价
    public function comparePrices(array $urls) {
        $results = [];
        foreach ($urls as $source => $url) {
            $price = $this->scrapeJDPrice($url);
            if ($price) {
                $results[] = [
                    'source' => $source,
                    'price'  => $price,
                    'url'    => $url
                ];
            }
        }
        // 按价格排序
        usort($results, function($a, $b) {
            return $a['price'] <=> $b['price'];
        });
        return $results;
    }
}

使用缓存提高性能

缓存爬取结果,避免频繁请求:

<?php
// PriceCache.php
class PriceCache {
    private $cacheDir = '/tmp/price_cache/';
    public function get($key) {
        $file = $this->cacheDir . md5($key) . '.cache';
        if (file_exists($file) && (time() - filemtime($file) < 3600)) { // 1小时有效
            return unserialize(file_get_contents($file));
        }
        return null;
    }
    public function set($key, $value) {
        if (!is_dir($this->cacheDir)) {
            mkdir($this->cacheDir, 0777, true);
        }
        $file = $this->cacheDir . md5($key) . '.cache';
        file_put_contents($file, serialize($value));
    }
}
// 使用方式
$cache = new PriceCache();
$cacheKey = "price_jd_" . md5($productUrl);
$price = $cache->get($cacheKey);
if (!$price) {
    $crawler = new PriceCrawler();
    $price = $crawler->scrapeJDPrice($productUrl);
    $cache->set($cacheKey, $price);
}

基于比较器的智能比价

<?php
// PriceComparator.php
class PriceComparator {
    // 多条件比较器
    public function compare($quotes, $criteria = ['price' => 'asc', 'delivery_time' => 'asc']) {
        usort($quotes, function($a, $b) use ($criteria) {
            foreach ($criteria as $field => $order) {
                if (!isset($a[$field]) || !isset($b[$field])) continue;
                $result = $a[$field] <=> $b[$field];
                if ($result !== 0) {
                    return ($order === 'desc') ? -$result : $result;
                }
            }
            return 0;
        });
        return $quotes;
    }
    // 综合评分(价格权重60%,交货时间40%)
    public function score($quote, $maxPrice, $minDeliveryDays, $maxDeliveryDays) {
        $priceScore = 100 - (($quote['price'] - $minPrice) / ($maxPrice - $minPrice)) * 100;
        // 交货时间得分假设日期转换为天
        $deliveryScore = 100; 
        if (isset($quote['delivery_days'])) {
            $deliveryScore = 100 - (($quote['delivery_days'] - $minDeliveryDays) / ($maxDeliveryDays - $minDeliveryDays)) * 100;
        }
        return $priceScore * 0.6 + $deliveryScore * 0.4;
    }
}

注意事项

法律与合规

  • 自动化采集需遵守目标网站的 robots.txt 和用户协议
  • 某些平台(如淘宝)禁止爬虫,可考虑使用官方API(如1688开放平台)

安全过滤

  • 对用户输入进行严格过滤,防止XSS
  • 使用参数化查询防止SQL注入

性能优化

  • 使用 Redis 缓存爬取结果
  • 异步处理批量比价(使用队列 like Laravel Horizon)
  • 考虑使用 Elasticsearch 做价格索引和搜索

备选方案:使用第三方API

如果不想自己爬虫,可以对接:

  • 1688开放平台(批发市场数据)
  • 京东联盟API(电商价格数据)
  • 比价网站API(如慢慢买、什么值得买)

完整示例:小项目快速实现

如果项目较小,可以简化为纯手动录入模式:

// 简化版:管理员手动录入报价
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $productName = $_POST['product_name'];
    $supplier = $_POST['supplier'];
    $price = $_POST['price'];
    // 存储到数据库或文件
    $data = json_decode(file_get_contents('prices.json'), true) ?? [];
    $data[] = [
        'product' => $productName,
        'supplier' => $supplier,
        'price' => $price,
        'date' => date('Y-m-d')
    ];
    file_put_contents('prices.json', json_encode($data));
}
// 显示比价
$prices = json_decode(file_get_contents('prices.json'), true) ?? [];
usort($prices, function($a, $b) {
    return $a['price'] <=> $b['price'];
});
echo "<table><tr><th>产品</th><th>供应商</th><th>价格</th></tr>";
foreach ($prices as $p) {
    echo "<tr><td>{$p['product']}</td><td>{$p['supplier']}</td><td>¥{$p['price']}</td></tr>";
}
echo "</table>";

根据你的项目规模和需求,可以选择手动录入、数据库存储、爬虫自动采集或对接第三方API。数据准确性和时效性是比价系统的核心价值

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