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

PHP 實用技巧大全 (IP/Email 驗證、表單重整、下載 Header、FTP 斷點續傳)

     編輯:PHP 相關知識

PHP 實用技巧大全 (IP/Email 驗證、表單重整、下載 Header、FTP 斷點續傳)

整理常見 PHP 開發場景的最佳實踐代碼片段,涵蓋驗證、Session/快取控制、檔案下載、FTP 傳輸等。

1. 簡易 IP 位址合法性判斷

<?php
function isValidIp($ip) {
    // IPv4
    if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) return true;
    // IPv6
    if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) return true;
    return false;
}
// 或單行 (僅 IPv4)
if (!strcmp(long2ip(sprintf("%u", ip2long($ip))), $ip)) echo "is ip\n";

2. Email 格式驗證 (RFC 5322 簡化版)

<?php
function isValidEmail($email) {
    return (bool)filter_var($email, FILTER_VALIDATE_EMAIL);
}
// 正則版 (較嚴格)
$regex = '/^[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$/';
if (preg_match($regex, $email)) { /* valid */ }

3. IP 與 Subnet Mask 合法性檢查

<?php
$ip = '192.168.0.84';
$mask = '255.255.255.0';
$network = '192.168.0.0'; // 網路位址

$ipLong = ip2long($ip);
$maskLong = ip2long($mask);
$netLong = ip2long($network);

if (($ipLong & $maskLong) === $netLong) {
    echo "valid ip and mask\n";
}
// CIDR 寫法更簡潔
// 192.168.0.84/24  ->  ip2long('192.168.0.84') & ~((1 << (32-24))-1) === ip2long('192.168.0.0')

4. 解決表單回退後資料消失 (Session 快取控制)

問題:使用 session_start() 會發送 Cache-Control: no-cache,導致瀏覽器不快取頁面,回退時重新請求伺服器,若伺服器未保留 POST 資料則表單清空。

解決方案 (三選一):

<?php
// 方案 1: 允許私有快取 (推薦)
session_cache_limiter('private'); // 必須在 session_start() 前
session_start();

// 方案 2: 手動發送 Header (在 session_start 後)
session_start();
header("Cache-Control: private, max-age=10800"); // 3 小時

// 方案 3: 完全不快取 (敏感頁面)
session_cache_limiter('nocache');
session_start();
  • private:瀏覽器可快取,但 Proxy 不快取;回退時直接讀取快取,表單資料保留。
  • public:Proxy 也可快取 (不建議含敏感資訊頁面)。
  • nocache:完全不快取 (預設)。

5. 檔案下載 Header 標準輸出

<?php
function downloadFile($filePath, $downloadName = null) {
    if (!is_file($filePath) || !is_readable($filePath)) {
        http_response_code(404);
        exit('File not found');
    }
    $downloadName = $downloadName ?? basename($filePath);
    $size = filesize($filePath);

    // 清除輸出緩衝
    if (ob_get_level()) ob_end_clean();

    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename="' . rawurlencode($downloadName) . '"');
    header('Content-Transfer-Encoding: binary');
    header('Accept-Ranges: bytes');
    header('Content-Length: ' . $size);
    header('Cache-Control: private, must-revalidate'); // 允許瀏覽器快取下載檔
    header('Pragma: public'); // HTTP/1.0 相容

    // 分塊輸出避免記憶體耗盡
    $handle = fopen($filePath, 'rb');
    while (!feof($handle)) {
        echo fread($handle, 8192);
        flush(); // 送出給 Web Server
    }
    fclose($handle);
    exit;
}

6. FTP 下載支援斷點續傳 (Range Request)

<?php
function ftpDownloadRange($ftpConn, $remoteFile, $localFile = null) {
    $localFile = $localFile ?? basename($remoteFile);
    $fileSize = ftp_size($ftpConn, $remoteFile);
    if ($fileSize === -1) die("Remote file not found");

    $rangeStart = 0;
    $rangeEnd = $fileSize - 1;

    if (isset($_SERVER['HTTP_RANGE'])) {
        // 解析 Range: bytes=START-END
        preg_match('/bytes=(\d+)-(\d*)/', $_SERVER['HTTP_RANGE'], $matches);
        $rangeStart = (int)$matches[1];
        $rangeEnd = $matches[2] !== '' ? (int)$matches[2] : $fileSize - 1;
        if ($rangeStart >= $fileSize || $rangeEnd >= $fileSize) {
            header('HTTP/1.1 416 Range Not Satisfiable');
            header('Content-Range: bytes */' . $fileSize);
            exit;
        }
        http_response_code(206); // Partial Content
    } else {
        http_response_code(200);
    }

    $contentLength = $rangeEnd - $rangeStart + 1;

    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename="' . rawurlencode($localFile) . '"');
    header('Accept-Ranges: bytes');
    header('Content-Length: ' . $contentLength);
    header('Content-Range: bytes ' . $rangeStart . '-' . $rangeEnd . '/' . $fileSize);
    header('Cache-Control: private');
    header('Pragma: public');

    // FTP 不支援隨機讀取,需下載整檔再切片 (效能差)
    // 生產環境建議用 HTTP 伺服器 (Nginx/X-Sendfile) 或雲存儲簽名 URL
    $tmp = tmpfile();
    ftp_fget($ftpConn, $tmp, $remoteFile, FTP_BINARY);
    fseek($tmp, $rangeStart);
    while (!feof($tmp) && $contentLength > 0) {
        $read = min(8192, $contentLength);
        echo fread($tmp, $read);
        $contentLength -= $read;
        flush();
    }
    fclose($tmp);
}

注意:FTP 協定無原生 Range 支援,上述做法需先下載整檔至暫存再切片,**效能極差**。實務上大檔案下載請直接使用 HTTP 伺服器 (Nginx sendfile/aio)、雲存儲 (S3 簽名 URL) 或 CDN。

7. 額外技巧:快速判斷是否 AJAX 請求

function isAjax() {
    return isset($_SERVER['HTTP_X_REQUESTED_WITH']) &&
           strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest';
}
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved