PHP 內建函數庫雖強大,但實務開發常需針對特定業務封裝工具函數。本文精選 31 個高頻實用自訂函數,涵蓋隨機字串、郵件編碼驗證、目錄操作、JSON/XML 解析、Slug 生成、真實 IP 取得、強制下載、標籤雲、Gravatar、文字截斷、ZIP 壓縮解壓、URL 處理、縮圖、AJAX 偵測、關鍵字高亮、Feedburner 統計、密碼生成、CSS 壓縮、短網址、年齡計算、執行計時、維護模式、快取控制、序數詞綴等。
function readable_random_string($length = 6) {
$conso = ['b','c','d','f','g','h','j','k','l','m','n','p','r','s','t','v','w','x','y','z'];
$vocal = ['a','e','i','o','u'];
$password = '';
for ($i = 0; $i < $length / 2; $i++) {
$password .= $conso[array_rand($conso)] . $vocal[array_rand($vocal)];
}
return $password;
}
function generate_rand($l) {
$c = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
$rand = '';
for ($i = 0; $i < $l; $i++) {
$rand .= $c[random_int(0, strlen($c) - 1)]; // PHP 7+ 用 random_int
}
return $rand;
}
function encode_email($email = 'info@domain.com', $linkText = 'Contact Us', $attrs = 'class="emailencoder"') {
$email = str_replace(['@', '.'], ['@', '.'], $email);
$linkText = str_replace(['@', '.'], ['@', '.'], $linkText);
return '<script>document.write(\'<a href="mailto:' . $email . '" ' . $attrs . '>' . $linkText . '</a>\');</script>';
}
similar_text($string1, $string2, $percent); // $percent 回傳相似百分比
function myTruncate($string, $limit, $break = " ", $pad = "...") {
if (strlen($string) <= $limit) return $string;
if (false !== ($breakpoint = strpos($string, $break, $limit))) {
if ($breakpoint < strlen($string) - 1) {
return substr($string, 0, $breakpoint) . $pad;
}
}
return $string;
}
if (!preg_match("/^(http|ftp):/", $_POST['url'])) {
$_POST['url'] = 'https://' . $_POST['url'];
}
function makeClickableLinks($text) {
$text = preg_replace('/((f|ht)tp:\/\/[^\s]+)/i', '<a href="$1">$1</a>', $text);
$text = preg_replace('/([\s(\[{])(www\.[^\s]+)/i', '$1<a href="https://$2">$2</a>', $text);
$text = preg_replace('/([\w\-\.]+@[\w\-\.]+\.\w+)/', '<a href="mailto:$1">$1</a>', $text);
return $text;
}
function make_ranked($rank) {
$last = (int)substr($rank, -1);
$seclast = (int)substr($rank, -2, 1);
if ($last > 3 || $last == 0) $ext = 'th';
elseif ($last == 3) $ext = 'rd';
elseif ($last == 2) $ext = 'nd';
else $ext = 'st';
// 11, 12, 13 例外
if ($seclast == 1) $ext = 'th';
return $rank . $ext;
}
function is_valid_email($email, $test_mx = false) {
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) return false;
if ($test_mx) {
list(, $domain) = explode('@', $email);
return checkdnsrr($domain, 'MX');
}
return true;
}
function force_download($file) {
if (isset($file) && file_exists($file)) {
header("Content-Length: " . filesize($file));
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . basename($file) . '"');
readfile($file);
exit;
}
echo "No file selected";
}
function is_ajax() {
return !empty($_SERVER['HTTP_X_REQUESTED_WITH'])
&& strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest';
}
function highlight($string, array $words) {
if (empty($words) || !is_string($string)) return $string;
$pattern = '/\b(' . implode('|', array_map('preg_quote', $words)) . ')\b/i';
return preg_replace($pattern, '<strong>$1</strong>', $string);
}
function list_files($dir) {
if (is_dir($dir) && $handle = opendir($dir)) {
while (($file = readdir($handle)) !== false) {
if (!in_array($file, ['.', '..', 'Thumbs.db'])) {
echo '<a target="_blank" href="' . $dir . $file . '">' . $file . '</a><br>';
}
}
closedir($handle);
}
}
function destroyDir($dir, $virtual = false) {
$ds = DIRECTORY_SEPARATOR;
$dir = $virtual ? realpath($dir) : $dir;
$dir = rtrim($dir, $ds);
if (is_dir($dir) && $handle = opendir($dir)) {
while ($file = readdir($handle)) {
if ($file === '.' || $file === '..') continue;
$path = $dir . $ds . $file;
is_dir($path) ? destroyDir($path) : unlink($path);
}
closedir($handle);
return rmdir($dir);
}
return false;
}
function create_zip($files = [], $destination = '', $overwrite = false) {
if (file_exists($destination) && !$overwrite) return false;
$valid_files = array_filter($files, 'file_exists');
if (!$valid_files) return false;
$zip = new ZipArchive();
if ($zip->open($destination, $overwrite ? ZipArchive::OVERWRITE : ZipArchive::CREATE) !== true) return false;
foreach ($valid_files as $file) $zip->addFile($file, basename($file));
return $zip->close() && file_exists($destination);
}
function unzip_file($file, $destination) {
$zip = new ZipArchive();
if ($zip->open($file) !== true) die('Could not open archive');
$zip->extractTo($destination);
$zip->close();
echo 'Archive extracted to directory';
}
$json = '{"id":1,"name":"foo","email":"foo@foobar.com","interest":["wordpress","php"]}';
$obj = json_decode($json);
echo $obj->name; // foo
echo $obj->interest[1]; // php
$xml = simplexml_load_string($xml_string);
foreach ($xml->user as $user) {
echo $user['id'] . ' ' . $user->name . ' ' . $user->email . '<br>';
}
function create_slug($string) {
return strtolower(trim(preg_replace('/[^A-Za-z0-9-]+/', '-', $string), '-'));
}
function getRealIpAddr() {
if (!empty($_SERVER['HTTP_CLIENT_IP'])) return $_SERVER['HTTP_CLIENT_IP'];
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) return $_SERVER['HTTP_X_FORWARDED_FOR'];
return $_SERVER['REMOTE_ADDR'];
}
function show_gravatar($email, $size = 80, $default = '', $rating = 'G') {
echo '<img src="https://www.gravatar.com/avatar/' . md5(strtolower(trim($email)))
. '?s=' . $size . '&d=' . urlencode($default) . '&r=' . $rating
. '" width="' . $size . '" height="' . $size . '" />';
}
function resize_image($filename, $tmpname, $xmax, $ymax) {
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
$create = ['jpg' => 'imagecreatefromjpeg', 'jpeg' => 'imagecreatefromjpeg', 'png' => 'imagecreatefrompng', 'gif' => 'imagecreatefromgif'];
if (!isset($create[$ext])) return false;
$im = $create[$ext]($tmpname);
$x = imagesx($im); $y = imagesy($im);
if ($x <= $xmax && $y <= $ymax) return $im;
if ($x >= $y) { $newx = $xmax; $newy = $y * $xmax / $x; }
else { $newy = $ymax; $newx = $x * $ymax / $y; }
$im2 = imagecreatetruecolor($newx, $newy);
imagecopyresampled($im2, $im, 0, 0, 0, 0, $newx, $newy, $x, $y);
return $im2;
}
function getTinyUrl($url) {
return file_get_contents("https://tinyurl.com/api-create.php?url=" . urlencode($url));
}
$time_start = microtime(true); // ... 程式碼 ... $time_end = microtime(true); echo 'Script took ' . ($time_end - $time_start) . ' seconds to execute';
<link href="/stylesheet.css?<?php echo time(); ?>" rel="stylesheet" type="text/css" />
function getCloud(array $data, $minFontSize = 12, $maxFontSize = 30) {
$min = min($data); $max = max($data);
$spread = $max - $min ?: 1;
$html = '';
foreach ($data as $tag => $count) {
$size = $minFontSize + ($count - $min) * ($maxFontSize - $minFontSize) / $spread;
$html .= '<a style="font-size:' . floor($size) . 'px" href="#" title="' . $tag . ' (' . $count . ')">' . htmlspecialchars($tag) . '</a> ';
}
return $html;
}
function get_average_readers($feed_id, $interval = 7) {
$today = date('Y-m-d'); $ago = date('Y-m-d', strtotime("-$interval days"));
$url = "https://feedburner.google.com/api/awareness/1.0/GetFeedData?uri=$feed_id&dates=$ago,$today";
$xml = simplexml_load_string(file_get_contents($url));
$total = 0; $count = 0;
foreach ($xml->feed->entry as $entry) { $total += (int)$entry['circulation']; $count++; }
return $count ? round($total / $count) : 0;
}
function generatePassword($length = 9, $strength = 0) {
$vowels = 'aeuy'; $consonants = 'bdghjmnpqrstvz';
if ($strength >= 1) $consonants .= 'BDGHJLMNPQRSTVWXZ';
if ($strength >= 2) $vowels .= 'AEUY';
if ($strength >= 4) $consonants .= '23456789';
if ($strength >= 8) $vowels .= '@#$%';
$password = ''; $alt = time() % 2;
for ($i = 0; $i < $length; $i++) {
$pool = $alt ? $consonants : $vowels;
$password .= $pool[random_int(0, strlen($pool) - 1)];
$alt = 1 - $alt;
}
return $password;
}
header('Content-type: text/css');
ob_start(function ($buffer) {
$buffer = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $buffer); // 移除註解
return str_replace(["\r\n", "\r", "\n", "\t", ' ', ' '], '', $buffer); // 移除空白
});
include('master.css'); include('typography.css'); include('grid.css');
ob_end_flush();
function age($date) {
$time = strtotime($date);
if ($time === false) return '';
list($year, $month, $day) = explode('-', date('Y-m-d', $time));
$age = date('Y') - $year;
if (date('m-d') < "$month-$day") $age--;
return $age;
}
function maintenance($mode = false) {
$script = basename($_SERVER['SCRIPT_FILENAME']);
if ($mode && $script !== 'maintenance.php') { header('Location: /maintenance.php'); exit; }
if (!$mode && $script === 'maintenance.php') { header('Location: /'); exit; }
}
這 31 個函數涵蓋了 PHP 開發 80% 的常見需求。建議將常用者整理為專案的 helpers.php 或 Traits,配合 Composer 自動載入,建立團隊專屬工具庫。注意:部分原始代碼使用已棄用函數(ereg, split, rand),實際使用請替換為 preg_*, explode, random_int 等現代替代品。