web.xml配置详细说明

1 定义头和根元素

部署描述符文件就像所有XML文件一样,必须以一个XML头开始。这个头声明可以使用的XML版本并给出文件的字符编码。

DOCYTPE声明必须立即出现在此头之后。这个声明告诉服务器适用的servlet规范的版本(如2.2或2.3)并指定管理此文件其余部分内容的语法的DTD(Document Type Definition,文档类型定义)。

所有部署描述符文件的顶层(根)元素为web-app。请注意,XML元素不像HTML,他们是大小写敏感的。因此,web-App和WEB-APP都是不合法的,web-app必须用小写。

2 部署描述符文件内的元素次序

XML 元素不仅是大小写敏感的,而且它们还对出现在其他元素中的次序敏感。例如,XML头必须是文件中的第一项,DOCTYPE声明必须是第二项,而web- app元素必须是第三项。在web-app元素内,元素的次序也很重要。服务器不一定强制要求这种次序,但它们允许(实际上有些服务器就是这样做的)完全拒绝执行含有次序不正确的元素的Web应用。这表示使用非标准元素次序的web.xml文件是不可移植的。

下面的列表给出了所有可直接出现在web-app元素内的合法元素所必需的次序。例如,此列表说明servlet元素必须出现在所有servlet-mapping元素之前。请注意,所有这些元素都是可选的。因此,可以省略掉某一元素,但不能把它放于不正确的位置。

l icon icon元素指出IDE和GUI工具用来表示Web应用的一个和两个图像文件的位置。

l display-name display-name元素提供GUI工具可能会用来标记这个特定的Web应用的一个名称。

l description description元素给出与此有关的说明性文本。

l context-param context-param元素声明应用范围内的初始化参数。

l filter 过滤器元素将一个名字与一个实现javax.servlet.Filter接口的类相关联。

l filter-mapping 一旦命名了一个过滤器,就要利用filter-mapping元素把它与一个或多个servlet或JSP页面相关联。

l listener servlet API的版本2.3增加了对事件监听程序的支持,事件监听程序在建立、修改和删除会话或servlet环境时得到通知。Listener元素指出事件监听程序类。

l servlet 在向servlet或JSP页面制定初始化参数或定制URL时,必须首先命名servlet或JSP页面。Servlet元素就是用来完成此项任务的。

l servlet-mapping 服务器一般为servlet提供一个缺省的URL:http://host/webAppPrefix/servlet/ServletName。但是,常常会更改这个URL,以便servlet可以访问初始化参数或更容易地处理相对URL。在更改缺省URL时,使用servlet-mapping元素。

l session-config 如果某个会话在一定时间内未被访问,服务器可以抛弃它以节省内存。可通过使用HttpSession的setMaxInactiveInterval方法明确设置单个会话对象的超时值,或者可利用session-config元素制定缺省超时值。

l mime-mapping 如果Web应用具有想到特殊的文件,希望能保证给他们分配特定的MIME类型,则mime-mapping元素提供这种保证。

l welcom-file-list welcome-file-list元素指示服务器在收到引用一个目录名而不是文件名的URL时,使用哪个文件。

l error-page error-page元素使得在返回特定HTTP状态代码时,或者特定类型的异常被抛出时,能够制定将要显示的页面。

l taglib taglib元素对标记库描述符文件(Tag Libraryu Descriptor file)指定别名。此功能使你能够更改TLD文件的位置,而不用编辑使用这些文件的JSP页面。

l resource-env-ref resource-env-ref元素声明与资源相关的一个管理对象。

l resource-ref resource-ref元素声明一个资源工厂使用的外部资源。

l security-constraint security-constraint元素制定应该保护的URL。它与login-config元素联合使用

l login-config 用login-config元素来指定服务器应该怎样给试图访问受保护页面的用户授权。它与sercurity-constraint元素联合使用。

l security-role security-role元素给出安全角色的一个列表,这些角色将出现在servlet元素内的security-role-ref元素的role-name子元素中。分别地声明角色可使高级IDE处理安全信息更为容易。

l env-entry env-entry元素声明Web应用的环境项。

l ejb-ref ejb-ref元素声明一个EJB的主目录的引用。

l ejb-local-ref ejb-local-ref元素声明一个EJB的本地主目录的应用。

3 分配名称和定制的UL

在web.xml中完成的一个最常见的任务是对servlet或JSP页面给出名称和定制的URL。用servlet元素分配名称,使用servlet-mapping元素将定制的URL与刚分配的名称相关联。

3.1 分配名称

为了提供初始化参数,对servlet或JSP页面定义一个定制URL或分配一个安全角色,必须首先给servlet或JSP页面一个名称。可通过 servlet元素分配一个名称。最常见的格式包括servlet-name和servlet-class子元素(在web-app元素内),如下所示:


Test
moreservlets.TestServlet

这表示位于WEB-INF/classes/moreservlets/TestServlet的servlet已经得到了注册名Test。给 servlet一个名称具有两个主要的含义。首先,初始化参数、定制的URL模式以及其他定制通过此注册名而不是类名引用此servlet。其次,可在 URL而不是类名中使用此名称。因此,利用刚才给出的定义,URL http://host/webAppPrefix/servlet/Test 可用于 http://host/webAppPrefix/servlet/moreservlets.TestServlet 的场所。

请记住:XML元素不仅是大小写敏感的,而且定义它们的次序也很重要。例如,web-app元素内所有servlet元素必须位于所有servlet- mapping元素(下一小节介绍)之前,而且还要位于5.6节和5.11节讨论的与过滤器或文档相关的元素(如果有的话)之前。类似地,servlet 的servlet-name子元素也必须出现在servlet-class之前。5.2节”部署描述符文件内的元素次序”将详细介绍这种必需的次序。

例如,程序清单5-1给出了一个名为TestServlet的简单servlet,它驻留在moreservlets程序包中。因为此servlet是扎根在一个名为deployDemo的目录中的Web应用的组成部分,所以TestServlet.class放在deployDemo/WEB- INF/classes/moreservlets中。程序清单5-2给出将放置在deployDemo/WEB-INF/内的web.xml文件的一部分。此web.xml文件使用servlet-name和servlet-class元素将名称Test与TestServlet.class相关联。图 5-1和图5-2分别显示利用缺省URL和注册名调用TestServlet时的结果。

程序清单5-1 TestServlet.java

package moreservlets;

import java.io.*;

import javax.servlet.*;

import javax.servlet.http.*;

/** Simple servlet used to illustrate servlet naming
* and custom URLs.
* 

* Taken from More Servlets and JavaServer Pages * from Prentice Hall and Sun Microsystems Press, * http://www.moreservlets.com/. * ? 2002 Marty Hall; may be freely used or adapted. */ public class TestServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); String uri = request.getRequestURI(); out.println(ServletUtilities.headWithTitle("Test Servlet") + "n" + "

URI: " + uri + "

n" + ""); } }

程序清单5-2 web.xml(说明servlet名称的摘录)







Test
moreservlets.TestServlet



3.2 定义定制的URL

大多数服务器具有一个缺省的serlvet URL:

http://host/webAppPrefix/servlet/packageName.ServletName。虽然在开发中使用这个URL很方便,但是我们常常会希望另一个URL用于部署。例如,可能会需要一个出现在Web应用顶层的URL(如,http: //host/webAppPrefix/Anyname),并且在此URL中没有servlet项。位于顶层的URL简化了相对URL的使用。此外,对许多开发人员来说,顶层URL看上去比更长更麻烦的缺省URL更简短。

事实上,有时需要使用定制的URL。比如,你可能想关闭缺省URL映射,以便更好地强制实施安全限制或防止用户意外地访问无初始化参数的servlet。如果你禁止了缺省的URL,那么你怎样访问servlet呢?这时只有使用定制的URL了。

为了分配一个定制的URL,可使用servlet-mapping元素及其servlet-name和url-pattern子元素。Servlet- name元素提供了一个任意名称,可利用此名称引用相应的servlet;url-pattern描述了相对于Web应用的根目录的URL。url- pattern元素的值必须以斜杠(/)起始。

下面给出一个简单的web.xml摘录,它允许使用URL http://host/webAppPrefix/UrlTest而不是http://host/webAppPrefix/servlet/Test或

http: //host/webAppPrefix/servlet/moreservlets.TestServlet。请注意,仍然需要XML头、 DOCTYPE声明以及web-app封闭元素。此外,可回忆一下,XML元素出现地次序不是随意的。特别是,需要把所有servlet元素放在所有 servlet-mapping元素之前。


Test
moreservlets.TestServlet



Test
/UrlTest

URL模式还可以包含通配符。例如,下面的小程序指示服务器发送所有以Web应用的URL前缀开始,以..asp结束的请求到名为BashMS的servlet。


BashMS
msUtils.ASPTranslator



BashMS
/*.asp

3.3 命名JSP页面

因为JSP页面要转换成sevlet,自然希望就像命名servlet一样命名JSP页面。毕竟,JSP页面可能会从初始化参数、安全设置或定制的URL中受益,正如普通的serlvet那样。虽然JSP页面的后台实际上是servlet这句话是正确的,但存在一个关键的猜疑:即,你不知道JSP页面的实际类名(因为系统自己挑选这个名字)。因此,为了命名JSP页面,可将jsp-file元素替换为servlet-calss元素,如下所示:


Test
/TestPage.jsp

命名JSP页面的原因与命名servlet的原因完全相同:即为了提供一个与定制设置(如,初始化参数和安全设置)一起使用的名称,并且,以便能更改激活 JSP页面的URL(比方说,以便多个URL通过相同页面得以处理,或者从URL中去掉.jsp扩展名)。但是,在设置初始化参数时,应该注意,JSP页面是利用jspInit方法,而不是init方法读取初始化参数的。

例如,程序清单5-3给出一个名为TestPage.jsp的简单JSP页面,它的工作只是打印出用来激活它的URL的本地部分。TestPage.jsp放置在deployDemo应用的顶层。程序清单5-4给出了用来分配一个注册名PageName,然后将此注册名与http://host/webAppPrefix/UrlTest2/anything 形式的URL相关联的web.xml文件(即,deployDemo/WEB-INF/web.xml)的一部分。

程序清单5-3 TestPage.jsp





JSP Test Page



URI: <%= request.getRequestURI() %>

程序清单5-4 web.xml(说明JSP页命名的摘录) PageName /TestPage.jsp PageName /UrlTest2/*

4 禁止激活器servlet

对servlet 或JSP页面建立定制URL的一个原因是,这样做可以注册从 init(servlet)或jspInit(JSP页面)方法中读取得初始化参数。但是,初始化参数只在是利用定制URL模式或注册名访问 servlet或JSP页面时可以使用,用缺省URL http://host/webAppPrefix/servlet/ServletName 访问时不能使用。因此,你可能会希望关闭缺省URL,这样就不会有人意外地调用初始化servlet了。这个过程有时称为禁止激活器servlet,因为多数服务器具有一个用缺省的servlet URL注册的标准servlet,并激活缺省的URL应用的实际servlet。

有两种禁止此缺省URL的主要方法:

l 在每个Web应用中重新映射/servlet/模式。

l 全局关闭激活器servlet。

重要的是应该注意到,虽然重新映射每个Web应用中的/servlet/模式比彻底禁止激活servlet所做的工作更多,但重新映射可以用一种完全可移植的方式来完成。相反,全局禁止激活器servlet完全是针对具体机器的,事实上有的服务器(如ServletExec)没有这样的选择。下面的讨论对每个Web应用重新映射/servlet/ URL模式的策略。后面提供在Tomcat中全局禁止激活器servlet的详细内容。

4.1 重新映射/servlet/URL模式

在一个特定的Web应用中禁止以http://host/webAppPrefix/servlet/ 开始的URL的处理非常简单。所需做的事情就是建立一个错误消息servlet,并使用前一节讨论的url-pattern元素将所有匹配请求转向该 servlet。只要简单地使用:

/servlet/*
作为servlet-mapping元素中的模式即可。

例如,程序清单5-5给出了将SorryServlet servlet(程序清单5-6)与所有以http://host/webAppPrefix/servlet/ 开头的URL相关联的部署描述符文件的一部分。

程序清单5-5 web.xml(说明JSP页命名的摘录)







Sorry
moreservlets.SorryServlet



 Sorry 
/servlet/*



程序清单5-6 SorryServlet.java

package moreservlets;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

/** Simple servlet used to give error messages to
* users who try to access default servlet URLs
* (i.e., http://host/webAppPrefix/servlet/ServletName)
* in Web applications that have disabled this
* behavior.
* 

* Taken from More Servlets and JavaServer Pages * from Prentice Hall and Sun Microsystems Press, * http://www.moreservlets.com/. * ? 2002 Marty Hall; may be freely used or adapted. */ public class SorryServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); String title = "Invoker Servlet Disabled."; out.println(ServletUtilities.headWithTitle(title) + "n" + "

" + title + "

n" + "Sorry, access to servlets by means ofn" + "URLs that begin withn" + "http://host/webAppPrefix/servlet/n" + "has been disabled.n" + ""); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }

4.2 全局禁止激活器:Tomcat

Tomcat 4中用来关闭缺省URL的方法与Tomcat 3中所用的很不相同。下面介绍这两种方法:

1.禁止激活器: Tomcat 4

Tomcat 4用与前面相同的方法关闭激活器servlet,即利用web.xml中的url-mapping元素进行关闭。不同之处在于Tomcat使用了放在 install_dir/conf中的一个服务器专用的全局web.xml文件,而前面使用的是存放在每个Web应用的WEB-INF目录中的标准 web.xml文件。

因此,为了在Tomcat 4中关闭激活器servlet,只需在install_dir/conf/web.xml中简单地注释出/servlet/* URL映射项即可,如下所示:


再次提醒,应该注意这个项是位于存放在install_dir/conf的Tomcat专用的web.xml文件中的,此文件不是存放在每个Web应用的WEB-INF目录中的标准web.xml。

2.禁止激活器:Tomcat3

在Apache Tomcat的版本3中,通过在install_dir/conf/server.xml中注释出InvokerInterceptor项全局禁止缺省 servlet URL。例如,下面是禁止使用缺省servlet URL的server.xml文件的一部分。


5 初始化和预装载servlet与JSP页面

这里讨论控制servlet和JSP页面的启动行为的方法。特别是,说明了怎样分配初始化参数以及怎样更改服务器生存期中装载servlet和JSP页面的时刻。

5.1 分配servlet初始化参数

利用init-param元素向servlet提供初始化参数,init-param元素具有param-name和param-value子元素。例如,在下面的例子中,如果initServlet servlet是利用它的注册名(InitTest)访问的,它将能够从其方法中调用getServletConfig(). getInitParameter(”param1″)获得”Value 1″,调用getServletConfig().getInitParameter(”param2″)获得”2″。


InitTest
moreservlets.InitServlet
param1 value1
param2 2

在涉及初始化参数时,有几点需要注意:

l 返回值。GetInitParameter的返回值总是一个String。因此,在前一个例子中,可对param2使用Integer.parseInt获得一个int。

l JSP中的初始化。JSP页面使用jspInit而不是init。JSP页面还需要使用jsp-file元素代替servlet-class。

l 缺省URL。初始化参数只在通过它们的注册名或与它们注册名相关的定制URL模式访问Servlet时可以使用。因此,在这个例子中,param1和 param2初始化参数将能够在使用URL http://host/webAppPrefix/servlet/InitTest 时可用,但在使用URL http://host/webAppPrefix/servlet/myPackage.InitServlet 时不能使用。

例如,程序清单5-7给出一个名为InitServlet的简单servlet,它使用init方法设置firstName和emailAddress字段。程序清单5-8给出分配名称InitTest给servlet的web.xml文件。

程序清单5-7 InitServlet.java

package moreservlets;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

/** Simple servlet used to illustrate servlet
* initialization parameters.
* 

* Taken from More Servlets and JavaServer Pages * from Prentice Hall and Sun Microsystems Press, * http://www.moreservlets.com/. * ? 2002 Marty Hall; may be freely used or adapted. */ public class InitServlet extends HttpServlet { private String firstName, emailAddress; public void init() { ServletConfig config = getServletConfig(); firstName = config.getInitParameter("firstName"); emailAddress = config.getInitParameter("emailAddress"); } public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); String uri = request.getRequestURI(); out.println(ServletUtilities.headWithTitle("Init Servlet") + "n" + "

Init Parameters:

n" + "
    n" + "
  • First name: " + firstName + "n" + "
  • Email address: " + emailAddress + "n" + "
n" + ""); } } 程序清单5-8 web.xml(说明初始化参数的摘录) InitTest moreservlets.InitServlet firstName Larry emailAddress Ellison@Microsoft.com

5.2 分配JSP初始化参数

给JSP页面提供初始化参数在三个方面不同于给servlet提供初始化参数。

1)使用jsp-file而不是servlet-class。因此,WEB-INF/web.xml文件的servlet元素如下所示:


PageName
/RealPage.jsp



2) 几乎总是分配一个明确的URL模式。对servlet,一般相应地使用以http://host/webAppPrefix/servlet/ 开始的缺省URL。只需记住,使用注册名而不是原名称即可。这对于JSP页面在技术上也是合法的。例如,在上面给出的例子中,可用URL http://host/webAppPrefix/servlet/PageName 访问RealPage.jsp的对初始化参数具有访问权的版本。但在用于JSP页面时,许多用户似乎不喜欢应用常规的servlet的URL。此外,如果 JSP页面位于服务器为其提供了目录清单的目录中(如,一个既没有index.html也没有index.jsp文件的目录),则用户可能会连接到此 JSP页面,单击它,从而意外地激活未初始化的页面。因此,好的办法是使用url-pattern(5.3节)将JSP页面的原URL与注册的 servlet名相关联。这样,客户机可使用JSP页面的普通名称,但仍然激活定制的版本。例如,给定来自项目1的servlet定义,可使用下面的 servlet-mapping定义:


PageName
/RealPage.jsp

3)JSP页使用jspInit而不是init。自动从JSP页面建立的servlet或许已经使用了inti方法。因此,使用JSP声明提供一个init方法是不合法的,必须制定jspInit方法。

为了说明初始化JSP页面的过程,程序清单5-9给出了一个名为InitPage.jsp的JSP页面,它包含一个jspInit方法且放置于 deployDemo Web应用层次结构的顶层。一般,http://host/deployDemo/InitPage.jsp 形式的URL将激活此页面的不具有初始化参数访问权的版本,从而将对firstName和emailAddress变量显示null。但是, web.xml文件(程序清单5-10)分配了一个注册名,然后将该注册名与URL模式/InitPage.jsp相关联。

程序清单5-9 InitPage.jsp



JSP Init Test

Init Parameters:

  • First name: <%= firstName %>
  • Email address: <%= emailAddress %>
<%! private String firstName> 程序清单5-10 web.xml(说明JSP页面的init参数的摘录) InitPage /InitPage.jsp firstName Bill emailAddress gates@oracle.com InitPage /InitPage.jsp

5.3 提供应用范围内的初始化参数

一般,对单个地servlet或JSP页面分配初始化参数。指定的servlet或JSP页面利用ServletConfig的 getInitParameter方法读取这些参数。但是,在某些情形下,希望提供可由任意servlet或JSP页面借助ServletContext 的getInitParameter方法读取的系统范围内的初始化参数。

可利用context-param元素声明这些系统范围内的初始化值。context-param元素应该包含param-name、param-value以及可选的description子元素,如下所示:

support-email blackhole@mycompany.com
可回忆一下,为了保证可移植性,web.xml内的元素必须以正确的次序声明。但这里应该注意,context-param元素必须出现任意与文档有关的元素(icon、display-name或description)之后及filter、filter-mapping、listener或 servlet元素之前。

5.4 在服务器启动时装载servlet

假如servlet或JSP页面有一个要花很长时间执行的init (servlet)或jspInit(JSP)方法。例如,假如init或jspInit方法从某个数据库或ResourceBundle查找产量。这种情况下,在第一个客户机请求时装载servlet的缺省行为将对第一个客户机产生较长时间的延迟。因此,可利用servlet的load-on- startup元素规定服务器在第一次启动时装载servlet。下面是一个例子。






可以为此元素体提供一个整数而不是使用一个空的load-on-startup。想法是服务器应该在装载较大数目的servlet或JSP页面之前装载较少数目的servlet或JSP页面。例如,下面的servlet项(放置在Web应用的WEB-INF目录下的web.xml文件中的web-app元素内)将指示服务器首先装载和初始化SearchServlet,然后装载和初始化由位于Web应用的result目录中的index.jsp文件产生的 servlet。


Search
myPackage.SearchServlet
1


Results
/results/index.jsp
2

6 声明过滤器

servlet版本2.3引入了过滤器的概念。虽然所有支持servlet API版本2.3的服务器都支持过滤器,但为了使用与过滤器有关的元素,必须在web.xml中使用版本2.3的DTD。

过滤器可截取和修改进入一个servlet或JSP页面的请求或从一个servlet或JSP页面发出的相应。在执行一个servlet或JSP页面之前,必须执行第一个相关的过滤器的doFilter方法。在该过滤器对其FilterChain对象调用doFilter时,执行链中的下一个过滤器。如果没有其他过滤器,servlet或JSP页面被执行。过滤器具有对到来的ServletRequest对象的全部访问权,因此,它们可以查看客户机名、查找到来的cookie等。为了访问servlet或JSP页面的输出,过滤器可将响应对象包裹在一个替身对象(stand-in object)中,比方说把输出累加到一个缓冲区。在调用FilterChain对象的doFilter方法之后,过滤器可检查缓冲区,如有必要,就对它进行修改,然后传送到客户机。

例如,程序清单5-11帝国难以了一个简单的过滤器,只要访问相关的servlet或JSP页面,它就截取请求并在标准输出上打印一个报告(开发过程中在桌面系统上运行时,大多数服务器都可以使用这个过滤器)。

程序清单5-11 ReportFilter.java

package moreservlets;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;

/** Simple filter that prints a report on the standard output
* whenever the associated servlet or JSP page is accessed.
* 

* Taken from More Servlets and JavaServer Pages * from Prentice Hall and Sun Microsystems Press, * http://www.moreservlets.com/. * ? 2002 Marty Hall; may be freely used or adapted. */ public class ReportFilter implements Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException { HttpServletRequest req = (HttpServletRequest)request; System.out.println(req.getRemoteHost() + " tried to access " + req.getRequestURL() + " on " + new Date() + "."); chain.doFilter(request,response); } public void init(FilterConfig config) throws ServletException { } public void destroy() {} }

一旦建立了一个过滤器,可以在web.xml中利用filter元素以及filter-name(任意名称)、file-class(完全限定的类名)和(可选的)init-params子元素声明它。请注意,元素在web.xml的web-app元素中出现的次序不是任意的;允许服务器(但不是必需的)强制所需的次序,并且实际中有些服务器也是这样做的。但这里要注意,所有filter元素必须出现在任意filter-mapping元素之前, filter-mapping元素又必须出现在所有servlet或servlet-mapping元素之前。

例如,给定上述的ReportFilter类,可在web.xml中作出下面的filter声明。它把名称Reporter与实际的类ReportFilter(位于moreservlets程序包中)相关联。


Reporter
moresevlets.ReportFilter

一旦命名了一个过滤器,可利用filter-mapping元素把它与一个或多个servlet或JSP页面相关联。关于此项工作有两种选择。

首先,可使用filter-name和servlet-name子元素把此过滤器与一个特定的servlet名(此servlet名必须稍后在相同的 web.xml文件中使用servlet元素声明)关联。例如,下面的程序片断指示系统只要利用一个定制的URL访问名为SomeServletName 的servlet或JSP页面,就运行名为Reporter的过滤器。


Reporter
SomeServletName

其次,可利用filter-name和url-pattern子元素将过滤器与一组servlet、JSP页面或静态内容相关联。例如,相面的程序片段指示系统只要访问Web应用中的任意URL,就运行名为Reporter的过滤器。


Reporter
/*

例如,程序清单5-12给出了将ReportFilter过滤器与名为PageName的servlet相关联的web.xml文件的一部分。名字 PageName依次又与一个名为TestPage.jsp的JSP页面以及以模式http: //host/webAppPrefix/UrlTest2/ 开头的URL相关联。TestPage.jsp的源代码已经JSP页面命名的谈论在前面的3节”分配名称和定制的URL”中给出。事实上,程序清单5- 12中的servlet和servlet-name项从该节原封不动地拿过来的。给定这些web.xml项,可看到下面的标准输出形式的调试报告(换行是为了容易阅读)。

audit.irs.gov tried to access

mycompany.com/deployDemo/UrlTest2/business/tax-plan.html

on Tue Dec 25 13:12:29 EDT 2001.

程序清单5-12 Web.xml(说明filter用法的摘录)




Reporter
moresevlets.ReportFilter



Reporter
PageName



PageName
/RealPage.jsp



PageName
/UrlTest2/*



7 指定欢迎页

假如用户提供了一个像http: //host/webAppPrefix/directoryName/ 这样的包含一个目录名但没有包含文件名的URL,会发生什么事情呢?用户能得到一个目录表?一个错误?还是标准文件的内容?如果得到标准文件内容,是 index.html、index.jsp、default.html、default.htm或别的什么东西呢?

Welcome-file-list 元素及其辅助的welcome-file元素解决了这个模糊的问题。例如,下面的web.xml项指出,如果一个URL给出一个目录名但未给出文件名,服务器应该首先试用index.jsp,然后再试用index.html。如果两者都没有找到,则结果有赖于所用的服务器(如一个目录列表)。


index.jsp
index.html

虽然许多服务器缺省遵循这种行为,但不一定必须这样。因此,明确地使用welcom-file-list保证可移植性是一种良好的习惯。

8 指定处理错误的页面

现在我了解到,你在开发servlet和JSP页面时从不会犯错误,而且你的所有页面是那样的清晰,一般的程序员都不会被它们的搞糊涂。但是,是人总会犯错误的,用户可能会提供不合规定的参数,使用不正确的URL或者不能提供必需的表单字段值。除此之外,其它开发人员可能不那么细心,他们应该有些工具来克服自己的不足。

error-page元素就是用来克服这些问题的。它有两个可能的子元素,分别是:error-code和exception- type。第一个子元素error-code指出在给定的HTTP错误代码出现时使用的URL。第二个子元素excpetion-type指出在出现某个给定的Java异常但未捕捉到时使用的URL。error-code和exception-type都利用location元素指出相应的URL。此 URL必须以/开始。location所指出的位置处的页面可通过查找HttpServletRequest对象的两个专门的属性来访问关于错误的信息,这两个属性分别是:javax.servlet.error.status_code和javax.servlet.error.message。

可回忆一下,在web.xml内以正确的次序声明web-app的子元素很重要。这里只要记住,error-page出现在web.xml文件的末尾附近,servlet、servlet-name和welcome-file-list之后即可。

8.1 error-code元素

为了更好地了解error-code元素的值,可考虑一下如果不正确地输入文件名,大多数站点会作出什么反映。这样做一般会出现一个404错误信息,它表示不能找到该文件,但几乎没提供更多有用的信息。另一方面,可以试一下在www.microsoft.com、www.ibm.com 处或者特别是在www.bea.com 处输出未知的文件名。这是会得出有用的消息,这些消息提供可选择的位置,以便查找感兴趣的页面。提供这样有用的错误页面对于Web应用来说是很有价值得。事实上rm-error-page子元素)。由form-login-page给出的HTML表单必须具有一个j_security_check的 ACTION属性、一个名为j_username的用户名文本字段以及一个名为j_password的口令字段。

例如,程序清单5-19指示服务器使用基于表单的验证。Web应用的顶层目录中的一个名为login.jsp的页面将收集用户名和口令,并且失败的登陆将由相同目录中名为login-error.jsp的页面报告。

程序清单5-19 web.xml(说明login-config的摘录)






FORM
/login.jsp /login-error.jsp



9.2 限制对Web资源的访问

现在,可以指示服务器使用何种验证方法了。”了不起,”你说道,”除非我能指定一个来收到保护的 URL,否则没有多大用处。”没错。指出这些URL并说明他们应该得到何种保护正是security-constriaint元素的用途。此元素在 web.xml中应该出现在login-config的紧前面。它包含是个可能的子元素,分别是:web-resource-collection、 auth-constraint、user-data-constraint和display-name。下面各小节对它们进行介绍。

l web-resource-collection

此元素确定应该保护的资源。所有security-constraint元素都必须包含至少一个web-resource-collection项。此元素由一个给出任意标识名称的web-resource-name元素、一个确定应该保护的URL的url-pattern元素、一个指出此保护所适用的 HTTP命令(GET、POST等,缺省为所有方法)的http-method元素和一个提供资料的可选description元素组成。例如,下面的 Web-resource-collection项(在security-constratint元素内)指出Web应用的proprietary目录中所有文档应该受到保护。



Proprietary
/propritary/*



重要的是应该注意到,url-pattern仅适用于直接访问这些资源的客户机。特别是,它不适合于通过MVC体系结构利用 RequestDispatcher来访问的页面,或者不适合于利用类似jsp:forward的手段来访问的页面。这种不匀称如果利用得当的话很有好处。例如,servlet可利用MVC体系结构查找数据,把它放到bean中,发送请求到从bean中提取数据的JSP页面并显示它。我们希望保证决不直接访问受保护的JSP页面,而只是通过建立该页面将使用的bean的servlet来访问它。url-pattern和auth-contraint元素可通过声明不允许任何用户直接访问JSP页面来提供这种保证。但是,这种不匀称的行为可能让开发人员放松警惕,使他们偶然对应受保护的资源提供不受限制的访问。

l auth-constraint

尽管web-resource-collention元素质出了哪些URL应该受到保护,但是auth-constraint元素却指出哪些用户应该具有受保护资源的访问权。此元素应该包含一个或多个标识具有访问权限的用户类别role- name元素,以及包含(可选)一个描述角色的description元素。例如,下面web.xml中的security-constraint元素部门规定只有指定为Administrator或Big Kahuna(或两者)的用户具有指定资源的访问权。




administrator
kahuna


重要的是认识到,到此为止,这个过程的可移植部分结束了。服务器怎样确定哪些用户处于任何角色以及它怎样存放用户的口令,完全有赖于具体的系统。

例如,Tomcat使用install_dir/conf/tomcat-users.xml将用户名与角色名和口令相关联,正如下面例子中所示,它指出用户joe(口令bigshot)和jane(口令enaj)属于administrator和kahuna角色。





l user-data-constraint

这个可选的元素指出在访问相关资源时使用任何传输层保护。它必须包含一个transport-guarantee子元素(合法值为NONE、 INTEGRAL或CONFIDENTIAL),并且可选地包含一个description元素。transport-guarantee为NONE值将对所用的通讯协议不加限制。INTEGRAL值表示数据必须以一种防止截取它的人阅读它的方式传送。虽然原理上(并且在未来的HTTP版本中),在 INTEGRAL和CONFIDENTIAL之间可能会有差别,但在当前实践中,他们都只是简单地要求用SSL。例如,下面指示服务器只允许对相关资源做 HTTPS连接:




CONFIDENTIAL


l display-name

security-constraint的这个很少使用的子元素给予可能由GUI工具使用的安全约束项一个名称。

9.3 分配角色名

迄今为止,讨论已经集中到完全由容器(服务器)处理的安全问题之上了。但servlet以及JSP页面也能够处理它们自己的安全问题。

例如,容器可能允许用户从bigwig或bigcheese角色访问一个显示主管人员额外紧贴的页面,但只允许bigwig用户修改此页面的参数。完成这种更细致的控制的一种常见方法是调用HttpServletRequset的isUserInRole方法,并据此修改访问。

Servlet的 security-role-ref子元素提供出现在服务器专用口令文件中的安全角色名的一个别名。例如,假如编写了一个调用 request.isUserInRole(”boss”)的servlet,但后来该servlet被用在了一个其口令文件调用角色manager而不是boss的服务器中。下面的程序段使该servlet能够使用这两个名称中的任何一个。




boss
manager


也可以在web-app内利用security-role元素提供将出现在role-name元素中的所有安全角色的一个全局列表。分别地生命角色使高级IDE容易处理安全信息。

10 控制会话超时

如果某个会话在一定的时间内未被访问,服务器可把它扔掉以节约内存。可利用HttpSession的setMaxInactiveInterval方法直接设置个别会话对象的超时值。如果不采用这种方法,则缺省的超时值由具体的服务器决定。但可利用session-config和session- timeout元素来给出一个适用于所有服务器的明确的超时值。超时值的单位为分钟,因此,下面的例子设置缺省会话超时值为三个小时(180分钟)。


180

11 Web应用的文档化

越来越多的开发环境开始提供servlet和JSP的直接支持。例子有Borland Jbuilder Enterprise Edition、Macromedia UltraDev、Allaire JRun Studio(写此文时,已被Macromedia收购)以及IBM VisuaAge for Java等。

大量的web.xml元素不仅是为服务器设计的,而且还是为可视开发环境设计的。它们包括icon、display-name和discription等。

可回忆一下,在web.xml内以适当地次序声明web-app子元素很重要。不过,这里只要记住icon、display-name和description是web.xml的web-app元素内的前三个合法元素即可。

l icon

icon元素指出GUI工具可用来代表Web应用的一个和两个图像文件。可利用small-icon元素指定一幅16 x 16的GIF或JPEG图像,用large-icon元素指定一幅32 x 32的图像。下面举一个例子:


/images/small-book.gif
/images/tome.jpg

l display-name

display-name元素提供GUI工具可能会用来标记此Web应用的一个名称。下面是个例子。

Rare Books
l description

description元素提供解释性文本,如下所示:


This Web application represents the store developed for
rare-books.com, an online bookstore specializing in rare
and limited-edition books.

12 关联文件与MIME类型

服务器一般都具有一种让Web站点管理员将文件扩展名与媒体相关联的方法。例如,将会自动给予名为mom.jpg的文件一个image/jpeg的MIME 类型。但是,假如你的Web应用具有几个不寻常的文件,你希望保证它们在发送到客户机时分配为某种MIME类型。mime-mapping元素(具有 extension和mime-type子元素)可提供这种保证。例如,下面的代码指示服务器将application/x-fubar的MIME类型分配给所有以.foo结尾的文件。


foo
application/x-fubar

或许,你的Web应用希望重载(override)标准的映射。例如,下面的代码将告诉服务器在发送到客户机时指定.ps文件作为纯文本(text/plain)而不是作为PostScript(application/postscript)。


ps
application/postscript

13 定位TLD

JSP taglib元素具有一个必要的uri属性,它给出一个TLD(Tag Library Descriptor)文件相对于Web应用的根的位置。TLD文件的实际名称在发布新的标签库版本时可能会改变,但我们希望避免更改所有现有JSP页面。此外,可能还希望使用保持taglib元素的简练性的一个简短的uri。这就是部署描述符文件的taglib元素派用场的所在了。Taglib包含两个子元素:taglib-uri和taglib-location。taglib-uri元素应该与用于JSP taglib元素的uri属性的东西相匹配。Taglib-location元素给出TLD文件的实际位置。例如,假如你将文件chart-tags- 1.3beta.tld放在WebApp/WEB-INF/tlds中。现在,假如web.xml在web-app元素内包含下列内容。


/charts.tld

/WEB-INF/tlds/chart-tags-1.3beta.tld


给出这个说明后,JSP页面可通过下面的简化形式使用标签库。

<%@ taglib uri="/charts.tld" prefix="somePrefix" %>
14 指定应用事件监听程序

应用事件监听器程序是建立或修改servlet环境或会话对象时通知的类。它们是servlet规范的版本2.3中的新内容。这里只简单地说明用来向Web应用注册一个监听程序的web.xml的用法。

注册一个监听程序涉及在web.xml的web-app元素内放置一个listener元素。在listener元素内,listener-class元素列出监听程序的完整的限定类名,如下所示:

package.ListenerClass 虽然listener元素的结构很简单,但请不要忘记,必须正确地给出web-app元素内的子元素的次序。listener元素位于所有的servlet 元素之前以及所有filter-mapping元素之后。此外,因为应用生存期监听程序是serlvet规范的2.3版本中的新内容,所以必须使用 web.xml DTD的2.3版本,而不是2.2版本。

例如,程序清单5-20给出一个名为ContextReporter的简单的监听程序,只要Web应用的Servlet-Context建立(如装载Web应用)或消除(如服务器关闭)时,它就在标准输出上显示一条消息。程序清单5-21给出此监听程序注册所需要的web.xml文件的一部分。

程序清单5-20 ContextReporterjava

package moreservlets;

import javax.servlet.*;
import java.util.*;

/** Simple listener that prints a report on the standard output
* when the ServletContext is created or destroyed.
* 

* Taken from More Servlets and JavaServer Pages * from Prentice Hall and Sun Microsystems Press, * http://www.moreservlets.com/. * ? 2002 Marty Hall; may be freely used or adapted. */ public class ContextReporter implements ServletContextListener { public void contextInitialized(ServletContextEvent event) { System.out.println("Context created on " + new Date() + "."); } public void contextDestroyed(ServletContextEvent event) { System.out.println("Context destroyed on " + new Date() + "."); } } 程序清单5-21 web.xml(声明一个监听程序的摘录) package.ListenerClass ...

15 J2EE元素

本节描述用作J2EE环境组成部分的Web应用的web.xml元素。这里将提供一个简明的介绍,详细内容可以参阅http://java.sun.com/j2ee/j2ee-1_3-fr-spec.pdf的Java 2 Plantform Enterprise Edition版本1.3规范的第5章。

l distributable

distributable 元素指出,Web应用是以这样的方式编程的:即,支持集群的服务器可安全地在多个服务器上分布Web应用。例如,一个可分布的应用必须只使用 Serializable对象作为其HttpSession对象的属性,而且必须避免用实例变量(字段)来实现持续性。distributable元素直接出现在discription元素之后,并且不包含子元素或数据,它只是一个如下的标志。


l resource-env-ref

resource -env-ref元素声明一个与某个资源有关的管理对象。此元素由一个可选的description元素、一个resource-env-ref- name元素(一个相对于java:comp/env环境的JNDI名)以及一个resource-env-type元素(指定资源类型的完全限定的类),如下所示:



jms/StockQueue


javax.jms.Queue


l env-entry

env -entry元素声明Web应用的环境项。它由一个可选的description元素、一个env-entry-name元素(一个相对于java: comp/env环境JNDI名)、一个env-entry-value元素(项值)以及一个env-entry-type元素(java.lang程序包中一个类型的完全限定类名,java.lang.Boolean、java.lang.String等)组成。下面是一个例子:


minAmout
100.00
minAmout

l ejb-ref

ejb -ref元素声明对一个EJB的主目录的应用。它由一个可选的description元素、一个ejb-ref-name元素(相对于java: comp/env的EJB应用)、一个ejb-ref-type元素(bean的类型,Entity或Session)、一个home元素(bean的主目录接口的完全限定名)、一个remote元素(bean的远程接口的完全限定名)以及一个可选的ejb-link元素(当前bean链接的另一个 bean的名称)组成。

l ejb-local-ref

ejb-local-ref元素声明一个EJB的本地主目录的引用。除了用local-home代替home外,此元素具有与ejb-ref元素相同的属性并以相同的方式使用

OpenLDAP学习笔记

Copyright ? 2004,2005, 本文遵从GNU 的自由文档许可证(Free Document License)的条款,欢迎转载、修改、散布。

发布时间:2004年04月07日

最近更新:2005年08月08日

Abstract

LDAP(轻量级目录服务访问协议,Lightweight Directory Access Protocol)基于X.500标准,支持TCP/IP,使用简单方便。现在越来越多的网络应用系统都支持LDAP。OpenLDAP是LDAP的一种开源实现,本笔记基于OpenLDAP2.1.29。
——————————————————————————–

Table of Contents

1. 目录服务简介
1.1. X.500和LDAP
1.2. LDAP产品
2. OpenLDAP安装笔记
2.1. 源码安装
2.2. 数据录入
2.2.1. 手动录入方法
2.2.2. 文件方式
2.2.3. 脚本方式
2.3. 常用命令介绍
2.4. 启用sasl验证
2.5. 配置服务器复制
3. 管理工具
3.1. phpldapadmin
3.2. gq
3.3. CPU
3.4. JXplore
4. HowTo
4.1. 禁止整个服务器的匿名访问
Chapter 1. 目录服务简介
Table of Contents

1.1. X.500和LDAP
1.2. LDAP产品
目录是一个为查询、浏览和搜索而优化的专业分布式数据库,它成树状结构组织数据,就好象Linux/Unix系统中的文件目录一样。目录数据库和关系数据库不同,它有优异的读性能,但写性能差,并且没有事务处理、回滚等复杂功能,不适于存储修改频繁的数据。所以目录天生是用来查询的,就好象它的名字一样。目录服务是由目录数据库和一套访问协议组成的系统。类似以下的信息适合储存在目录中:

企业员工和企业客户之类人员信息;

公用证书和安全密钥;

邮件地址、网址、IP等电脑信息;

电脑配置信息。

1.1. X.500和LDAP
现在国际上的目录服务标准有两个,一个是较早的X.500标准,一个是较新的LDAP标准。

X.500是一个协议族,由一系列的概念和协议组成,包括:

X.501是模型定义,定义目录服务的基本模型和概念;

X.509是认证框架,定义如何处理目录服务中客户和服务器认证;

X.511是抽象服务定义,定义X.500提供的功能性服务;

X.518是分布式操作过程定义,定义如何跨平台处理目录服务;

X.519是协议规范,定义了X.500协议,包括DAP(Directory Access Protocol,目录访问协议)、DSP(Directory System Protocol,目录系统协议)、DOP(Directory Operator Protocol,目录操作绑定协议)、DISP(Directory Information Shadowing Protocol,目录信息阴影协议 );

X.520定义属性类型要求;

X.521定义对象类型;

X.525定义如果在目录服务器间复制内容。

X.500标准中定义了很多内容,包括:

定义了信息模型,确定目录中信息的格式和字符集,如何在项中表示目录信息(定义对象类、属性等模式);

定义命名空间,确定对信息进行的组织和引用,如何组织和命名项-目录信息树DIT和层次命名模型;

定义功能模型,确定可以在信息上执行的操作;

定义认证框架,保证目录中信息的安全,如何实现目录中信息的授权保护-访问控制模型;

定义分布操作模型,确定数据如何分布和如何对分布数据执行操作,如何将全局目录树划分为管理域,以便管理。

定义客户端与服务器之间的通信的各种协议。

由于X.500较复杂,且需严格遵照OSI七层协议模型。造成应用开发较困难。所以开发了LDAP,以便在INTERNET上使用。

LDAP协议于1993年获批准,产生LDAPv1版,1997年发布最新的LDAPv3版,该版本是LDAP协议发展的一个里程碑,它作为X.500的简化版提供了很多自有的特性,使LDAP功能更为完备,具有更强大的生命力。

LDAP也是一个协议族,包含以下内容:

RFC 2251–LDAPv3核心协议,定义了LDAPv3协议的基本模型和基本操作;

RFC 2252–定义LDAPv3基本数据模式(Schema)(包括语法、匹配规则、属性类型和对象类)以及标准的系统数据模式;

RFC 2253–定义LDAPv3中的分辩名(DN)表达式;

RFC 2254–定义了LDAPv3中的过滤表达式;

RFC 2255–定义LDAPv3统一资源地址的格式;

RFC 2256–定义LDAPv3中使用X.500的Schema列表;

RFC 2829–定义了LDAPv3中的认证方式;

RFC 2830–定义了如何通过扩展使用TLS服务;

RFC 1823–定义了C的LDAP客户端API开发接口;

RFC 2847–定义了LDAP数据导入、导出文件接口LDIF。

这些协议定义了LDAP的内容,包括:

定义了一个信息模型,确定了LDAP目录中信息的格式和字符集,如何表示目录信息(定义对象类、属性、匹配规则和语法等模式);

定义了命名空间,确定信息的组织方式–目录树DIT,以DN和RDN为基础的命名方式,以及LDAP信息的Internet表示方式;

定义了功能模型,确定在可以在信息上执行的操作及API。

定义了安全框架,保证目录中信息的安全,定义匿名、用户名/密码、SASL等多种认证方式,以及与TLS结合的通讯保护框架;

定义分布式操作模型,基于指引方式的分布式操作框架;

定义了LDAP扩展框架。

1.2. LDAP产品
现在市场上有关LDAP的产品已有很多,各大软件公司都在他们的产品中集成了LDAP服务,如Microsoft的ActiveDirectory、Lotus的Domino Directory、IBM的WebSphere中也集成了LDAP服务。LDAP的开源实现是OpenLDAP,它比商业产品一点也不差,而且源码开放。

Chapter 2. OpenLDAP安装笔记
Table of Contents

2.1. 源码安装
2.2. 数据录入
2.2.1. 手动录入方法
2.2.2. 文件方式
2.2.3. 脚本方式
2.3. 常用命令介绍
2.4. 启用sasl验证
2.5. 配置服务器复制
2.1. 源码安装
我的安装方法是以源码编译的方式进行的,以root用户进行安装。安装所需软件如下:

openldap-2.1.29

Berkeley DB 4.2.52

具体的安装步骤如下:

由于openldap需要Berkeley DB来存放数据,所以需先安装Berkeley DB 4.2.52,可到它的网站下载,网址见上面。运行下面的命令解压:


# tar -zxvf db-4.2.52.tar.gz

解完压后,会生成一个db-4.2.52目录,进行该目录下的build_unix目录。执行以下命令进行配置安装。

# ../dist/configure
# make
# make install

也是按linux源码安装的三步曲完成,没有什么好说的了。该软件默认是安装在/usr/local/BerkeleyDB.4.2目录下。安装完成后,要把/usr/local/BerkeleyDB.4.2/lib的库路径加到/etc/ld.so.conf文件内,添加完成后执行一次ldconfig,使配置文件生效。这样编译openldap时才能找到相应的库文件。这样资料库就安装完成了,接下来可以安装openldap了。ld.so.conf是什么东西?它就是系统动态链接库的配置文件。此文件内,存放着可被LINUX共享的动态链接库所在目录的名字(系统目录/lib,/usr/lib除外),各个目录名间以空白字符(空格,换行等)或冒号或逗号分隔。一般的LINUX发行版中,此文件均含一个共享目录/usr/X11R6/lib,为X window窗口系统的动态链接库所在的目录。 ldconfig是它的管理命令,具体操作方法可查询man手册,这里就不细讲了。

到openldap官方网站下载最新的稳定版源码,并解压。查看INSTALLT 和README文档,这个很重要,因为安装方法和一些注意事项都在里面有介绍。认真弄明白文档内容能节省你不少的安装调试时间。这也是开源软件的一个特点,给用户提供了最大的灵活性和可配置性。但也增加了系统安装配置的难度,需要有相关的文档配置说明和指导。在官方网站上还有详细的帮助文件,在整个系统配置中需要经常查询。

# tar -zxvf openldap-stable-20040329.tgz

解压完成后,会生成一个openldap-2.1.29目录。进行该目录,执行以下命令进行配置安装。

# env CPPFLAGS="-I/usr/local/BerkeleyDB.4.2/include"
LDFLAGS="-L/usr/local/BerkeleyDB.4.2/lib" ./configure --prefix=/usr/local/openldap
--enable-ldbm

注意以上配置语句,要设置资料库的include和lib路径,否则在配置到资料库相关内容时会提示Berkeley DB版本不兼容,并中断配置。如果没有--enable-ldbm选项,在make test时会提示ldbm找不到。为了减少出错,还是加上为好。

#make depens
#make
#make test

在make test阶段要花费较长时间进行测试,好像有16项吧。你可以放松一下,上上网,聊聊天,听听歌,呵呵,开玩笑了,这个时间应该是最紧张的了。成与不成就看这下的了,如果没问题就可安装了。

#make install

通过配置命令可以看出,我们把openldap安装到/usr/local/openldap目录下。建议以源码安装的软件都放到独立的目录下,不要放到软件默认的目录。好处是方便管理和控制,所有文件在统一的目录下,卸载软件只要删除整个目录就可以了。

安装完相关软件后就可以着手配置了。Berkeley DB资料库没什么好配置的。主要是配置openldap 服务。配置文件在软件的安装目录的etc/openldap下,有四个文件,主要的是slapd.conf and ldap.conf,其它两个是backup文件。首先,我们先来配置slapd.conf文档。系统默认的slapd.conf文件如下:

# $OpenLDAP: pkg/ldap/servers/slapd/slapd.conf,v 1.23.2.8 2003/05/24 23:19:14 kurt Exp $
#
# See slapd.conf(5) for details on configuration options.
# This file should NOT be world readable.
#
include /usr/local/openldap/etc/openldap/schema/core.schema
#设置schema配置文档包含

# Define global ACLs to disable default read access.

# Do not enable referrals until AFTER you have a working directory
# service AND an understanding of referrals.
#referral ldap://root.openldap.org

pidfile /usr/local/openldap/var/slapd.pid
#设置pid和args文档位置
argsfile /usr/local/openldap/var/slapd.args

# Load dynamic backend modules:
# modulepath /usr/local/openldap/libexec/openldap
# moduleload back_bdb.la
# moduleload back_ldap.la
# moduleload back_ldbm.la
# moduleload back_passwd.la
# moduleload back_shell.la

# Sample security restrictions
# Require integrity protection (prevent hijacking)
# Require 112-bit (3DES or better) encryption for updates
# Require 63-bit encryption for simple bind
# security ssf=1 update_ssf=112 simple_bind=64

# Sample access control policy:
# Root DSE: allow anyone to read it
# Subschema (sub)entry DSE: allow anyone to read it
# Other DSEs:
# Subschema (sub)entry DSE: allow anyone to read it
# Other DSEs:
# Allow self write access
# Allow authenticated users read access
# Allow anonymous users to authenticate
# Directives needed to implement policy:
# access to dn.base="" by * read
# access to dn.base="cn=Subschema" by * read
# access to *
# by self write
# by users read
# by anonymous auth
#
# if no access controls are present, the default policy is:
# Allow read by all
#
# rootdn can always write!

#######################################################################
# ldbm database definitions
#######################################################################

database bdb
#设置使用的资料库,也可用lbdm。
suffix "dc=my-domain,dc=com"
#设置目录后缀
rootdn "cn=Manager,dc=my-domain,dc=com"
#设置目录管理员
# Cleartext passwords, especially for the rootdn, should
# be avoid. See slappasswd(8) and slapd.conf(5) for details.
# Use of strong authentication encouraged.
rootpw secret
#设置管理密码,这里用了明文的“secret”密码。这样设置不安全,需使用加密的密码,下面会讲到如何设置加密密码。
# The database directory MUST exist prior to running slapd AND
# should only be accessible by the slapd and slap tools.
# Mode 700 recommended.
directory /usr/local/openldap/var/openldap-data
#设置资料库路径
# Indices to maintain
index objectClass eq
#设置目录项索引

要服务器正常动作,要修改一些始初参数和设置,修改后的配置文档如下:

# $OpenLDAP: pkg/ldap/servers/slapd/slapd.conf,v 1.23.2.8 2003/05/24 23:19:14 kurt Exp $
#
# See slapd.conf(5) for details on configuration options.
# This file should NOT be world readable.
#
#为了有效使用目录服务,包含相关的文件。注意,在包含文件时是要按一定顺序的,因为
#文件里的属性存在依赖关系。如果顺序不对,服务器启动不了,文档间的依赖关系在文档
#中都有说明,请仔细查看一下。如果懒得看也可以按我的顺序。
include /usr/local/openldap/etc/openldap/schema/core.schema
include /usr/local/openldap/etc/openldap/schema/corba.schema
include /usr/local/openldap/etc/openldap/schema/cosine.schema
include /usr/local/openldap/etc/openldap/schema/inetorgperson.schema
include /usr/local/openldap/etc/openldap/schema/misc.schema
include /usr/local/openldap/etc/openldap/schema/openldap.schema
include /usr/local/openldap/etc/openldap/schema/nis.schema
include /usr/local/openldap/etc/openldap/schema/samba.schema
# Define global ACLs to disable default read access.

# Do not enable referrals until AFTER you have a working directory
# service AND an understanding of referrals.
#referral ldap://root.openldap.org

pidfile /usr/local/openldap/var/slapd.pid
argsfile /usr/local/openldap/var/slapd.args

loglevel 1
#增加了日志功能,需修改syslog配置文件,在文件中增加一项:local4.* /var/log/ldap.log日志级别定义可查相官方网站的文档。
#1级记录的信息很多,可用于调试。
# Load dynamic backend modules:
# modulepath /usr/local/openldap/libexec/openldap
# moduleload back_bdb.la
# moduleload back_ldap.la
# moduleload back_ldbm.la
# moduleload back_passwd.la
# moduleload back_shell.la

# Sample security restrictions
# Require integrity protection (prevent hijacking)
# Require 112-bit (3DES or better) encryption for updates
# Require 63-bit encryption for simple bind
# security ssf=1 update_ssf=112 simple_bind=64

# Sample access control policy:
# Root DSE: allow anyone to read it
# Subschema (sub)entry DSE: allow anyone to read it
# Other DSEs:
# Allow self write access
# Allow authenticated users read access
# Allow anonymous users to authenticate
# Directives needed to implement policy:
# access to dn.base="" by * read
# access to dn.base="cn=Subschema" by * read
# access to *
# by self write
# by users read
# by anonymous auth
#
# if no access controls are present, the default policy is:
# Allow read by all
#
# rootdn can always write!

#######################################################################
# ldbm database definitions
#######################################################################

database bdb
suffix "dc=it,dc=com"
#改成你自已的目录后缀,
rootdn "cn=root,dc=it,dc=com"
#设置root为管理员,与linux的root没有什么关系。
# Cleartext passwords, especially for the rootdn, should
# be avoid. See slappasswd(8) and slapd.conf(5) for details.
# Use of strong authentication encouraged.
rootpw {MD5}mjkiuPt0wXhpxxkdiOOO+0000000AKq0by
#设置root密码,用MD5加密。密码串用slappasswd -h {MD5}指令生成
# The database directory MUST exist prior to running slapd AND
# should only be accessible by the slapd and slap tools.
# Mode 700 recommended.
directory /usr/local/openldap/var/openldap-data
# Indices to maintain
index objectClass eq
#这里可根据你的需要设置相关索引,以加快查询速度。具体内容可查询官方网站管理手册。

#ACL configure以下内容定义访问控制
access to attr=userPassworduserPassword
#只能由自已修改,有效验证用户查询。
by self write
by anonymous auth
access to attr=mail
by dn="cn=root,dc=it,dc=tigerhead" writemail
#只能由自已修改,有效验证用户查询。
by self write
by anonymous auth
access to dn=".*,dc=it,dc=tigerhead"
#允许所有人查询没受控制访问限制的信息。
by self write
by * read

到现在为止,服务器基本就配置完成了,可以启动了,服务器程序是位于安装目录的libexec下的slapd程序。注意,不是sldap哦。ok,到现在为止,服务器基本就配置完成了,可以启动了,服务器程序是位于安装目录的libexec下的slapd程序。注意,不是sldap哦。启动服务器执行以下命令:

# ./slapd

如果没有提示什么出错信息,直接返回shell状态,就说明服务器正常启动了,你可以查询日志或用ps -aux查看。或用以下命令查询服务器:

ldapsearch -x -b '' -s base '(objectclass=*)' namingContexts

如果命令执行成功,返回一些信息,则说明服务器正常运行了。如果启动不成功,它会提示一些出错信息,多数是slapd.conf配置出错。回头仔细核查一下配置文档。

客户端配置文档是ldap.conf。该文档相当简单,其实不用配置也能正常操作。

# $OpenLDAP: pkg/ldap/libraries/libldap/ldap.conf,v 1.9 2000/09/04 19:57:01 kurt Exp $
#
# LDAP Defaults
#

# See ldap.conf(5) for details
# This file should be world readable but not world writable.

BASE dc=it, dc=com设置目录起点
#URI ldap://ldap.example.com ldap://ldap-master.example.com:666

#SIZELIMIT 12
#TIMELIMIT 15
#DEREF never

2.2. 数据录入
服务器正常运作后,就可以录入信息了。信息的录入有三种方法,一种是手工录入,一种是.ldif文件格式录入,一种是脚本自动录入。我们先从最基础的手工录入方式开始介绍,了解录入信息的格式。明白了手工录入的格式,其它两种方式都很容易明白。信息录入用到ldapadd这个程序。可在安装目录的bin目录下找到。

2.2.1. 手动录入方法
第一步是要建立DN:

# ldapadd -x -D 'cn=root,dc=it,dc=com' -W
dn: dc=it,dc=com
objectClass: dcObject
objectClass: organization
dc: it
o: Corporation
description: d Corporation
注意:如果你用复制/粘贴功能把以上内容拷贝过去,一定要注意每行后面不要有空格,建议还是手工输入,按Ctrl+d存盘。

第二步是建立RDN:

# ldapadd -x -D 'cn=root,dc=it,dc=com' -W
#-x表示用简单验证,-D表示指定目录,-W表示弹出密码输入提示

输入密码,这里的密码是在配置文件中rootpw项设置的密码,不是操作系统中root用户的密码。验证通过后就可输入以下内容:

dn: uid=qq,dc=it,dc=com
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
uid: qq
cn: qq
sn: qq
telephoneNumber: 138888888
description: openldap test
telexNumber: tex-8888888
street: my street
postOfficeBox: postofficebox
displayName: qqdisplay
homePhone: home1111111
mobile: mobile99999
mail:qq@qq.com

输入完所有信息后,按Ctrl+d结束存盘。如果出现出错信息,请查一下对象类和属性的对应关系有没有错或输入失误。初学者就容易出错的地方是对象类和属性的对应关系没有处理好。对象类和属性是在schema文档中定义的。它们之间的关系是这样的,对象类中有些属性是必选的,有些属性是可选的。录入信息的属性必须在对象类中有定义才能用。

输入以下命令可查询到刚才输入的信息。

# ldapsearch -x -b 'dc=it,dc=com'
-b选项是设置目录起点,如果设置了客户端的BASE配置参数,该项可不用。

如果按以上配置文件设置了acl,用上面的查询命令是查询不到受保护的内容的。如上面的userPassword and mail。要查询到这些受限内容,需要通过验证才可以:

# ldapsearch -x -LLL -h it.com -b 'dc=it,dc=com' -D 'uid=qq,dc=it,dc=com' -W 'uid=qq'
接着提示输入密码。输入userPassword的密码回车,所有信息就都出来了。

2.2.2. 文件方式
.ldif文件方式也就是把以上手工输入的内容先写入一个.ldif文件中,然后,用ldapadd命令的-f参数导入。

# ldapadd -x -D "cn=root,dc=it,dc=com" -W -f test.ldif

一个完整的global.ldif文件例子:

dn: dc=info, dc=net
objectClass: top
objectClass: organization
o: info.net

dn: ou=People, dc=info, dc=net
objectClass: top
objectClass: organizationalUnit
ou: People
description: User Info

dn: cn=Admin, dc=info, dc=net
objectClass: top
objectClass: person
objectClass: organizationalPerson
cn: Admin
sn: Admin
userPassword: Admin
description: Administrator for info.net

dn: id=1, ou=People, dc=info, dc=net
objectclass: top
objectclass: InfoPerson
id: 1
username: 张三
tel:021-63138990
card_id:ABC001

我们也可用slapadd命令来导入数据。该命令可以导入包含一些系统信息的ldif文件,如:

dn: dc=it,dc=com
objectClass: top
objectClass: dcObject
objectClass: organization
dc: it
structuralObjectClass: organization
entryUUID: d97b06da-d77e-1028-9866-d4ec7ac00d12
creatorsName: cn=anonymous #系统信息
createTimestamp: 20041201005115Z #系统信息
o:: 5bm/5bee5biC6JmO5aS055S15rGg6ZuG5Zui5pyJ6ZmQ5YWs5Y+4
userPassword:: e01ENX14TXBDT0tDNUk0SU56RkNhYjNXRW13PT0=
entryCSN: 2004120603:50:08Z#0x0001#0#0000 #系统信息
modifiersName: cn=admin,dc=it,dc=com #系统信息
modifyTimestamp: 20041206035008Z #系统信息
再次提醒,注意每行后面不要留有空格。

2.2.3. 脚本方式
脚本录入方式需要自已编写脚本,或到网上下载。有一个用PHP写的LDAP管理工具不错,叫phpLDAPadmin。可以到以下网址下载:http://phpldapadmin.sourceforge.net。安装方法也很简单,只要解压出来,拷贝到apache的web目录下,按说明配置一下设定文档,就ok了。

2.3. 常用命令介绍
接着为大家介绍一下几个常用的ldap命令,如果你用了phpLDAPadmin程序,其实它已经有一个很好的图形介面帮你完成这些命令了。但了解一下还是对你还是很有益的,因为命令方法才是最根本的。

删除命令ldapdelete

# ldapdelete -x -D 'cn=root,dc=it,dc=com' -W 'uid=qq1,dc=it,dc=com'

重新索引ldap数据库命令slapindex

# slapindex -f slapd.conf

设置使用者密码,当然了,你的用户需要有userPassword项了。

#ldappasswd -x -D "cn=root,dc=it,dc=com" -W "uid=qq1,dc=it,dc=com" -S
New password:
Re-enter new password:
Enter bind password:
Result: Success (0)
"Enter bind password" 是 "cn=root,dc=it,dc=com"管理员的密码。

管理员密码更改

#slappasswd
New password
Re-enter new password
{SSHA}83DJ4KVwqlk1uh9k2uDb8+NT1U4RgkEs

接下再拷贝到 path/to/sldap.conf 的 rootpw 即可,重启使用配置文件生效

通过ldapmodify修改目录内容

# ldapmodify -x -D "cn=root,dc=it,dc=com" -W -f modify.ldif

通过ldif文件修改ldap数据,ldif文件格式如下:

dn: cn=qq,dc=it,dc=com
changetype: modify
replace: mail
mail: modme@example.com
-
add: title
title: Grand Poobah
-
add: jpegPhoto
jpegPhoto:< file:///tmp/modme.jpeg
-
delete: description
-

2.4. 启用sasl验证
前提是你在系统中安装了sasl认证库,并在编译openldap时支持它,默认就支持了。到http://asg.web.cmu.edu/cyrus下载。安装方法见我写的sendmail安装笔记。安装好之后,需要在sasl中建立相应的帐号,用以下命令可完成。

# saslpasswd2 -c test

接着配置slapd.conf文件,加入以下内容。

sasl-regexp
uid=(.*),cn=.*,cn=auth
uid=$1,dc=it,dc=com

重启服务器使配置文件生效。这个配置是最大权限的配置,如果要细化请查阅相关文档。用以下命令测试。

# ldapsearch -U qq -b 'uid=qq,dc=it,dc=com' -D 'dc=it,dc=com' -Y DIGEST-MD5

采用digest-md5验证,提示密码,输入saslpasswd2的密码。

2.5. 配置服务器复制
在一些关键的应用场合,我们需设置多个ldap服务器实例,且数据要保持同步。当一台服务器出现故障或被黑客攻击时,我们就能继续保持应用的正常运行。通过DNS的轮流查询功能,还能实现服务器的负载均衡,提高响应速度。在openldap中有一个slurpd进程,利用slurpd进程可帮助我们实现多台ldap服务器数据的同步功能。下面简单介绍一下主、从ldap服务器的配置。

slurpd运行在主服务器上,它能把主服务器上的变化通过LDAP协议传送到从服务器上。从服务器上的变化不能传送到主服务器上,也就是说是单向同步的。主从服务器的版本最好一样,以减少兼容性问题。主从服务器的安装方法是一样的,关键是配置文件有所不同。我的操作系统是debian sarge,在确保主从服务器能正常运行的前提下进行以下配置:

首先,把主从服务器关闭。通过以下三步操作静态同步主从服务器上的数据:

把主服务器上/var/lib/ldap目录下的所有数据库文件全部拷贝到从服务器的同目录中,覆盖原有文件。

把主服务器上的/etc/ldap/schema目录下的所有schema文件拷贝到从服务器的同目录中,覆盖原有文件。

把主服务器上/etc/ldap/slapd.conf文件拷贝到从服务器的同目录中,覆盖原有文件。

配置主服务器上的slapd.conf文件,取消replogfile指令前的注释符号,取消后的结果如下:

# Where to store the replica logs for database #1
replogfile /var/lib/ldap/replog

增加replica指令,如:

#replace config
replica uri=ldap://192.168.6.195:389 #指定从服务器主机名和端口号
binddn="cn=admin,dc=com" #指定需同步的DN的管理员
bindmethod=simple credentials=1 #指定验证方式和需同步的DN的管理员密码

配置从服务器上的slapd.conf文件,增加updatedn指令,如:

updatedn "cn=admin,dc=com" #与主服务器的binddn对应

在从服务器的配置文件中,不要包含replica和replogfile指令。

先启动主服务器的slapd和slurpd,再启动从服务器的slapd。

配置完成后,我们可测试一下,在主服务器上修改一个目录项,在从服务器上可查看目录项的数据已同步。

Chapter 3. 管理工具
Table of Contents

3.1. phpldapadmin
3.2. gq
3.3. CPU
3.4. JXplore
开源的目录服务管理工具有很多,包括phpldapadmin,gq,CPU,JXplore等。这些工具可帮助我们方便维护目录服务器上的数据。这些工具各有优缺点,下面简要介绍一下,详细的内容可参考相关的官方网站。

3.1. phpldapadmin

3.2. gq

3.3. CPU

3.4. JXplore

Chapter 4. HowTo
Table of Contents

4.1. 禁止整个服务器的匿名访问
4.1. 禁止整个服务器的匿名访问
在slapd.conf配置文件中加入disallow bind_anon即可。

数据库编码为gb2312,重新改写了wap程序编码为utf-8


$user = iconv("utf-8", "gb2312",addslashes(urldecode($_POST['username'])));
$pass = md5(urldecode($_POST['password']));
$SQL = "SELECT `password` FROM " . USER_TABLE . " WHERE `username` = '$user'";
$Result = $DB -> query($SQL);
$Row = $DB -> queryArray($Result);
if($Row['password'] == $pass){
session_register(name');
$_SESSION[name'] = iconv("gb2312", "utf-8",$user);
}

使用PHP连接LDAP服务器

本文将演示如何使用PHP连接一个LDAP服务器。具体的例子是连接到一个公共的LDAP服务器并且进行搜索。这个例子模拟的是Netscape Communicator 4.*,通过自己的地址本连接到LDAP资源。
LDAP介绍

  可能不少人已经听说过LDAP,但是却不了解它具体是什么东东和如何工作。在这里我将不会很详细地介绍LDAP,只是对该协议做一个简介。

  LDAP是一个用来发布目录信息到许多不同资源的协议。通常它都作为一个集中的地址本使用,不过根据组织者的需要,它可以做得更加强大。

  LDAP最基本的形式是一个连接数据库的标准方式。该数据库为读查询作了优化。因此它可以很快地得到查询结果,不过在其它方面,例如更新,就慢得多。要特别注意的是,LDAP通常作为一个hierarchal数据库使用,而不是一个关系数据库。因此,它的结构用树来表示比用表格好。正因为这样,就不能用SQL语句了。

  简单说来,LDAP是一个得到关于人或者资源的集中、静态数据的快速方式。

要求

   PHPV.4(以前的版本也可以,不过没有经过测试),编译支持LADP,即使用编译时带–with-ldap公共的LDAP目录。在例子中提供了两个。

例子概览

1.设置公共LDAP服务器的信息
2.创建一个LDAP查询
3.连接到LDAP服务器
4.如果连接成功,处理查询
5.格式化输出
6.关闭连接
7.设计搜索界面的HTML表格
8.显示结果

设置公共LDAP服务器的信息

  我们要做的第一件事情是定义所有欲搜索的LDAP服务器的信息

“LDAP_NAME” = 新的LDAP项目的名字
“LDAP_SERVER” = 新的LDAP项目的IP地址或者主机名
“LDAP_ROOT_DN” = 新的LDAP项目的根的辨识名

建立LDAP查询

  前面已经提到,LDAP查询与SQL查询是不一样的。因此,语句要受到一定的限制,以下是一个基本的例子。

//Create Query $ldap_query = “cn=$common”;

  在我们的例子中,“cn”是我们要进行搜索的属性,而$common是由搜索的form中得到的字符串变量。LDAP的查询语句语句可使用通配符‘*’。例如‘$stanley’将可以找出‘dan stanley’。

连接到LDAP服务器

  以下的函数连接到一个LDAP资源,并且将连接的识别号赋给一个变量,就好象连接到一个通常的数据库一样,例如MySQL。

  在我们的例子中,“$connect_id”是连接的识别号,$LDAP_SERVER是可能的ldap服务器数组,而$SERVER_ID是由搜索表格得到的LDAP服务器变量。

如果连接成功,处理查询

   如果连接成功的话,我们将得到一个有效的LDAP连接识别号,这样我们就可以处理查询。

  一旦我们与LDAP服务器建立好连接,我们就必须进行认证。PHP在连接大多数的数据库时,都是通过发送用户名和密码来进行的。不过,在LDAP中,认证是未知的,直到进行一个bind操作。在我们的例子中,“$bind_id”是绑定连接的标识符。我们是通过匿名绑定到公共的LDAP服务器的。因此,在执行ldap_bind()时,只使用连接识别号就可以了,无需其它的参数。

  在经过认证后(这里是匿名的),我们就可以使用ldap_search()函数来执行查询,产生的$search_id是我们搜索的连接识别符。

  然后,我们使用ldap_get_entries()函数将结果集赋给$result_array变量。这样我们能够以逻辑的方式排列信息,以便显示。
格式化输出

  在执行完LDAP搜索后,返回的数据是以查找的顺序排列的。不过我们在排序时没有SQL这样方便,使用ORDER BY语句就可以了。通常多数公共的LDAP目录都没有标准的大小规范。排序是基于字符的ASCII值,我们必须将字符全部格式化为小写,以便按字母的顺序输出。

  要特别注意的是,返回的LDAP结果集是一个多维的数组。因此,我们脚本中的$result_array的结构如下:

$result_array[0]["cn"] [0] = "Dannie Stanley"
["dn"] [0] = "uid=dannie,dc=spinweb.net"
["givenname"][0] = "Dannie"
["sn"] [0] = "Stanley"
["mail"] [0] = "danSPAM@spinweb.net"
$result_array[1]["cn"] [0] = "Michael Reynolds"
["dn"] [0] = "uid=michael,dc=spinweb.net"
["givenname"][0] = "Michael"
["sn"] [0] = "Reynolds"
["mail"] [0] = "michaelSPAM@spinweb.net"

  数据以这种格式存放的原因是每个属性都可能有超过一个值(象树的结构)。例如,如果我的名字是‘Dannie’,我还可以在LDAP中增加一些属性,例如:

$result_array[0]["cn"] [0] = "Dannie Stanley"
["dn"] [0] = "uid=dannie,dc=spinweb.net"
["givenname"][0] = "Dannie"
["givenname"][0] = "Dan"
["sn"] [0] = "Stanley"
["mail"] [0] = "danSPAM@spinweb.net"

  在我们的搜索中,我们只关心每个属性的首个值,因此除了dn只有一个值外,其它我们只使用每个属性中序号为0的值。以下就是属性和它们含义的简单列表:

"cn" = Common Name
"dn" = Distinguished Name
"givenname" = First Name
"sn" = Last Name
"mail" = Email地址

//如果搜索成功,将结果排序
if($result_array)
{
for($i=0; $i {
$format_array[$i][0] = strtolower($result_array[$i]["cn"][0]);
$format_array[$i][1] = $result_array[$i]["dn"];
$format_array[$i][2] = strtolower($result_array[$i]["givenname"][0]);
$format_array[$i][3] = strtolower($result_array[$i]["sn"][0]);
$format_array[$i][4] = strtolower($result_array[$i]["mail"][0]);
}

//排序数组
sort($format_array, "SORT_STRING");

for($i=0; $i {
$cn = $format_array[$i][0];
$dn = $format_array[$i][1];
$fname = ucwords($format_array[$i][2]);
$lname = ucwords($format_array[$i][3]);
$email = $format_array[$i][4];

if($dn && $fname && $lname && $email)
{
$result_list .= "$fname $lname";
$result_list .= " <$email>
";
}
elseif($dn && $cn && $email)
{
$result_list .= "$cnldap://$LDAP_SERVER[$SERVER_ID]/$dn/"'>$cn>";
$result_list .= " $emailmailto:$email/"'>$email>
";
}
}
}
else
{
echo "Result set empty for query: $ldap_query";
}

?>
   在我们的例子中,$format_array是我们建立的新数组,里面包括有查询的结果,并且被格式化用作输出。首先循环$result_array中的每个元素,并且将它分配给一个两维的数组用作排序。同时我们使用strtolower()函数将所有的值变为小写。

  接着,我们使用PHP自带的一个称为sort()的函数进行排序。首个参数是要排序的数组,另一个是要执行的排序类型,该类型是由PHP的文档定义的。由于我们根据字符串排序,我们使用“SORT_STRING”。

  第三,我们循环已经格式化好的数组,并且将它分配给一个名字为$result_list的输出字符,该字符包含了HTML描述。要特别注意的是,在超链接中,我使用的是ldap的URL格式。这个格式的例子类似:HREF="ldap://ldap.domain.net/uid=dannie,dc=domain.net"。

关闭连接

  现在我们所有的数据已经包含在$result_list中了,我们可以安全地关闭LDAP的连接。

//关闭连接
ldap_close($connect_id);

定制搜索界面的HTML表格

  最后,我们要定制搜索用的HTML表格,它是用来给用户执行搜索的。

//定制表格
echo "


";
echo "Search in:



"; echo "

";
echo "Search for:";
echo "
";
echo "(You can use * for wildcard searches, ex. * Stanley will find all Stanleys)
";
echo "



";

?>

  代码中的$PHP_SELF是一个全局的常量,代表的是脚本页面自身,其中的循环是用来通过我们的$LDAP_NAME变量创建SELECT选项。

显示结果

  现在所有的工作已经完成了,我们将打印出结果集。如果没有符合的结果,将会显示"No Results"的信息。

<php

//显示结果
if($result_list)
{
echo "


$result_list


";
}
else
echo "No Results";

?>

源代码

  以下是完整的源代码,只要将它剪切并粘贴到一个HTML文档,就可以尝试一下了。

$LDAP_NAME[0] = "Netscape Net Center";
$LDAP_SERVER[0] = "memberdir.netscape.com";
$LDAP_ROOT_DN[0] = "ou=member_directory,o=netcenter.com";

$LDAP_NAME[1] = "Bigfoot";
$LDAP_SERVER[1] = "ldap.bigfoot.com";
$LDAP_ROOT_DN[1] = "";

//如果没有选择服务器的话将它设置为0
if(!$SERVER_ID)
$SERVER_ID=0;

//建立查询
$ldap_query = "cn=$common";

//连接到LDAP
$connect_id = ldap_connect($LDAP_SERVER[$SERVER_ID]);

if($connect_id)
{
//认证
$bind_id = ldap_bind($connect_id);

//执行搜索
$search_id = ldap_search($connect_id, $LDAP_ROOT_DN[$SERVER_ID], $ldap_query);

//将结果集合分配给一个数组
$result_array = ldap_get_entries($connect_id, $search_id);
}
else
{
//显示连接错误
echo "Could not connect to LDAP server: $LDAP_SERVER[$SERVER_ID]";
}

//如果搜索成功,将结果排序
if($result_array)
{
for($i=0; $i {
$format_array[$i][0] = strtolower($result_array[$i]["cn"][0]);
$format_array[$i][1] = $result_array[$i]["dn"];
$format_array[$i][2] = strtolower($result_array[$i]["givenname"][0]);
$format_array[$i][3] = strtolower($result_array[$i]["sn"][0]);
$format_array[$i][4] = strtolower($result_array[$i]["mail"][0]);
}

//排序数组
sort($format_array, "SORT_STRING");

for($i=0; $i {
$cn = $format_array[$i][0];
$dn = $format_array[$i][1];
$fname = ucwords($format_array[$i][2]);
$lname = ucwords($format_array[$i][3]);
$email = $format_array[$i][4];

if($dn && $fname && $lname && $email)
{
$result_list .= "$fname">ldap://$LDAP_SERVER[$SERVER_ID]/$dn/"'>$fname $lname";
$result_list .= " <$email>
";
}
elseif($dn && $cn && $email)
{
$result_list .= "$cnldap://$LDAP_SERVER[$SERVER_ID]/$dn/"'>$cn>";
$result_list .= " <$emailmailto:$email/"'>$email>
";
}
}
}
else
{
echo "Result set empty for query: $ldap_query";
}

//关闭连接
ldap_close($connect_id);

//定制表格
echo "


";
echo "Search in:


"; echo "

";
echo "Search for:";
echo "
";
echo "(You can use * for wildcard searches, ex. * Stanley will find all Stanleys)
";
echo "



";

//显示结果
if($result_list)
{
echo "


$result_list


";
}
else
echo "No Results";
}

?>


Linux 下网络蜘蛛wget使用

wget 是linux自带的工具。补丁程序:http://www.smth.edu.cn/bbscon.php?bid=69&id=118152&ap=500

使用举列:

wget -r -np --level=0 -k http://www.cnread.net/cnread1/dnwl/cxsj/c/cyyb/



walker
04-12-21, 09:11
$ wget --help
GNU Wget 1.9.1,非交互式的网络文件下载工具。
用法: wget [选项]... [URL]...
长选项必须用的参数在使用短选项时也是必须的。

启动:
-V, --version 显示 Wget 的版本并且退出。
-h, --help 打印此帮助。
-b, -background 启动后进入后台操作。
-e, -execute=COMMAND 运行‘.wgetrc’形式的命令。

日志记录及输入文件:
-o, --output-file=文件 将日志消息写入到指定文件中。
-a, --append-output=文件 将日志消息追加到指定文件的末端。
-d, --debug 打印调试输出。
-q, --quiet 安静模式(不输出信息)。
-v, --verbose 详细输出模式(默认)。
-nv, --non-verbose 关闭详细输出模式,但不进入安静模式。
-i, --input-file=文件 下载从指定文件中找到的 URL。
-F, --force-html 以 HTML 方式处理输入文件。
-B, --base=URL 使用 -F -i 文件选项时,在相对链接前添加指定的 URL。

下载:
-t, --tries=次数 配置重试次数(0 表示无限)。
--retry-connrefused 即使拒绝连接也重试。
-O --output-document=文件 将数据写入此文件中。
-nc, --no-clobber 不更改已经存在的文件,也不使用在文件名后
添加 .#(# 为数字)的方法写入新的文件。
-c, --continue 继续接收已下载了一部分的文件。
--progress=方式 选择下载进度的表示方式。
-N, --timestamping 除非远程文件较新,否则不再取回。
-S, --server-response 显示服务器回应消息。
--spider 不下载任何数据。
-T, --timeout=秒数 配置读取数据的超时时间 (秒数)。
-w, --wait=秒数 接收不同文件之间等待的秒数。
--waitretry=秒数 在每次重试之间稍等一段时间 (由 1 秒至指定的 秒数不等)。
--random-wait 接收不同文件之间稍等一段时间(由 0 秒至 2*WAIT 秒不等)。
-Y, --proxy=on/off 打开或关闭代理服务器。
-Q, --quota=大小 配置接收数据的限额大小。
--bind-address=地址 使用本机的指定地址 (主机名称或 IP) 进行连接。
--limit-rate=速率 限制下载的速率。
--dns-cache=off 禁止查找存于高速缓存中的 DNS。
--restrict-file-names=OS 限制文件名中的字符为指定的 OS (操作系统) 所允许的字符。

目录:
-nd --no-directories 不创建目录。
-x, --force-directories 强制创建目录。
-nH, --no-host-directories 不创建含有远程主机名称的目录。
-P, --directory-prefix=名称 保存文件前先创建指定名称的目录。
--cut-dirs=数目 忽略远程目录中指定数目的目录层。

HTTP 选项:
--http-user=用户 配置 http 用户名。
--http-passwd=密码 配置 http 用户密码。
-C, --cache=on/off (不)使用服务器中的高速缓存中的数据 (默认是使用的)。
-E, --html-extension 将所有 MIME 类型为 text/html 的文件都加上 .html 扩展文件名。
--ignore-length 忽略“Content-Length”文件头字段。
--header=字符串 在文件头中添加指定字符串。
--proxy-user=用户 配置代理服务器用户名。
--proxy-passwd=密码 配置代理服务器用户密码。
--referer=URL 在 HTTP 请求中包含“Referer:URL”头。
-s, --save-headers 将 HTTP 头存入文件。
-U, --user-agent=AGENT 标志为 AGENT 而不是 Wget/VERSION。
--no-http-keep-alive 禁用 HTTP keep-alive(持久性连接)。
--cookies=off 禁用 cookie。
--load-cookies=文件 会话开始前由指定文件载入 cookie。
--save-cookies=文件 会话结束后将 cookie 保存至指定文件。
--post-data=字符串 使用 POST 方法,发送指定字符串。
--post-file=文件 使用 POST 方法,发送指定文件中的内容。

HTTPS (SSL) 选项:
--sslcertfile=文件 可选的客户段端证书。
--sslcertkey=密钥文件 对此证书可选的“密钥文件”。
--egd-file=文件 EGD socket 文件名。
--sslcadir=目录 CA 散列表所在的目录。
--sslcafile=文件 包含 CA 的文件。
--sslcerttype=0/1 Client-Cert 类型 0=PEM (默认) / 1=ASN1 (DER)
--sslcheckcert=0/1 根据提供的 CA 检查服务器的证书
--sslprotocol=0-3 选择 SSL 协议;0=自动选择,
1=SSLv2 2=SSLv3 3=TLSv1

FTP 选项:
-nr, --dont-remove-listing 不删除“.listing”文件。
-g, --glob=on/off 设置是否展开有通配符的文件名。
--passive-ftp 使用“被动”传输模式。
--retr-symlinks 在递归模式中,下载链接所指示的文件(连至目录
则例外)。
递归下载:
-r, --recursive 递归下载。
-l, --level=数字 最大递归深度(inf 或 0 表示无限)。
--delete-after 删除下载后的文件。
-k, --convert-links 将绝对链接转换为相对链接。
-K, --backup-converted 转换文件 X 前先将其备份为 X.orig。
-m, --mirror 等效于 -r -N -l inf -nr 的选项。
-p, --page-requisites 下载所有显示完整网页所需的文件,例如图像。
--strict-comments 打开对 HTML 备注的严格(SGML)处理选项。

递归下载时有关接受/拒绝的选项:
-A, --accept=列表 接受的文件样式列表,以逗号分隔。
-R, --reject=列表 排除的文件样式列表,以逗号分隔。
-D, --domains=列表 接受的域列表,以逗号分隔。
--exclude-domains=列表 排除的域列表,以逗号分隔。
--follow-ftp 跟随 HTML 文件中的 FTP 链接。
--follow-tags=列表 要跟随的 HTML 标记,以逗号分隔。
-G, --ignore-tags=列表 要忽略的 HTML 标记,以逗号分隔。
-H, --span-hosts 递归时可进入其它主机。
-L, --relative 只跟随相对链接。
-I, --include-directories=列表 要下载的目录列表。
-X, --exclude-directories=列表 要排除的目录列表。
-np, --no-parent 不搜索上层目录。

请将错误报告或建议寄给 。

目录下载: wget -rL ftp://url/path

Linux / Unix Command: wget

NAME
wget - GNU Wget Manual
SYNOPSIS
wget [option]... [URL]...
DESCRIPTION
GNU Wget is a free utility for non-interactive download of files from the Web. It supports HTTP, HTTPS, and FTP protocols, as well as retrieval through HTTP proxies.
Wget is non-interactive, meaning that it can work in the background, while the user is not logged on. This allows you to start a retrieval and disconnect from the system, letting Wget finish the work. By contrast, most of the Web browsers require constant user's presence, which can be a great hindrance when transferring a lot of data.

Wget can follow links in HTML pages and create local versions of remote web sites, fully recreating the directory structure of the original site. This is sometimes referred to as ``recursive downloading.'' While doing that, Wget respects the Robot Exclusion Standard (/robots.txt). Wget can be instructed to convert the links in downloaded HTML files to the local files for offline viewing.

Wget has been designed for robustness over slow or unstable network connections; if a download fails due to a network problem, it will keep retrying until the whole file has been retrieved. If the server supports regetting, it will instruct the server to continue the download from where it left off.

OPTIONS
Basic Startup Options
-V
--version
Display the version of Wget.
-h
--help
Print a help message describing all of Wget's command-line options.
-b
--background
Go to background immediately after startup. If no output file is specified via the -o, output is redirected to wget-log.
-e command
--execute command
Execute command as if it were a part of .wgetrc. A command thus invoked will be executed after the commands in .wgetrc, thus taking precedence over them.
Logging and Input File Options
-o logfile
--output-file=logfile
Log all messages to logfile. The messages are normally reported to standard error.
-a logfile
--append-output=logfile
Append to logfile. This is the same as -o, only it appends to logfile instead of overwriting the old log file. If logfile does not exist, a new file is created.
-d
--debug
Turn on debug output, meaning various information important to the developers of Wget if it does not work properly. Your system administrator may have chosen to compile Wget without debug support, in which case -d will not work. Please note that compiling with debug support is always safe---Wget compiled with the debug support will not print any debug info unless requested with -d.
-q
--quiet
Turn off Wget's output.
-v
--verbose
Turn on verbose output, with all the available data. The default output is verbose.
-nv
--non-verbose
Non-verbose output---turn off verbose without being completely quiet (use -q for that), which means that error messages and basic information still get printed.
-i file
--input-file=file
Read URLs from file, in which case no URLs need to be on the command line. If there are URLs both on the command line and in an input file, those on the command lines will be the first ones to be retrieved. The file need not be an HTML document (but no harm if it is)---it is enough if the URLs are just listed sequentially.
However, if you specify --force-html, the document will be regarded as html. In that case you may have problems with relative links, which you can solve either by adding "" to the documents or by specifying --base=url on the command line.

-F
--force-html
When input is read from a file, force it to be treated as an HTML file. This enables you to retrieve relative links from existing HTML files on your local disk, by adding "" to HTML, or using the --base command-line option.
-B URL
--base=URL
When used in conjunction with -F, prepends URL to relative links in the file specified by -i.
Download Options
--bind-address=ADDRESS
When making client TCP/IP connections, "bind()" to ADDRESS on the local machine. ADDRESS may be specified as a hostname or IP address. This option can be useful if your machine is bound to multiple IPs.
-t number
--tries=number
Set number of retries to number. Specify 0 or inf for infinite retrying.
-O file
--output-document=file
The documents will not be written to the appropriate files, but all will be concatenated together and written to file. If file already exists, it will be overwritten. If the file is -, the documents will be written to standard output. Including this option automatically sets the number of tries to 1.
-nc
--no-clobber
If a file is downloaded more than once in the same directory, Wget's behavior depends on a few options, including -nc. In certain cases, the local file will be clobbered, or overwritten, upon repeated download. In other cases it will be preserved.
When running Wget without -N, -nc, or -r, downloading the same file in the same directory will result in the original copy of file being preserved and the second copy being named file.1. If that file is downloaded yet again, the third copy will be named file.2, and so on. When -nc is specified, this behavior is suppressed, and Wget will refuse to download newer copies of file. Therefore, ``"no-clobber"'' is actually a misnomer in this mode---it's not clobbering that's prevented (as the numeric suffixes were already preventing clobbering), but rather the multiple version saving that's prevented.

When running Wget with -r, but without -N or -nc, re-downloading a file will result in the new copy simply overwriting the old. Adding -nc will prevent this behavior, instead causing the original version to be preserved and any newer copies on the server to be ignored.

When running Wget with -N, with or without -r, the decision as to whether or not to download a newer copy of a file depends on the local and remote timestamp and size of the file. -nc may not be specified at the same time as -N.

Note that when -nc is specified, files with the suffixes .html or (yuck) .htm will be loaded from the local disk and parsed as if they had been retrieved from the Web.

-c
--continue
Continue getting a partially-downloaded file. This is useful when you want to finish up a download started by a previous instance of Wget, or by another program. For instance:

wget -c ftp://sunsite.doc.ic.ac.uk/ls-lR.Z
If there is a file named ls-lR.Z in the current directory, Wget will assume that it is the first portion of the remote file, and will ask the server to continue the retrieval from an offset equal to the length of the local file.

Note that you don't need to specify this option if you just want the current invocation of Wget to retry downloading a file should the connection be lost midway through. This is the default behavior. -c only affects resumption of downloads started prior to this invocation of Wget, and whose local files are still sitting around.

Without -c, the previous example would just download the remote file to ls-lR.Z.1, leaving the truncated ls-lR.Z file alone.

Beginning with Wget 1.7, if you use -c on a non-empty file, and it turns out that the server does not support continued downloading, Wget will refuse to start the download from scratch, which would effectively ruin existing contents. If you really want the download to start from scratch, remove the file.

Also beginning with Wget 1.7, if you use -c on a file which is of equal size as the one on the server, Wget will refuse to download the file and print an explanatory message. The same happens when the file is smaller on the server than locally (presumably because it was changed on the server since your last download attempt)---because ``continuing'' is not meaningful, no download occurs.

On the other side of the coin, while using -c, any file that's bigger on the server than locally will be considered an incomplete download and only "(length(remote) - length(local))" bytes will be downloaded and tacked onto the end of the local file. This behavior can be desirable in certain cases---for instance, you can use wget -c to download just the new portion that's been appended to a data collection or log file.

However, if the file is bigger on the server because it's been changed, as opposed to just appended to, you'll end up with a garbled file. Wget has no way of verifying that the local file is really a valid prefix of the remote file. You need to be especially careful of this when using -c in conjunction with -r, since every file will be considered as an ``incomplete download'' candidate.

Another instance where you'll get a garbled file if you try to use -c is if you have a lame HTTP proxy that inserts a ``transfer interrupted'' string into the local file. In the future a ``rollback'' option may be added to deal with this case.

Note that -c only works with FTP servers and with HTTP servers that support the "Range" header.

--progress=type
Select the type of the progress indicator you wish to use. Legal indicators are ``dot'' and ``bar''.
The ``bar'' indicator is used by default. It draws an ASCII progress bar graphics (a.k.a ``thermometer'' display) indicating the status of retrieval. If the output is not a TTY, the ``dot'' bar will be used by default.

Use --progress=dot to switch to the ``dot'' display. It traces the retrieval by printing dots on the screen, each dot representing a fixed amount of downloaded data.

When using the dotted retrieval, you may also set the style by specifying the type as dot:style. Different styles assign different meaning to one dot. With the "default" style each dot represents 1K, there are ten dots in a cluster and 50 dots in a line. The "binary" style has a more ``computer''-like orientation---8K dots, 16-dots clusters and 48 dots per line (which makes for 384K lines). The "mega" style is suitable for downloading very large files---each dot represents 64K retrieved, there are eight dots in a cluster, and 48 dots on each line (so each line contains 3M).

Note that you can set the default style using the "progress" command in .wgetrc. That setting may be overridden from the command line. The exception is that, when the output is not a TTY, the ``dot'' progress will be favored over ``bar''. To force the bar output, use --progress=bar:force.

-N
--timestamping
Turn on time-stamping.
-S
--server-response
Print the headers sent by HTTP servers and responses sent by FTP servers.
--spider
When invoked with this option, Wget will behave as a Web spider, which means that it will not download the pages, just check that they are there. You can use it to check your bookmarks, e.g. with:

wget --spider --force-html -i bookmarks.html
This feature needs much more work for Wget to get close to the functionality of real WWW spiders.

-T seconds
--timeout=seconds
Set the read timeout to seconds seconds. Whenever a network read is issued, the file descriptor is checked for a timeout, which could otherwise leave a pending connection (uninterrupted read). The default timeout is 900 seconds (fifteen minutes). Setting timeout to 0 will disable checking for timeouts.
Please do not lower the default timeout value with this option unless you know what you are doing.

--limit-rate=amount
Limit the download speed to amount bytes per second. Amount may be expressed in bytes, kilobytes with the k suffix, or megabytes with the m suffix. For example, --limit-rate=20k will limit the retrieval rate to 20KB/s. This kind of thing is useful when, for whatever reason, you don't want Wget to consume the entire evailable bandwidth.
Note that Wget implementeds the limiting by sleeping the appropriate amount of time after a network read that took less time than specified by the rate. Eventually this strategy causes the TCP transfer to slow down to approximately the specified rate. However, it takes some time for this balance to be achieved, so don't be surprised if limiting the rate doesn't work with very small files. Also, the ``sleeping'' strategy will misfire when an extremely small bandwidth, say less than 1.5KB/s, is specified.

-w seconds
--wait=seconds
Wait the specified number of seconds between the retrievals. Use of this option is recommended, as it lightens the server load by making the requests less frequent. Instead of in seconds, the time can be specified in minutes using the "m" suffix, in hours using "h" suffix, or in days using "d" suffix.
Specifying a large value for this option is useful if the network or the destination host is down, so that Wget can wait long enough to reasonably expect the network error to be fixed before the retry.

--waitretry=seconds
If you don't want Wget to wait between every retrieval, but only between retries of failed downloads, you can use this option. Wget will use linear backoff, waiting 1 second after the first failure on a given file, then waiting 2 seconds after the second failure on that file, up to the maximum number of seconds you specify. Therefore, a value of 10 will actually make Wget wait up to (1 + 2 + ... + 10) = 55 seconds per file.
Note that this option is turned on by default in the global wgetrc file.

--random-wait
Some web sites may perform log analysis to identify retrieval programs such as Wget by looking for statistically significant similarities in the time between requests. This option causes the time between requests to vary between 0 and 2 * wait seconds, where wait was specified using the -w or --wait options, in order to mask Wget's presence from such analysis.
A recent article in a publication devoted to development on a popular consumer platform provided code to perform this analysis on the fly. Its author suggested blocking at the class C address level to ensure automated retrieval programs were blocked despite changing DHCP-supplied addresses.

The --random-wait option was inspired by this ill-advised recommendation to block many unrelated users from a web site due to the actions of one.

-Y on/off
--proxy=on/off
Turn proxy support on or off. The proxy is on by default if the appropriate environmental variable is defined.
-Q quota
--quota=quota
Specify download quota for automatic retrievals. The value can be specified in bytes (default), kilobytes (with k suffix), or megabytes (with m suffix).
Note that quota will never affect downloading a single file. So if you specify wget -Q10k ftp://wuarchive.wustl.edu/ls-lR.gz, all of the ls-lR.gz will be downloaded. The same goes even when several URLs are specified on the command-line. However, quota is respected when retrieving either recursively, or from an input file. Thus you may safely type wget -Q2m -i sites---download will be aborted when the quota is exceeded.

Setting quota to 0 or to inf unlimits the download quota.

Directory Options
-nd
--no-directories
Do not create a hierarchy of directories when retrieving recursively. With this option turned on, all files will get saved to the current directory, without clobbering (if a name shows up more than once, the filenames will get extensions .n).
-x
--force-directories
The opposite of -nd---create a hierarchy of directories, even if one would not have been created otherwise. E.g. wget -x http://fly.srk.fer.hr/robots.txt will save the downloaded file to fly.srk.fer.hr/robots.txt.
-nH
--no-host-directories
Disable generation of host-prefixed directories. By default, invoking Wget with -r http://fly.srk.fer.hr/ will create a structure of directories beginning with fly.srk.fer.hr/. This option disables such behavior.
--cut-dirs=number
Ignore number directory components. This is useful for getting a fine-grained control over the directory where recursive retrieval will be saved.
Take, for example, the directory at ftp://ftp.xemacs.org/pub/xemacs/. If you retrieve it with -r, it will be saved locally under ftp.xemacs.org/pub/xemacs/. While the -nH option can remove the ftp.xemacs.org/ part, you are still stuck with pub/xemacs. This is where --cut-dirs comes in handy; it makes Wget not ``see'' number remote directory components. Here are several examples of how --cut-dirs option works.
No options -> ftp.xemacs.org/pub/xemacs/
-nH -> pub/xemacs/
-nH --cut-dirs=1 -> xemacs/
-nH --cut-dirs=2 -> .

--cut-dirs=1 -> ftp.xemacs.org/xemacs/
...
If you just want to get rid of the directory structure, this option is similar to a combination of -nd and -P. However, unlike -nd, --cut-dirs does not lose with subdirectories---for instance, with -nH --cut-dirs=1, a beta/ subdirectory will be placed to xemacs/beta, as one would expect.

-P prefix
--directory-prefix=prefix
Set directory prefix to prefix. The directory prefix is the directory where all other files and subdirectories will be saved to, i.e. the top of the retrieval tree. The default is . (the current directory).
HTTP Options
-E
--html-extension
If a file of type text/html is downloaded and the URL does not end with the regexp \.[Hh][Tt][Mm][Ll]?, this option will cause the suffix .html to be appended to the local filename. This is useful, for instance, when you're mirroring a remote site that uses .asp pages, but you want the mirrored pages to be viewable on your stock Apache server. Another good use for this is when you're downloading the output of CGIs. A URL like http://site.com/article.cgi?25 will be saved as article.cgi?25.html.
Note that filenames changed in this way will be re-downloaded every time you re-mirror a site, because Wget can't tell that the local X.html file corresponds to remote URL X (since it doesn't yet know that the URL produces output of type text/html. To prevent this re-downloading, you must use -k and -K so that the original version of the file will be saved as X.orig.

--http-user=user
--http-passwd=password
Specify the username user and password password on an HTTP server. According to the type of the challenge, Wget will encode them using either the "basic" (insecure) or the "digest" authentication scheme.
Another way to specify username and password is in the URL itself. Either method reveals your password to anyone who bothers to run "ps". To prevent the passwords from being seen, store them in .wgetrc or .netrc, and make sure to protect those files from other users with "chmod". If the passwords are really important, do not leave them lying in those files either---edit the files and delete them after Wget has started the download.

For more information about security issues with Wget,

-C on/off
--cache=on/off
When set to off, disable server-side cache. In this case, Wget will send the remote server an appropriate directive (Pragma: no-cache) to get the file from the remote service, rather than returning the cached version. This is especially useful for retrieving and flushing out-of-date documents on proxy servers.
Caching is allowed by default.

--cookies=on/off
When set to off, disable the use of cookies. Cookies are a mechanism for maintaining server-side state. The server sends the client a cookie using the "Set-Cookie" header, and the client responds with the same cookie upon further requests. Since cookies allow the server owners to keep track of visitors and for sites to exchange this information, some consider them a breach of privacy. The default is to use cookies; however, storing cookies is not on by default.
--load-cookies file
Load cookies from file before the first HTTP retrieval. file is a textual file in the format originally used by Netscape's cookies.txt file.
You will typically use this option when mirroring sites that require that you be logged in to access some or all of their content. The login process typically works by the web server issuing an HTTP cookie upon receiving and verifying your credentials. The cookie is then resent by the browser when accessing that part of the site, and so proves your identity.

Mirroring such a site requires Wget to send the same cookies your browser sends when communicating with the site. This is achieved by --load-cookies---simply point Wget to the location of the cookies.txt file, and it will send the same cookies your browser would send in the same situation. Different browsers keep textual cookie files in different locations:

Netscape 4.x.
The cookies are in ~/.netscape/cookies.txt.
Mozilla and Netscape 6.x.
Mozilla's cookie file is also named cookies.txt, located somewhere under ~/.mozilla, in the directory of your profile. The full path usually ends up looking somewhat like ~/.mozilla/default/some-weird-string/cookies.txt.
Internet Explorer.
You can produce a cookie file Wget can use by using the File menu, Import and Export, Export Cookies. This has been tested with Internet Explorer 5; it is not guaranteed to work with earlier versions.
Other browsers.
If you are using a different browser to create your cookies, --load-cookies will only work if you can locate or produce a cookie file in the Netscape format that Wget expects.
If you cannot use --load-cookies, there might still be an alternative. If your browser supports a ``cookie manager'', you can use it to view the cookies used when accessing the site you're mirroring. Write down the name and value of the cookie, and manually instruct Wget to send those cookies, bypassing the ``official'' cookie support:
wget --cookies=off --header "Cookie: I=I"
--save-cookies file
Save cookies from file at the end of session. Cookies whose expiry time is not specified, or those that have already expired, are not saved.
--ignore-length
Unfortunately, some HTTP servers (CGI programs, to be more precise) send out bogus "Content-Length" headers, which makes Wget go wild, as it thinks not all the document was retrieved. You can spot this syndrome if Wget retries getting the same document again and again, each time claiming that the (otherwise normal) connection has closed on the very same byte.
With this option, Wget will ignore the "Content-Length" header---as if it never existed.

--header=additional-header
Define an additional-header to be passed to the HTTP servers. Headers must contain a : preceded by one or more non-blank characters, and must not contain newlines.
You may define more than one additional header by specifying --header more than once.
wget --header='Accept-Charset: iso-8859-2' \
--header='Accept-Language: hr' \
http://fly.srk.fer.hr/
Specification of an empty string as the header value will clear all previous user-defined headers.

--proxy-user=user
--proxy-passwd=password
Specify the username user and password password for authentication on a proxy server. Wget will encode them using the "basic" authentication scheme.
Security considerations similar to those with --http-passwd pertain here as well.

--referer=url
Include `Referer: url' header in HTTP request. Useful for retrieving documents with server-side processing that assume they are always being retrieved by interactive web browsers and only come out properly when Referer is set to one of the pages that point to them.
-s
--save-headers
Save the headers sent by the HTTP server to the file, preceding the actual contents, with an empty line as the separator.
-U agent-string
--user-agent=agent-string
Identify as agent-string to the HTTP server.
The HTTP protocol allows the clients to identify themselves using a "User-Agent" header field. This enables distinguishing the WWW software, usually for statistical purposes or for tracing of protocol violations. Wget normally identifies as Wget/version, version being the current version number of Wget.

However, some sites have been known to impose the policy of tailoring the output according to the "User-Agent"-supplied information. While conceptually this is not such a bad idea, it has been abused by servers denying information to clients other than "Mozilla" or Microsoft "Internet Explorer". This option allows you to change the "User-Agent" line issued by Wget. Use of this option is discouraged, unless you really know what you are doing.

FTP Options
-nr
--dont-remove-listing
Don't remove the temporary .listing files generated by FTP retrievals. Normally, these files contain the raw directory listings received from FTP servers. Not removing them can be useful for debugging purposes, or when you want to be able to easily check on the contents of remote server directories (e.g. to verify that a mirror you're running is complete).
Note that even though Wget writes to a known filename for this file, this is not a security hole in the scenario of a user making .listing a symbolic link to /etc/passwd or something and asking "root" to run Wget in his or her directory. Depending on the options used, either Wget will refuse to write to .listing, making the globbing/recursion/time-stamping operation fail, or the symbolic link will be deleted and replaced with the actual .listing file, or the listing will be written to a .listing.number file.

Even though this situation isn't a problem, though, "root" should never run Wget in a non-trusted user's directory. A user could do something as simple as linking index.html to /etc/passwd and asking "root" to run Wget with -N or -r so the file will be overwritten.

-g on/off
--glob=on/off
Turn FTP globbing on or off. Globbing means you may use the shell-like special characters (wildcards), like *, ?, [ and ] to retrieve more than one file from the same directory at once, like:

wget ftp://gnjilux.srk.fer.hr/*.msg
By default, globbing will be turned on if the URL contains a globbing character. This option may be used to turn globbing on or off permanently.

You may have to quote the URL to protect it from being expanded by your shell. Globbing makes Wget look for a directory listing, which is system-specific. This is why it currently works only with Unix FTP servers (and the ones emulating Unix "ls" output).

--passive-ftp
Use the passive FTP retrieval scheme, in which the client initiates the data connection. This is sometimes required for FTP to work behind firewalls.
--retr-symlinks
Usually, when retrieving FTP directories recursively and a symbolic link is encountered, the linked-to file is not downloaded. Instead, a matching symbolic link is created on the local filesystem. The pointed-to file will not be downloaded unless this recursive retrieval would have encountered it separately and downloaded it anyway.
When --retr-symlinks is specified, however, symbolic links are traversed and the pointed-to files are retrieved. At this time, this option does not cause Wget to traverse symlinks to directories and recurse through them, but in the future it should be enhanced to do this.

Note that when retrieving a file (not a directory) because it was specified on the commandline, rather than because it was recursed to, this option has no effect. Symbolic links are always traversed in this case.

Recursive Retrieval Options
-r
--recursive
Turn on recursive retrieving.
-l depth
--level=depth
Specify recursion maximum depth level depth. The default maximum depth is 5.
--delete-after
This option tells Wget to delete every single file it downloads, after having done so. It is useful for pre-fetching popular pages through a proxy, e.g.:

wget -r -nd --delete-after http://whatever.com/~popular/page/
The -r option is to retrieve recursively, and -nd to not create directories.

Note that --delete-after deletes files on the local machine. It does not issue the DELE command to remote FTP sites, for instance. Also note that when --delete-after is specified, --convert-links is ignored, so .orig files are simply not created in the first place.

-k
--convert-links
After the download is complete, convert the links in the document to make them suitable for local viewing. This affects not only the visible hyperlinks, but any part of the document that links to external content, such as embedded images, links to style sheets, hyperlinks to non-HTML content, etc.
Each link will be changed in one of the two ways:

*
The links to files that have been downloaded by Wget will be changed to refer to the file they point to as a relative link.
Example: if the downloaded file /foo/doc.html links to /bar/img.gif, also downloaded, then the link in doc.html will be modified to point to ../bar/img.gif. This kind of transformation works reliably for arbitrary combinations of directories.

*
The links to files that have not been downloaded by Wget will be changed to include host name and absolute path of the location they point to.
Example: if the downloaded file /foo/doc.html links to /bar/img.gif (or to ../bar/img.gif), then the link in doc.html will be modified to point to http://hostname/bar/img.gif.

Because of this, local browsing works reliably: if a linked file was downloaded, the link will refer to its local name; if it was not downloaded, the link will refer to its full Internet address rather than presenting a broken link. The fact that the former links are converted to relative links ensures that you can move the downloaded hierarchy to another directory.

Note that only at the end of the download can Wget know which links have been downloaded. Because of that, the work done by -k will be performed at the end of all the downloads.

-K
--backup-converted
When converting a file, back up the original version with a .orig suffix. Affects the behavior of -N.
-m
--mirror
Turn on options suitable for mirroring. This option turns on recursion and time-stamping, sets infinite recursion depth and keeps FTP directory listings. It is currently equivalent to -r -N -l inf -nr.
-p
--page-requisites
This option causes Wget to download all the files that are necessary to properly display a given HTML page. This includes such things as inlined images, sounds, and referenced stylesheets.
Ordinarily, when downloading a single HTML page, any requisite documents that may be needed to display it properly are not downloaded. Using -r together with -l can help, but since Wget does not ordinarily distinguish between external and inlined documents, one is generally left with ``leaf documents'' that are missing their requisites.

For instance, say document 1.html contains an "" tag referencing 1.gif and an "" tag pointing to external document 2.html. Say that 2.html is similar but that its image is 2.gif and it links to 3.html. Say this continues up to some arbitrarily high number.

If one executes the command:
wget -r -l 2 http://I/1.html
then 1.html, 1.gif, 2.html, 2.gif, and 3.html will be downloaded. As you can see, 3.html is without its requisite 3.gif because Wget is simply counting the number of hops (up to 2) away from 1.html in order to determine where to stop the recursion. However, with this command:
wget -r -l 2 -p http://I/1.html
all the above files and 3.html's requisite 3.gif will be downloaded. Similarly,
wget -r -l 1 -p http://I/1.html
will cause 1.html, 1.gif, 2.html, and 2.gif to be downloaded. One might think that:
wget -r -l 0 -p http://I/1.html
would download just 1.html and 1.gif, but unfortunately this is not the case, because -l 0 is equivalent to -l inf---that is, infinite recursion. To download a single HTML page (or a handful of them, all specified on the commandline or in a -i URL input file) and its (or their) requisites, simply leave off -r and -l:
wget -p http://I/1.html
Note that Wget will behave as if -r had been specified, but only that single page and its requisites will be downloaded. Links from that page to external documents will not be followed. Actually, to download a single page and all its requisites (even if they exist on separate websites), and make sure the lot displays properly locally, this author likes to use a few options in addition to -p:
wget -E -H -k -K -p http://I/I
To finish off this topic, it's worth knowing that Wget's idea of an external document link is any URL specified in an "" tag, an "" tag, or a "" tag other than "".

Recursive Accept/Reject Options
-A acclist --accept acclist
-R rejlist --reject rejlist
Specify comma-separated lists of file name suffixes or patterns to accept or reject.
-D domain-list
--domains=domain-list
Set domains to be followed. domain-list is a comma-separated list of domains. Note that it does not turn on -H.
--exclude-domains domain-list
Specify the domains that are not to be followed..
--follow-ftp
Follow FTP links from HTML documents. Without this option, Wget will ignore all the FTP links.
--follow-tags=list
Wget has an internal table of HTML tag / attribute pairs that it considers when looking for linked documents during a recursive retrieval. If a user wants only a subset of those tags to be considered, however, he or she should be specify such tags in a comma-separated list with this option.
-G list
--ignore-tags=list
This is the opposite of the --follow-tags option. To skip certain HTML tags when recursively looking for documents to download, specify them in a comma-separated list.
In the past, the -G option was the best bet for downloading a single page and its requisites, using a commandline like:
wget -Ga,area -H -k -K -r http://I/I
However, the author of this option came across a page with tags like "" and came to the realization that -G was not enough. One can't just tell Wget to ignore "", because then stylesheets will not be downloaded. Now the best bet for downloading a single page and its requisites is the dedicated --page-requisites option.

-H
--span-hosts
Enable spanning across hosts when doing recursive retrieving.
-L
--relative
Follow relative links only. Useful for retrieving a specific home page without any distractions, not even those from the same hosts.
-I list
--include-directories=list
Specify a comma-separated list of directories you wish to follow when downloading Elements of list may contain wildcards.
-X list
--exclude-directories=list
Specify a comma-separated list of directories you wish to exclude from download Elements of list may contain wildcards.
-np
--no-parent
Do not ever ascend to the parent directory when retrieving recursively. This is a useful option, since it guarantees that only the files below a certain hierarchy will be downloaded.
EXAMPLES
The examples are divided into three sections loosely based on their complexity.
Simple Usage
*
Say you want to download a URL. Just type:

wget http://fly.srk.fer.hr/
*
But what will happen if the connection is slow, and the file is lengthy? The connection will probably fail before the whole file is retrieved, more than once. In this case, Wget will try getting the file until it either gets the whole of it, or exceeds the default number of retries (this being 20). It is easy to change the number of tries to 45, to insure that the whole file will arrive safely:

wget --tries=45 http://fly.srk.fer.hr/jpg/flyweb.jpg
*
Now let's leave Wget to work in the background, and write its progress to log file log. It is tiring to type --tries, so we shall use -t.

wget -t 45 -o log http://fly.srk.fer.hr/jpg/flyweb.jpg &
The ampersand at the end of the line makes sure that Wget works in the background. To unlimit the number of retries, use -t inf.

*
The usage of FTP is as simple. Wget will take care of login and password.

wget ftp://gnjilux.srk.fer.hr/welcome.msg
*
If you specify a directory, Wget will retrieve the directory listing, parse it and convert it to HTML. Try:

wget ftp://prep.ai.mit.edu/pub/gnu/
links index.html
Advanced Usage
*
You have a file that contains the URLs you want to download? Use the -i switch:

wget -i I
If you specify - as file name, the URLs will be read from standard input.

*
Create a five levels deep mirror image of the GNU web site, with the same directory structure the original has, with only one try per document, saving the log of the activities to gnulog:

wget -r http://www.gnu.org/ -o gnulog
*
The same as the above, but convert the links in the HTML files to point to local files, so you can view the documents off-line:

wget --convert-links -r http://www.gnu.org/ -o gnulog
*
Retrieve only one HTML page, but make sure that all the elements needed for the page to be displayed, such as inline images and external style sheets, are also downloaded. Also make sure the downloaded page references the downloaded links.

wget -p --convert-links http://www.server.com/dir/page.html
The HTML page will be saved to www.server.com/dir/page.html, and the images, stylesheets, etc., somewhere under www.server.com/, depending on where they were on the remote server.

*
The same as the above, but without the www.server.com/ directory. In fact, I don't want to have all those random server directories anyway---just save all those files under a download/ subdirectory of the current directory.

wget -p --convert-links -nH -nd -Pdownload \
http://www.server.com/dir/page.html
*
Retrieve the index.html of www.lycos.com, showing the original server headers:

wget -S http://www.lycos.com/
*
Save the server headers with the file, perhaps for post-processing.

wget -s http://www.lycos.com/
more index.html
*
Retrieve the first two levels of wuarchive.wustl.edu, saving them to /tmp.

wget -r -l2 -P/tmp ftp://wuarchive.wustl.edu/
*
You want to download all the GIFs from a directory on an HTTP server. You tried wget http://www.server.com/dir/*.gif, but that didn't work because HTTP retrieval does not support globbing. In that case, use:

wget -r -l1 --no-parent -A.gif http://www.server.com/dir/
More verbose, but the effect is the same. -r -l1 means to retrieve recursively, with maximum depth of 1. --no-parent means that references to the parent directory are ignored, and -A.gif means to download only the GIF files. -A ``*.gif'' would have worked too.

*
Suppose you were in the middle of downloading, when Wget was interrupted. Now you do not want to clobber the files already present. It would be:

wget -nc -r http://www.gnu.org/
*
If you want to encode your own username and password to HTTP or FTP, use the appropriate URL syntax.

wget ftp://hniksic:mypassword@unix.server.com/.emacs
Note, however, that this usage is not advisable on multi-user systems because it reveals your password to anyone who looks at the output of "ps".

*
You would like the output documents to go to standard output instead of to files?

wget -O - http://jagor.srce.hr/ http://www.srce.hr/
You can also combine the two options and make pipelines to retrieve the documents from remote hotlists:
wget -O - http://cool.list.com/ | wget --force-html -i -
Very Advanced Usage
*
If you wish Wget to keep a mirror of a page (or FTP subdirectories), use --mirror (-m), which is the shorthand for -r -l inf -N. You can put Wget in the crontab file asking it to recheck a site each Sunday:

crontab
0 0 * * 0 wget --mirror http://www.gnu.org/ -o /home/me/weeklog
*
In addition to the above, you want the links to be converted for local viewing. But, after having read this manual, you know that link conversion doesn't play well with timestamping, so you also want Wget to back up the original HTML files before the conversion. Wget invocation would look like this:

wget --mirror --convert-links --backup-converted \
http://www.gnu.org/ -o /home/me/weeklog
*
But you've also noticed that local viewing doesn't work all that well when HTML files are saved under extensions other than .html, perhaps because they were served as index.cgi. So you'd like Wget to rename all the files served with content-type text/html to name.html.

wget --mirror --convert-links --backup-converted \
--html-extension -o /home/me/weeklog \
http://www.gnu.org/
Or, with less typing:
wget -m -k -K -E http://www.gnu.org/ -o /home/me/weeklog
SEE ALSO
GNU Info entry for wget.

php4支持xslt

首先需要下载如下软件包:

sourceforge.net/projects/expat/

从这里下载最新的 expat

我下载的是:expat-2.0.0.tar.gz

www.gingerall.com/charlie/ga/xml/d_sab.xml

从这里下载sablot

我下载的是:Sablot-1.0.2.tar.gz

xmlsoft.org/

从这里下载 libxslt

我下载的是:libxslt-1.1.9.tar.gz

三个包分别解压缩

先来libxslt

./configure –prefix=/usr/local/libxslt –with-libxml-prefix=/usr/local/libxml2 && make && make install

再来expat

./configure && make && make install

继续sablot

./configure && make && make install

最后重新编译php

./configure –prefix=/usr/local/php/ –enable-force-cgi-redirect –enable-mbstring=all –enable-mbregex –enable-mbstr-enc-trans –enable-versioning –enable-trans-sid –enable-ftp –with-mysql=/usr/local/mysql/ –with-apxs2=/usr/local/apache2/bin/apxs –with-openssl=/usr/local/openssl –with-soap=yes –with-curl=/usr/local/curl/ –with-zlib-dir=/usr/local/zlib/ –with-mcrypt=/usr/local/libmcrypt/ –with-gd=/usr/local/gd2 –with-jpeg-dir=/usr –with-freetype-dir=/usr/local/freetype –with-ttf –with-png-dir=/usr –with-mhash=/usr/local/mhash/ –with-dom=/usr/local/libxml2 –with-iconv=/usr/local/libiconv –enable-xslt –with-xslt-sablot –with-xsl=/usr/local/libxslt

make && make insteall

重新安装zend吧。

over this~~~

SSH登录linux妙用后台命令

用SSH管理linux服务器,有时可能要下载点大的软件或者文件包.又或者要打包一个上5G的文件夹,那是多么漫长的等待….

更麻烦的是,下载的时候如果SSH 客户端N久没动作会断掉连接,于是下载到一半的东西也会跟着死掉.

当然,你说我可以打开多个SSH客户窗口来操作….,那我不得不说,这是个笨办法.

比如我想打包一个文件夹,可以用如下的命令

#tar zcvf file.tar.gz /path/document/*

不想等,就把他放到后台去(后面加个&)

#tar zcvf file.tar.gz /path/document/* &

如果你要回来.就使用fg 命令

我们想当然的,下载也是这样

#wget http://www.phpv.net/file.tar.gz &

但如果你超时或者有事离开而退出SSH 那正在下载的file.tar.gz 文件也会随之停下了…

怎么办?让我们用nohup 来完成/

NAME
nohup – run a command immune to hangups, with output to a non-tty

SYNOPSIS
nohup COMMAND [ARG]…
nohup OPTION

DESCRIPTION
Run COMMAND, ignoring hangup signals.

–help display this help and exit

–version
output version information and exit

REPORTING BUGS
Report bugs to <bug-coreutils@gnu.org>.

SEE ALSO
The full documentation for nohup is maintained as a Texinfo manual. If
the info and nohup programs are properly installed at your site, the
command

info nohup

should give you access to the complete manual.
以上是man nohup出来的.

用法很简单,就在命令前加 nohup

#nohup wget http://www.phpv.net/file.tar.gz

nohup: appending output to `nohup.out’
没反映……………………………死机了???

CTRL+Z 回到命令行模式…

要避免上面的方法,就加个 & 在命令后面

#nohup wget http://www.phpv.net/file.tar.gz &

#

好了.现在随便你怎样exit,睡一觉回来看,什么工作都完成了.

使用rsync来实现文件同步

使用rsync来实现文件同步
部分参考 www.xfocus.net/articles/200107/214.html
先对这个dd进行简介,当你的网站访问量大了,一台服务器承受不住了
那好,这个时候,rsync来了。
rsync ->>> remote synchronize
呵呵,不用解释了吧
第一步,先来下载这个免费的软件。
rsync.samba.org/ 或者 samba.anu.edu.au/rsync
解压缩后,编译很简单

./configure –prefix=/usr/local/rsync && make && make install
然后先来配置服务端吧
先来编辑服务端配置文件
#vi /etc/rsyncd.conf
uid = root
gid = root
hosts allow = testhost1
hosts deny = 192.168.0.*/24
use chroot = no	 # 不使用chroot
max connections = 10	 # 最大连接数为4
pid file = /var/run/rsyncd.pid
lock file = /var/run/rsync.lock
log file = /var/log/rsyncd.log	# 日志记录文件
[sync_files]	 # 这里是认证的模块名,在client端需要指定
path = /root/sync_files	# 需要做镜像的目录
comment = rsync 192.168.0.*
ignore errors	 # 可以忽略一些无关的IO错误
read only = yes	 # 只读
list = no	 # 不允许列文件
auth users = rsyncuser	 # 认证的用户名,如果没有这行,则表明是匿名,多个用户用,分隔
secrets file = /etc/rsyncd.pas	# 认证文件名
pid file = /var/run/rsyncd.pid
#motd file = /etc/rsyncd.motd
#log file = /var/log/rsyncd.log
#lock file = /var/run/rsync.lock

然后编辑你上面指定的认证文件,我这里是: /etc/rsyncd.pas

#vi /etc/rsyncd.pas
格式为: username:password
rsyncuser:123456
安全起见,更改认证文件属性
#chmod 0600 /etc/rsyncd.pas
ok,现在启动下试试看吧。
#/usr/local/rsync/bin/rsync -daemon
你也可以指定rsync运行的端口
#/usr/local/rsync/bin/rsync -daemon -port=873

如果要在启动时把服务起来,有几种不同的方法,比如:

加入inetd.conf
编辑/etc/services,加入rsync 873/tcp,指定rsync的服务端口是873
编加/etc/inetd.conf,加入rsync stream tcp nowait root /bin/rsync rsync –daemon

加入rc.local
在各种操作系统中,rc文件存放位置不尽相同,可以修改使系统启动时rsync –daemon加载进去。
我这里是直接加入 /etc/rc.local

/usr/local/rsync/bin/rsync -daemon -port=873

记得配置防火墙,允许你rsync端口的tcp和udp协议。
下面开始配置客户端
下面这个命令行中-vzrtopg里的v是verbose,z是压缩,r是recursive,topg都是保持文件原有属性如属主、时间的参数。–progress是指显示出详细的进度情况,–delete是指如果服务器端删除了这一文件,那么客户端也相应把文件删除,保持真正的一致。后面的inburst@ip中,
inburst是指定密码文件中的用户名,之后的::inburst这一inburst是模块名,也就是在/etc/rsyncd.conf中自定义的名称。最后的/tmp是备份
到本地的目录名。
在这里面,还可以用-e ssh的参数建立起加密的连接。可以用–password-file=/password/path/file来指定密码文件,这样就可以在脚本中使
用而无需交互式地输入验证密码了,这里需要注意的是这份密码文件权限属性要设得只有属主可读。

#/usr/local/rsync/bin/rsync -vzrtopg -progress -delete inburst@192.168.0.52::inburst /tmp/

Password:
或者你也可以制定password文件
由于需要系统crontab执行,所以这里采用读入密码文件的方式,

#vi /etc/rsyncd.pas
加入
rsyncuser:123456
更改文件权限:
#chmod 0600 /etc/rsyncd.pas
#/usr/local/rsync/bin/rsync -vzrtopg –progress –delete –password-file=/etc/rsyncd.pas rsyncuser@192.168.0.6::/root/sync_files /tmp/
不知道为什么,总是给我报这样的错误:
@ERROR: auth failed on module sync_files
rsync error: error starting client-server protocol (code 5) at main.c(1171)
不管是加载密码文件还是输入密码,全部都报这个错误,为了节省时间,去掉了如下两行
auth users = rsyncuser	 # 认证的用户名,如果没有这行,则表明是匿名,多个用户用,分隔
secrets file = /etc/rsyncd.pas	# 认证文件名

改为用ip进行限制操作。

#/usr/local/rsync/bin/rsync -vzrtopg –progress –delete –password-file=/etc/rsyncd.pas rsyncuser@192.168.0.6::/root/sync_files /tmp

这个时候就成功了。
以后有时间再研究认证问题吧,时间紧,任务急,把验证先绕过。

基于Linux的搜索引擎实现

搜索引擎是为用户提供快速获取网页信息的工具,其主要的功能是系统通过用户输入关键字,检索后端网页数据库,将相关网页的链接和摘要信息反馈给用户。从搜索的范围上一般分为站内网页搜索和全局网页搜索。随着网页数量的急剧增加,搜索引擎已经成为上网查询信息的必须手段,各个大型网站均已经提供网页数据搜索服务,并且出现了许多为大型网站提供专业搜索引擎服务的公司,如为Yahoo提供搜索服务的Google,为新浪网和263等国内网站提供服务的百度公司等。专业的搜索服务费用高而免费的搜索引擎软件基本都是基于英文的检索,所以都不太适合Intranet环境(如校园网等)的需要。
搜索引擎的基本组成一般分为网页收集程序、网页后端数据组织存储、网页数据检索三部分。决定搜索引擎好坏的关键因素是数据查询的响应时间,即如何组织好满足全文检索需要的大量网页数据。
GNU/Linux作为一个优秀的网络操作系统,其发行版本中集成了大量的网络应用软件,如 Web服务器(Apache + PHP)、目录服务器(OpenLDAP)、脚本语言(Perl)、网页收集程序(Wget)等。所以,通过将它们集中进行应用,便可以实现一个简单、高效的搜索引擎服务器。
一、基本组成和使用方法
1、网页数据收集
Wget程序是一个优秀的网页收集程序,它采用多线程设计能够方便地将网站内容镜像到本地目录中,并且能够灵活定制收集网页的类型、递归收集层次、目录限额、收集时间等。通过专用的收集程序完成网页的收集工作,既降低了设计的难度又提高了系统的性能。为了减小本地数据的规模,可只收集能够查询的html文件、txt文件、脚本程序asp和php只使用缺省的结果,而不收集如图形文件或是其他的数据文件。
2、网页数据过滤
由于html文件中存在大量的标记,如

等,这些标记数据没有实际的搜索价值,所以加入数据库前必须对收集的数据进行过滤。Perl作为广泛使用的脚本语言,拥有非常强大而丰富的程序库,可以方便地完成网页的过滤。通过使用HTML-Parser库可以方便地提取出网页中包含的文字数据、标题数据、链接数据等。该程序库可以在www.cpan.net中下载,并且该网站收集的Perl程序涉及范围之广,远远超出我们的现象。
3、目录服务
目录服务是针对大量数据检索需要开发的服务,最早出现在X.500协议集中,后来扩展到TCP/IP中发展成为LDAP(Lightweight Directory Acess Protocol)协议,其相关的标准为1995年制定的RFC1777和1997年制定的RFC2251等。LDAP协议已经作为工业标准被Sun、Lotus、微软等公司广泛应用到其相关产品中,但是专用的基于Windows平台的目录服务器却较少见,OpenLDAP是免费的运行于Unix系统的目录服务器,其产品的性能优秀,已经被许多的Linux发行版本收集(Redhat、Mandrake等),并且提供了包括C、Perl、PHP等的开发接口。
使用目录服务技术代替普通的关系数据库作为网页数据的后端存取平台主要基于目录服务的技术优势。目录服务简化了数据处理类型,去掉了通用关系数据库的费时的事务机制,而是采用全局替换的策略对数据进行更新,其应用的重点是大量数据的检索服务(一般数据更新和检索的频率比例要求在1:10以上),强调检索速度和全文查询,提供完整的数据备份,非常适合搜索引擎之类服务的需要。从目录服务技术解决问题的重点不难看出其在数据检索上的优势,它的提出时间远远落后于关系数据库的提出时间,实际上反映了根据具体问题优化数据解决方案的原则。这与目前广泛存在的凡是涉及大量数据处理必选SQL Server的处理方法形成鲜明对比。
通过选用成熟的目录服务技术提高网页查询的效率,能够简洁有效地提高数据处理能力。这也充分显示了GNU/Linux系统运行开放软件的优势,毕竟不能方便地获得运行于其他平台的目录服务器。
4、查询程序设计
搜索引擎的前端界面是网页,用户通过在特定的网页中输入关键字提交给Web服务器进行处理。运行在Apache Web服务器上的PHP脚本通过运行其相关ldap函数便可以执行关键字的查询工作。主要进行的工作是根据关键字构造查询、向目录服务器提交查询、显示查询结果等。Linux + Apache + PHP作为广泛使用Web服务器,与WinNT + IIS + ASP相比其性能毫不逊色,在目前的Linux发行版本中都集成了Apache + PHP 以及缺省的ldap、pgsql、imap等模块。
5、计划任务
搜索引擎的网页数据收集、数据过滤、加入目录数据库等工作都应该是自动完成的,在UNIX系统中有cron进程来专门完成按照特定时间调度任务,为了不影响系统的运行,一般可以把这些工作安排到深夜进行。
二、具体步骤和注意事项
1、配置Wget软件
在RedHat 6.2发行版中已经集成了该软件包,可以直接进行安装。将需要镜像的站点地址编辑为一个文件中,通过 -I 参数读入该文件;为镜像的站点指定一个本地下载目录;为了避免内部网中链接的重复引用,一般只镜像该站点内的数据;还可以根据网站的具体情况,指定其镜像的深度。
2、配置Openldap服务
在RedHat 6.2发行版中已经集成了Openldap-1.2.9,其配置文件存放在/etc/openldap的目录中。主要的配置文件是slapd.conf,关键要打开对检索速度至关重要的index选项,可以使用setup工具,将ldap在系统引导后作为缺省服务启动。
Ldap服务可以通过文本文件方式存放数据,即LDIF文件格式。使用此方式可以高效地更新目录服务数据,需要注意LDIF格式是通过空行对数据进行分隔的,并且通过运行ldif2lbm将LDIF格式数据导入目录数据库中时需要暂停目录服务。
3、编制数据过滤和LDIF文件生成脚本
为了方便地过滤网页数据,可以调用Perl的HTML-Parser库函数,该程序包下载后需要进行编译,在eg目录下生成了相关的htext,htitle程序,在Perl中可以通过调用外部程序的方式运行该程序,并对其过滤结果通过重定向的方法生成临时文件。本搜索引擎设计的目录数据属性有dn、link、title、modifydate、contents,其中的dn通过Link进行唯一性标识,将过滤后的网页文本内容通过/usr/sbin/ldif程序进行自动编码后放入LDIF文件中。
基本的LDIF文件格式如下:
dn: dc=27jd,dc=zzb
objectclass: top
objectclass: organization

dn: link= http://freemail.27jd.zzh/index.html, dc=27jd ,dc=zzb
link: http://freemail.27jd.zzh/index.html
title: Webmail主页
modifydate: 2001年2月8日
contents::
CgpXZWJtYWls1vfSswoKCgoKIKHvoaG7ttOtyrnTw1dlYm1haWzPtc2zoaGh7yDO0t
KqyerH69PKz+QhISFPdXRsb29rxeTWw6O6U01UUDogZnJlZW1haWwuMjdqZC56emJQ
T1AzOiBmcm
VlbWFpbC4yN2pkLnp6YkROUyA6IDExLjk5LjY0Ljiy4srU08O7p6O6bWFpbGd1ZXN00
8O7p7/awe
6jum1haWxndWVzdNLR16Ky4dPDu6cg08O7p8P7OkAgZnJlZW1haWwuMjdqZC56emK/
2sHuOqChoa
AgIKHyzOG5qbf+zvEgofKzo7z7zsrM4iCh8s2o0bbCvKHyICCh8sq1z9bUrcDtIKHywfTR1
LK+of
IgofK8vMr1sr/W99Kzsb7Ptc2z08nK1NHpvLzK9bK/zfjC59bQ0MS9qMGius3OrLukCgoK
CqAKCg
o=
objectclass:webpage

基本的slapd.conf文件如下:
defaultaccess read
include /etc/openldap/slapd.at.conf
#include /etc/openldap/slapd.oc.conf
schemacheck off
sizelimit 20000
pidfile /var/run/slapd.pid
argsfile /var/run/slapd.args
#######################################################################
# ldbm database definitions
#######################################################################
database ldbm
dbcachesize 1000000
index contents,title
suffix “dc=27jd, dc=zzb”
directory /usr/tmp
rootdn “cn=root,dc=27jd, dc=zzb”
rootpw secret

通过对一个4万个网页(约300M左右)的本地html文件目录进行过滤后生成的LDIF文件约180M左右,如果只取文字数据的前400个字符作为网页内容,则生成文件约35M左右。
4、配置PHP+LDAP服务
在Redhat6.2中已经集成了PHP3和php-ldap模块,选择完全安装时便已经安装到/usr/lib/apache目录中,注意检查/etc/httpd/php3.ini中的动态扩展(Dynamic Extensions)中的extension=ldap.so是否被选择。PHP3中提供了丰富的LDAP存取函数,能够方便完成对目录数据的搜索功能。有关Apach + PHP编程方面的资料较多,在此不在赘述。注意在PHP3中的LDAP搜索函数ldap_search不能处理其返回结果超过目录服务设定的最大检索数据,所以可以根据具体情况,在slapd的配置文件中设定较大的检索数据限制(sizelimit),此问题在PHP4中已经解决。
5、任务调度
在Redhat6.2中已经集成了crond并且缺省安装后便已经启动。其相关配置文件有/etc/crontab、/etc/cron.daily、/etc/cron.hourly、/etc/weekly、/etc/monthly,你只需要根据数据的更新频度,将网页收集、网页过滤、生成LDIF文件、停止目录服务、更新目录数据、重新启动目录服务,作为一个简单的Shell程序放入到相应的目录中即可。
三、效果与思考
以上简单的介绍了我们的搜索引擎的实现方法和注意事项,这仅仅是我们在对GNU/Linux了解得非常肤浅的情况下设计的以目录服务为核心的满足内部网需要的搜索引擎系统,并不能代表GNU/Linux和它集成的大量软件的真正实力。
通过在一台安装RedHat Linux 6.2 的Sparc Ultra 250上实际测试,对拥有4万个网页的目录数据进行搜索时,基于上述方法设计的搜索引擎响应速度一般在3秒左右,目录数据完全更新大约需要4小时左右,能够满足内部网的需要。实际上,限制搜索响应速度的关键是PHP3的ldap_search函数没有提供数据限制的功能,导致在查询结果集过大时系统响应速度变慢,因为每次用户能够浏览的查询结果实际是非常少的,而服务器端每次的查询总是返回全部结果,在PHP4中的ldap_search通过指定sizelimit参数,能够有效解决该问题。
目录服务的应用范围非常广泛,实际上作为大型的信息站点为了提高客户访问效率,都或多或少采用了目录服务的技术。目录服务根据具体的应用需求的优化设计方法,对我们决定应用系统的开发无疑是一个启发,应该说在基于索引信息的领域LDAP服务远远优于传统的关系数据库系统。
基于GNU/Linux进行网络服务器程序设计,能够充分体会到开放源代码的魅力和实力,它既能够简化系统的设计,又大大地提高了工作效率,同时也有效降低了系统的成本。程序设计由一切从零开始的复杂繁琐的重复劳动,简化为问题抽象、功能分解、查找资源、组合系统四个部分,更加强调对系统的认识、开阔的视野和学习的能力,同时开放源代码也为系统进一步优化提供了坚实的基础