收集自各大 PHP 專案的實戰工具函數,涵蓋網路、日期、HTML、用戶代理偵測等高頻領域。本文為上集,包含 7 大類函數,附參數詳解、邏輯分析與現代化改良。
function GetIP(): string {
$ipKeys = [
'HTTP_X_FORWARDED_FOR', // 標準代理標頭 (可能多 IP)
'HTTP_CLIENT_IP', // 部分代理使用
'REMOTE_ADDR', // 直接連線或最後一層代理
];
foreach ($ipKeys as $key) {
$val = $_SERVER[$key] ?? '';
if ($val) {
$ips = array_map('trim', explode(',', $val));
foreach ($ips as $ip) {
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
return $ip;
}
}
return $ips[0]; // 全為私有 IP 時取第一個
}
}
// 相容 getenv (CGI 模式)
$envKeys = ['HTTP_X_FORWARDED_FOR', 'HTTP_CLIENT_IP', 'REMOTE_ADDR'];
foreach ($envKeys as $key) {
$val = getenv($key);
if ($val) return $val;
}
return 'Unknown';
}
function DateAdd(string $date, int $interval, string $unit = 'd'): string {
// 支援單位: y(年), m(月), d(日), h(時), i(分), s(秒)
$units = ['y'=>'year', 'm'=>'month', 'd'=>'day', 'h'=>'hour', 'i'=>'minute', 's'=>'second'];
$unit = $units[$unit] ?? 'day';
$dt = new DateTime($date);
$intervalStr = ($interval >= 0 ? '+' : '') . abs($interval) . " {$unit}";
$dt->modify($intervalStr);
return $dt->format('Y-m-d'); // 或依需求回傳完整格式
}
// 範例
DateAdd('2024-01-15', 10, 'd'); // 2024-01-25
DateAdd('2024-01-15', 1, 'm'); // 2024-02-15 (自動處理月末)
DateAdd('2024-01-15', -3, 'd'); // 2024-01-12
// 簡化版 (僅支援日)
function DateAddSimple(string $date, int $days): string {
return date('Y-m-d', strtotime($date . " {$days} days"));
}
function GetWeekDay(string $date): int {
// 回傳 0(日) - 6(六)
return (int)date('w', strtotime($date));
}
// 中文星期名
function GetWeekDayName(string $date, string $lang = 'zh'): string {
$names = [
'zh' => ['日','一','二','三','四','五','六'],
'en' => ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'],
];
$w = GetWeekDay($date);
return $names[$lang][$w] ?? $names['zh'][$w];
}
// 範例
GetWeekDay('2024-01-15'); // 1 (週一)
GetWeekDayName('2024-01-15'); // "一"
function check_date(string $date): bool {
$parts = explode('-', $date);
if (count($parts) !== 3) return false;
[$y, $m, $d] = $parts;
if (!ctype_digit($y) || !ctype_digit($m) || !ctype_digit($d)) return false;
return checkdate((int)$m, (int)$d, (int)$y);
}
function check_time(string $time): bool {
$parts = explode(':', $time);
if (count($parts) !== 3) return false;
[$h, $m, $s] = $parts;
if (!ctype_digit($h) || !ctype_digit($m) || !ctype_digit($s)) return false;
return $h >= 0 && $h <= 23 && $m >= 0 && $m <= 59 && $s >= 0 && $s <= 59;
}
function check_datetime(string $datetime): bool {
$parts = explode(' ', $datetime);
if (count($parts) !== 2) return false;
return check_date($parts[0]) && check_time($parts[1]);
}
// 現代版:DateTime 例外處理
function checkDateModern(string $date, string $format = 'Y-m-d'): bool {
$dt = DateTime::createFromFormat($format, $date);
return $dt !== false && $dt->format($format) === $date;
}
function DateDiff(string $date1, string $date2, string $unit = 'd'): float|false {
$units = [
's' => 1,
'i' => 60,
'h' => 3600,
'd' => 86400,
'w' => 604800,
'm' => 2629746, // 近似月秒數
'y' => 31556952, // 近似年秒數
];
$divisor = $units[$unit] ?? $units['d'];
$t1 = strtotime($date1);
$t2 = strtotime($date2);
if ($t1 === false || $t2 === false) return false;
return ($t1 - $t2) / $divisor;
}
// 範例
DateDiff('2024-01-20', '2024-01-15', 'd'); // 5 天
DateDiff('2024-01-15 12:00', '2024-01-15 10:00', 'h'); // 2 小時
DateDiff('2024-01-15 10:00', '2024-01-15 12:00', 'i'); // -120 分鐘 (date1 - date2)
// 精確版:DateInterval (支援月/年真實長度)
function DateDiffExact(string $date1, string $date2): DateInterval {
$dt1 = new DateTime($date1);
$dt2 = new DateTime($date2);
return $dt1->diff($dt2); // 可取 ->y, ->m, ->d, ->h, ->i, ->s
}
// 使用
$diff = DateDiffExact('2024-01-20', '2024-01-15');
echo $diff->days; // 5
$diff = DateDiffExact('2024-03-01', '2024-01-15');
echo "{$diff->y}年{$diff->m}月{$diff->d}天"; // 0年1月16天
function get_innerhtml(string $html, string $tag): array {
// 分割
$parts = preg_split("/<\/{$tag}>/i", $html);
$pattern = "/<{$tag}[^>]*>/i";
$results = [];
foreach ($parts as $part) {
list(, $inner) = preg_split($pattern, $part, 2);
$results[] = $inner ?? '';
}
return $results;
}
// 範例
$html = 'something ';
print_r(get_innerhtml($html, 'td')); // ['something']
// 現代 DOM 版
function getInnerHtmlDom(string $html, string $tag): array {
$dom = new DOMDocument();
@$dom->loadHTML('' . $html);
$results = [];
foreach ($dom->getElementsByTagName($tag) as $el) {
$results[] = $el->ownerDocument->saveHTML($el); // 含標籤
// 或 $el->textContent 純文字
}
return $results;
}
function get_input_value(string $inputHtml): string|false {
$pos = stripos($inputHtml, 'value=');
if ($pos === false) return false;
$pos += 6; // 跳過 'value='
$str = substr($inputHtml, $pos);
if ($str[0] === '"' || $str[0] === "'") {
$quote = $str[0];
$end = strpos($str, $quote, 1);
return $end !== false ? substr($str, 1, $end - 1) : false;
}
$end = strpos($str, ' ');
return $end !== false ? substr($str, 0, $end) : $str;
}
// 現代 DOM 版
function getInputValueDom(string $html): string|false {
$dom = new DOMDocument();
@$dom->loadHTML('' . $html);
$input = $dom->getElementsByTagName('input')->item(0);
return $input?->getAttribute('value') ?? false;
}
function getcontentbetween(string $a, string $b, string $str): string|false {
if ($str === '' || $a === '' || $b === '') return false;
$start = strpos($str, $a);
if ($start === false) return false;
$start += strlen($a);
$end = strpos($str, $b, $start);
if ($end === false) return false;
return substr($str, $start, $end - $start);
}
// 範例
getcontentbetween('', ' ', 'My Page '); // 'My Page'
function browse_infor(): string {
$agent = $_SERVER['HTTP_USER_AGENT'] ?? '';
$browser = 'Unknown';
$version = '';
// 現代瀏覽器特徵順序重要 (Chrome 包含 Safari 字樣)
if (preg_match('/Edg\/(\d+)/', $agent, $m)) { $browser = 'Edge'; $version = $m[1]; }
elseif (preg_match('/OPR\/(\d+)/', $agent, $m)) { $browser = 'Opera'; $version = $m[1]; }
elseif (preg_match('/Firefox\/(\d+)/', $agent, $m)) { $browser = 'Firefox'; $version = $m[1]; }
elseif (preg_match('/Chrome\/(\d+)/', $agent, $m)) { $browser = 'Chrome'; $version = $m[1]; }
elseif (preg_match('/Safari\/(\d+)/', $agent, $m)) { $browser = 'Safari'; $version = $m[1]; }
elseif (preg_match('/MSIE (\d+)/', $agent, $m)) { $browser = 'Internet Explorer'; $version = $m[1]; }
elseif (preg_match('/Trident\/.*rv:(\d+)/', $agent, $m)) { $browser = 'Internet Explorer'; $version = $m[1]; }
return $browser . ($version ? " {$version}" : '');
}
// 使用
echo browse_infor(); // "Chrome 120" 或 "Firefox 115"
function osinfo(): string {
$agent = $_SERVER['HTTP_USER_AGENT'] ?? '';
$os = 'Unknown';
// 移動裝置優先
if (preg_match('/Android (\d+)/', $agent, $m)) $os = "Android {$m[1]}";
elseif (preg_match('/iPhone OS (\d+)_(\d+)/', $agent, $m)) $os = "iOS {$m[1]}.{$m[2]}";
elseif (preg_match('/iPad.*OS (\d+)_(\d+)/', $agent, $m)) $os = "iPadOS {$m[1]}.{$m[2]}";
// 桌面作業系統
elseif (preg_match('/Windows NT 10\.0/', $agent)) $os = 'Windows 10/11';
elseif (preg_match('/Windows NT 6\.3/', $agent)) $os = 'Windows 8.1';
elseif (preg_match('/Windows NT 6\.2/', $agent)) $os = 'Windows 8';
elseif (preg_match('/Windows NT 6\.1/', $agent)) $os = 'Windows 7';
elseif (preg_match('/Windows NT 6\.0/', $agent)) $os = 'Windows Vista';
elseif (preg_match('/Windows NT 5\.1/', $agent)) $os = 'Windows XP';
elseif (preg_match('/Mac OS X (\d+)_(\d+)/', $agent, $m)) $os = "macOS {$m[1]}.{$m[2]}";
elseif (preg_match('/Linux/', $agent)) $os = 'Linux';
elseif (preg_match('/FreeBSD/', $agent)) $os = 'FreeBSD';
elseif (preg_match('/Unix/', $agent)) $os = 'Unix';
return $os;
}
這 7 大類工具函數構成了 PHP 專案的基礎設施。**核心升級路徑**:字串操作 → 正則 → **DOMDocument/DateTime/Filter 函數/隨機數擴展**。日期運算請全面改用 `DateTime`/`DateInterval` 物件,支援時區、閏年、夏令時間等複雜邏輯。UA 解析建議使用成熟庫 (如 `WhichBrowser/Parser`),自維護正則難以跟上瀏覽器更新。IP 獲取在雲端/容器環境下極其複雜,建議接入專用服務或信任入口層 (Nginx/ALB) 透過標準標頭傳遞真實 IP。