Apache 的 rewrite 模組設定非本文重點,請參閱其他文章。本類別僅支援 PHP 5.3.0 以上版本,繼承上一版單一類別、全靜態呼叫的特點,新增跨模組呼叫功能,讓模組與頁面間的函式共享更簡單。
#-------------- .htaccess start ---------------
RewriteEngine on
RewriteRule !\.(js|ico|gif|jpg|png|css|swf|htm|txt)$ index.php
php_flag magic_quotes_gpc off
php_flag register_globals off
#-------------- .htaccess end ---------------
在站點根目錄的 index.php 末尾加入以下程式碼即可啟用重寫(前提:Apache rewrite 正常、.htaccess 支援已開啟、類別檔 class.rewrite.php 已載入、模組檔案位置與寫法正確):
//........
Rewrite::__config(
$config['path'], // URL 基礎位置,例如 'https://xxxxx/mysite/'
$config['md_path'], // 模組檔案實體目錄,例如 'c:/phpsite/www/mysite/modules/'
array('phpinfo') // 允許直接呼叫的系統函式
);
Rewrite::__parse();
//........
檔案名稱:testPk.php
<?php
class Rw_testPk extends Rewrite {
// 前導函式:只要存取 testpk 頁面必定執行,可用於權限控制或全域變數
public static function init() {
// if (!defined('SITE_PASS')) {
echo self::$linktag . '<br/>'; // self::$linktag 為頁面解析路徑值
// }
}
// 存取 "https://localhost/testpk/" 時執行
public static function index() {
echo 'test';
}
// 存取 "https://localhost/testpk/blank" 或 "https://localhost/testpk/index/blank" 時執行
public static function blank() {}
}
?>
<?php
class Rewrite {
public static $debug = false; // 是否開啟除錯
public static $time_pass = 0; // 模組整體執行時間
public static $version = 2.2;
public static $pretag = 'Rw_'; // 模組類別名稱前綴
public static $linktag = 'index'; // 頁面連結標記,用於選單效果與存取權限
protected static $time_start = 0;
protected static $time_end = 0;
protected static $physical_path = ''; // 模組檔案實體路徑
protected static $website_path = ''; // 模組站點路徑(可能在子目錄)
protected static $ob_contents = '';
protected static $uid = 0; // 配合個人主頁存取,如 https://localhost/423/ 對應 profile?uid=423
private static $allow_sys_fun = array(); // 允許的系統函式
private static function __get_microtime() {
list($usec, $sec) = explode(" ", microtime());
return ((float)$usec + (float)$sec);
}
public static function __debug($d = true) {
static::$debug = $d;
}
public static function __config($website_path = '', $physical_path = '', $allow_sys_fun = array()) {
self::$physical_path = $physical_path;
self::$website_path = $website_path;
self::$allow_sys_fun = $allow_sys_fun;
}
public static function __msg($str) {
if (static::$debug) {
echo "\n<pre>\n" . print_r($str, true) . "\n</pre>\n";
}
}
public static function __start() {
self::$time_start = self::__get_microtime();
}
public static function __end($re = false) {
self::$time_end = self::__get_microtime();
self::$time_pass = round((self::$time_end - self::$time_start), 6) * 1000;
if ($re) {
return self::$time_pass;
} else {
self::__msg('PASS_TIME: ' . self::$time_pass . ' ms');
}
}
// 內部跨模組 URL 解析呼叫
public static function __parseurl($url = '', $fun = '', $data = NULL) {
if (!empty($url) && !empty($fun)) {
$p = static::$physical_path;
if (file_exists($p . $url) || file_exists($p . $url . '.php')) {
$part = strtolower(basename($p . $url, '.php'));
static::$linktag = $part . '/' . $fun;
$fname = static::$pretag . $part;
if (class_exists($fname, false)) {
if (method_exists($fname, $fun)) {
return $fname::$fun($data);
}
} else {
include($p . $url);
if (class_exists($fname, false) && method_exists($fname, $fun)) {
return $fname::$fun($data);
}
}
}
}
}
// 核心連結解析函式
public static function __parse($Url = '') {
self::__start();
$p = static::$physical_path;
$w = static::$website_path;
$req_execute = false;
$url_p = empty($Url) ? $_SERVER['REQUEST_URI'] : $Url;
$local = parse_url($w);
$req = parse_url($url_p);
$req_path = preg_replace('|[^\w/.\\\]|', '', $req['path']);
$req_para = empty($Url) ? strstr($_SERVER['SERVER_NAME'], '.', true) : 'www';
if (empty($Url) && substr_count($_SERVER['SERVER_NAME'], '.') == 2 && $req_para != 'www') {
self::__goto($req_para, preg_replace('|^' . $local['path'] . '|', "", $req_path));
return;
} else {
$req_path_arr = empty($req_path) ? array() : preg_split("|[/\\\]+|", preg_replace('|^' . $local['path'] . '|', "", $req_path));
$req_fun = array_pop($req_path_arr);
if (substr($req_fun, 0, 2) == '__') {
$req_fun = substr($req_fun, 2);
}
$req_path_rearr = array_filter($req_path_arr);
self::__msg($req_path_rearr);
$req_temp = implode('/', $req_path_rearr);
$fname = $req_temp . '/' . $req_fun;
if (!empty($req_fun) && in_array($req_fun, static::$allow_sys_fun)) {
$req_fun();
} else {
if (!empty($req_fun) && file_exists($p . $fname . '.php')) {
include($p . $fname . '.php');
} else {
$fname = empty($req_temp) ? 'index' : $req_temp;
if (file_exists($p . $fname . '.php')) {
include($p . $fname . '.php');
} else {
$fname = $req_temp . '/index';
if (file_exists($p . $fname . '.php')) {
include($p . $fname . '.php');
} else {
// 個人主頁特殊導向
$uid = is_numeric($req_temp) ? $req_temp : strstr($req_temp, '/', true);
$ufun = is_numeric($req_temp) ? 'index' : strstr($req_temp, '/');
if (is_numeric($uid)) {
self::$uid = $uid;
if (!isset($_GET['uid'])) $_GET['uid'] = $uid;
$fname = 'profile/' . $ufun;
if (file_exists($p . $fname . '.php')) {
include($p . $fname . '.php');
} else {
header("location:" . $w);
exit();
}
} else if (file_exists($p . 'index.php')) {
$fname = 'index';
include($p . 'index.php');
} else {
header("location:" . $w);
exit();
}
}
}
}
}
$ev_fname = strrpos($fname, '/') === false ? $fname : substr($fname, strrpos($fname, '/') + 1);
$ev_fname = static::$pretag . $ev_fname;
if (class_exists($ev_fname, false) && method_exists($ev_fname, $req_fun)) {
static::$linktag = $req_fun == 'index' ? $fname . '/' : $fname . '/' . $req_fun;
if ($req_fun != 'init' && method_exists($ev_fname, 'init')) {
$ev_fname::init();
}
$ev_fname::$req_fun();
} else if (class_exists($ev_fname, false) && method_exists($ev_fname, 'index')) {
static::$linktag = $fname . '/';
if (method_exists($ev_fname, 'init')) {
$ev_fname::init();
}
$ev_fname::index();
} else if ($fname != 'index' && class_exists(static::$pretag . 'index', false) && method_exists(static::$pretag . 'index', 'index')) {
$ev_fname = static::$pretag . 'index';
static::$linktag = 'index/';
if (method_exists($ev_fname, 'init')) {
$ev_fname::init();
}
$ev_fname::index();
} else {
self::__msg('Function Not Exist!');
}
}
self::__end();
}
// 使用者自訂連結解析(資料庫儲存)
public static function __goto($para = '', $path = '') {
$w = static::$website_path;
if (empty($para)) {
exit('未知連結,解析失敗,無法存取');
}
if (class_exists('Parseurl')) {
$prs = Parseurl::selectone(array('tag', '=', $para));
self::__msg($prs);
if (!empty($prs)) {
$parastr = $prs['tag'];
$output = array();
$_GET[$prs['idtag']] = $prs['id'];
parse_str($prs['parastr'], $output);
$_GET = array_merge($_GET, $output);
$path = $prs['type'] . '/' . preg_replace('|^/' . $prs['type'] . '|', '', $path);
self::__msg($path);
header('location:' . $w . $path . '?' . http_build_query($_GET));
exit();
} else {
header("location:" . $w);
exit();
}
} else {
header("location:" . $w);
exit();
}
}
}
?>