實務開發中常需處理 URL、HTML、路徑、表格等結構化資料。本文整理 6 個高復用工具函數:當前 URL 獲取、全形數字轉半形、HTML 標籤清理/轉換、相對路徑轉絕對、連結提取、HTML 表格轉陣列,附原理分析與改良版。
function get_php_url(): string {
if (!empty($_SERVER['REQUEST_URI'])) {
return $_SERVER['REQUEST_URI'];
}
// 相容舊環境/CLI
$script = $_SERVER['PHP_SELF'] ?? '';
$query = $_SERVER['QUERY_STRING'] ?? '';
return $query ? $script . '?' . $query : $script;
}
// 改良版:取得完整絕對 URL
function getCurrentFullUrl(): string {
$scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || ($_SERVER['SERVER_PORT'] ?? 80) == 443
? 'https' : 'http';
$host = $_SERVER['HTTP_HOST'] ?? ($_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT']);
$uri = get_php_url();
return "{$scheme}://{$host}{$uri}";
}
function GetAlabNum(string $fnum): string {
// 全形 → 半形映射 (含數字、常用符號)
$full = ['0','1','2','3','4','5','6','7','8','9','.','-','+',':'];
$half = ['0','1','2','3','4','5','6','7','8','9','.','-','+',':'];
$fnum = str_replace($full, $half, $fnum);
// 進一步過濾:僅保留 ASCII 可列印字元 (移除中文等)
$result = '';
$len = strlen($fnum);
for ($i = 0; $i < $len; $i++) {
if (ord($fnum[$i]) > 0x80) { $i++; continue; } // 跳過雙位元組字元
$result .= $fnum[$i];
}
return $result !== '' ? $result : '0';
}
// 現代版:支援 Unicode 正規化 (需 intl 擴展)
function toHalfWidthModern(string $str): string {
if (class_exists('Normalizer')) {
$str = Normalizer::normalize($str, Normalizer::NFKC); // 全形字母/數字/符號自動轉半形
}
// 保留 ASCII 可列印字元
return preg_replace('/[^\x20-\x7E]/', '', $str);
}
function Text2Html(string $txt): string {
$txt = str_replace(' ', ' ', $txt); // 雙空格 → 單空格 (視需求)
$txt = str_replace('<', '<', $txt); // < → <
$txt = str_replace('>', '>', $txt); // > → >
$txt = preg_replace('/[\r\n]{1,}/', "
\r\n", $txt); // 換行 →
return $txt;
}
// 現代標準:htmlspecialchars (必加 ENT_QUOTES | ENT_HTML5)
function Text2HtmlModern(string $txt): string {
return nl2br(htmlspecialchars($txt, ENT_QUOTES | ENT_HTML5, 'UTF-8'));
}
function ClearHtml(string $str): string {
$str = str_replace('<', '<', $str);
$str = str_replace('>', '>', $str);
return $str;
}
// 正確做法:strip_tags (可選保留標籤)
function ClearHtmlModern(string $str, string $allowable_tags = ''): string {
return strip_tags($str, $allowable_tags);
// 範例:strip_tags($html, '
') 保留段落、換行、粗體
}
function relative_to_absolute(string $content, string $baseUrl): string {
// 解析基礎 URL
$parsed = parse_url($baseUrl);
$scheme = $parsed['scheme'] ?? 'http';
$host = $parsed['host'] ?? '';
if (!$host) return $content;
$base = "{$scheme}://{$host}";
// href="/path" → href="https://host/path"
$content = preg_replace('/href\s*=\s*["\']\//', 'href="' . $base . '/', $content);
// src="/path" → src="https://host/path"
$content = preg_replace('/src\s*=\s*["\']\//', 'src="' . $base . '/', $content);
return $content;
}
// 更完整版:處理所有相對路徑 (../, ./, 無前綴)
function makeLinksAbsolute(string $html, string $baseUrl): string {
$dom = new DOMDocument();
@$dom->loadHTML('' . $html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
$xpath = new DOMXPath($dom);
foreach (['href', 'src'] as $attr) {
foreach ($xpath->query("//*[@{$attr}]") as $node) {
$value = $node->getAttribute($attr);
if ($value && !preg_match('/^[a-z]+:/i', $value) && $value[0] !== '#') {
$node->setAttribute($attr, rtrim($baseUrl, '/') . '/' . ltrim($value, '/'));
}
}
}
return $dom->saveHTML();
}
function get_all_url(string $html): array {
// 正則版 (簡單、快速、但不嚴謹)
preg_match_all('/"\'\s]+)["\']?[^>]*>([^<]+)<\/a>/i', $html, $matches);
return ['name' => $matches[2], 'url' => $matches[1]];
}
// DOM 版 (標準、健壯、支援巢狀/屬性順序不固定)
function getAllLinksDom(string $html): array {
$dom = new DOMDocument();
@$dom->loadHTML('' . $html);
$links = [];
foreach ($dom->getElementsByTagName('a') as $a) {
$href = $a->getAttribute('href');
$text = trim($a->textContent);
if ($href) $links[] = ['url' => $href, 'name' => $text];
}
return $links;
}
function get_tr_array(string $tableHtml): array {
// 將 ... 轉為 CSV 風格分隔
$table = preg_replace("']*>'si", '"', $tableHtml);
$table = str_replace(' ', '",', $table);
$table = str_replace('', "{tr}", $table);
// 移除所有 HTML 標籤
$table = preg_replace("'<[/!]*?[^<>]*?>'si", "", $table);
// 移除空白字元
$table = str_replace(['\r','\n','\t',' ',' '], '', $table);
$rows = explode('{tr}', $table);
array_pop($rows); // 最後空元素
return $rows; // 每行如 '"cell1","cell2","cell3"'
}
function get_td_array(string $tableHtml): array {
// 移除 table, tr 標籤,保留 td 內容結構
$table = preg_replace("']*>'si", "", $tableHtml);
$table = preg_replace("']*>'si", "", $table);
$table = preg_replace("']*>'si", "", $table);
$table = str_replace(' ', "{tr}", $table);
$table = str_replace('', "{td}", $table);
// 清理標籤與空白
$table = preg_replace("'<[/!]*?[^<>]*?>'si", "", $table);
$table = preg_replace("'([\r\n])[\s]+'", "", $table);
$table = str_replace([' ', ' '], '', $table);
$rows = explode('{tr}', $table);
array_pop($rows);
$result = [];
foreach ($rows as $row) {
$cells = explode('{td}', $row);
array_pop($cells);
$result[] = $cells;
}
return $result;
}
// 現代 DOM 版 (推薦生產環境)
function parseTableDom(string $html): array {
$dom = new DOMDocument();
@$dom->loadHTML('' . $html);
$tables = [];
foreach ($dom->getElementsByTagName('table') as $table) {
$rows = [];
foreach ($table->getElementsByTagName('tr') as $tr) {
$cells = [];
foreach ($tr->getElementsByTagName('td') as $td) {
$cells[] = trim($td->textContent);
}
if ($cells) $rows[] = $cells;
}
if ($rows) $tables[] = $rows;
}
return $tables; // 多表格支援
}
七、提取英文單詞 (去重、排序)
function split_en_str(string $str, bool $distinct = true): array {
preg_match_all('/([a-zA-Z]+)/', $str, $matches);
$words = $matches[1];
if ($distinct) $words = array_unique($words);
sort($words, SORT_STRING | SORT_FLAG_CASE); // 不區分大小寫排序
return $words;
}
// 範例
$text = "Hello world, hello PHP! World is beautiful.";
print_r(split_en_str($text));
/*
Array
(
[0] => beautiful
[1] => hello
[2] => is
[3] => php
[4] => world
)
*/
總結與現代化建議
功能 舊版做法 現代推薦 關鍵優勢
URL 獲取 $_SERVER 手動拼接 封裝函數 + parse_url 可測試、可復用、支援代理標頭
全半形轉換 陣列映射 + 位元組檢查 Normalizer::NFKC (intl) Unicode 標準、支援字母/符號、無遺漏
HTML 清理 str_replace 手動 htmlspecialchars / strip_tags 標準、安全、支援編碼
路徑轉絕對 正則替換 href/src DOMDocument + DOMXPath 結構化、不漏標籤、支援巢狀
連結提取 preg_match_all DOMDocument getElementsByTagName 健壯、標準、編碼安全
表格解析 正則字串替換 DOMDocument 遍歷 tr/td 正確處理 rowspan/colspan、巢狀表格
核心原則:**HTML 解析請用 DOMDocument,不要用正則**。正則無法正確處理巢狀標籤、屬性順序、編碼實體、條件註解等真實世界複雜性。PHP 的 `DOMDocument` 雖然 API 稍顯繁瑣,但配合 `DOMXPath` 是處理 HTML/XML 的正統之道。
- 上一篇文章: PHP 系統資訊、型別轉換、陣列操作、時間日期與隨機數函數速查 (第四輯)
- 下一篇文章: PHP 高頻實用函數庫 (第二輯):隨機字串、中文截取、客戶端 IP、Email 驗證、分頁與插入 ID 獲取
Copyright © 程式碼之家 All Rights Reserved