├── package.json ├── README.md └── Rewrite.php /package.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 请求转发模块说明 : 2 | 3 | ## Install 4 | 5 | $ fis server install rewrite 6 | 7 | ## Usage 8 | 9 | 1. 对外提供match方法,供其他调试模块调用,具体方法参考代码注释说明。 10 | 11 | 2. 默认读取根目录server.conf文件,书写方式是: 12 | 13 | rewrite和redirect开头的会被翻译成一条匹配规则,自上而下的匹配。所有非rewrite和redirect开头的会被当做注释处理。 14 | 15 | rewrite : 匹配规则后转发到一个文件 16 | redirect : 匹配规则后重定向到另一个url 17 | 18 | rewrite ^\/news\?.*tn\=[a-zA-Z0-9]+.* app/data/news.php 19 | redirect ^\/index\?.* /photo/index/a 20 | rewrite ^\/(.*)\?.* app/data/$1.php 21 | -------------------------------------------------------------------------------- /Rewrite.php: -------------------------------------------------------------------------------- 1 | 'image/bmp', 9 | 'css' => 'text/css', 10 | 'doc' => 'application/msword', 11 | 'dtd' => 'text/xml', 12 | 'gif' => 'image/gif', 13 | 'hta' => 'application/hta', 14 | 'htc' => 'text/x-component', 15 | 'htm' => 'text/html', 16 | 'html' => 'text/html', 17 | 'xhtml' => 'text/html', 18 | 'ico' => 'image/x-icon', 19 | 'jpe' => 'image/jpeg', 20 | 'jpeg' => 'image/jpeg', 21 | 'jpg' => 'image/jpeg', 22 | 'js' => 'text/javascript', 23 | 'json' => 'application/json', 24 | 'mocha' => 'text/javascript', 25 | 'mp3' => 'audio/mp3', 26 | 'mp4' => 'video/mpeg4', 27 | 'mpeg' => 'video/mpg', 28 | 'mpg' => 'video/mpg', 29 | 'manifest' => 'text/cache-manifest', 30 | 'pdf' => 'application/pdf', 31 | 'png' => 'image/png', 32 | 'ppt' => 'application/vnd.ms-powerpoint', 33 | 'rmvb' => 'application/vnd.rn-realmedia-vbr', 34 | 'rm' => 'application/vnd.rn-realmedia', 35 | 'rtf' => 'application/msword', 36 | 'svg' => 'image/svg+xml', 37 | 'swf' => 'application/x-shockwave-flash', 38 | 'tif' => 'image/tiff', 39 | 'tiff' => 'image/tiff', 40 | 'txt' => 'text/plain', 41 | 'vml' => 'text/xml', 42 | 'vxml' => 'text/xml', 43 | 'wav' => 'audio/wav', 44 | 'wma' => 'audio/x-ms-wma', 45 | 'wmv' => 'video/x-ms-wmv', 46 | 'woff' => 'image/woff', 47 | 'xml' => 'text/xml', 48 | 'xls' => 'application/vnd.ms-excel', 49 | 'xq' => 'text/xml', 50 | 'xql' => 'text/xml', 51 | 'xquery' => 'text/xml', 52 | 'xsd' => 'text/xml', 53 | 'xsl' => 'text/xml', 54 | 'xslt' => 'text/xml' 55 | ); 56 | 57 | /** 58 | * HTTP状态码表 59 | * @var array 60 | */ 61 | public static $statusMap = array( 62 | 200 => 'OK', 63 | 304 => 'Not Modified', 64 | 404 => 'File Not Found', 65 | 403 => 'Forbidden', 66 | 500 => 'Internal Server Error' 67 | ); 68 | 69 | /** 70 | * 设置HTTP请求头信息 71 | * @param int $code HTTP状态码 72 | * @param null|string $status 状态信息 73 | */ 74 | public static function header($code = 200, $status = null) { 75 | if ($status === null && isset(self::$statusMap[$code])) { 76 | $status = self::$statusMap[$code]; 77 | } 78 | 79 | if (php_sapi_name() == 'cgi') { 80 | header("Status: $code $status"); 81 | } else { 82 | header("HTTP/1.1 $code $status"); 83 | } 84 | } 85 | 86 | /** 87 | * 添加用户自定义的url处理规则 88 | * @param $type 规则名称 89 | * @param callable $callback 用户处理callback函数,callback参数为匹配的$matches数组 90 | */ 91 | public static function addRewriteRule($type, $callback){ 92 | if(is_callable($callback)){ 93 | $type = strtolower($type); 94 | self::$userRules[$type] = $callback; 95 | } 96 | } 97 | 98 | public static function setRoot($root){ 99 | self::$root = $root; 100 | } 101 | 102 | public static function getRoot(){ 103 | return isset(self::$root) ? self::$root : dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR; 104 | } 105 | 106 | private static function padString($path, $matches) { 107 | for ($i = 1, $len = count($matches); $i < $len; $i++) { 108 | $path = preg_replace('/\\$' . $i . '\\b/', $matches[$i], $path); 109 | $path = preg_replace('/\\\\' . $i . '\\b/', $matches[$i], $path); 110 | } 111 | return $path; 112 | } 113 | 114 | /** 115 | * $url : 需要匹配的url 116 | * $matches : 正则匹配的引用 117 | * 返回值 : 118 | * true : 表示命中正则 119 | * false : 表示没有命中 120 | */ 121 | public static function match($url, &$matches = null){ 122 | $root = self::getRoot(); 123 | //命中server.conf文件中定义的rewrite,redirect规则 124 | $configFile = $root . 'server.conf'; 125 | if(file_exists($configFile) && ($handle = fopen($configFile, 'r'))){ 126 | while (($buffer = fgets($handle)) !== false) { 127 | $ruleTokens = preg_split('/\s+/', trim($buffer)); 128 | $type = strtolower($ruleTokens[0]); 129 | if(preg_match('/^\w+$/', $type)){ 130 | $rule = array( 131 | 'rule' => $ruleTokens[1], 132 | 'rewrite' => $ruleTokens[2], 133 | 'type' => $type 134 | ); 135 | $ret = self::_match($rule, $root, $url, $matches); 136 | if($ret) { 137 | fclose($handle); 138 | return $ret; 139 | } 140 | } 141 | } 142 | if (!feof($handle)) { 143 | echo "Error: unexpected fgets() fail\n"; 144 | } 145 | fclose($handle); 146 | } 147 | return false; 148 | } 149 | 150 | private static function _match($rule, $root, $url, &$matches = null){ 151 | if(preg_match('/' . $rule['rule'] . '/', $url, $matches)){ 152 | $rewrite = self::padString($rule['rewrite'], $matches); 153 | $type = $rule['type']; 154 | if(isset(self::$userRules[$type])){ 155 | $ret = call_user_func(self::$userRules[$type], $rewrite, $url, $root, $matches); 156 | if($ret === false){ 157 | return false; 158 | } else { 159 | return true; 160 | } 161 | } if($type == 'rewrite'){ 162 | if(file_exists($file = $root . $rewrite)){ 163 | $pos = strrpos($rewrite, '.'); 164 | if(false !== $pos){ 165 | $ext = substr($rewrite, $pos + 1); 166 | if($ext == 'php'){ 167 | self::includePhp($root . $rewrite, $matches); 168 | } else { 169 | self::header(200); 170 | if(isset(self::$MIME[$ext])){ 171 | $content_type = 'Content-Type: ' . self::$MIME[$ext]; 172 | } else { 173 | $content_type = 'Content-Type: application/x-' . $ext; 174 | } 175 | header($content_type); 176 | echo file_get_contents($root . $rewrite); 177 | } 178 | } else { 179 | echo file_get_contents($root . $rewrite); 180 | } 181 | } else { 182 | self::header(404); 183 | } 184 | } else if($type == 'redirect'){ 185 | header('Location: ' . $rewrite); 186 | exit(); 187 | } 188 | return true; 189 | } 190 | return false; 191 | } 192 | 193 | private static function includePhp($file, $matches){ 194 | try{ 195 | $fis_matches = $matches; 196 | include($file); 197 | }catch(Exception $e){ 198 | throw new Exception("include php file " . $file . "failed"); 199 | } 200 | } 201 | } 202 | --------------------------------------------------------------------------------