首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 實用片段集錦:HTTP POST、MySQL 連線、網頁抓取與 Simple HTML DOM 解析

     編輯:PHP 相關知識

1. 發送 HTTP POST 請求 (原生 cURL 封裝)

<?php
/**
 * 發送 POST 請求並返回回應主體
 * @param string $url 請求 URL
 * @param array $data POST 欄位陣列
 * @param array $options 額外 cURL 選項
 * @return string|false 回應主體或 false 失敗
 */
function httpPost(string $url, array $data = [], array $options = []): string|false {
    $ch = curl_init($url);
    $defaultOptions = [
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => http_build_query($data), // 自動編碼 application/x-www-form-urlencoded
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 30,
        CURLOPT_CONNECTTIMEOUT => 10,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_SSL_VERIFYPEER => true,
        CURLOPT_SSL_VERIFYHOST => 2,
        CURLOPT_USERAGENT => 'MyApp/1.0 (+https://example.com)',
        CURLOPT_HTTPHEADER => [
            'Accept: application/json',
            'Content-Type: application/x-www-form-urlencoded',
        ],
    ];
    curl_setopt_array($ch, $defaultOptions + $options);
    
    $response = curl_exec($ch);
    $errno = curl_errno($ch);
    $error = curl_error($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    
    if ($errno !== 0) {
        error_log("cURL 錯誤 [$errno]: $error (URL: $url)");
        return false;
    }
    if ($httpCode < 200 || $httpCode >= 300) {
        error_log("HTTP 錯誤 $httpCode (URL: $url)");
        return false;
    }
    return $response;
}

// 使用範例
$response = httpPost('https://api.example.com/login', [
    'username' => 'user123',
    'password' => 'secret',
]);
if ($response !== false) {
    $data = json_decode($response, true);
    // 處理 $data...
}
?>

2. 發送 JSON POST 請求 (API 串接常用)

<?php
function httpPostJson(string $url, array $payload, array $options = []): string|false {
    $ch = curl_init($url);
    $json = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR);
    $defaultOptions = [
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => $json,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 30,
        CURLOPT_HTTPHEADER => [
            'Accept: application/json',
            'Content-Type: application/json',
            'Content-Length: ' . strlen($json),
        ],
    ];
    curl_setopt_array($ch, $defaultOptions + $options);
    $response = curl_exec($ch);
    $errno = curl_errno($ch);
    curl_close($ch);
    if ($errno !== 0) return false;
    return $response;
}
?>

3. MySQL 連線與查詢 (PDO 最佳實務)

<?php
/**
 * 建立 PDO 連線 (單例模式)
 */
function getPdo(): PDO {
    static $pdo = null;
    if ($pdo instanceof PDO) return $pdo;
    
    $dsn = 'mysql:host=127.0.0.1;dbname=myapp;charset=utf8mb4';
    $user = 'db_user';
    $pass = 'db_pass';
    
    $pdo = new PDO($dsn, $user, $pass, [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        PDO::ATTR_EMULATE_PREPARES => false, // 使用原生預處理
        PDO::MYSQL_ATTR_SSL_CA => '/path/to/ca.pem', // 如需 SSL
    ]);
    return $pdo;
}

/**
 * 執行查詢並返回所有結果
 */
function fetchAll(string $sql, array $params = []): array {
    $stmt = getPdo()->prepare($sql);
    $stmt->execute($params);
    return $stmt->fetchAll();
}

/**
 * 執行查詢並返回單行
 */
function fetchOne(string $sql, array $params = []): array|false {
    $stmt = getPdo()->prepare($sql);
    $stmt->execute($params);
    return $stmt->fetch();
}

/**
 * 執行寫入 (INSERT/UPDATE/DELETE) 返回影響行數
 */
function execute(string $sql, array $params = []): int {
    $stmt = getPdo()->prepare($sql);
    $stmt->execute($params);
    return $stmt->rowCount();
}

// 使用範例
$users = fetchAll('SELECT id, name, email FROM users WHERE status = ? AND created_at > ?', [1, '2024-01-01']);
$user = fetchOne('SELECT * FROM users WHERE email = ?', ['user@example.com']);
$affected = execute('INSERT INTO logs (message, level) VALUES (?, ?)', ['User logged in', 'info']);
?>

4. 簡單網頁抓取 (file_get_contents / cURL)

<?php
/**
 * 取得網頁原始碼
 * @param string $url
 * @param int $timeout 秒
 * @return string|false
 */
function fetchPage(string $url, int $timeout = 30): string|false {
    // 方法 A:file_get_contents (需 php.ini allow_url_fopen=On)
    $ctx = stream_context_create([
        'http' => [
            'timeout' => $timeout,
            'user_agent' => 'MyApp/1.0',
            'follow_location' => 1,
            'max_redirects' => 5,
        ],
        'ssl' => [
            'verify_peer' => true,
            'verify_peer_name' => true,
        ],
    ]);
    $content = @file_get_contents($url, false, $ctx);
    if ($content !== false) return $content;
    
    // 方法 B:cURL 後備 (更穩健)
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => $timeout,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_SSL_VERIFYPEER => true,
        CURLOPT_USERAGENT => 'MyApp/1.0',
    ]);
    $content = curl_exec($ch);
    curl_close($ch);
    return $content !== false ? $content : false;
}
?>

5. Simple HTML DOM Parser 解析網頁結構

安裝:`composer require sunra/php-simple-html-dom-parser` (支援 PHP 8+、PSR-4)

<?php
require 'vendor/autoload.php';
use Sunra\PhpSimple\HtmlDomParser;

$html = fetchPage('https://example.com/articles');
if ($html === false) die('抓取失敗');

$dom = HtmlDomParser::strGetHtml($html);

// 1. 選取單一元素 (CSS 選擇器)
$title = $dom->find('h1.title', 0)?->plaintext ?? '無標題';

// 2. 選取多個元素並遍歷
$articles = $dom->find('article.post');
foreach ($articles as $article) {
    $link = $article->find('a', 0)?->href ?? '';
    $summary = $article->find('.excerpt', 0)?->plaintext ?? '';
    $date = $article->find('time', 0)?->datetime ?? '';
    echo "[$date] $title: $summary\n";
}

// 3. 屬性操作
$img = $dom->find('img.cover', 0);
if ($img) {
    $src = $img->src;
    $alt = $img->alt;
    $img->src = 'https://cdn.example.com/' . basename($src); // 修改屬性
}

// 4. 移除不需要的元素 (如廣告、腳本)
foreach ($dom->find('script, style, .ads, #footer') as $el) {
    $el->outertext = '';
}

// 5. 輸出清理後的 HTML
$cleanHtml = $dom->save();
?>

6. 進階:非同步並發抓取 (curl_multi)

<?php
function fetchMulti(array $urls, int $maxConcurrent = 10, int $timeout = 30): array {
    $results = [];
    $mh = curl_multi_init();
    $handles = [];
    
    // 初始化所有 handle
    foreach ($urls as $i => $url) {
        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT => $timeout,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_SSL_VERIFYPEER => true,
            CURLOPT_USERAGENT => 'MyApp/1.0',
            CURLOPT_PRIVATE => $url, // 儲存 URL 供識別
        ]);
        curl_multi_add_handle($mh, $ch);
        $handles[(int)$ch] = $ch;
    }
    
    $running = null;
    do {
        // 執行並發
        curl_multi_exec($mh, $running);
        // 等待活動
        curl_multi_select($mh, 0.1);
        
        // 檢查完成的 handle
        while ($info = curl_multi_info_read($mh)) {
            $ch = $info['handle'];
            $url = curl_getinfo($ch, CURLINFO_PRIVATE);
            $errno = curl_errno($ch);
            $response = $errno === 0 ? curl_multi_getcontent($ch) : false;
            $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            
            $results[$url] = [
                'success' => $errno === 0 && $httpCode >= 200 && $httpCode < 300,
                'body' => $response,
                'http_code' => $httpCode,
                'error' => $errno ? curl_error($ch) : null,
            ];
            
            curl_multi_remove_handle($mh, $ch);
            curl_close($ch);
        }
    } while ($running > 0);
    
    curl_multi_cleanup($mh);
    return $results;
}

// 使用:並發抓取 100 個 URL
$urls = array_map(fn($i) => "https://api.example.com/item/$i", range(1, 100));
$results = fetchMulti($urls, 20);
?>

總結與建議

  • HTTP 請求:優先使用 cURL 封裝函式,支援 HTTPS、逾時、錯誤處理、JSON/表單雙模。
  • 資料庫:堅持 PDO + 預處理語句,單例模式複用連線,關閉模擬預處理。
  • 網頁抓取:`file_get_contents` 簡單但受限 `allow_url_fopen`;cURL 更穩健、可控。大量並發用 `curl_multi` 或 Swoole/Fibers。
  • HTML 解析:`Simple HTML DOM` (PHP 版) 語法直覺、支援 CSS 選擇器,適合中小型解析。大型/高效能需求考慮 `DOMDocument` + `DOMXPath` 或 `symfony/dom-crawler`。
  • 安全:驗證 SSL 憑證、過濾輸出防 XSS、限制抓取頻率尊重 `robots.txt`、設定合理 User-Agent。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved