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

Email/URL 驗證與自動連結轉換:從 eregi 到 preg 現代化遷移指南

     編輯:PHP 綜合知識

原始碼回顧與淘汰警示

原程式碼使用 eregi()/eregi_replace() (POSIX Regex,**PHP 5.3 棄用、PHP 7.0 移除**),且正則表達式對 RFC 5322 (Email) 與 RFC 3986 (URL) 涵蓋不足。

<?php
function validateEmail($email) { return eregi("^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$", $email); }
function validateURL($url) { return eregi("^((ht|f)tp://)((([a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3}))|(([0-9]{1,3}\.){3}([0-9]{1,3})))((/|\?)[a-z0-9~#%&'_\+=:\?\.-]*)*)$", $url); }
function convertURLS($text) { /* ... eregi_replace ... */ }
function convertMail($text) { /* ... eregi_replace ... */ }
function convertAllLinks($text) { return convertMail(convertURLS($text)); }
?>

現代化重構策略

1. Email 驗證:使用 filter_var + 選擇性 Regex

function validateEmail(string $email): bool {
    // 基礎格式 + 長度限制 (RFC 5321: 254 字元)
    if (strlen($email) > 254) return false;
    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) return false;
    // 選擇性:禁止連續點、開頭結尾點、IP 域名等邊緣案例
    // 一般應用 filter_var 已足夠,嚴格場景可加強正則
    return true;
}

2. URL 驗證:filter_var + parse_url 深度檢查

function validateURL(string $url): bool {
    if (!filter_var($url, FILTER_VALIDATE_URL, FILTER_FLAG_SCHEME_REQUIRED | FILTER_FLAG_HOST_REQUIRED)) {
        return false;
    }
    $parsed = parse_url($url);
    // 限制協議
    if (!in_array($parsed['scheme'] ?? '', ['http', 'https', 'ftp'])) return false;
    // 選擇性:禁止 localhost、私有 IP、IDN 攻擊等
    return true;
}

3. 智慧型自動連結轉換:preg_replace_callback 統一處理

避免「先轉 URL 再轉 Email」導致巢狀 <a> 標籤錯誤,單次掃描同時處理。

function autoLink(string $text, array $options = []): string {
    $defaults = [
        'target' => '_blank',
        'rel' => 'noopener noreferrer',
        'class' => 'auto-link',
        'maxLength' => 80, // 顯示文字截斷
        'emailClass' => 'auto-link-email',
        'urlClass' => 'auto-link-url',
    ];
    $opts = array_merge($defaults, $options);

    // 統一正則:優先匹配 URL (含 scheme),再匹配 www. 開頭,最後匹配 Email
    // 使用 (*SKIP)(*FAIL) 避免重複匹配已轉換區塊 (需 PCRE)
    $pattern = '
        ~
        (?: (https?|ftp):// [^\s<>"\']++ )           # 1: 完整 URL
        |
        (?: www\.[^\s<>"\']++ )                      # 2: www. 開頭
        |
        (?: [\w.+-]++ @ [\w.-]++ \.[a-z]{2,} )      # 3: Email
        ~ix
    ';

    return preg_replace_callback($pattern, function($m) use ($opts) {
        if (!empty($m[1])) { // 完整 URL
            $url = $m[0];
            $display = strlen($url) > $opts['maxLength'] ? substr($url, 0, $opts['maxLength']) . '…' : $url;
            $attrs = 'class="' . htmlspecialchars($opts['urlClass']) . '" target="' . $opts['target'] . '" rel="' . $opts['rel'] . '" href="' . htmlspecialchars($url) . '"';
            return "<a $attrs>$display</a>";
        }
        if (!empty($m[2])) { // www.
            $url = 'https://' . $m[0];
            $display = strlen($m[0]) > $opts['maxLength'] ? substr($m[0], 0, $opts['maxLength']) . '…' : $m[0];
            $attrs = 'class="' . htmlspecialchars($opts['urlClass']) . '" target="' . $opts['target'] . '" rel="' . $opts['rel'] . '" href="' . htmlspecialchars($url) . '"';
            return "<a $attrs>$display</a>";
        }
        if (!empty($m[3])) { // Email
            $email = $m[0];
            $display = strlen($email) > $opts['maxLength'] ? substr($email, 0, $opts['maxLength']) . '…' : $email;
            $attrs = 'class="' . htmlspecialchars($opts['emailClass']) . '" href="mailto:' . htmlspecialchars($email) . '"';
            return "<a $attrs>$display</a>";
        }
        return $m[0];
    }, $text);
}

4. 進階:使用成熟庫 league/html-to-text 或 voku/url-parser

若專案需處理複雜 HTML 內容 (避免破壞既有標籤)、Unicode 域名 (IDN)、短網址展開、安全性掃描,建議引入 Composer 套件:

composer require league/html-to-text voku/url-parser

use League\HTMLToText\HTMLToText;
use Voku\Helper\UrlParser;

$parser = new UrlParser();
$text = $parser->getLinks($htmlContent); // 解析既有連結
// 或使用 HTMLToText 轉純文字後再 autoLink

正則表達式對照表

功能舊式現代建議
Email 驗證eregi(...{2,3})$filter_var(FILTER_VALIDATE_EMAIL) + 長度檢查
URL 驗證複雜 POSIX Regexfilter_var(FILTER_VALIDATE_URL, FLAGS) + parse_url
自動連結eregi_replace 多次掃描preg_replace_callback 單次掃描 + 回呼
編碼處理假設 ASCIIu 修飾符支援 UTF-8/IDN

安全性補充

  • XSS 防護:輸出屬性值必須 htmlspecialchars(),href 協議白名單。
  • SSRF 風險:若後續爬取連結內容,需驗證 Host 非內網 IP。
  • 效能:極長文字 (>1MB) 考慮分塊處理或使用 mb_ereg_replace_callback。

結語

棄用 eregi 系列,擁抱 filter_var (C 級效能) 與 preg_replace_callback (靈活控制)。對於生產系統,優先考慮成熟 Composer 套件處理邊緣案例與安全性,自行維護正則僅適合簡單、可控場景。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved