開發中反覆造輪子既浪費又易出錯。本文提供 7 個高頻實用工具函式的現代化、安全、可直接落地的實作碼,涵蓋字串、網路、檔案、驗證、導航、分頁核心場景。
<?php
function randomString(int $length = 32, string $chars = ''): string {
$chars = $chars ?: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
$bytes = random_bytes($length);
$result = '';
for ($i = 0; $i < $length; $i++) {
$result .= $chars[$bytes[$i] % strlen($chars)];
}
return $result;
}
// 用法: randomString(16), randomString(32, '0123456789') // 純數字
?>
關鍵:使用 random_bytes() (PHP 7+) 而非 mt_rand(),確保密碼學安全。
<?php
function truncateUtf8(string $string, int $length, string $suffix = '...'): string {
if (mb_strlen($string, 'UTF-8') <= $length) return $string;
return mb_substr($string, 0, $length - mb_strlen($suffix), 'UTF-8') . $suffix;
}
// 用法: truncateUtf8('中文內容很長...', 20) // '中文內容很...'
?>
<?php
function getClientIp(): string {
$headers = [
'HTTP_CF_CONNECTING_IP', // Cloudflare
'HTTP_X_FORWARDED_FOR', // 標準代理
'HTTP_X_REAL_IP', // Nginx proxy
'HTTP_CLIENT_IP',
'REMOTE_ADDR',
];
foreach ($headers as $header) {
if (!empty($_SERVER[$header])) {
$ips = explode(',', $_SERVER[$header]);
$ip = trim($ips[0]);
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
return $ip;
}
}
}
return $_SERVER['REMOTE_ADDR'] ?? 'unknown';
}
?>
支援 Cloudflare、多層代理、過濾私有/保留 IP,回傳公開真實 IP。
<?php
function ensureDir(string $path, int $mode = 0755): bool {
$path = rtrim($path, '/\\');
if (is_dir($path)) return true;
$parent = dirname($path);
if ($parent !== '.' && $parent !== '/') {
ensureDir($parent, $mode);
}
return @mkdir($path, $mode, true) || is_dir($path);
}
// 用法: ensureDir('storage/uploads/2024/01/15')
?>
<?php
function isValidEmail(string $email): bool {
if (strlen($email) > 254) return false;
// PHP 內建驗證 (採用較寬鬆標準)
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) return false;
// 額外檢查:本地部分不超過 64 字元、域名合法
[$local, $domain] = explode('@', $email, 2);
if (strlen($local) > 64) return false;
if (!checkdnsrr($domain, 'MX') && !checkdnsrr($domain, 'A')) return false;
return true;
}
?>
<?php
function redirect(string $url, int $status = 302, array $headers = []): never {
// 防開放重導向:驗證 $url 為同源或白名單
if (str_starts_with($url, '/') || parse_url($url, PHP_URL_HOST) === $_SERVER['HTTP_HOST']) {
// AJAX 請求回傳 JSON
if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) &&
strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest') {
header('Content-Type: application/json');
echo json_encode(['redirect' => $url]);
exit;
}
// 一般跳轉
foreach ($headers as $k => $v) header("$k: $v");
header("Location: $url", true, $status);
exit;
}
throw new InvalidArgumentException("Unsafe redirect URL: $url");
}
?>
<?php
class Paginator {
public function __construct(
public int $totalItems,
public int $perPage = 15,
public int $currentPage = 1,
public string $urlPattern = '?page={page}' // {page} 會被替換
) {
$this->currentPage = max(1, min($this->currentPage, $this->totalPages()));
}
public function totalPages(): int {
return (int) ceil($this->totalItems / $this->perPage);
}
public function offset(): int {
return ($this->currentPage - 1) * $this->perPage;
}
public function limit(): int {
return $this->perPage;
}
public function getUrl(int $page): string {
return str_replace('{page}', (string)$page, $this->urlPattern);
}
public function getLinks(int $range = 2): array {
$links = [];
$start = max(1, $this->currentPage - $range);
$end = min($this->totalPages(), $this->currentPage + $range);
for ($i = $start; $i <= $end; $i++) {
$links[$i] = $this->getUrl($i);
}
return $links;
}
}
// 用法
$paginator = new Paginator($totalUsers, 20, (int)($_GET['page'] ?? 1));
$users = $db->query("SELECT * FROM users LIMIT {$paginator->offset()}, {$paginator->limit()}");
// 視圖中: foreach ($paginator->getLinks() as $page => $url) ...
?>
App\Helpers 或 App\Support 命名空間files 自動載入或建立 Service Provider 註冊工具函式庫是專案品質的基石,善用標準庫、成熟套件,專注業務創新。