文件讀寫
function readFile(string $path): string|false {
if (!is_file($path)) return false;
return file_get_contents($path); // PHP 4.3+ 內建,比 fopen/fread 簡潔
}
function writeFile(string $path, string $data, bool $lock = true): int|false {
$flags = $lock ? LOCK_EX : 0;
return file_put_contents($path, $data, $flags);
}
靜態頁生成
function generateStatic(string $sourceUrl, string $destPath, array $vars = []): bool {
ob_start();
extract($vars);
include $sourceUrl; // 模板文件中直接使用變量
$html = ob_get_clean();
return writeFile($destPath, $html) !== false;
}
分頁類(PDO 版)
class Paginator {
public function __construct(
private PDO $pdo,
private string $table,
private string $where = '',
private array $params = [],
private int $perPage = 20
) {}
public function getTotal(): int {
$sql = "SELECT COUNT(*) FROM {$this->table} {$this->where}";
return (int)$this->pdo->prepare($sql)->execute($this->params)->fetchColumn();
}
public function getPage(int $page): array {
$offset = ($page - 1) * $this->perPage;
$sql = "SELECT * FROM {$this->table} {$this->where} LIMIT {$offset}, {$this->perPage}";
return $this->pdo->prepare($sql)->execute($this->params)->fetchAll();
}
public function getLinks(int $page, int $display = 5): string {
$total = $this->getTotal();
$pages = ceil($total / $this->perPage);
if ($pages <= 1) return '';
$html = '';
return $html;
}
}
圖片上傳(安全版)
function uploadImage(array $file, string $destDir, array $allowExt = ['jpg','jpeg','png','gif','webp'], int $maxSize = 2*1024*1024): array {
// 1. 錯誤碼檢查
if ($file['error'] !== UPLOAD_ERR_OK) return ['ok'=>false, 'msg'=>'上傳錯誤碼:'.$file['error']];
// 2. 大小
if ($file['size'] > $maxSize) return ['ok'=>false, 'msg'=>'文件過大'];
// 3. 擴展名 + MIME 雙重驗證
$ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
if (!in_array($ext, $allowExt)) return ['ok'=>false, 'msg'=>'禁止的格式'];
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime = $finfo->file($file['tmp_name']);
if (!in_array($mime, ['image/jpeg','image/png','image/gif','image/webp'])) return ['ok'=>false, 'msg'=>'MIME 不匹配'];
// 4. 隨機文件名防衝突/遍歷
$newName = bin2hex(random_bytes(16)) . ".{$ext}";
$destPath = rtrim($destDir, '/') . '/' . $newName;
if (!move_uploaded_file($file['tmp_name'], $destPath)) return ['ok'=>false, 'msg'=>'移動失敗'];
// 5. 可選:二次渲染去除 EXIF/腳本
// $img = imagecreatefromstring(file_get_contents($destPath)); imagejpeg($img, $destPath);
return ['ok'=>true, 'path'=>$destPath, 'url'=>'/uploads/'.$newName, 'size'=>$file['size']];
}
目錄遞歸刪除
function deleteDir(string $dir): bool {
if (!is_dir($dir)) return false;
$items = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS),
RecursiveIteratorIterator::CHILD_FIRST
);
foreach ($items as $item) {
$item->isDir() ? rmdir($item->getPathname()) : unlink($item->getPathname());
}
return rmdir($dir);
}
常用驗證正則
| 類型 | 正則 |
| Email | /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/ |
| 手機(中國大陸) | /^1[3-9]\d{9}$/ |
| 身份證(18位) | /^\d{17}[\dXx]$/ |
| URL | /^https?:\/\/[^\s]+$/i |
| IPv4 | /^(?:(?:25[0-5]|2[0-4]\d|[01]?\d?\d)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d?\d)$/ |
IP 合法性快速判斷
function isValidIp(string $ip): bool {
return filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6) !== false;
}
// CIDR 範圍檢查
function ipInCidr(string $ip, string $cidr): bool {
[$range, $bits] = explode('/', $cidr);
$mask = ~((1 << (32 - $bits)) - 1);
return (ip2long($ip) & $mask) === (ip2long($range) & $mask);
}
文件下載響應頭
function downloadHeaders(string $filename, int $size, string $mime = 'application/octet-stream'): void {
header('Content-Type: ' . $mime);
header('Content-Disposition: attachment; filename="' . rawurlencode($filename) . '"');
header('Content-Length: ' . $size);
header('Accept-Ranges: bytes');
header('Cache-Control: private, must-revalidate');
header('Pragma: public');
}