Apache的Mod_rewrite学习

车东很早就写了一篇文章来介绍利用mod_rewrite模块来达到用静态页面形式的链接隐藏后台的动态页面
  Apache的rewrite模块,提供了一个基于规则的重写(rewrite,也许译为重构更为合适)引擎,来实时重写发送到Apache的请求URL。因功能极其强大,被称为URL重写的“瑞士军刀”。

  这个模块使用一个基于正则表达式解析器开发的重写引擎,根据web管理员定义的规则来实时(on the fly)重写请求URL。它支持任意数目的重写规则,以及附加到一条规则上的任意数目的规则条件,从而提供了一套非常灵活和功能强大的URL处理机制。URL处理操作的实施与否,依赖于各种各样的条件检查,如检查服务器变量、环境变量、HTTP头字段、时间戳的值,甚至外部数据库的检索结果。这个模块可以在服务器范围内(http.conf)、目录范围内(.htaccess)或请求串(query-string)的一部分处理有关的URL。重写的结果URL,可以指向一个站内的处理程序、指向站外的重定向或者一个站内的代理。与灵活和功能强大相随的是设置的复杂,别指望一天内弄明白整个模块。(所以,这个学习笔记也分了几部分:)
  

内部处理过程

API阶段
  首先,Apache处理HTTP请求是分阶段进行的,Apache API为每个阶段提供了一个钩子(hook)。Mod_rewrite使用了其中的两个钩子:一个用来在HTTP请求被读取但还没有访问授权验证之前进行URL_to_filename转换,一个用来在授权验证完成且目录设置文件(.htaccess)读取之后、但内容处理器(content handler)被调用之前激化,进行修补(fixup).因此,当一个请求到达,Apache决定了相关的服务器(或虚拟服务器)以后进行URL_to_filename阶段,重写引擎(rewrite engine)开始处理服务器设置中的重写指令(mod_rewrite directives).接下来几个阶段过后进入修补阶段,此时最终的数据所在的物理目录已经找到,目录配置中的重写指令开始执行。在这两个阶段,mod_rewrite都是将URL重写为新的URL或文件名,所以看起来并没有明显的区别。对API的这种应用,并不是一开始就是这样设计的,而是Apache1.x不得已而为之。为了搞清这个问题,以下两点需要记住。
  1)虽然mod_rewrite能进行URL到URL、URL到文件名字甚至文件名字到文件名字的转换,API(1.x)目前提供了一个URL_to_filename转换。在Apache2.0中,这两个钩子会被加进去,整个过程会更加清晰。一个事实必须清楚的记得:Apache在URL_to_filename钩子中,做得比API设计的功能更多。
  2)不可思议的是,mod_rewrite能在目录范围内(如根据.htaccess文件的指令配置)进行URL处理,虽然URL很早就已经被转换为文件名字了。只所以会如此,是因为.htaccess文件存在于文件系统中。也就是说,在这个阶段来进行URL处理,是非常晚的时候了。为了解决这个”先有鸡还是先有蛋”的问题,mod_rewrite用了一个小技巧:当在目范围内处理URL/filename时,mod_rewrite先将文件名逆转回相关的URL(虽然通常是不可能的,但请参见下面用以实现这个技巧的RewriteBase指令),然后据这个新URL生成一个站内的子请求(internal sub-request),这又重开始了API进程。Mod_rewrite尽量使这些复杂的步骤对用户透明,但应要记住:虽然目录范围URL的真正处理过程很快很高效,但这一阶段会因为这个”鸡和蛋”的问题而变得很慢和低效。从另一方面来看,这也是mod_rewrite提供给普通用户进行目录范围内的URL处理的唯一途径.
规则集(RewriteRule指令集合)处理过程
  当mod_rewrite在上述的两个API阶段被激活时,它会从它的配置数据结构(在开始服务器上下文(per-server context)或目录上下文(per-directory context)时创建的)中读取配置的规则集,然后URL重写引擎启动来执行包含的规则集(一个或多条规则以及它们的条件)。两种上下文中的处理过程都是一样的,差别只是在最后的结果处理过程上。
  规则集中规则的顺序是非常重要的,因为重写引擎以特定的顺序来处理它们。重写引擎顺序遍历规则集,当一条规则匹配时,引擎会去遍历与它相关的条件集(RewriteCond指令集合).由于历史的原因,条件集先被列出来,因此控制流流程有点曲折(long-winded).如图一所示:mod_rewrite_fig1.gif
  正如所看到的,首先URL会与每条规则的模板(pattern)比较,当匹配失败时,立即停止对当前规则的处理进入下一条规则。当匹配成功时,mod_rewrite寻找相关的规则条件。如果找不到相关的条件,则直接执行规则中定义的替换,然后回到规则遍历的过程。如果找到了相关的条件,则启动一个内部循环,依次检查各个条件。对于检查,我们不是拿一个模板来匹配当前的URL,而是先创建一个TestString串,将串内的变量、后向引用(bakc-reference)、查询结果(map lookups)等展开,然后用这个TestString和条件式中的CondPattern进行匹配,如果匹配失败,则整个条件集且这个规则都不再执行,重要回到规则遍历中;如果匹配成功,则检查下一个条件,如果所有的条件都满足,则执行规则中定义的替换动作。  
特殊字符的转义
  既然基于正则式,则当然会有特殊字符的问题。在1.3.20版本的Apache中,通过在特殊字符前加一个“”来将TestString或Sustitution串的特殊字符转义。
正则式的后向引用
mod_rewrite_fig2.gif  有一点需要记住:一旦在模板(pattern)或条件模板(CondPattern)中使用了括号,则后向引用已经自动产生了,你可以在Sustitution或TestString中通过$N或%N来引用相关的值。如图,描述了后向引用的值可以传到的位置。

配置指令(Configuration Directives)

 

指令 语法 默认值 说明 备注
RewriteEngine RewriteEngine on|off Off 开关重构引擎 默认时不能继承,故每个虚拟主机都要有自己的开关指令。
RewriteOptions RewriteOptions Option MaxRedirects=10 设置一些特殊参数 inherit:配置是否继承,MaxRedirects=number:内部重定向次数
RewriteLog RewriteLog file-path None 设定重写log文件 用RewriteLogLevel 0来禁止日志
RewriteLogLevel RewriteLogLevel Level RewriteLogLevel 0 设置日志级别 0表示没有,2以上用于debug,9及以上表示全部信息
RewriteLock RewriteLock file-path None 设置RewriteMap程序的同步锁文件 要求是本地文件,此文件只对rewriting map-program有效。
RewriteMap RewriteMap MapName MapType:MapSource Notused per default 定义重写影射 具体说明参见文档
RewriteBase RewriteBase URL-path physical directory path 设置目录范围内重写的基本URL 具体说明参见文档
RewriteCond RewriteCond TestString CondPattern None 定义规则条件 具体说明参见文档
RewriteRule RewriteRule Pattern Substitution None 定义重写规则 具体说明参见文档

 

 

  今天学习重写规则的语法。

RewriteRule
Syntax: RewriteRule Pattern Substitution [flags]
  一条RewriteRule指令,定义一条重写规则,规则间的顺序非常重要。对Apache1.2及以后的版本,模板(pattern)是一个POSIX正则式,用以匹配当前的URL。当前的URL不一定是用记最初提交的URL,因为可能用一些规则在此规则前已经对URL进行了处理。
  对mod_rewrite来说,!是个合法的模板前缀,表示“非”的意思,这对描述“不满足某种匹配条件”的情况非常方便,或用作最后一条默认规则。当使用!时,不能在模板中有分组的通配符,也不能做后向引用。
  当匹配成功后,Substitution会被用来替换相应的匹配,它除了可以是普通的字符串以外,还可以包括:

  1. $N,引用RewriteRule模板中匹配的相关字串,N表示序号,N=0..9
  2. %N,引用最后一个RewriteCond模板中匹配的数据,N表示序号
  3. %{VARNAME},服务器变量
  4. ${mapname:key|default},映射函数调用

这些特殊内容的扩展,按上述顺序进行。
  一个URL的全部相关部分都会被Substitution替换,而且这个替换过程会一直持续到所有的规则都被执行完,除非明确地用L标志中断处理过程。
  当susbstitution有”-”前缀时,表示不进行替换,只做匹配检查。
  利用RewriteRule,可定义含有请求串(Query String)的URL,此时只需在Sustitution中加入一个?,表示此后的内容放入QUERY_STRING变量中。如果要清空一个QUERY_STRING变量,只需要以?结束Substitution串即可。
  如果给一个Substitution增加一个http://thishost[:port]的前缀,则mod_rewrite会自动将此前缀去掉。因此,利用http://thisthost做一个无条件的重定向到自己,将难以奏效。要实现这种效果,必须使用R标志。
  Flags是可选参数,当有多个标志同时出现时,彼此间以逗号分隔。

  1. ‘redirect|R [=code]’ (强制重定向)
      给当前的URI增加前缀http://thishost[:thisport]/, 从而生成一个新的URL,强制生成一个外部重定向(external redirection,指生的URL发送到客户端,由客户端再次以新的URL发出请求,虽然新URL仍指向当前的服务器). 如果没有指定的code值,则HTTP应答以状态值302 (MOVED TEMPORARILY),如果想使用300-400(不含400)间的其它值可以通过在code的位置以相应的数字指定,也可以用标志名指定: temp (默认值), permanent, seeother.
      注意,当使用这个标志时,要确实substitution是个合法的URL,这个标志只是在URL前增加http://thishost[:thisport]/前缀而已,重写操作会继续进行。如果要立即将新URL重定向,用L标志来中重写流程。
  2. ‘forbidden|F’ (强制禁止访问URL所指的资源)
      立即返回状态值403 (FORBIDDEN)的应答包。将这个标志与合适的RewriteConds 联合使用,可以阻断访问某些URL。
  3. ‘gone|G’ (强制返回URL所指资源为不存在(gone))
      立即返回状态值410 (GONE)的应答包。用这个标志来标记URL所指的资源永久消失了.
  4. # ‘proxy|P’ (强制将当前URL送往代理模块(proxy module))
      这个标志,强制将substitution当作一个发向代理模块的请求,并立即将共送往代理模块。因此,必须确保substitution串是一个合法的URI (如, 典型的情况是以http://hostname开头),否则会从代理模块得到一个错误. 这个标志,是ProxyPass指令的一个更强劲的实现,将远程请求(remote stuff)映射到本地服务器的名字空间(namespace)中来。
      注意,使用这个功能必须确保代理模块已经编译到Apache 服务器程序中了. 可以用“httpd -l ”命令,来检查输出中是否含有mod_proxy.c来确认一下。如果没有,而又需要使用这个功能,则需要重新编译“httpd”程序并使用mod_proxy有效。
  5. ‘last|L’ (最后一条规则)
      中止重写流程,不再对当前URL施加更多的重写规则。这相当于perl的last命令或C的break命令。
  6. ‘next|N’ (下一轮)
      重新从第一条重写规则开始执行重写过程,新开的过程中的URL不应当与最初的URL相同。 这相当于Perl的next命令或C的continue命令. 千万小心不要产生死循环。
  7. # ‘chain|C’ (将当前的规则与其后续规则綑绑(chained))
      当规则匹配时,处理过程与没有綑绑一样;如果规则不匹配,则綑绑在一起的后续规则也不在检查和执行。
  8. ‘type|T=MIME-type’ (强制MIME类型)
      强制将目标文件的MIME-type为某MIME类型。例如,这可用来模仿mod_alias模块对某目录的ScriptAlias指定,通过强制将该目录下的所有文件的类型改为 “application/x-httpd-cgi”.
  9. ‘nosubreq|NS’ (used only if no internal sub-request )
      这个标志强制重写引擎跳过为内部sub-request的重写规则.例如,当mod_include试图找到某一目录下的默认文件时 (index.xxx),sub-requests 会在Apache内部发生. Sub-requests并非总是有用的,在某些情况下如果整个规则集施加到它上面,会产生错误。利用这个标志可排除执行一些规则。
  10. ‘nocase|NC’ (模板不区分大小写)
      这个标志会使得模板匹配当前URL时忽略大小写的差别。
  11. ‘qsappend|QSA’ (追加请求串(query string))
      这个标志,强制重写引擎为Substitution的请求串追加一部分串,则不是替换掉原来的。借助这个标志,可以使用一个重写规则给请求串增加更多的数据。
  12. ‘noescape|NE’ (不对输出结果中的特殊字符进行转义处理)
      通常情况下,mod_write的输出结果中,特殊字符(如’%’, ‘$’, ‘;’, 等)会转义为它们的16进制形式(如分别为’%25′, ‘%24’, and ‘%3B’)。这个标志会禁止mod_rewrite对输出结果进行此类操作。 这个标志只能在 Apache 1.3.20及以后的版本中使用。
  13. ‘passthrough|PT’ (通过下一个处理器)
      这个标志强制重写引擎用filename字段的值来替换内部request_rec数据结构中uri字段的值。. 使用这个标志,可以使后续的其它URI-to-filename转换器的Alias、ScriptAlias、Redirect等指令,也能正常处理RewriteRule指令的输出结果。用一个小例子来说明它的语义:如果要用mod_rewrite的重写引擎将/abc转换为/def,然后用mod_alas将/def重写为ghi,则要:
    RewriteRule ^/abc(.*) /def$1 [PT]
    Alias /def /ghi
    如果PT标志被忽略,则mod_rewrite也能很好完成工作,如果., 将 uri=/abc/… 转换为filename=/def/… ,完全符合一个URI-to-filename转换器的动作。接下来 mod_alias 试图做 URI-to-filename 转换时就会出问题。
    注意:如果要混合都含有URL-to-filename转换器的不同的模块的指令,必须用这个标志。最典型的例子是mod_alias和mod_rewrite的使用。
  14. ‘skip|S=num’ (跳过后面的num个规则)
      当前规则匹配时,强制重写引擎跳过后续的num个规则。用这个可以来模仿if-then-else结构:then子句的最后一条rule的标志是skip=N,而N是else子句的规则条数。
  15. ‘env|E=VAR:VAL’ (设置环境变量)
      设置名为VAR的环境变量的值为VAL,其中VAL中可以含有正则式的后向引用($N或%N)。这个标志可以使用多次,以设置多个环境变量。这儿设置的变量,可以在多种情况下被引用,如在XSSI或CGI中。另外,也可以在RewriteCond模板中以%{ENV:VAR}的形式被引用。

注意:一定不要忘记,在服务器范围内的配置文件中,模板(pattern)用以匹配整个URL;而在目录范围内的配置文件中,目录前缀总是被自动去掉后再进行模板匹配的,且在替换完成后自动再加上这个前缀。这个功能对很多种类的重写是非常重要的,因为如果没有去前缀,则要进行父目录的匹配,而父目录的信息并不是总能得到的。一个例外是,当substitution中有http://打头时,则不再自动增加前缀了,如果P标志出现,则会强制转向代理。
注意:如果要在某个目录范围内启动重写引擎,则需要在相应的目录配置文件中设置“RewriteEngine on”,且目录的“Options FollowSymLinks”必须设置。如果管理员由于安全原因没有打开FollowSymLinks,则不能使用重写引擎。

 

 

  今天学习重写规则的条件。

RewriteCond
Syntax: RewriteCond TestString CondPattern [flags]
  RewriteCond指令定义一条规则条件。在一条RewriteRule指令前面可能会有一条或多条RewriteCond指令,只有当自身的模板(pattern)匹配成功且这些条件也满足时规则才被应用于当前URL处理。
  TestString是一个字符串,除了包含普通的字符外,还可以包括下列的可扩展结构:

  1. $N,RewriteRule后向引用,其中(0 <= N <= 9)
      $N引用紧跟在RewriteCond后面的RewriteRule中模板中的括号中的模板在当前URL中匹配的数据。
  2. %N,RewriteCond后向引用,其中(0 <= N <= 9)
      %N引用最后一个RewriteCond的模板中的括号中的模板在当前URL中匹配的数据。
  3. ${mapname:key|default},RewriteMap扩展.
    具体参见RewriteMap
  4. %{ NAME_OF_VARIABLE } ,服务器变量。
    变量的名字如下表(分类显示)

    HTTP headers: connection & request: server internals: system stuff:
    HTTP_USER_AGENT REMOTE_ADDR DOCUMENT_ROOT TIME_YEAR
    HTTP_REFERER REMOTE_HOST SERVER_ADMIN TIME_MON
    HTTP_COOKIE REMOTE_USER SERVER_NAME TIME_DAY
    HTTP_FORWARDED REMOTE_IDENT SERVER_ADDR TIME_HOUR
    HTTP_HOST REQUEST_METHOD SERVER_PORT TIME_MIN
    HTTP_PROXY_CONNECTION SCRIPT_FILENAME SERVER_PROTOCOL TIME_SEC
    HTTP_ACCEPT PATH_INFO SERVER_SOFTWARE TIME_WDAY
      QUERY_STRING   TIME
      AUTH_TYPE    
    specials: 说明
    API_VERSION Apache与模块间的接口的版本号
    THE_REQUEST 客户端发送到来的HTTP请求行的整行信息,不含其它的头字段信息,如(”GET /index.html HTTP/1.1″)
    REQUEST_URI HTTP请求行中请求的资源
    REQUEST_FILENAME 请求中对应的服务器本地文件系统中全路径文件名
    IS_SUBREQ 根据是否为SubRequest,分别值为”true”或”false”

    特别说明:

    • SCRIPT_FILENAME和REQUEST_FILENAME变量含有相同的值,也就是Apache服务器内部数据结构request_rec的filename字段的值。第一个变量是一个CGI变量,而第二个则与REQUEST_URI(含有request_rec数据结构中uri字段的值)保持一致。
    • %{ENV:variable}中的variable可以是任何环境变量的名字。对其值的查找,先通过Apache内部的数据结构,(如找不到)再在Apache服务器进程中通过getenv()查找。
    • %{HTTP:header}中的header可以是任何HTTP MIME-header的名字,其值通过查找HTTP请求信息而得。  

       

    • %{LA-U:variable} 用来引用后续API阶段中定义的、当前还不知道的值,具体实现是通过执行一个基于URL的内部的sub-request来决定的variable的最终的值。例如,假如你想在服务器范围内利用REMOTE_USER的值来完成重写,但这个值是在验证阶段设置的,而验证阶段是在URL转换阶段的后面。从另一方面讲,由于mod_rewrite在修补(fixup)API阶段进行目录范围的重写,而修补阶段在验证阶段的后面,所以此时只要用%{REMOTE_USER}就可以取得该值了。
    • %{LA-F:variable},执行一个基于文件名字(filename)的内部sub-request来决定variable的最终的值。大多数时间内,这和LA-U相同。

  CondPattern是一个条件模板,也就是说,是一个扩展正则式(extended regular expression),用与跟TestString进行匹配。作为一个标准的扩展正则式,CondPattern有以下补充:

  1. 可以在模板串前增加一个!前缀,以用表示不匹配模板。但并不是所有的test都可以加!前缀。
  2. CondPattern中可以使用以下特殊变量:
    • ‘ 将condPattern当作一个普通字符串,将它和TestString进行比较,当TestString 的字符小于CondPattern为真.
    • ‘>CondPattern’ (大于)
      将condPattern当作一个普通字符串,将它和TestString进行比较,当TestString 的字符大于CondPattern为真.
    • ‘=CondPattern’ (等于)
      将condPattern当作一个普通字符串,将它和TestString进行比较,当TestString 与CondPattern完全相同时为真.如果CondPattern只是 “” (两个引号紧挨在一起) 此时需TestString 为空字符串方为真.
    • ‘-d’ (是否为目录)
      将testString当作一个目录名,检查它是否存在以及是否是一个目录.
    • ‘-f’ (是否是regular file)
      将testString当作一个文件名,检查它是否存在以及是否是一个regular文件.
    • ‘-s’ (是否为长度不为0的regular文件)
      将testString当作一个文件名,检查它是否存在以及是否是一个长度大于0的regular文件
    • ‘-l’ (是否为symbolic link)
      将testString当作一个文件名,检查它是否存在以及是否是一个 symbolic link.
    • ‘-F’ (通过subrequest来检查某文件是否可访问)
      检查TestString是否是一个合法的文件,而且通过服务器范围内的当前设置的访问控制进行访问。这个检查是通过一个内部subrequest完成的, 因此需要小心使用这个功能以降低服务器的性能。
    • ‘-U’ (通过subrequest来检查某个URL是否存在)
      检查TestString是否是一个合法的URL,而且通过服务器范围内的当前设置的访问控制进行访问。这个检查是通过一个内部subrequest完成的, 因此需要小心使用这个功能以降低服务器的性能。

  [flags]是第三个参数,多个标志之间用逗号分隔。

  1. ‘nocase|NC’ (不区分大小写)
      在扩展后的TestString和CondPattern中,比较时不区分文本的大小写。注意,这个标志对文件系统和subrequest检查没有影响.
  2. ‘ornext|OR’ (建立与下一个条件的或的关系)
      默认的情况下,二个条件之间是AND的关系,用这个标志将关系改为OR。例如:

    RewriteCond %{REMOTE_HOST} ^host1.* [OR]
    RewriteCond %{REMOTE_HOST} ^host2.* [OR]
    RewriteCond %{REMOTE_HOST} ^host3.*
    RewriteRule …

    如果没有[OR]标志,需要写三个条件/规则.

例子:根据客户端浏览器的不同,返回不同的首页面。

RewriteCond %{HTTP_USER_AGENT} ^Mozilla.*
RewriteRule ^/$ /homepage.max.html [L]
RewriteCond %{HTTP_USER_AGENT} ^Lynx.*
RewriteRule ^/$ /homepage.min.html [L]
RewriteRule ^/$ /homepage.std.html [L]

  今天学习重写影射等内容。

RewriteMap
Syntax: RewriteMap MapName MapType:MapSource
  RewriteMap指令定义一个重写影射(Rewriting Map),在规则的substitution串中,通过影射函数(mapping-functions)来查找关键字(key),并用关键字对应的值来进行来行插入或替换操作。这个查找的对象,可以是各种各样的。
  MapName是影射的名字,将用来通过下列的某种结构来为substitution定义影射函数:
${ MapName : LookupKey }
${ MapName : LookupKey | DefaultValue }
当这些结构之一出现substitution串中时,重写引擎会到mapname影射中查找lookupkey关键字,如果找到了就用返回的值(substvalue)来替换该结构,如果找不到就用defaultvalue来替换该结构,如果没有defaultvalue,就用空串来替换。
  MapType 和mapSource组合有以下几种:

  1. 标准的普通文本(Standard Plain Text)
    MapType: txt, MapSource: Unix文件系统中合法的带有路径的regular file名
    此种情况下,MapSource文件是一个普通的ASCII文本文件,可以含有空行、注释行(以#打头),及以下结构的键值对行(每个键值对一行)。
    MatchingKey SubstValue
    例如:Mapsource文件叫/path/to/file/map.txt,其内容为
##
## map.txt — rewriting map
##
Ralf.S.Engelschall rse # Bastard Operator From Hell
Mr.Joe.Average joe # Mr. Average

在配置文件中则可以这样定义重写映射:

RewriteMap real-to-user txt:/path/to/file/map.txt

 

  • 随机的普通文本(Randomized Plain Text)
    MapType: rnd, MapSource: Unix文件系统中合法的带有路径的regular file名   这种情况与标准普通文本情况很相似,差别只是在SubstValue的格式上:此时的SubstValue由一些用”|”分隔的值组成的串,这个“|”是“或者”的意思。当根据键值找到对应的SubstValue后,mod_rewrite借助“|”将此串分解为一些候选项,然后随机选择一项作为最终的SubstValue的值返回。这听起来有点疯狂或毫无用处,其实这是设计用来在反向代理(reverse proxy)的情况下做负载均衡,用来查找服务器的名字。
    例如:MapSource文件的名字为/path/to/file/map.txt,内容如下:

    ##
    ## map.txt — rewriting map
    ##
    static www1|www2|www3|www4
    dynamic www5|www6

    在配置文件中定义的重写影射为:

    RewriteMap servers rnd:/path/to/file/map.txt
  • Hash File
    MapType: dbm, MapSource: Unix文件系统中合法的带有路径的regular file名   这儿的Mapsource文件是一个二进制的NDBM格式的文件,含有与普通文本格式文件时相同的内容,为了实现快速查找进行了优化处理后以一种特殊的格式来表达。 可以用任何NDBM工具或者用下面的Perl脚本txt2dbm.pl来创建这种格式的文件:

    #!/path/to/bin/perl
    ##
    ## txt2dbm — convert txt map to dbm format
    ## 

    use NDBM_File;
    use Fcntl;

    ($txtmap, $dbmmap) = @ARGV;

    open(TXT, “<$txtmap”) or die “Couldn’t open $txtmap!n”;
    tie (%DB, ‘NDBM_File’, $dbmmap,O_RDWR|O_TRUNC|O_CREAT, 0644) or die “Couldn’t create $dbmmap!n”;

    while () {
    next if (/^s*#/ or /^s*$/);
    $DB{$1} = $2 if (/^s*(S+)s+(S+)/);
    }

    untie %DB;
    close(TXT);

    此脚本的使用方法如下:

    $ perl txt2dbm.pl map.txt map.db
  • Apache内部函数(Internal Function)
    MapType: int, MapSource: Apache内部函数   这时,MapSource是一个Apache内置函数,目前还不能创建自己的内部函数,只能使用Apache已经定义好的:

    • toupper
      将键值转换为大写
    • tolower
      将键值转换为小写
    • escape
      将键值中的特殊字符转换为以16进制表示。
    • unescape
      将键值中16进制表示的特殊字符转换为原来的样子。
  • 外部重写程序(External Rewriting Program)
    MapType: prg, MapSource: Unix文件系统中合法的带有路径的regular file名   这儿的MapSource是一个程序而不是一个影射文件。你可以使用任何语言创建这个程序,但这个程序必须是可执行的(也就是说,要么是二进制码,要么是首行带有”#!/path/to/interpreter”格式的解释器的可执行脚本)。

      这个程序在Apache启动时被运行,然后它就用它的标准输入与标准输出的文件句柄与重写引擎通信(暗指程序能无限时等待标准输入,见下列)。对每个影射函数的查找要求,它把其标准输入中得到的字符串(newline-terminated string?)作为键值,然后通过标准输出返回查找到的值,如果找不到相应的值,则返回以四字符的字符串”NULL“。下面一个简单的例子,实现将键值作为查找结果返回:

    #!/usr/bin/perl
    $| = 1;
    while () {
    # …put here any transformations or lookups…
    print $_;
    }

    注意:

    1. “Keep it simple, stupid” (KISS),因为当规则执行时,一量这个外部程序挂起,整个Apache服务器就挂起了
    2. 避免下述常见错误:缓存了标准输出的I/O。这会导致死循环。这也是为什么上例中有“$|=1”这么一行的原因
    3. 用RewriteLock指令定义一个lockfile,以同步与外部程序的通信。默认情况下并没有这样的同步
  •   RewriteMap可以出现不只一次。每个影射函数用RewriteMap来声明它的影射文件. While you cannot declare a map in per-directory context it is of course possible to use this map in per-directory context.(?)对普通文本和DBM格式的文件,其键值被缓存在Apache内核中,直到影射文件的mtime 变化了或Apache重启动了。此时,可以将规则中的影射函数用于每个请求。
    RewriteBase
    Syntax: RewriteBase URL-path
      RewriteBase明确地指出目录范围内的重写结果的baseURL.RewriteRule指令可以用在目录范围内的配置文件里(.htaccess)。在目录范围的重写实施时,由本地路径信息构成的前缀已经被去掉,重写规则只对剩余的部分进行处理。处理结束后,被去掉的路径信息要自动加上,因为当对一个URL进行替换后,重新引擎需要将它重新插入到服务器的处理流程中去。如果服务器端的URL与文件的物理路径有直接有关系,则每当在.htacess文中定义重写规则时都需要用RewriteBase指URL-path。
    杂项Environment Variables
      mod_rewrite还维护着两个非标准的CGI/SSI环境变量,名为SCRIPT_URL和 SCRIPT_URI,存放着当前资源的逻辑web视图(logical Web-view)。标准的CGI/SSI变量SCRIPT_NAME 和 SCRIPT_FILENAME中存放着当前资源的物理系统视图(physical System-view)。请看例子:

    SCRIPT_NAME=/sw/lib/w3s/tree/global/u/rse/.www/index.html
    SCRIPT_FILENAME=/u/rse/.www/index.html
    SCRIPT_URL=/u/rse/
    SCRIPT_URI=http://en1.engelschall.com/u/rse/

    发表评论

    电子邮件地址不会被公开。 必填项已用*标注