Etag和Expires原來和設定

摘要
1、Etag和Expires中Client 端Http Request Header及Server端Http Reponse Header工作原理。
2、靜態下Apache、Lighttpd和Nginx中Etag和Expires配置
3、非實時交互動態頁面中Etag和Expires處理
在客戶端通過瀏覽器發出第一次請求某一個URL時,根據 HTTP 協議的規定,瀏覽器會向服務器傳送報頭(Http Request Header),服務器端響應同時記錄相關屬性標記(Http Reponse Header),服務器端的返回狀態會是200,格式類似如下:
HTTP/1.1 200 OK
Date: Tue, 03 Mar 2009 04:58:40 GMT
Content-Type: image/jpeg
Content-Length: 83185
Last-Modified: Tue, 24 Feb 2009 08:01:04 GMT
Cache-Control: max-age=2592000

Expires: Thu, 02 Apr 2009 05:14:08 GMT
Etag: 「5d8c72a5edda8d6a:3239〞

客戶端第二次請求此URL時,根據 HTTP 協議的規定,瀏覽器會向服務器傳送報頭(Http Request Header),服務器端響應並記錄相關記錄屬性標記文件沒有發生改動,服務器端返回304,直接從緩存中讀取:
HTTP/1.x 304 Not Modified
Date: Tue, 03 Mar 2009 05:03:56 GMT
Content-Type: image/jpeg
Content-Length: 83185
Last-Modified: Tue, 24 Feb 2009 08:01:04 GMT
Cache-Control: max-age=2592000
Expires: Thu, 02 Apr 2009 05:14:08 GMT
Etag: 「5d8c72a5edda8d6a:3239〞
其中Last-ModifiedExpiresEtag是標記頁面緩存標識

一、Last-Modified、Expires和Etag相關工作原理
1、Last-Modified
在瀏覽器第一次請求某一個URL時,服務器端的返回狀態會是200,內容是你請求的資源,同時有一個Last-Modified的屬性標記(Http Reponse Header)此文件在服務期端最後被修改的時間,格式類似這樣:
Last-Modified: Tue, 24 Feb 2009 08:01:04 GMT
客戶端第二次請求此URL時,根據 HTTP 協議的規定,瀏覽器會向服務器傳送 If-Modified-Since 報頭(Http Request Header),詢問該時間之後文件是否有被修改過:
If-Modified-Since: Tue, 24 Feb 2009 08:01:04 GMT
如果服務器端的資源沒有變化,則自動返回 HTTP 304 (NotChanged.)狀態碼,內容為空,這樣就節省了傳輸數據量。當服務器端代碼發生改變或者重啟服務器時,則重新發出資源,返回和第一次請求時類 似。從而保證不向客戶端重複發出資源,也保證當服務器有變化時,客戶端能夠得到最新的資源。
註:如果If-Modified-Since的時間比服務器當前時間(當前的請求時間request_time)還晚,會認為是個非法請求

2、Etag工作原理
HTTP 協議規格說明定義ETag為「被請求變量的實體標記」 。簡單點即服務器響應時給請求URL標記,並在HTTP響應頭中將其傳送到客戶端,類似服務器端返回的格式:
Etag: 「5d8c72a5edda8d6a:3239〞
客戶端的查詢更新格式是這樣的:
If-None-Match: 「5d8c72a5edda8d6a:3239〞
如果ETag沒改變,則返回狀態304。
即:在客戶端發出請求後,Http Reponse Header中包含 Etag: 「5d8c72a5edda8d6a:3239〞
標識,等於告訴Client端,你拿到的這個的資源有表示ID:5d8c72a5edda8d6a:3239。當下次需要發Request索要同一個 URI的時候,瀏覽器同時發出一個If-None-Match報頭( Http RequestHeader)此時包頭中信息包含上次訪問得到的Etag: 「5d8c72a5edda8d6a:3239〞標識。
If-None-Match: 「5d8c72a5edda8d6a:3239「
,這樣,Client端等於Cache了兩份,服務器端就會比對2者的etag。如果If-None-Match為False,不返回200,返回304 (Not Modified) Response。

3、Expires
給出的日期/時間後,被響應認為是過時。如Expires: Thu, 02 Apr 2009 05:14:08 GMT
需和Last-Modified結合使用。用於控制請求文件的有效時間,當請求數據在有效期內時客戶端瀏覽器從緩存請求數據而不是服務器端. 當緩存中數據失效或過期,才決定從服務器更新數據。

4、Last-Modified和Expires
Last-Modified標識能夠節省一點帶寬,但是還是逃不掉發一個HTTP請求出去,而且要和Expires一起用。而Expires標識卻使得瀏覽器乾脆連HTTP請求都不用發,比如當用戶F5或者點擊Refresh按鈕的時候就算對於有Expires的URI,一樣也會發一個HTTP請求出去,所以,Last-Modified還是要用的,而 且要和Expires一起用。

5、Etag和Expires
如果服務器端同時設置了Etag和Expires時,Etag原理同樣,即與Last-Modified/Etag對應的HttpRequest Header:If-Modified-Since和If-None-Match。我們可以看到這兩個Header的值和WebServer發出的 Last-Modified,Etag值完全一樣;在完全匹配If-Modified-Since和If-None-Match即檢查完修改時間和 Etag之後,服務器才能返回304.

6、Last-Modified和Etag
Last-Modified 和ETags請求的http報頭一起使用,服務器首先產生 Last-Modified/Etag標記,服務器可在稍後使用它來判斷頁面是否已經被修改,來決定文件是否繼續緩存
過程如下:
1. 客戶端請求一個頁面(A)。
2. 服務器返回頁面A,並在給A加上一個Last-Modified/ETag。
3. 客戶端展現該頁面,並將頁面連同Last-Modified/ETag一起緩存。
4. 客戶再次請求頁面A,並將上次請求時服務器返回的Last-Modified/ETag一起傳遞給服務器。
5. 服務器檢查該Last-Modified或ETag,並判斷出該頁面自上次客戶端請求之後還未被修改,直接返迴響應304和一個空的響應體。
註:
1、Last-Modified和Etag頭都是由Web Server發出的Http Reponse Header,Web Server應該同時支持這兩種頭。
2、Web Server發送完Last-Modified/Etag頭給客戶端後,客戶端會緩存這些頭;
3、客戶端再次發起相同頁面的請求時,將分別發送與Last-Modified/Etag對應的Http RequestHeader:If-Modified-Since和If-None-Match。我們可以看到這兩個Header的值和 WebServer發出的Last-Modified,Etag值完全一樣;
4、通過上述值到服務器端檢查,判斷文件是否繼續緩存;

二、Apache、Lighttpd和Nginx中針配置Etag和Expires,有效緩存純靜態如css/js/pic/頁面/流媒體等文件。
A、Expires
A.1、Apache Etag
使用Apache的mod_expires 模塊來設置,這包括控制應答時的Expires頭內容和Cache-Control頭的max-age指令
ExpiresActive On
ExpiresByType image/gif 「access plus 1 month」
ExpiresByType image/jpg 「access plus 1 month」
ExpiresByType image/jpeg 「access plus 1 month」
ExpiresByType image/x-icon 「access plus 1 month」
ExpiresByType image/bmp 「access plus 1 month」
ExpiresByType image/png 「access plus 1 month」
ExpiresByType text/html 「access plus 30 minutes」
ExpiresByType text/css  「access plus 30 minutes」
ExpiresByType text/txt  「access plus 30 minutes」
ExpiresByType text/js   」access plus 30 minutes」
ExpiresByType application/x-javascript   」access plus 30 minutes」
ExpiresByType application/x-shockwave-flash     」access plus 30 minutes」

<ifmodule mod_expires.c>
<filesmatch 「\.(jpg|gif|png|css|js)$」>
ExpiresActive on
ExpiresDefault 「access plus 1 year」
</filesmatch>
</ifmodule>
當設置了expires後,會自動輸出Cache-Control 的max-age 信息
具體關於 Expires 詳細內容可以查看Apache官方文檔。
在這個時間段裡,該文件的請求都將直接通過緩存服務器獲取,
當然如果需要忽略瀏覽器的刷新請求(F5),緩存服務器squid還需要使用 refresh_pattern 選項來忽略該請求
refresh_pattern -i \.gif$ 1440 100% 28800 ignore-reload
refresh_pattern -i \.jpg$ 1440 100% 28800 ignore-reload
refresh_pattern -i \.jpeg$ 1440 100% 28800 ignore-reload
refresh_pattern -i \.png$ 1440 100% 28800 ignore-reload
refresh_pattern -i \.bmp$ 1440 100% 28800 ignore-reload
refresh_pattern -i \.htm$ 60 100% 100 ignore-reload
refresh_pattern -i \.html$ 1440 50% 28800 ignore-reload
refresh_pattern -i \.xml$ 1440 50% 28800 ignore-reload
refresh_pattern -i \.txt$ 1440 50% 28800 ignore-reload
refresh_pattern -i \.css$ 1440 50% 28800 reload-into-ims
refresh_pattern -i \.js$ 60 50% 100 reload-into-ims
refresh_pattern . 10 50% 60
有關Squid中Expires的說明,請參考Squid官方中refresh_pattern介紹。

A.2、Lighttpd Expires
和Apache一樣Lighttpd設置expire也要先查看是否支持了mod_expire模塊,
下面的設置是讓URI中所有images目錄下的文件1小時後過期;
expire.url = ( 「/images/」 => 「access 1 hours」 )
下面是讓作用於images目錄及其子目錄的文件;
$HTTP[“url”] =~ 「^/images/」 {
expire.url = ( 「」 => 「access 1 hours」 )
}
也可以指定文件的類型;
$HTTP[“url”] =~ 「\.(jpg|gif|png|css|js)$」 {
expire.url = ( 「」 => 「access 1 hours」 )
}
具體參考Lighttpd官方Expires解釋

A.3、Nginx中Expires
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
{
expires 30d;
}
location ~ .*\.(js|css)?$
{
expires 1h;
}
這類文件並不常修改,通過 expires 指令來控制其在瀏覽器的緩存,以減少不必要的請求。 expires 指令可以控制 HTTP 應答中的「 Expires 」和「 Cache-Control 」的頭標(起到控制頁面緩存的作用)。其他請參考Nginx中Expires

B.1、Apache中Etag設置
在Apache中設置Etag的支持比較簡單,只用在含有靜態文件的目錄中建立一個文件.htaccess, 裡面加入:
FileETag MTime Size
這樣就行了,詳細的可以參考Apache的FileEtag文檔頁

B.2、Lighttpd Etag
在Lighttpd中設置Etag支持:
etag.use-inode: 是否使用inode作為Etag
etag.use-mtime: 是否使用文件修改時間作為Etag
etag.use-size: 是否使用文件大小作為Etag
static-file.etags: 是否啟用Etag的功能
第四個參數肯定是要enable的, 前面三個就看實際的需要來選吧,推薦使用修改時間

B.3、 Nginx Etag
Nginx中默認沒有添加對Etag標識.Igor Sysoev的觀點」在對靜態文件處理上看不出如何Etag好於Last-Modified標識。」
Note:
Yes, it』s addition,and it』s easy to add, however, I do not see howETag is better than Last-Modified for static files. -Igor Sysoev
A nice short description is here:
http://www.mnot.net/cache_docs/#WORK
It looks to me that it makes some caches out there to cache theresponse from the origin server more reliable as in rfc2616(ftp://ftp.rfc-editor.org/in-notes/rfc2616.txt) is written.
3.11 Entity Tags 13.3.2 Entity Tag Cache Validators 14.19 ETag
當然也有第三方nginx-static-etags 模塊了,請參考
http://mikewest.org/2008/11/generating-etags-for-static-content-using-nginx

三、對於非實時交互動態頁面中Epires和Etag處理
對數據更新並不頻繁、如tag分類歸檔等等,可以考慮對其cache。簡單點就是在非實時交互的動態程序中輸出expires和etag標識,讓其緩存。 但需要注意關閉session,防止http response時http header包含session id標識;
3.1、Expires
如expires.php
<?php
header(』Cache-Control: max-age=86400,must-revalidate』);
header(』Last-Modified: 『 .gmdate(』D, d M Y H:i:s』) . 『 GMT』 );
header(」Expires: 」 .gmdate (』D, d M Y H:i:s』, time() + 『86400′ ). 『 GMT』);
?>
以上信息表示該文件自請求後24小時後過期。
其他需要處理的動態頁面直接調用即可。
3.2、Etag
根據Http返回狀態來處理。當返回304直接從緩存中讀取
如etag.php
<?php
cache();
echo date(」Y-m-d H:i:s」);
function cache()
{
$etag = 「http://longrujun.name」;
if ($_SERVER[‘HTTP_IF_NONE_MATCH’] == $etag)
{
header(』Etag:』.$etag,true,304);
exit;
}
else header(』Etag:』.$etag);
}
?>

HTTP_USER_AGENT Spider check

$botchar = “/(Googlebot|YahooSeeker|mediapartners|baiduspider|sohu-search|soso|spider|sohu-search|yodao|robozilla|msnbot)/i”; //add yourself
if(preg_match($botchar, $_SERVER[‘HTTP_USER_AGENT’]))
reutrn true;
else
return false;

Memcached

Memcached 是內存緩存組件,可提供給php 使用 ,減輕mysql的負擔

資源:

Memcached 主站 : http://www.danga.com/memcached/

php上的Memcached class 介紹: http://hk.php.net/memcache

windwos版上用的Memcached 程序 :http://jehiah.cz/projects/memcached-win32/

pecl 給出的php extention : http://pecl4win.php.net/ext.php/php_memcache.dll

 安裝:

copy好php_memcache.dll 到你的php extention folder

修改php.ini 加上

extension=php_memcache.dll

重啟apache 就ok

文件系統(File System)地獄測試

做php的caching 時會留意到,到底文件系統(File system) 的查找速度會如何.

今次特意做了個三層文件系統的傳取測試:

系統環境:
CPU: INTEL E6320
RAM: 2GB
Apache 2.23 ,php 4.4.4 ,zend 1.5

測試設置:
用md5制做檔案名,
for 1000次做10000個187KB文件(TOTAL 1.78GB)

分別分三個模式儲存:
用MD5文檔名

  1. ./{0~2}/MD5(i).php
  2. ./{0~2}/{2~4}/MD5(i).php
  3. ./{0~2}/{2~4}/{4~6}/MD5(i).php

然後分別做隨機抽取文件做效能測試:

以300次平均時間來計算

  1. 0.045秒
  2. 0.035秒
  3. 0.0475秒

2 > 1 > 3 .

結論:

二層分階像在10000 個文件比較有優勢,效率最高,但暫時人無力做十萬個文件的湔試;

本次測試的文件: FileSystem_test.zip

PHP 的命令行模式(CLI)

从版本 4.3.0 开始,PHP 提供了一种新类型的 SAPI(Server Application Programming Interface,服务端应用编程端口)支持,名为 CLI,意为 Command Line Interface,即命令行接口。顾名思义,该 SAPI 模块主要用作 PHP 的开发外壳应用。CLI SAPI 和其它 SAPI 模块相比有很多的不同之处,我们详细阐述。值得一提的是,CLICGI 是不同的 SAPI,尽管它们之间有很多共同的行为。

搞 了差不多一星期终于有一点成果了,现在PHP 的CLI MODE对于在其他网页的信息查取非常有用。比如定时去拿某网页上的新闻,以前做法是做好了PHP页然后再做一个HTML页作指向,并用WINDOWS的 task工具定时打开html页,这样做的问题是,Browser会越开越多,而且php有timeout情况,在网速极不稳情况下会出现失败的情况。用 了CLI MODE 可以用BAT档运行PHP脚本,而且运行完之后console mode窗口会关闭,而且CLI MODE timeout是无限,即是程序会等待到信息拿到为止,最好的是占用资源小了好多,但开发时要有编程的概念了>_<

osys 的CLI MODE 基本完成 可以把原來在OSYS 下的 模塊文件嵌入CLI 的BAT檔咝?通用性^^)

而截取息的function也开始定了几个有用的如:
opensocfile //打开socket (由鬼鬼写的 经改良成函数调用)
copyfile //把网络文件copy到本地 如文件存在则不copy
makedir //在本机上生作文件夹可把path下所有没生成的都生成出来
sloveurl //把URL 分拆成ARRAY传回 分成 HOST , PATH ,FILENAME等 PATH 和 FILENAME 也另有ARRAY生成

gettable , gettr , gettd //这三个要连起来用 用来分析HTML代码中的TABLE TAG 并生成ARRAY

BAT 档框架 O-xygen
@REM

:

//php 脚本

:

?>
部份html分析function
$searcharray[]=“/
<>]*>(.+?)/esi”
;
$replacearray[]=“gettable(‘\1’)”
;
$out = preg_replace($searcharray, $replacearray, $con
);
//——————————chop tool——————————————

function gettable($out){
global
$table
;
$out=stripslashes($out
);
$table[count($table)]=“”
;
$searcharray[]=“/
<>]*>(.+?)/esi”
;
$replacearray[]=“gettr(‘\1’)”
;
$out = preg_replace($searcharray, $replacearray, $out
);
}
function
gettr($out
){
global
$table
;
$out=stripslashes($out
);
$table[count($table)-1][]=“”
;
$searcharray[]=“/ <>]*>(.+?)/esi”
;
$replacearray[]=“gettd(‘\1’)”
;
$out = preg_replace($searcharray, $replacearray, $out
);
}
function
gettd($out
){
global
$table
;
$out=stripslashes($out
);
$out=str_replace(array(” “),array(“”),$out
);
$table[count($table)-1][count($table[count($table)-1])-1][]=$out
;
}

//—————————————————————————–

function sloveurl($url){
if(
ereg (“http://([^:^@^/]+)/(.*)”,$url,$regs
)){
$s_url[“domain”] = $regs[1
];
$s_url[“path_arr”]= split(“/”,$regs[2
]);
//if( count($s_url[“path_arr”]) > 1 ){

$s_url[“path”] = $regs[2];
//}else{
// $s_url[“path”] = “”;
//}

$s_url[“filename”]= $s_url[“path_arr”][count($s_url[“path_arr”])-1];
$s_url[“filename”]= split(“?”,$s_url[“filename”
]);
if(
$s_url[“filename”][1] <>“”
){
$s_url[“QUERY”]=$s_url[“filename”][1
];
}
$s_url[“filename”]=$s_url[“filename”][0
];
$sn = split(“.”,$s_url[“filename”
]);
$s_url[“fna”] = $sn[0
];
$s_url[“fex”] = $sn[1
];
return
$s_url
;
}
return
false
;
}

function makedir($path){

for($i=1;$i<count($path);$i++){

$foder=“”;
for(
$a=1;$a<=$i;$a
++){
$foder.=$path[$a].“/”
;
}
if(!
file_exists($foder
)){
@
mkdir($foder
);
}
}

}

function copyfile($ffrom,$fto){
if(!
file_exists($fto
)){
if(
copy($ffrom,$fto
)){
return
true
;
}
}
return
false
;
}

function opensocfile($url,$port=80,$data_array=“”)
{
if (
ereg (“http://([^:^@^/]+)(.*)”,$url,$regs
)) {

$host = $regs[1];

}

//$UserAgent=”Mozilla/4.0 (compatible; MSIE 7.00; Windows 99)”;
$UserAgent=“Osys_PHP_spider+0.1”
;

$fp = fsockopen($host,$port,$errno,$errstr,3600);
if (
$fp
){

if($data_array<>“”){
$formdata = “”
;
while (list(
$key,$value) = each($data_array
)){
if (
strlen($formdata) != 0
)
$formdata .= “&”
;
$formdata .= rawurlencode($key).“=”.rawurlencode($value
);
}
}
//end if

$formdata = trim($formdata);
$out = “POST $url HTTP/1.0 “
;
$out .= “Host: $host:$port “
;
$out .= “User-Agent: $UserAgent “
;
$out .= “Accept: */* “
;
$out .= “Content-Type: application/x-www-form-urlencoded “
;
$out .= “Content-Length: “.strlen($formdata).” “
;
$out .= “Connection: close “
;
$out .= “$formdata “
;

fputs($fp, $out);
while (!
feof($fp
)) {
$content .= fgets($fp,10240
);
}
fclose($fp
);
//去掉返回的header数据
$content = substr($content,strpos($content,” “)+4
);
return
$content
;
}
return
false
;
}

DIY匹配UTF-8中文字符的正则表达式

急着用的朋友可以先拿去用,这个正则非原创,但是经过我的修改,如有问题,请回复告知,代码是写给PHP初学者的,高手请自抠正则。



$word = 中文;
if (preg_match(/^([.chr(228)..chr(233).]{1}[.chr(128)..chr(191).]{1}[.chr(128)..chr(191).]{1}){1}/,$word) == true || preg_match(/([.chr(228)..chr(233).]{1}[.chr(128)..chr(191).]{1}[.chr(128)..chr(191).]{1}){1}$/,$word) == true || preg_match(/([.chr(228)..chr(233).]{1}[.chr(128)..chr(191).]{1}[.chr(128)..chr(191).]{1}){2,}/,$word) == true)
{
echo 很好,这是一个UTF-8编码的汉字;
}
else
{
echo 抱歉,这不是一个UTF-8编码的汉字;
}
?>

先不要被上面那个稀奇古怪的代码吓到,看完这篇文章以后,你就不会觉得它了不起了:)另外,本文不会卖弄大量的关于编码的概念,如果需要额外的扩展阅读,请通过google查找,相信一定能够满足您的阅读需求。

关于编码:

上 海的邮政编码是200000 ,上海的地理编码(经纬度)是lat:31.2356;lng:121.4728,上海的电话编码(国际区号)是:086021。类比在计算机里面, “汉”字的gb2312编码是:1011 1010 1011 1010(16进制:BABA);“汉”字的Unicode编码是 0110 1100 0100 1001(16进制:6C49);“汉”字的UTF-8编码是1110 0110 1011 0001 1000 1001 (16进制:E6B189)。所以,不同的汉字,在不同的编码方式下,表示的方法也是不一样的。

关于unicode:

随 着全球化的到来,全球性的的沟通变得异常的普遍,在互联网的世界里,为了能够让用户方便的访问全世界不同地域,不同文字(编码)的站点,历史上先 后有两个试图独立设计Unicode的组织,即国际标准化组织(ISO)和一个软件制造商的协会(unicode.org)。在1991年前后,双方都认 识到世界不需要两个不兼容的字符集。于是它们开始合并双方的工作成果,并为创立一个单一编码表而协同工作。于是,真正意义上的Unicode孕育而生。

Unicode 的学名是”Universal Multiple-Octet Coded Character Set”,简称为UCS。UCS可以看作是”Unicode Character Set”的缩写。简单的说Unicode是一种可以容纳全世界所有语言文字的编码方案。

unicode编码在前面已经看到了,补充一点,有的时候还会用10进制中文字符,所以“汉”字还有可能是这个样子:27721

<script>
document.write(.charCodeAt());//显示27721
<
/script>

关于UTF-8:

UTF -8是unicode编码的扩展(也可以说是子集),由Ken Thompson于1992年创建,只要将某个字符的unicode编码一一插入相应的空位(刚好有16个空位)就可以成为一个UTF-8编码,细心的研 究一下刚才给出的“汉”字的例子,你就能发现这一点。

1 1 1 0 _ _ _ _ 1 0 _ _ _ _ _ _ 1 0 _ _ _ _ _ _

好了,我们现在已经了解了关于unicode,编码和UTF-8的相关知识(虽然并不全面),但是我们还需要一些工具:

一个进制转换的页面(觉得麻烦的话可以google现成的):

一份编码对照表:

http://www.ansell-uebersetzungen.com/gbuni.html

准备好以后,我们就开始DIY匹配UTF-8中文字符的正则表达式,有能力的朋友可以不阅读下面的文章,自己对照正则表达式判断和分析过程(我一开始就是这么做的!),下面的进度比较快,对编码不了解的朋友需要借助参考资料阅读。

仔细研究《编码对照表》,你会发现unicode编码中的汉字编码区间是连续的,位于4E00和9FA0之间,用《进制转换页面》把16进制转换成2进制:

4E00 :  0100 1110 0000 0000
9FA0 :  1001 1111 1010 0000

上面的二进制编码就是要写入1 1 1 0 _ _ _ _ 1 0 _ _ _ _ _ _ 1 0 _ _ _ _ _ _ 的16个空位,就像:

1110 0100 1011 1000 1000 0000
1110 1001 1011 1110 1010 0000

将新组成的2进制形式UTF-8编码使用《进制转换页面》整理成16进制的(分析过程使用)格式:

1110 0100 1011 1000 1000 0000 : E4 B8 80
1110 1001 1011 1110 1010 0000 : E9 BE A0

精确拆分的结果如下:

第一段:E4 B8 80 到 E4 BF BF
第二段:E5 80 80 到 E8 BF BF
第三段:E9 80 80 到 E9 BE A0

正则的作者显然是为了编写的方便,将汉字的UTF-8编码集扩大为了:E4 80 80 到 E9 BF BF ,在对使用效果影响不大的情况下,我们也不妨简化处理:

[“.chr (228).”-“.chr(233).”]{1}表示一个E4(228的16进制表示)到E9之间的编码,[“.chr(128). “-“.chr(191).”]{1}表示80到BF之间的编码,于是就组成了 ([“.chr(228).”-“.chr(233).”]{1}[“.chr(128).”-“.chr(191).”]{1}[“.chr(128). “-“.chr(191).”]{1}){1}这个匹配UTF-8单个汉字的正则,最后经过修正,成为本文开始给出的表达式。

中文检查

用js脚本控制
我这里有现成的脚本
<script language=”javascript”>
function chkNum(obj,msg)
{

var str = obj.value;

var r = str.match(/^[1-9]d{0,}$/);

if(null==r)

{

alert(msg);

obj.select();

return false;

}

else

return true;
}
</script>
<SCRIPT>
function onlychinese()
{
if ((window.event.keyCode >=32) && (window.event.keyCode <= 126))
{
window.event.keyCode = 0 ;
}
}
</SCRIPT>
<input type=text onblur=”CheNum(this,’请输入数字’);”>
<input type=text onkeypress=”onlychinese();”>

<?php
$number = $_GET['number'];
$text = $_GET['text'];

// 仅允许数字
function chk_number($str) {
if(!preg_match("/^[0-9]{1,}$/",$str)) {
echo "Error!";
}else {
echo "OK";
}
}

// 检查中文
function chk_chinese($str) {
if(!preg_match("/^[x80-xff]{1,}$/",$str)) {
echo "Error!";
}else {
echo "OK";
}
}
echo "数字检查:";
chk_number($number);
echo "<br />中文检查:";
chk_chinese($text);
?>