cp's profile我的资料库PhotosBlogLists Tools Help

Blog


    November 26

    .htaccess 学习笔记

    .htaccess可以做大量范围的事情,包括:文件夹密码保护、用户自动重新指向、自定义错误页面、变更你的文件扩展名、屏蔽特定的用户IP地址、只允许特定的IP地址、停止目录表以及使用其他文件作为index文件,等等......

    1. Introduction 介绍
    文件名 .htaccess 属性 644 (RW-R–R–)
    htaccess会影响它所在目录下的所有子目录
    注意大多数内容都要求保持在一行之内,不要换行,否则会引起错误

    2. Error Documents 错误文档
    Official document: ErrorDocument Directive
    ErrorDocument code document
    例子
    ErrorDocument 400 /errors/badrequest.html
    ErrorDocument 404 http://yoursite/errors/notfound.html
    ErrorDocument 401 “Authorization Required”
    (注意之后内容如果出现的双引号需要转义为 \”)
    常见HTTP状态码
    Successful Client Requests
    200 OK
    201 Created
    202 Accepted
    203 Non-Authorative Information
    204 No Content
    205 Reset Content
    206 Partial Content
    Client Request Redirected
    300 Multiple Choices
    301 Moved Permanently
    302 Moved Temporarily
    303 See Other
    304 Not Modified
    305 Use Proxy
    Client Request Errors
    400 Bad Request
    401 Authorization Required
    402 Payment Required (not used yet)
    403 Forbidden
    404 Not Found
    405 Method Not Allowed
    406 Not Acceptable (encoding)
    407 Proxy Authentication Required
    408 Request Timed Out
    409 Conflicting Request
    410 Gone
    411 Content Length Required
    412 Precondition Failed
    413 Request Entity Too Long
    414 Request URI Too Long
    415 Unsupported Media Type
    Server Errors
    500 Internal Server Error
    501 Not Implemented
    502 Bad Gateway
    503 Service Unavailable
    504 Gateway Timeout
    505 HTTP Version Not Supported

    3. Password Protection 密码保护
    Official document: Authentication, Authorization and Access Control
    假设密码文件为.htpasswd
    AuthUserFile /usr/local/safedir/.htpasswd (这里必须使用全路径名)
    AuthName EnterPassword
    AuthType Basic
    两种常见验证方式:
    Require user windix
    (仅允许用户windix登陆)
    Require valid-user
    (所有合法用户都可登陆)
    Tip: 如何生成密码文件
    使用htpasswd命令(apache自带)
    第一次生成需要创建密码文件
    htpasswd -c .htpasswd user1
    之后增加新用户
    htpasswd .htpasswd user2

    4. Enabling SSI Via htaccess 通过htaccess允许SSI(Server Side Including)功能
    AddType text/html .shtml
    AddHandler server-parsed .shtml
    Options Indexes FollowSymLinks Includes
    DirectoryIndex index.shtml index.html

    5. Blocking users by IP 根据IP阻止用户访问
    order allow,deny
    deny from 123.45.6.7
    deny from 12.34.5. (整个C类地址)
    allow from all

    6. Blocking users/sites by referrer 根据referrer阻止用户/站点访问
    需要mod_rewrite模块
    例1. 阻止单一referrer: badsite.com
    RewriteEngine on
    # Options +FollowSymlinks
    RewriteCond %{HTTP_REFERER} badsite\.com [NC]
    RewriteRule .* - [F]
    例2. 阻止多个referrer: badsite1.com, badsite2.com
    RewriteEngine on
    # Options +FollowSymlinks
    RewriteCond %{HTTP_REFERER} badsite1\.com [NC,OR]
    RewriteCond %{HTTP_REFERER} badsite2\.com
    RewriteRule .* - [F]
    [NC] - 大小写不敏感(Case-insensite)
    [F] - 403 Forbidden
    注意以上代码注释掉了”Options +FollowSymlinks”这个语句。如果服务器未在 httpd.conf 的 段落设置 FollowSymLinks, 则需要加上这句,否则会得到”500 Internal Server error”错误。

    7. Blocking bad bots and site rippers (aka offline browsers) 阻止坏爬虫和离线浏览器
    需要mod_rewrite模块
    坏爬虫? 比如一些抓垃圾email地址的爬虫和不遵守robots.txt的爬虫(如baidu?)
    可以根据 HTTP_USER_AGENT 来判断它们
    (但是还有更无耻的如”中搜 zhongsou.com”之流把自己的agent设置为 “Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)” 太流氓了,就无能为力了)
    RewriteEngine On
    RewriteCond %{HTTP_USER_AGENT} ^BlackWidow [OR]
    RewriteCond %{HTTP_USER_AGENT} ^Bot\ mailto:craftbot@yahoo.com [OR]
    RewriteCond %{HTTP_USER_AGENT} ^ChinaClaw [OR]
    RewriteCond %{HTTP_USER_AGENT} ^Custo [OR]
    RewriteCond %{HTTP_USER_AGENT} ^DISCo [OR]
    RewriteCond %{HTTP_USER_AGENT} ^Download\ Demon [OR]
    RewriteCond %{HTTP_USER_AGENT} ^eCatch [OR]
    RewriteCond %{HTTP_USER_AGENT} ^EirGrabber [OR]
    RewriteCond %{HTTP_USER_AGENT} ^EmailSiphon [OR]
    RewriteCond %{HTTP_USER_AGENT} ^EmailWolf [OR]
    RewriteCond %{HTTP_USER_AGENT} ^Express\ WebPictures [OR]
    RewriteCond %{HTTP_USER_AGENT} ^ExtractorPro [OR]
    RewriteCond %{HTTP_USER_AGENT} ^EyeNetIE [OR]
    RewriteCond %{HTTP_USER_AGENT} ^FlashGet [OR]
    RewriteCond %{HTTP_USER_AGENT} ^GetRight [OR]
    RewriteCond %{HTTP_USER_AGENT} ^GetWeb! [OR]
    RewriteCond %{HTTP_USER_AGENT} ^Go!Zilla [OR]
    RewriteCond %{HTTP_USER_AGENT} ^Go-Ahead-Got-It [OR]
    RewriteCond %{HTTP_USER_AGENT} ^GrabNet [OR]
    RewriteCond %{HTTP_USER_AGENT} ^Grafula [OR]
    RewriteCond %{HTTP_USER_AGENT} ^HMView [OR]
    RewriteCond %{HTTP_USER_AGENT} HTTrack [NC,OR]
    RewriteCond %{HTTP_USER_AGENT} ^Image\ Stripper [OR]
    RewriteCond %{HTTP_USER_AGENT} ^Image\ Sucker [OR]
    RewriteCond %{HTTP_USER_AGENT} Indy\ Library [NC,OR]
    RewriteCond %{HTTP_USER_AGENT} ^InterGET [OR]
    RewriteCond %{HTTP_USER_AGENT} ^Internet\ Ninja [OR]
    RewriteCond %{HTTP_USER_AGENT} ^JetCar [OR]
    RewriteCond %{HTTP_USER_AGENT} ^JOC\ Web\ Spider [OR]
    RewriteCond %{HTTP_USER_AGENT} ^larbin [OR]
    RewriteCond %{HTTP_USER_AGENT} ^LeechFTP [OR]
    RewriteCond %{HTTP_USER_AGENT} ^Mass\ Downloader [OR]
    RewriteCond %{HTTP_USER_AGENT} ^MIDown\ tool [OR]
    RewriteCond %{HTTP_USER_AGENT} ^Mister\ PiX [OR]
    RewriteCond %{HTTP_USER_AGENT} ^Navroad [OR]
    RewriteCond %{HTTP_USER_AGENT} ^NearSite [OR]
    RewriteCond %{HTTP_USER_AGENT} ^NetAnts [OR]
    RewriteCond %{HTTP_USER_AGENT} ^NetSpider [OR]
    RewriteCond %{HTTP_USER_AGENT} ^Net\ Vampire [OR]
    RewriteCond %{HTTP_USER_AGENT} ^NetZIP [OR]
    RewriteCond %{HTTP_USER_AGENT} ^Octopus [OR]
    RewriteCond %{HTTP_USER_AGENT} ^Offline\ Explorer [OR]
    RewriteCond %{HTTP_USER_AGENT} ^Offline\ Navigator [OR]
    RewriteCond %{HTTP_USER_AGENT} ^PageGrabber [OR]
    RewriteCond %{HTTP_USER_AGENT} ^Papa\ Foto [OR]
    RewriteCond %{HTTP_USER_AGENT} ^pavuk [OR]
    RewriteCond %{HTTP_USER_AGENT} ^pcBrowser [OR]
    RewriteCond %{HTTP_USER_AGENT} ^RealDownload [OR]
    RewriteCond %{HTTP_USER_AGENT} ^ReGet [OR]
    RewriteCond %{HTTP_USER_AGENT} ^SiteSnagger [OR]
    RewriteCond %{HTTP_USER_AGENT} ^SmartDownload [OR]
    RewriteCond %{HTTP_USER_AGENT} ^SuperBot [OR]
    RewriteCond %{HTTP_USER_AGENT} ^SuperHTTP [OR]
    RewriteCond %{HTTP_USER_AGENT} ^Surfbot [OR]
    RewriteCond %{HTTP_USER_AGENT} ^tAkeOut [OR]
    RewriteCond %{HTTP_USER_AGENT} ^Teleport\ Pro [OR]
    RewriteCond %{HTTP_USER_AGENT} ^VoidEYE [OR]
    RewriteCond %{HTTP_USER_AGENT} ^Web\ Image\ Collector [OR]
    RewriteCond %{HTTP_USER_AGENT} ^Web\ Sucker [OR]
    RewriteCond %{HTTP_USER_AGENT} ^WebAuto [OR]
    RewriteCond %{HTTP_USER_AGENT} ^WebCopier [OR]
    RewriteCond %{HTTP_USER_AGENT} ^WebFetch [OR]
    RewriteCond %{HTTP_USER_AGENT} ^WebGo\ IS [OR]
    RewriteCond %{HTTP_USER_AGENT} ^WebLeacher [OR]
    RewriteCond %{HTTP_USER_AGENT} ^WebReaper [OR]
    RewriteCond %{HTTP_USER_AGENT} ^WebSauger [OR]
    RewriteCond %{HTTP_USER_AGENT} ^Website\ eXtractor [OR]
    RewriteCond %{HTTP_USER_AGENT} ^Website\ Quester [OR]
    RewriteCond %{HTTP_USER_AGENT} ^WebStripper [OR]
    RewriteCond %{HTTP_USER_AGENT} ^WebWhacker [OR]
    RewriteCond %{HTTP_USER_AGENT} ^WebZIP [OR]
    RewriteCond %{HTTP_USER_AGENT} ^Wget [OR]
    RewriteCond %{HTTP_USER_AGENT} ^Widow [OR]
    RewriteCond %{HTTP_USER_AGENT} ^WWWOFFLE [OR]
    RewriteCond %{HTTP_USER_AGENT} ^Xaldon\ WebSpider [OR]
    RewriteCond %{HTTP_USER_AGENT} ^Zeus
    RewriteRule ^.* - [F,L]
    [F] - 403 Forbidden
    [L] - ?

    8. Change your default directory page 改变缺省目录页面
    DirectoryIndex index.html index.php index.cgi index.pl

    9. Redirects 转向
    单个文件
    Redirect /old_dir/old_file.html http://yoursite.com/new_dir/new_file.html
    整个目录
    Redirect /old_dir http://yoursite.com/new_dir
    效果: 如同将目录移动位置一样
    http://yoursite.com/old_dir -> http://yoursite.com/new_dir
    http://yoursite.com/old_dir/dir1/test.html -> http://yoursite.com/new_dir/dir1/test.html
    Tip: 使用用户目录时Redirect不能转向的解决方法
    当你使用Apache默认的用户目录,如 http://mysite.com/~windix,当你想转向 http://mysite.com/~windix/jump时,你会发现下面这个Redirect不工作:
    Redirect /jump http://www.google.com
    正确的方法是改成
    Redirect /~windix/jump http://www.google.com
    (source: .htaccess Redirect in “Sites” not redirecting: why?
    )

    10. Prevent viewing of .htaccess file 防止.htaccess文件被查看
    order allow,deny
    deny from all

    11. Adding MIME Types 添加 MIME 类型
    AddType application/x-shockwave-flash swf
    Tips: 设置类型为 application/octet-stream 将提示下载

    12. Preventing hot linking of images and other file types 防盗链
    需要mod_rewrite模块
    RewriteEngine on
    RewriteCond %{HTTP_REFERER} !^$
    RewriteCond %{HTTP_REFERER} !^http://(www/\.)?mydomain.com/.*$ [NC]
    RewriteRule \.(gif|jpg|js|css)$ - [F]
    解析:
    若 HTTP_REFERER 非空 (来源为其他站点,非直接连接) 并且
    若 HTTP_REFERER 非(www.)mydomain.com开头(忽略大小写[NC]) (来源非本站)
    对于所有含有 .gif/.jpg/.js/.css 结尾的文件给出 403 Forbidden 错误[F]
    也可指定响应,如下例显示替换图片
    RewriteRule \.(gif|jpg)$
    [R,L]
    [R] - 转向(Redirect)
    [L] - 连接(Link)

    13. Preventing Directory Listing 防止目录列表时显示
    IndexIgnore *
    IndexIgnore *.jpg *.gif
    Tips:
    允许目录列表显示: Options +Indexes
    禁止目录列表显示: Options -Indexes
    显示提示信息: 页首 文件HEADER, 页尾 文件README

    常用的重定向方式有: 301 redirect, 302 redirect 与 meta fresh:

    301 redirect: 301代表永久性转移(Permanently Moved),301重定向是网页更改地址后对搜索引擎友好的最好方法,只要不是暂时搬移的情况,都建议使用301来做转址。

    302 redirect: 302代表暂时性转移(Temporarily Moved ),在前些年,不少Black Hat SEO曾广泛应用这项技术作弊,目前,各大主要搜索引擎均加强了打击力度,象Google前些年对Business.com以及近来对BMW德国网站的惩罚。即使网站客观上不是spam,也很容易被搜寻引擎容易误判为spam而遭到惩罚。

    meta fresh: 这在2000年前比较流行,不过现在已很少见。其具体是通过网页中的meta指令,在特定时间后重定向到新的网页,如果延迟的时间太短(约5秒之內),会被判断为spam。

    301 Redirect实现网页重定向

    IIS服务器实现301重定向

    * 打开internet信息服务管理器,在欲重定向的网页或目录上按右键
    * 选择“重定向到URL”
    * 在“重定向到”输入框中输入要跳转到的目标网页的URL地址
    * 选中“资源的永久重定向”(切记)
    * 最后点击“应用”


    Apache服务器实现301重定向

    相比较来说,Apache实现起来要比IIS简单多了。在Apache中,有个很重要的文件.htaccess,通过对它的设置,可以实现很多强大的功能,301重定向只是其中之一。

    Redirect permanent / http://www.bloghuman.com/ (将目录下内容重定向到http://www.bloghuman.com/)
    redirect permanent /index.php http://www.bloghuman.com/index.php?go=category_6(将网页index.php重定向到http://www.bloghuman.com/index.php?go=category_6)


    通过合理地配置重定向参数中的正则表达式,可以实现更复杂的匹配。有兴趣的朋友可参考本站Apache手册

    PHP下的301重定向

    <?
    Header( "HTTP/1.1 301 Moved Permanently" ) ;
    Header( "Location: http://www.bloghuman.com" );
    ?


    ASP下的301重定向

    <%@ Language=VBScript %>
    <%
    Response.Status="301 Moved Permanently"
    Response.AddHeader "Location","http://hiup.baidu.com/liberty88"
    %>


    ASP .NET下的301重定向

    <script runat="server">
    private void Page_Load(object sender, System.EventArgs e)
    {
    Response.Status = "301 Moved Permanently";
    Response.AddHeader ("Location","http://hiup.baidu.com/liberty88");
    }
    </script>



    ColdFusion下的301重定向

    <.cfheader statuscode="301" statustext="Moved permanently">
    <.cfheader name="Location" value="http://hiup.baidu.com/liberty88">


    旧域名重定向到新域名
    创建一个.htaccess文件,并将下面提供的代码写入文件内,它可以确保旧域名所有的目录或者网页正确的跳转到新域名内。

    记住.htaccess文件一定要放在旧网站的根目录下,并且新网站要和旧网站保持相同的目录结构及网页文件


    Options +FollowSymLinks
    RewriteEngine on
    RewriteRule (.*) http://www.domain.com/$1 [R=301,L]


    请将上面的www.domain.com修改成你想要跳转到的域名。
    此外,我建议大家归总旧网站的外部链接,并联系相应的站点修改导入链链的URL,以指向新站点。

    注意:.htaccess文件只有在使用安装有Mod Rewrite模块的Apache作为WEB服务器的Linux主机上才能起作用

    域名301重定向到www的二级域名

    在以前的文章中我反复提及过:www.domain.com是domain.com域下的一个二级域名,并对二级域名和一级目录之间如何选择以及网站结构优化做了一个详细的分析,有兴趣的可以读一下两篇文章,网站结构优化是SEO中最重要

    OK,继续域301跳转到www二级域的实现方式:

    创建一个.htaccess文件,并将下面提供的代码写入文件内,它可以确保所有来自对domain.com的请求都转向到对www.domain.com进行请求。记住.htaccess文件一定要放在旧网站的根目录下,并且新网站要和旧网站保持相同的目录结构及网页文件


    Options +FollowSymlinks
    RewriteEngine on
    rewritecond %{http_host} ^domain.com [nc]
    rewriterule ^(.*)$ http://www.domain.com/$1 [r=301,nc]


    请将上面的domain.com和www.domain.com修改成你想要跳转到的域名。

    注意:.htaccess文件只有在使用安装有Mod Rewrite模块的Apache作为WEB服务器的Linux主机上才能起作用

    301重定向检测工具

    配置完成后,一定认真检查一下是否正确。Internet有很多类似的Server Header检查工具,如Check Server Headers Tool - HTTP Status Codes Checker


    网站302重定向使用不当导致被GOOGLE惩罚

      Business.com是网上最大的商业搜索引擎和分类目录,以专业提供商业信息而享负盛名,包括近19万网页。若以“business”为关键词在Google中进行搜索,该网站名列第一。不过在9月5日,Business.com遇到一件蹊跷之事:它的首页由PR8变成了PR0, 而且Google搜索结果中找不到首页。好在被“蒸发”的只是首页,不过庆幸的是第二天首页又回到了Google的搜索结果,但PR仍旧为0。

      Business.com的问题出在它的重定向命令上。该网站让business.com跳转到www.business.com,这种重定向本该是永久性的。我们知道,301属于永久性重定向,而302则属于临时性重定向,只有当一个网站或网页在24到48小时之内临时移到其它位置的情况下才能使用该命令。但Business.com却错误地使用了“HTTP/1.1302 Object Moved”状态码。

      其实网站重定向极为普遍,譬如不满意原来的域名而申请了一个新域名;买下容易被人错拼的域名,防止客户因为拼错URL而找不到网站,等等。可是,很多人却会由于使用了错误的重定向状态码而遭“灭站之灾”,就象Business.com。尽管他们的重定向理由充分合理,然而若使用不当,则可能被Google误认为是利用多个域名指向同一网站,那么你的网站就会被封掉,罪名是“利用重复的内容来干扰Google搜索结果的网站排名”。Business.com就是最好的前车之鉴。只不过大多数使用错误重定向参数的网站没Business.com这么幸运,一个小小的重定向就可能使网站前功尽弃,只能从头来过:重新申请新域名,重新发布新网站,等等。记住:Google绝不会同情任何人即使无心犯下的错误。


    网站服务器响应网页浏览请求的运作流程

      让我们先来了解一下用户/搜索引擎和网站一开始的交互流程。当用户或搜索引擎向一个网站服务器发出网页浏览请求时,该服务器将:
    1.通过域名服务器(DNS)将域名转换为网站的IP地址,然后返回给客户
    2.打开一个该IP套接口连接
    3.记下通过该套接口的一个HTTP数据流
    4.从WEB服务器接收一个响应请求的HTTP数据流。该数据流包含状态码,状态码的值由HTTP协议所决定。这里所说的“HTTP数据流”信息也叫“头信息(Header)”。头信息中包括了日期,服务器类型,通常还会有一条“200 OK”信息。如果一切良好,那么网络服务器就会将“200 OK”信息以及请求页面发送出去。如果网站在这时候已经建立了重定向,那么服务器就会在头信息中包含一个“302 Moved Temporarily”或“301 Moved Permanent”之类的响应信息。搜索引擎会根据服务器头信息中的内容作出决定。


    网站重定向的注意事项

      1.若准备将服务器上的文件移到其它地方时,须就以下信息正确地通知搜索引擎的爬行程序:
    - 目标地址:这些文件被移向何方
    - 移动属性:暂时移走还是永久性移走
      2.对拥有多个域名的网站,专家建议应把那些不想在搜索引擎上推广的域名用301跳转命令来永久性重定向。


    确保网站实施了正确的301重定向

    对于正确实施301重定向,有这样几个方法可供大家参考:
    1.在.htaccess文件中增加301重定向指令
    2.适用于使用Unix网络服务器的用户。通过此指令通知搜索引擎的spider你的站点文件不在此地址下。这是较为常用的办法。形如:Redirect 301 / http://www.yourdomain.com/
    3.在服务器软件的系统管理员配置区完成301重定向
    适用于使用Window网络服务器的用户
    4.采用“mod_rewrite”技术
    通过该技术进行的改变将在.htaccess文件中体现出来,形如:

    Options +FollowSymLinks
    RewriteEngine on
    RewriteCond %{HTTP_HOST} ^yourdomain.com
    RewriteRule ^(.*)$ http://www.yourdomain.com/$1 [R=permanent,L]

    5.绑定/本地DNS(域名别名跳转)
    如果具有对本地DNS记录进行编辑修改的权限,则只要添加一个记录就可以解决此问题。
    若无此权限,则可要求网站托管服务商对DNS服务器进行相应设置。
    DNS服务器的设置
    若要将aaa.domain.com指向www.domain.com,则只需在DNS服务中应增加一个别名记录,可写成:aaa IN CNAME www.domain.com。
    如需配置大量的虚拟域名,则可写成:* IN CNAME www.domain.com.
    这样就可将所有未设置的以domain.com结尾的记录全部重定向到www.domain.com上。
    6.用ASP/PHP实现301重定向
    代码在上面已经介绍过了

    资深SEO专家Dan Thies的看法和建议

      对于Business.com所遭遇的问题Dan Thies深有体会,因为他也有过类似的遭遇。他的网站上有一个会员跟踪脚本,其中一个会员的站点通过302命令映射到这个跟踪脚本,而这个跟踪脚本又是通过302映射到他的主页。当在Google中用“keyword research”进行搜索,他的主页排名在前十位,然而地址显示的却是那个会员的网址。结果使他哭笑不得:访问者通过Google搜索结果进入他的网站,而他却不得不为这些访问量给那个会员支付报酬! 后来他用robots.txt文件禁止Spiders跟踪访问他的会员跟踪脚本才算解决了问题。
      对于Business.com,Dan Thies认为:“目前Google在302重定向"的处理上还存在一定的问题,但并不表示Google不允许302重定向。Business.com并未遭封或遭到惩罚,它们只是返回了错误的响应。”
      Dan Thies建议:如果使用了跟踪URL/脚本,又必须让访问者重定向到某一着陆页,那么一定要在robots.txt文件中禁止Spiders去访问第二个重定向。如果没有对跟踪URL/脚本进行重定向,而只是把另外一个URL上的内容给复制过来,那么应在robots.txt文件中禁止Spiders去访问跟踪URL,以防因内容重复而遭搜索引擎惩罚。

    301重定向经验谈

      一个多域名站主的经验之谈:
      “我只有一个网站,主域名是www.domain.com,此外还有诸如domain1.com、domain2.com、domain3.com等共计十几个域名。所有这些次级域名都映射到www.domain.com,而且所有域名对应的是同一个IP地址。由于事实上我只有一个站点,一个站点又只能对应一个.htaccess文件,显然不可能直接修改.htaccess文件来实现重定向。我采用了如下步骤:
     A.把domain1.com从domain.com上独立出来,让它成为服务器上的一个普通独立网站。
     B.为domain1.com创建一个.htaccess文本文件,并在文件中设置重定向代码为:
     Redirect permanent / http://www.domain.com/
     再将修改后的.htaccess文件上传给domain1.com所在服务器。
     这一步也可以在域名控制面板中完成。
     C.进入域名控制面板,将所有原来绑定到domain.com上的域名从domain.com上释放,然后重新绑定到doamin1.com。这样一来,这些被绑定的域名使用的都是domain1.com的.htaccess文件,因而也就意味着它们都被永久性重定向到domain.com上了。好了,大功告成! 就这么容易!
    October 26

    php下扩展php_curl.dll的安装

    版本:php5.05
    已经内置有php_curl.dll,在ext目录下,此DLL用于支持SSL和zlib.
    在php.ini中找到有extension=php_curl.dll, 去掉前面的注释.
    设置extension_dir=c:\php\ext, 刷新PHP页面时报错, 说找不到模块php_curl.dll.
    拷贝php_curl.dll 到windows\system32,还是同样的错.
    在网上找了一下,需要将:

    libeay32.dll, ssleay32.dll, php5ts.dll, php_curl.dll

    都拷贝到system32目录下,重启apache即可.

    October 16

    如何在shell脚本里判断一个ip的某端口是否打开

    如何在shell脚本里判断一个ip的某端口是否打开
    nmap -sS www.xxx.com -p 80 | grep open
    September 19

    用於自动备份的Shell Script

    一个用於自动备份的Shell Script
    我们先前提到,可利用Shell Script搭配crond来作定期的工作。要作定期性的工作,在UNIX上,就是与crond的搭配运用。

    --------------------------------------------------------------------------------

    首先我们先来研究如何对系统进行备份。
    要对系统进行备份,不外乎便是利用一些压缩工具。在许多UNIX系统上,tar及gzip是de facto的资料交换标准。我们经常可以看见一些tar.gz或tgz档,这些档案,被称为tarball。当然了,您也可以用bzip2、zip等等压缩工具来进行压缩,不必限定於gzip。但tar配合gzip是最普遍的,也是最方便的方式。

    要将我们想要的资料压缩起来,进行备份,可以结合tar及gzip一起进行。方式有很多种,最常用的指令是以下这一种:

    tar -c file/dir ... | gzip -9 > xxxx.tar.gz

    您也可以分开来做:

    tar -r file/dir ... -f xxxx.tar
    gzip -9 xxxx.tar



    tar -r file/dir ... -f xxxx.tar
    gzip -9 < xxxx.tar > xxxx.tar.gz



    --------------------------------------------------------------------------------

    在解过Linux下档案备份的基本知识後,我们来写一个将档案备份的Script。
    #!/bin/sh
    # Filename : backup

    DIRS="/etc /var /your_directories_or_files"
    BACKUP="/tmp/backup.tgz"

    tar -c $DIRS | gzip -9 > $BACKUP

    其中DIRS放的是您要备份的档案及目录,BACKUP是您的备份档。可不要将/tmp放进DIRS中,那样做,您是在做备份的备份,可能将您的硬碟塞爆。



    --------------------------------------------------------------------------------

    接下来测试
    [foxman@foxman bash]# chmod 755 backup
    [foxman@foxman bash]# ./backup

    执行完成後在/tmp就会有一个backup.tgz,里面储存了您重要的资料。您可用

    gzip -dc /tmp/backup.tgz | tar -vt

    tar vtfz /tmp/backup.tgz

    来看看里面的档案列表。

    要解开时,可用以下指令来完成复原:

    gzip -dc /tmp/backup.tgz | tar -xv

    tar xvfz /tmp/backup.tgz

    备份通常是仅备份系统通常最重要的部份,/etc可说是不可缺少的一部份。另外,看您系统中有那些重要的资料需要备份。通常来说,您没有必要备份/bin、/sbin、/usr/bin、/usr/sbin、/usr/X11R6/bin等等这些执行档目录。只要备份您重要的档案即可,别把整个硬碟备份,那是蛮呆的动作。



    --------------------------------------------------------------------------------

    如果您有许多台机器,可利用其中一台任务较轻的内部网路主机,做为主要备份主机。将所有机器都自动执行备份,然後利用NFS/Coda/Samba等网路档案系统,将备份的资料放到该备份机器中,该机器则定时收取备份资料,然後您再由该机器中进行一次备份。
    这里是整个系统备份方案的图示。


    在您进行之前,先解一下,系统中那些是要备份的,那些是不需要的。



    --------------------------------------------------------------------------------

    新的backup
    #!/bin/sh
    HOSTNAME=`hostname`
    DIRS="/etc /var /your_important_directory"
    BACKUP="/tmp/$HOSTNAME.tgz"
    NFS="/mnt/nfs"

    tar -c $DIRS | gzip -9 > $BACKUP
    mv -f $BACKUP $NFS



    --------------------------------------------------------------------------------

    备份主机内的Script : collect_backup
    #!/bin/sh
    NFS="/mnt/nfs"
    BACKUP="/backup"

    mv -f $NFS/*.tgz $BACKUP


    在此,您不能够将所有备份都直接放在/mnt/nfs,这是危险的。万一任一台机器不小心将/mnt/nfs所有内容删除,那麽备份就会消失。因此,您需要将/mnt/nfs移到一个只有该备份主机可存取的目录中。



    --------------------------------------------------------------------------------

    当这些个别的Script都测试好以後,接下来我们将他们放到crontab里面。找到您的crontab,它的位置可能在/var/spool/cron/crontabs/root、/etc/crontab、/var/cron/tabs/root。
    在crontab中选择以下之一加入(看您定期的时间):

    Slackware : /var/spool/cron/crontabs/root
    01 * * * * /full_backup_script_path/backup 1> /dev/null 2> /dev/null # 每小时(太过火一点)
    30 16 * * * /full_backup_script_path/backup 1> /dev/null 2> /dev/null # 每日16:30,下班前备份
    30 16 * * 0 /full_backup_script_path/backup 1> /dev/null 2> /dev/null # 每周一16:30
    0 5 1 * * /full_backup_script_path/backup 1> /dev/null 2> /dev/null # 每月一号5:0
    RedHat/Debian : /etc/crontab
    RedHat可直接将backup放入/etc/cron.hourly, /etc/cron.daily, /etc/cron.weekly, /etc/cron.monthly。或采用如上加入/etc/crontab的方式:
    有关crontab的用法,可查"man 5 crontab",在此不详述。

    备份主机的设定类同。

    注意: 所有机器不要同时进行备份,否则网路会大塞车。备份主机收取备份的时间要设为最後,否则会收不到备份资料。您可以在实作後,将时间间隔调整一下。



    --------------------------------------------------------------------------------

    看看,两个小小不到三行的Shell Script,配合cron这个定时工具。可以让原本需要耗时多个小时的人工备份工作,简化到不到十分钟。善用您的想像力,多加一点变化,可你让您的生活变得轻松异常,快乐悠哉。

    产生 Makefile

    在 Unix 上写程式的人大概都碰过 Makefile,尤其是用 C 来开发程式的人。用 make 来开发和编译程式的确很方便,可是要写出一个 Makefile就不简单了。偏偏介绍 Makefile 的文件不多,GNU Make 那份印出来要几百页的文件,光看完 Overview 就快阵亡了,难怪许多人闻 Unix 色变。本文将介绍如何利用 GNU Autoconf 及 Automake 这两套软体来协助我们『自动』产生 Makefile 档,并且让开发出来的软体可以像 Apache,MySQL 和常见的 GNU 软体一样,只要会 ``./configure'', ``make'',``make install'' 就可以把程式安装到系统中。如果您有心开发 OpenSource 的软体,或只是想在 Unix 系统下写写程式。希望这份介绍文件能帮助您轻松地进入 Unix Programming 的殿堂。

    1. 简介
    Makefile 基本上就是『目标』(target), 『关连』(dependencies) 和『动作』三者所组成的一连串规则。而 make 就会根据 Makefile 的规则来决定如何编译 (compile) 和连结 (link) 程式。实际上,make 可做的不只是编译和连结程式,例如 FreeBSD 的 port collection 中,Makefile 还可以做到自动下载原始程式套件,解压缩 (extract) ,修补(patch),设定,然後编译,安装至系统中。

    Makefile 基本构造虽然简单,但是妥善运用这些规则就也可以变出许多不同的花招。却也因此,许多刚开始学习写 Makefile 时会感到没有规范可循,每个人写出来的 Makefile 长得都不太一样,不知道从何下手,而且常常会受限於自己的开发环境,只要环境变数不同或路径改一下,可能Makefile 就得跟着修改。虽然有 GNU Makefile Conventions (GNUMakefile 惯例) 订出一些使用 GNU 程式设计时撰写 Makefile 的一些标准和规范,但是内容很长而且很复杂, 并且经常做些调整,为了减轻程式设计师维护 Makefile 的负担,因此有了 Automake。

    程式设计师只需写一些预先定义好的巨集 (macro),交给 Automake 处理後会产生一个可供 Autoconf 使用的 Makefile.in 档。再配合利用Autoconf 产生的自动设定档 configure 即可产生一份符合 GNU Makefile惯例的 Makeifle 了。

    2. 上路之前

    在开始试着用 Automake 之前,请先确认你的系统已经安装以下的软体:

    1. GNU Automake
    2. GNU Autoconf
    3. GNU m4
    4. perl
    5. GNU Libtool (如果你需要产生 shared library)

    我会建议你最好也使用 GNU C/C++ 编译器 、GNU Make 以及其它 GNU 的工具程式来做为开发的环境,这些工具都是属於 Open Source Software不仅免费而且功能强大。如果你是使用 Red Hat Linux 可以找到所有上述软体的 rpm 档,FreeBSD 也有现成的 package 可以直接安装,或着你也可以自行下载这些软体的原始档回来 DIY。以下的范例是在 Red HatLinux 5.2 + CLE2 的环境下所完成的。

    3. 一个简单的例子

    Automake 所产生的 Makefile 除了可以做到程式的编译和连结,也已经把如何产生程式文件 (如 manual page, info 档及 dvi 档) 的动作,还有把原始程式包装起来以供散 的动作都考虑进去了,所以原始程式所存放的目录架构最好符合 GNU 的标准惯例,接下来我拿 hello.c 来做为例子。

    在工作目录下建立一个新的子目录 ``devel'',再在 devel 下建立一个``hello'' 的子目录,这个目录将作为我们存放 hello 这个程式及其相关档案的地方:

    % mkdir devel
    % cd devel
    % mkdir hello
    % cd hello

    用编辑器写个 hello.c 档,
    #include
    int main(int argc, char** argv)
    {
    printf(``Hello, GNU!\n'');
    return 0;
    }

    接下来就要用 Autoconf 及 Automake 来帮我们产生 Makefile 档了,
    1. 用 autoscan 产生一个 configure.in 的雏型,执行 autoscan 後会产生一个configure.scan 的档案,我们可以用它做为 configure.in档的蓝本。

    % autoscan
    % ls
    configure.scan hello.c

    2. 编辑 configure.scan 档,如下所示,并且把它的档名改成 configure.in

    dnl Process this file with autoconf to produce a configure script.

    AC_IN99v(hello.c)
    AM_IN99v_AUTOMAKE(hello, 1.0)
    dnl Checks for programs.

    AC_PROG_CC
    dnl Checks for libraries.
    dnl Checks for header files.
    dnl Checks for typedefs, structures, and compiler characteristics.
    dnl Checks for library functions.
    AC_OUTPUT(Makefile)

    3. 执行 aclocal 和 autoconf ,分别会产生 aclocal.m4 及 configure 两个档案
    % aclocal
    % autoconf
    % ls
    aclocal.m4configureconfigure.inhello.c

    4. 编辑 Makefile.am 档,内容如下
    AUTOMAKE_OPTIONS= foreign
    bin_PROGRAMS= hello
    hello_SOURCES= hello.c

    5. 执行 automake --add-missing ,Automake 会根据 Makefile.am 档产生一些档案,包含最重要的 Makefile.in
    % automake --add-missing
    automake: configure.in: installing `./install-sh'
    automake: configure.in: installing `./mkinstalldirs'
    automake: configure.in: installing `./missing'

    6. 最後执行 ./configure ,
    % ./configure
    creating cache ./config.cache
    checking for a BSD compatible install... /usr/bin/in
    stall -c
    checking whether build environment is sane... yes
    checking whether make sets ${MAKE}... yes
    checking for working aclocal... found
    checking for working autoconf... found
    checking for working automake... found
    checking for working autoheader... found
    checking for working makeinfo... found
    checking for gcc... gcc
    checking whether the C compiler (gcc ) works... yes
    checking whether the C compiler (gcc ) is a cross-compiler... no
    checking whether we are using GNU C... yes
    checking whether gcc accepts -g... yes
    updating cache ./config.cache
    creating ./config.status
    creating Makefile

    现在你的目录下已经产生了一个 Makefile 档,下个 ``make'' 指令就可以开始编译 hello.c 成执行档,执行 ./hello 和 GNU 打声招呼吧!
    % make
    gcc -DPACKAGE=\"hello\" -DVERSION=\"1.0\" -I. -I. -g -O2 -c hello.c
    gcc -g -O2 -o hello hello.o
    % ./hello
    Hello! GNU!

    你还可以试试 ``make clean'',''make install'',''make dist'' 看看会有什麽结果。你也可以把产生出来的 Makefile 秀给你的老板,让他从此对你刮目相看 :-)

    4. 一探究竟
    上述产生 Makefile 的过程和以往自行编写的方式非常不一样,舍弃传统自行定义 make 的规则,使用 Automake 只需用到一些已经定义好的巨集即可。我们把巨集及目标 (target) 写在 Makefile.am 档内,Automake读入 Makefile.am 档後会把这一串已经定义好的巨集展开并且产生对应的Makefile.in 档, 然後再由 configure 这个 shell script 根据Makefile.in 产生适合的 Makefile。

    4.1 编辑 configure.in 档

    Autoconf 是用来产生 'configure' 档的工具。'configure' 是一个shell script,它可以自动设定原始程式以符合各种不同平台上 Unix 系统的特性,并且根据系统叁数及环境产生合适的 Makefile 档或是C 的标头档 (header file),让原始程式可以很方便地在这些不同的平台上被编译出来。Autoconf 会读取 configure.in 档然後产生 'configure' 这个shell script。
    configure.in 档的内容是一连串 GNU m4 的巨集,这些巨集经过autoconf 处理後会变成检查系统特徵的 shell script。configure.in 内巨集的顺序并没有特别的规定,但是每一个 configure.in 档必须在所有巨集前加入 AC_IN99v 巨集,然後在所有巨集的最後面加上 AC_OUTPUT 巨集。我们可先用 autoscan 扫描原始档以产生一个 configure.scan 档,再对 configure.scan 做些修改成 configure.in 档。在范例中所用到的巨集如下:

    dnl
    这个巨集後面的字不会被处理,可视为注解。
    AC_IN99v(FILE)
    这个巨集用来检查原始码所在的路径,autoscan 会自动产生,我们不必修改它。
    AM_IN99v_AUTOMAKE(PACKAGE,VERSION)
    这是使用 Automake 所必备的巨集,PACKAGE 是我们所要产生软体套件的名称,VERSION 是版本编号。
    AC_PROG_CC
    检查系统可用的 C 编译器,如果原始程式是用 C 写的就需要这个巨集。
    AC_OUTPUT(FILE)
    设定 configure 所要产生的档案,如果是 Makefile 的话,configure 便会把它检查出来的结果带入 Makefile.in 档然後产生合适的 Makefile。

    实际上,我们使用 Automake 时,还须要一些其它的巨集,这些额外的巨集我们用 aclocal 来帮我们产生。执行 aclocal 会产生 aclocal.m4 档,如果没有特别的用途,我们可以不必修改它,用 aclocal 所产生的巨集会告诉 Automake 怎麽做。

    有了 configure.in 及 aclocal.m4 两个档案後,便可以执行 autoconf来产生 configure 档了。

    4.2 编辑 Makefile.am 档

    接下来我们要编辑 Makefile.am 档,Automake 会根据 configure.in 中的巨集把Makefile.am 转成 Makefile.in 档。Makefile.am 档定义我们所要产的目标:

    AUTOMAKE_OPTIONS
    设定 automake 的选项。Automake 主要是帮助开发 GNU 软体的人员维护软体套件,所以在执行 automake 时,会检查目录下是否存在标准 GNU 软体套件中应具备的文件档案,例如 'NEWS'、'AUTHOR'、'ChangeLog' 等文件档。设成 foreign 时,automake 会改用一般软体套件的标准来检查。
    bin_PROGRAMS
    定义我们所要产生的执行档档名。如果要产生多个执行档,每个档名用空白字元隔开。
    hello_SOURCES
    定义 'hello' 这个执行档所需要的原始档。如果 'hello' 这个程式是由多个原始档所产生,必须把它所用到的原始档都列出来,以空白字元隔开。假设 'hello' 这个程式需要 'hello.c'、'main.c'、'hello.h' 三个档案的话,则定义 hello_SOURCES= hello.c main.c hello.h 如果我们定义多个执行档,则对每个执行档都要定义相对的filename_SOURCES。

    编辑好 Makefile.am 档,就可以用 automake --add-missing 来产生Makefile.in。加上 --add-missing 选项是告诉 automake 顺便帮我们加入包装一个软体套件所必备的档案。Automake 产生出来的 Makefile.in档是完全符合 GNU Makefile 的惯例,我们只要执行 configure 这个shell script 便可以产生合适的 Makefile 档了。

    4.3 使用 Makefile

    利用 configure 所产生的 Makefile 档有几个预设的目标可供使用,我们只拿其中几个简述如下:

    make all
    产生我们设定的目标,即此范例中的执行档。只打 make 也可以,此时会开始编译原始码,然後连结,并且产生执行档。
    make clean
    清除之前所编译的执行档及目的档 (object file, *.o)。
    make distclean
    除了清除执行档和目的档外,也把 configure 所产生的 Makefile也清除掉。
    make install
    将程式安装至系统中。如果原始码编译无误,且执行结果正确,便可以把程式安装至系统预设的执行档存放路径。如果我们用bin_PROGRAMS 巨集的话,程式会被安装至 /usr/local/bin 这个目录。
    make dist
    将程式和相关的档案包装成一个压缩档以供散播 (distribution) 。执行完在目录下会产生一个以 PACKAGE-VERSION.tar.gz 为名称的档案。PACKAGE 和 VERSION 这两个变数是根据 configure.in 档中
    AM_IN99v_AUTOMAKE(PACKAGE, VERSION) 的定义。在此范例中会产生'hello-1.0.tar.gz' 的档案。
    make distcheck
    和 make dist 类似,但是加入检查包装後的压缩档是否正常。这个目标除了把程式和相关档案包装成 tar.gz 档外,还会自动把这个压缩档解开,执行 configure,并且进行 make all 的动作,确认编译无误後,会显示这个 tar.gz 档已经准备好可供散播了。这个检查非常有用,检查过关的套件,基本上可以给任何一个具备 GNU 发展环境的人去重新编译。就 hello-1.tar.gz 这个范例而言,除了在 RedHat Linux 上,在 FreeBSD 2.2.x 版也可以正确地重新编译。

    要注意的是,利用 Autoconf 及 Automake 所产生出来的软体套件是可以在没有安装 Autoconf 及 Automake 的环境上使用的,因为 configure 是一个 shell script,它己被设计可以在一般 Unix 的 sh 这个 shell 下执行。但是如果要修改 configure.in 及 Makefile.am 档再产生新的configure 及 Makefile.in 档时就一定要有 Autoconf 及 Automake 了。

    5. 相关讯息

    Autoconf 和 Automake 功能十分强大,你可以从它们所附的 info 档找到详细的用法。你也可以从许多现存的 GNU 软体或 Open Source 软体中找到相关的 configure.in 或 Makefile.am 档,它们是学习 Autoconf 及Automake 更多技巧的最佳范例。

    这篇简介只用到了 Autoconf 及 Automake 的皮毛罢了,如果你有心加入Open Source 软体开发的行列,希望这篇文件能帮助你对产生 Makefile有个简单的依据。其它有关开发 GNU 程式或 C 程式设计及 Makefile 的详细运用及技巧,我建议你从 GNU Coding Standards3 (GNU 编码标准规定) 读起,里面包含了 GNU Makefile 惯例,还有发展 GNU 软体套件的标准程序和惯例。这些 GNU 软体的线上说明文件可以在 http://www.gnu.org/ 这个网站上找到。

    6. 结语
    经由 Autoconf 及 Automake 的辅助,产生一个 Makefile 似乎不再像以前那麽困难了,而使用 Autoconf 也使得我们在不同平台上或各家 Unix 之间散播及编译程式变得简单,这对於在 Unix 系统上开发程式的人员来 说减轻了许多负担。妥善运用这些 GNU 的工具软体,可以帮助我们更容易 去发展程式,而且更容易维护原始程式码。
    About this document ...  

    Make命令

    在make命令后不仅可以出现宏定义,还可以跟其他命令行参数,这些参数指定了需要编译的目标文件。其标准形式为:

    target1 [target2 …]:[:][dependent1 …][;commands][#…]
    [(tab) commands][#…]

    方括号中间的部分表示可选项。Targets和dependents当中可以包含字符、数字、句点和"/"符号。除了引用,commands中不能含有"#",也不允许换行。

    在通常的情况下命令行参数中只含有一个":",此时command序列通常和makefile文件中某些定义文件间依赖关系的描述行有关。如果与目标相关连的那些描述行指定了相关的command序列,那么就执行这些相关的command命令,即使在分号和(tab)后面的aommand字段甚至有可能是NULL。如果那些与目标相关连的行没有指定command,那么将调用系统默认的目标文件生成规则。

    如果命令行参数中含有两个冒号"::",则此时的command序列也许会和makefile中所有描述文件依赖关系的行有关。此时将执行那些与目标相关连的描述行所指向的相关命令。同时还将执行build-in规则。

    如果在执行command命令时返回了一个非"0"的出错信号,例如makefile文件中出现了错误的目标文件名或者出现了以连字符打头的命令字符串,make操作一般会就此终止,但如果make后带有"-i"参数,则make将忽略此类出错信号。

    Make命本身可带有四种参数:标志、宏定义、描述文件名和目标文件名。其标准形式为:

    Make [flags] [macro definitions] [targets]

    Unix系统下标志位flags选项及其含义为:

    -f file 指定file文件为描述文件,如果file参数为"-"符,那么描述文件指向标准输入。如果没有"-f"参数,则系统将默认当前目录下名为makefile或者名为Makefile的文件为描述文件。在Linux中, GNU make 工具在当前工作目录中按照GNUmakefile、makefile、Makefile的顺序搜索 makefile文件。

    -i 忽略命令执行返回的出错信息。
    -s 沉默模式,在执行之前不输出相应的命令行信息。
    -r 禁止使用build-in规则。
    -n 非执行模式,输出所有执行命令,但并不执行。
    -t 更新目标文件。
    -q make操作将根据目标文件是否已经更新返回"0"或非"0"的状态信息。
    -p 输出所有宏定义和目标文件描述。
    -d Debug模式,输出有关文件和检测时间的详细信息。

    Linux下make标志位的常用选项与Unix系统中稍有不同,下面我们只列出了不同部分:

    -c dir 在读取 makefile 之前改变到指定的目录dir。
    -I dir 当包含其他 makefile文件时,利用该选项指定搜索目录。
    -h help文挡,显示所有的make选项。
    -w 在处理 makefile 之前和之后,都显示工作目录。

    通过命令行参数中的target ,可指定make要编译的目标,并且允许同时定义编译多个目标,操作时按照从左向右的顺序依次编译target选项中指定的目标文件。如果命令行中没有指定目标,则系统默认target指向描述文件中第一个目标文件。

    debian编码错误修改

    debian编码错误修改
    export LC_ALL=POSIX

    运用autoconf和automake自动生成Makefile实例讲解

    几乎所有基于GNU工具的项目都使用GNU的auto系列工程管理工具管理工程。那3个命令是工程发行代码包
    的基本编译安装方式。
    configure是根据系统环境及某些自定义工程脚步生产Makefile
    make就是编译工程咯,相当于make all
    make install就是安装工程文件到系统咯
    make dist-gzip就是生成工程代码包了,XXX.tar.gz文件。
     
    对于一个UNIX/Linux下C程序员来说,一个比较麻烦的工作就是写自己的Makefile。
    可能你有如下经验:写一个简单的C程序,自己多写几行gcc命令就把程序变成可执行的了;写一个稍微复杂点的程序,源文件个数可能在30个左右,还是写一行行的gcc命令就麻烦了,你可能想到写个makefile,你可能也在这样做着;但你某一天会发现你写的这个Makefile可能不是一个所有 UNIX/Linux类操作系统下通用的Makefile,比如某人下载了你的程序去他自己电脑上可能make不了。

    这样,你就有必要了解并学会运用autoconf和automake了。
    autoconf是一个用于生成可以自动地配置软件源代码包以适应多种UNIX类系统的shell脚本的工具。由autoconf生成的配置脚本在运行的时候不需要用户的手工干预;通常它们甚至不需要手工给出参数以确定系统的类型。相反,它们对软件包可能需要的各种特征进行独立的测试。在每个测试之前,它们打印一个单行的消息以说明它们正在进行的检测,以使得用户不会因为等待脚本执行完毕而焦躁。因此,它们在混合系统或者从各种常见UNIX变种定制而成的系统中工作的很好。你也省了工作,没必要维护文件以储存由各个UNIX变种、各个发行版本所支持的特征的列表。
    automake是一个从文件Makefile.am自动生成Makefile.in的工具。每个Makefile.am基本上是一系列make的宏定义(make规则也会偶尔出现)生成的Makefile.in,服从GNU Makefile标准。
    为了生成Makefile.in,automake需要perl。但是由automake创建的发布完全服从GNU标准,并且在创建中不需要perl。

    在开始使用autoconf和automake之前,首先确认你的系统安装有GNU的如下软件:
    1. automake
    2. autoconf
    3. m4
    4. perl
    5. 如果你需要产生共享库(shared library)则还需要GNU Libtool

    介绍方法之前大家看一下下面这个图,先记下autoconf和automake工作的几个步骤:


    步骤解释如下:
    1、由你的源文件通过autoscan命令生成configure.scan文件,然后修改configure.scan文件并重命名为configure.in
    2、由aclocal命令生成aclocal.m4
    3、由autoconf命令生成configure
    4、编辑一个Makefile.am文件并由automake命令生成Makefile.in文件
    5、运行configure命令生成Makefile

    automake支持三种目录层次:flat、shallow和deep。
    一个flat包指的是所有文件都在一个目录中的包。为这类包提供的Makefile.am不需要SUBDIRS这个宏。这类包的一个例子是termutils。对应咱们程序员来说:就是所有源文件及自己写的头文件都位于当前目录里面,且没有子目录。
    一个deep包指的是所有的源代码都被储存在子目录中的包;顶层目录主要包含配置信息。GNU cpio是这类包的一个很好的例子,GNU tar也是。deep包的顶层Makefile.am将包括宏SUBDIRS,但没有其它定义需要创建的对象的宏。对应咱们程序员来说:就是所有源文件及自己写的头文件都位于当前目录的一个子目录里面,而当前目录里没有任何源文件。
    一个shallow包指的是主要的源代码储存在顶层目录中,而各个部分(典型的是库)则储存在子目录中的包。automake本身就是这类包(GNU make也是如此,它现在已经不使用automake)。对应咱们程序员来说:就是主要源文件在当前目录里,而其它一些实现各部分功能的源文件各自位于不同目录。

    前两个层次的程序编辑方法非常简单,按照上述步骤一步步即可。而第三种层次shallow稍微复杂一点,但这是我们经常写程序用到的结构。下面以一个例子说明shallow层次结构的源文件如何自动生成Makefile文件。
    例子源程序结构如下:
    hello是我们的工作目录,hello目录下有main.c源文件和comm、tools、db、network、interface等五个目录。 comm目录下有comm.c和comm.h源文件及头文件,tools目录下有tools.c和tools.h,同样其它目录分别有db.c、 db.h、network.c、network.h、interface.c、interface.h等一些源文件。

    按照如下步骤来自动生成Makefile吧:
    1、进入hello目录,运行autoscan命令,命令如下:
    cd hello
    autoscan
    2、ls会发现多了一个configure.scan文件。修改此文件,在AC_INIT宏之后加入AM_INIT_AUTOMAKE(hello, 1.0),这里hello是你的软件名称,1.0是版本号,即你的这些源程序编译将生成一个软件hello-1.0版。然后把 configure.scan文件的最后一行AC_OUTPUT宏填写完整变成AC_OUTPUT(Makefile),表明autoconf和 automake最终将生成Makefile文件。最后把configure.scan文件改名为configure.in。最终 configure.in文件内容如下:

    dnl Process this file with autoconf to produce a configure script.
    AC_INIT(target.c)
    AM_INIT_AUTOMAKE(hello, 1.0)
    dnl Checks for programs.
    AC_PROG_CC

    dnl Checks for libraries.

    dnl Checks for header files.

    dnl Checks for typedefs, structures, and compiler characteristics.

    dnl Checks for library functions.

    AC_OUTPUT(Makefile)

    3、运行aclocal命令,ls会发现多了一个aclocal.m4文件。
    4、然后运行autoconf命令,ls将发现生成了一个可执行的configure命令。
    5、编辑一个Makefile.am文件,文件内容如下:
    AUTOMAKE_OPTIONS=foreign
    bin_PROGRAMS=hello
    hello_SOURCES=main.c comm/comm.c comm/comm.h tools/tools.c tools/tools.h db/db.c db/db.h network/network.c network/network.h interface/interface.c interface/interface.h
    这表明你最后将通过一个make命令利用上述hello_SOURCES源文件生成一个hello的程序。
    6、运行automake --add-missing命令。屏幕提示如下:
    automake: configure.in: installing `./install-sh'
    automake: configure.in: installing `./mkinstalldirs'
    automake: configure.in: installing `./missing'
    7、然后你可以运行之前生成的configure命令来生成一个Makefile文件,输入./configure命令即可。
    8、编辑Makefile文件,找到$(LINK)所在的那一行,本来生成的文件内容如下:
    @rm -f hello
    $(LINK) $(hello_LDFLAGS) $(hello_OBJECTS) $(hello_LDADD) $(LIBS)
    在这两行之间增加几行变成:
    @rm -f hello
    @mv -f comm.o comm
    @mv -f tools.o tools
    @mv -f db.o db
    @mv -f network.o network
    @mv -f interface.o interface
    $(LINK) $(hello_LDFLAGS) $(hello_OBJECTS) $(hello_LDADD) $(LIBS)
    这是因为默认生成的Makefile将在编译后把所有目标文件置于当前目录,而在进行链接(link)时又会到各个子目录去找相应的目标文件。
    当然,为了完整,建议各位在clean部分加上如下一些行:
    @rm -f comm/comm.o
    @rm -f tools/tools.o
    @rm -f db/db.o
    @rm -f network/network.o
    @rm -f interface/interface.o

    好了,经过上述这些步骤后,现在你可以来编译生成你自己的可执行程序了。输入一个make all吧,然后就可以运行./hello来看你的程序运行了。

    运用autoconf和automake的最大好处是,你的程序以源程序方式发布后,其它所有人只需要依次输入
    ./configure
    make
    make install
    命令就可以把你的程序安装在自己的电脑上运行了。所有符合GNU标准的UNIX/Linux都不需要再修改Makefile里的任何字符。

    September 02

    CSS光标属性一览表

    光标类型  CSS  
    把你的光标放到相应文字上查看效果 要注意光标的实际效果依赖于用户的系统设置,与你在这里看到的效果并不一定一致。
    十字准心 cursor: crosshair;
    手 cursor: pointer;
    cursor: hand;
    写两个是为了照顾IE5,它只认hand。
    等待/沙漏 cursor: wait;
    帮助 cursor: help;
    无法释放 cursor: no-drop;
    文字/编辑 cursor: text;
    可移动对象 cursor: move;
    向上改变大小(North)  cursor: n-resize;
    向下改变大小(South)  cursor: s-resize;
    向右改变大小(East)  cursor: e-resize;
    向左改变大小(West)  cursor: w-resize;
    向上右改变大小(North East)  cursor: ne-resize;
    向上左改变大小(North West)  cursor: nw-resize;
    向下右改变大小(South East)  cursor: se-resize;
    向下左改变大小(South West)  cursor: sw-resize;
    自动 cursor: auto;
    禁止 cursor:not-allowed;
    处理中 cursor: progress;
    系统默认 cursor: default;
    用户自定义(可用动画) cursor: url(' # ');
    # = 光标文件地址   (注意文件格式必须为:.cur 或 .ani)。
    July 24

    web服务器返回状态集合

    Informational
    ==================================
    100 Continue
    指示客户端应该继续请求。回送用于通知客户端此次请求已经收到,并且没有被服务器拒绝。
    客户端应该继续发送剩下的请求数据或者请求已经完成,或者忽略回送数据。服务器必须发送
    最后的回送在请求之后。

    101 Switching Protocols
    服务器依照客服端请求,通过Upgrade头信息,改变当前连接的应用协议。服务器将根据Upgrade头立刻改变协议
    在101回送以空行结束的时候。

    Successful 
    ==================================
    200 OK
    指示客服端的请求已经成功收到,解析,接受。

    201 Created
    请求已经完成并一个新的返回资源被创建。被创建的资源可能是一个URI资源,通常URI资源在Location头指定。回送应该包含一个实体数据
    并且包含资源特性以及location通过用户或者用户代理来选择合适的方法。实体数据格式通过煤体类型来指定即content-type头。最开始服务器
    必须创建指定的资源在返回201状态码之前。如果行为没有被立刻执行,服务器应该返回202。



    202 Accepted
    请求已经被接受用来处理。但是处理并没有完成。请求可能或者根本没有遵照执行,因为处理实际执行过程中可能被拒绝。

    203 Non-Authoritative Information

    204 No Content
    服务器已经接受请求并且没必要返回实体数据,可能需要返回更新信息。回送可能包含新的或更新信息由entity-headers呈现。

    205 Reset Content
    服务器已经接受请求并且用户代理应该重新设置文档视图。

    206 Partial Content
    服务器已经接受请求GET请求资源的部分。请求必须包含一个Range头信息以指示获取范围可能必须包含If-Range头信息以成立请求条件。

    Redirection
    ==================================
    300 Multiple Choices
    请求资源符合任何一个呈现方式。

    301 Moved Permanently
    请求的资源已经被赋予一个新的URI。

    302 Found
    通过不同的URI请求资源的临时文件。


    303 See Other

    304 Not Modified
    如果客服端已经完成一个有条件的请求并且请求是允许的,但是这个文档并没有改变,服务器应该返回304状态码。304
    状态码一定不能包含信息主体,从而通常通过一个头字段后的第一个空行结束。

    305 Use Proxy
    请求的资源必须通过代理(由Location字段指定)来访问。Location资源给出了代理的URI。

    306 Unused

    307 Temporary Redirect

    Client Error 
    =====================
    400 Bad Request
    因为错误的语法导致服务器无法理解请求信息。

    401 Unauthorized
    如果请求需要用户验证。回送应该包含一个WWW-Authenticate头字段用来指明请求资源的权限。

    402 Payment Required
    保留状态码

    403 Forbidden
    服务器接受请求,但是被拒绝处理。

    404 Not Found
    服务器已经找到任何匹配Request-URI的资源。

    405 Menthod Not Allowed
    Request-Line请求的方法不被允许通过指定的URI。

    406 Not Acceptable

    407 Proxy Authentication Required

    408 Reqeust Timeout
    客服端没有提交任何请求在服务器等待处理时间内。

    409 Conflict

    410 Gone

    411 Length Required
    服务器拒绝接受请求在没有定义Content-Length字段的情况下。

    412 Precondition Failed

    413 Request Entity Too Large
    服务器拒绝处理请求因为请求数据超过服务器能够处理的范围。服务器可能关闭当前连接来阻止客服端继续请求。

    414 Request-URI Too Long
    服务器拒绝服务当前请求因为URI的长度超过了服务器的解析范围。

    415 Unsupported Media Type
    服务器拒绝服务当前请求因为请求数据格式并不被请求的资源支持。

    416 Request Range Not Satisfialbe

    417 Expectation Failed

    Server Error
    ===================================
    500 Internal Server Error
    服务器遭遇异常阻止了当前请求的执行

    501 Not Implemented
    服务器没有相应的执行动作来完成当前请求。

    502 Bad Gateway

    503 Service Unavailable
    因为临时文件超载导致服务器不能处理当前请求。

    504 Gateway Timeout

    505 Http Version Not Supported

    用rsync实现网站镜像和备份

    简介

    对于选择Linux 作为应用平台的的中小型企业或网站来说,往往面临如何实现数据远程备份或者网站镜象的问题,虽然有商业化的备份和镜象产品可供选择,但这些产品的价格往往过于昂贵。因此如何利用自由软件高效实现远程备份和网站镜象就成为一个值得讨论的话题。

    通过网络进行远程数据备份或者网站镜象的最简单的方法就是使用wget,但是这种方式每次都需要将所有数据都重新在网络上传输一遍,而不考虑哪些文件是经过更新的,因此效率非常低下。尤其在需要备份的数据量很大的时候,往往需要花费数个小时来在网络上进行数据传输。

    因此这里就介绍一种高效的网络远程备份和镜象工具-rsync,它可以满足绝大多数要求不是特别严格的备份需求。

    rsync是类unix系统下的数据镜像备份工具,从软件的命名上就可以看出来了——remote sync。它的特性如下:

    *可以镜像保存整个目录树和文件系统。
    *可以很容易做到保持原来文件的权限、时间、软硬链接等等。
    *无须特殊权限即可安装。
    *优化的流程,文件传输效率高。
    *可以使用rcp、ssh等方式来传输文件,当然也可以通过直接的socket连接。
    *支持匿名传输,以方便进行网站镜象。

    软件下载

    rysnc的主页地址为:

    目前最新版本为2.4.6。可以选择从原始网站下载:。也可以选择从本站下载:rsync 2.4.6。

    编译安装

    rsync的编译安装非常简单,只需要以下简单的几步:

    [root@www rsync-2.4.6]# ./configure
    [root@www rsync-2.4.6]# make
    [root@www rsync-2.4.6]# make install

    但是需要注意的是必须在服务器A和B上都安装rsync,其中A服务器上是以服务器模式运行rsync,而B上则以客户端方式运行rsync。这样在web服务器A上运行rsync守护进程,在B上定时运行客户程序来备份web服务器A上需要备份的内容。

    rsync服务器

    1、rsync服务器的启动

    在web服务器A上需要以守护进程方式来启动rsync服务器,只需要运行:

    [root@www rsync-2.4.6]# /usr/local/bin/rsync --daemon

    即可启动。rsync默认服务端口为873,服务器在该端口接收客户的匿名或者认证方式的备份请求。

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

    a、加入inetd.conf

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

    注:对于xinetd,设置方法类似。

    b、加入rc.local

    编辑/etc/rc.d/rc.local,在最后添加:

    /usr/local/bin/rsync --daemon

    2、rsync的配置

    对于rsync服务器来说,最重要和复杂的就是它的配置了。rsync服务器的配置文件为/etc/rsyncd.conf,其控制认证、访问、日志记录等等。

    该文件是由一个或多个模块结构组成。一个模块定义以方括弧中的模块名开始,直到下一个模块定义开始或者文件结束,模块中包含格式为name = value的参数定义。每个模块其实就对应需要备份的一个目录树,比方说在我们的实例环境中,有三个目录树需要备份:/www/、/home/web_user1/和/home/web_user2/,那么就需要在配置文件中定义三个模块,分别对应三个目录树。

    配置文件是行为单位的,也就是每个新行都表示一个新的注释、模块定义或者参数赋值。以#开始的行表示注释,以""结束的行表示下面一行是该行的继续。参数赋值中等号后可能是一个大小写不敏感的字符串、一个以trure/false表示的布尔值。

    全局参数

    在文件中[modlue]之前的所有参数都是全局参数,当然也可以在全局参数部分定义模块参数,这时候该参数的值就是所有模块的默认值。

    motd file

    "motd file"参数用来指定一个消息文件,当客户连接服务器时该文件的内容显示给客户,默认是没有motd文件的。

    log file

    "log file"指定rsync的日志文件,而不将日志发送给syslog。

    pid file

    指定rsync的pid文件。

    syslog facility

    指定rsync发送日志消息给syslog时的消息级别,常见的消息级别是:uth, authpriv, cron, daemon, ftp, kern, lpr, mail, news, security, sys-log, user, uucp, local0, local1, local2, local3,local4, local5, local6和local7。默认值是daemon。

    模块参数

    在全局参数之后就需要定义一个或多个模块了,模块中可以定义以下参数:

    comment

    给模块指定一个描述,该描述连同模块名在客户连接得到模块列表时显示给客户。默认没有描述定义。

    path

    指定该模块的供备份的目录树路径,该参数是必须指定的。

    use chroot

    如果"use chroot"指定为true,那么rsync在传输文件以前首先chroot到path参数所指定的目录下。这样做的原因是实现额外的安全防护,但是缺点是需要以roots权限,并且不能备份指向外部的符号连接所指向的目录文件。默认情况下chroot值为true。

    max connections

    指定该模块的最大并发连接数量以保护服务器,超过限制的连接请求将被告知随后再试。默认值是0,也就是没有限制。

    lock file

    指定支持max connections参数的锁文件,默认值是/var/run/rsyncd.lock。

    read only

    该选项设定是否允许客户上载文件。如果为true那么任何上载请求都会失败,如果为false并且服务器目录读写权限允许那么上载是允许的。默认值为true。

    list

    该选项设定当客户请求可以使用的模块列表时,该模块是否应该被列出。如果设置该选项为false,可以创建隐藏的模块。默认值是true。

    uid

    该选项指定当该模块传输文件时守护进程应该具有的uid,配合gid选项使用可以确定哪些可以访问怎么样的文件权限,默认值是"nobody"。

    gid

    该选项指定当该模块传输文件时守护进程应该具有的gid。默认值为"nobody"。

    exlude

    用来指定多个由空格隔开的多个模式列表,并将其添加到exclude列表中。这等同于在客户端命令中使用--exclude来指定模式,不过配置文件中指定的exlude模式不会传递给客户端,而仅仅应用于服务器。一个模块只能指定一个exlude选项,但是可以在模式前面使用"-"和"+"来指定是exclude还是include。

    但是需要注意的一点是该选项有一定的安全性问题,客户很有可能绕过exlude列表,如果希望确保特定的文件不能被访问,那就最好结合uid/gid选项一起使用。

    exlude from

    指定一个包含exclude模式的定义的文件名,服务器从该文件中读取exlude列表定义。

    include

    用来指定多个由空格隔开的多个rsync并应该exlude的模式列表。这等同于在客户端命令中使用--include来指定模式,结合include和exlude可以定义复杂的exlude/include规则 。一个模块只能指定一个include选项,但是可以在模式前面使用"-"和"+"来指定是exclude还是include。

    include from

    指定一个包含include模式的定义的文件名,服务器从该文件中读取include列表定义。

    auth users

    该选项指定由空格或逗号分隔的用户名列表,只有这些用户才允许连接该模块。这里的用户和系统用户没有任何关系。如果"auth users"被设置,那么客户端发出对该模块的连接请求以后会被rsync请求challenged进行验证身份这里使用的challenge/response认证协议。用户的名和密码以明文方式存放在"secrets file"选项指定的文件中。默认情况下无需密码就可以连接模块(也就是匿名方式)。

    secrets file

    该选项指定一个包含定义用户名:密码对的文件。只有在"auth users"被定义时,该文件才有作用。文件每行包含一个username:passwd对。一般来说密码最好不要超过8个字符。没有默认的secures file名,需要限式指定一个。(例如:/etc/rsyncd.secrets)

    strict modes

    该选项指定是否监测密码文件的权限,如果该选项值为true那么密码文件只能被rsync服务器运行身份的用户访问,其他任何用户不可以访问该文件。默认值为true。

    hosts allow

    该选项指定哪些IP的客户允许连接该模块。客户模式定义可以是以下形式:

    o xxx.xxx.xxx.xxx,客户主机只有完全匹配该IP才允许访问。例如:192.167.0.1

    o a.b.c.d/n,属于该网络的客户都允许连接该模块。例如:192.168.0.0/24

    o a.b.c.d/e.f.g.h,属于该网络的客户都允许连接该模块。例如:192.168.0.0/255.255.255.0

    o 一个主机名,客户主机只有拥有该主机名才允许访问,例如:backup.linuxaid.com.cn。


    o *.linuxaid.com.cn,所有属于该域的主机都允许。

    默认是允许所有主机连接。

    hosts deny

    指定不允许连接rsync服务器的机器,可以使用hosts allow的定义方式来进行定义。默认是没有hosts deny定义。

    ignore errors

    指定rsyncd在判断是否运行传输时的删除操作时忽略server上的IP错误,一般来说rsync在出现IO错误时将将跳过--delete操作,以防止因为暂时的资源不足或其它IO错误导致的严重问题。

    ignore nonreadable

    指定rysnc服务器完全忽略那些用户没有访问权限的文件。这对于在需要备份的目录中有些文件是不应该被备份者得到的情况是有意义的。

    transfer logging

    使rsync服务器使用ftp格式的文件来记录下载和上载操作在自己单独的日志中。

    log format

    通过该选项用户在使用transfer logging可以自己定制日志文件的字段。其格式是一个包含格式定义符的字符串,可以使用的格式定义符如下所示:

    o %h 远程主机名

    o %a 远程IP地址

    o %l 文件长度字符数

    o %p 该次rsync会话的进程id

    o %o 操作类型:"send"或"recv"

    o %f 文件名

    o %P 模块路径

    o %m 模块名

    o %t 当前时间

    o %u 认证的用户名(匿名时是null)

    o %b 实际传输的字节数

    o %c 当发送文件时,该字段记录该文件的校验码

    默认log格式为:"%o %h [%a] %m (%u) %f %l",一般来说,在每行的头上会添加"%t [%p] "。在源代码中同时发布有一个叫rsyncstats的perl脚本程序来统计这种格式的日志文件。

    timeout

    通过该选项可以覆盖客户指定的IP超时时间。通过该选项可以确保rsync服务器不会永远等待一个崩溃的客户。超时单位为秒钟,0表示没有超时定义,这也是默认值。对于匿名rsync服务器来说,一个理想的数字是600。

    refuse options

    通过该选项可以定义一些不允许客户对该模块使用的命令参数列表。这里必须使用命令全名,而不能是简称。但发生拒绝某个命令的情况时服务器将报告错误信息然后退出。如果要防止使用压缩,应该是:"dont compress = *"。

    dont compress

    用来指定那些不进行压缩处理再传输的文件,默认值是

    *.gz *.tgz *.zip *.z *.rpm *.deb *.iso *.bz2 *.tbz

    rsync客户命令

    在对rsync服务器配置结束以后,下一步就需要在客户端发出rsync命令来实现将服务器端的文件备份到客户端来。rsync是一个功能非常强大的工具,其命令也有很多功能特色选项,我们下面就对它的选项一一进行分析说明。

    首先,rsync的命令格式可以为:

    rsync [OPTION]... SRC [SRC]... [USER@]HOST:DEST

    rsync [OPTION]... [USER@]HOST:SRC DEST

    rsync [OPTION]... SRC [SRC]... DEST

    rsync [OPTION]... [USER@]HOST::SRC [DEST]

    rsync [OPTION]... SRC [SRC]... [USER@]HOST::DEST

    rsync [OPTION]... rsync://[USER@]HOST[:PORT]/SRC [DEST]
    rsync有六种不同的工作模式:

    拷贝本地文件;当SRC和DES路径信息都不包含有单个冒号":"分隔符时就启动这种工作模式。

    使用一个远程shell程序(如rsh、ssh)来实现将本地机器的内容拷贝到远程机器。当DST路径地址包含单个冒号":"分隔符时启动该模式。

    使用一个远程shell程序(如rsh、ssh)来实现将远程机器的内容拷贝到本地机器。当SRC地址路径包含单个冒号":"分隔符时启动该模式。

    从远程rsync服务器中拷贝文件到本地机。当SRC路径信息包含"::"分隔符时启动该模式。

    从本地机器拷贝文件到远程rsync服务器中。当DST路径信息包含"::"分隔符时启动该模式。

    列远程机的文件列表。这类似于rsync传输,不过只要在命令中省略掉本地机信息即可。

    1、用法

    在使用rsync传输文件时,需要指定一个源和一个目的,其中一个可能是远程机器的资源信息。例如:

    rsync *.c foo:src/

    表示将传输当前目录下所有以.c结尾的文件到机器foo的src目录下。如果任何文件已经存在于远程系统,则会调用远程更新协议来实现仅仅传输那些更新过的文件。

    rsync -avz foo:src/bar /data/tmp

    该命令则递归地传输机器foo上的src/bar目录下的所有内容到本地/data/tmp/bar目录中。文件以归档模式进行传输,以确保符号链结、属性、权限、属主等信息在传输中都被保存。此外,可以使用压缩技术来加快数据传输:

    rsync -avz foo:src/bar/ /data/tmp

    路径信息以"/"结尾时表示拷贝该目录,而不以"/"结尾表示拷贝该目录。当配合使用--delete选项时这两种情况的区别将会表现出来。

    也可以以本地模式来使用rsync,如果SRC和DST路径中都没有任何":"符号则表示该命令运行在本地模式,等同于cp命令。

    rsync somehost.mydomain.com::

    这种模式则将会列出somehost.mydomain.com.可以访问的所有模块信息。

    选项说明

    -v, --verbose 详细模式输出
    -q, --quiet 精简输出模式
    -c, --checksum 打开校验开关,强制对文件传输进行校验
    -a, --archive 归档模式,表示以递归方式传输文件,并保持所有文件属性,等于-rlptgoD
    -r, --recursive 对子目录以递归模式处理
    -R, --relative 使用相对路径信息

    rsync foo/bar/foo.c remote:/tmp/

    则在/tmp目录下创建foo.c文件,而如果使用-R参数:

    rsync -R foo/bar/foo.c remote:/tmp/

    则会创建文件/tmp/foo/bar/foo.c,也就是会保持完全路径信息。

    -b, --backup 创建备份,也就是对于目的已经存在有同样的文件名时,将老的文件重新命名为~filename。可以使用--suffix选项来指定不同的备份文件前缀。
    --backup-dir 将备份文件(如~filename)存放在在目录下。
    -suffix=SUFFIX 定义备份文件前缀
    -u, --update 仅仅进行更新,也就是跳过所有已经存在于DST,并且文件时间晚于要备份的文件。(不覆盖更新的文件)
    -l, --links 保留软链结
    -L, --copy-links 想对待常规文件一样处理软链结
    --copy-unsafe-links 仅仅拷贝指向SRC路径目录树以外的链结
    --safe-links 忽略指向SRC路径目录树以外的链结
    -H, --hard-links 保留硬链结
    -p, --perms 保持文件权限
    -o, --owner 保持文件属主信息
    -g, --group 保持文件属组信息
    -D, --devices 保持设备文件信息
    -t, --times 保持文件时间信息
    -S, --sparse 对稀疏文件进行特殊处理以节省DST的空间
    -n, --dry-run现实哪些文件将被传输
    -W, --whole-file 拷贝文件,不进行增量检测
    -x, --one-file-system 不要跨越文件系统边界
    -B, --block-size=SIZE 检验算法使用的块尺寸,默认是700字节
    -e, --rsh=COMMAND 指定替代rsh的shell程序
    --rsync-path=PATH 指定远程服务器上的rsync命令所在路径信息
    -C, --cvs-exclude 使用和CVS一样的方法自动忽略文件,用来排除那些不希望传输的文件
    --existing 仅仅更新那些已经存在于DST的文件,而不备份那些新创建的文件
    --delete 删除那些DST中SRC没有的文件
    --delete-excluded 同样删除接收端那些被该选项指定排除的文件
    --delete-after 传输结束以后再删除
    --ignore-errors 及时出现IO错误也进行删除
    --max-delete=NUM 最多删除NUM个文件
    --partial 保留那些因故没有完全传输的文件,以是加快随后的再次传输
    --force 强制删除目录,即使不为空
    --numeric-ids 不将数字的用户和组ID匹配为用户名和组名
    --timeout=TIME IP超时时间,单位为秒
    -I, --ignore-times 不跳过那些有同样的时间和长度的文件
    --size-only 当决定是否要备份文件时,仅仅察看文件大小而不考虑文件时间
    --modify-window=NUM 决定文件是否时间相同时使用的时间戳窗口,默认为0
    -T --temp-dir=DIR 在DIR中创建临时文件
    --compare-dest=DIR 同样比较DIR中的文件来决定是否需要备份
    -P 等同于 --partial
    --progress 显示备份过程
    -z, --compress 对备份的文件在传输时进行压缩处理
    --exclude=PATTERN 指定排除不需要传输的文件模式
    --include=PATTERN 指定不排除而需要传输的文件模式
    --exclude-from=FILE 排除FILE中指定模式的文件
    --include-from=FILE 不排除FILE指定模式匹配的文件
    --version 打印版本信息
    --address 绑定到特定的地址
    --config=FILE 指定其他的配置文件,不使用默认的rsyncd.conf文件
    --port=PORT 指定其他的rsync服务端口
    --blocking-io 对远程shell使用阻塞IO
    -stats 给出某些文件的传输状态
    --progress 在传输时现实传输过程
    --log-format=FORMAT 指定日志文件格式
    --password-file=FILE 从FILE中得到密码
    --bwlimit=KBPS 限制I/O带宽,KBytes per second
    -h, --help 显示帮助信息

    实例分析

    这里假设有两台服务器:A和B。其中A是主web服务器,具有域名),B服务器是备份机,其域名为backup.linuxaid.com.cn(202.99.11.121)。其中A的web内容存放在以下几个地方:/www/和/home/web_user1/和/home/web_user2/。我们需要在备份机B上建立对这几个目录内容的备份。

    服务器配置实例

    那么在上创建rsyncd的配置文件/etc/rsyncd.conf,内容如下:

    uid = nobody
    gid = nobody
    use chroot = no
    max connections = 4
    pid file = /var/run/rsyncd.pid
    lock file = /var/run/rsync.lock
    log file = /var/log/rsyncd.log

    [www]
    path = /www/
    ignore errors
    read only = true
    list = false
    hosts allow = 202.99.11.121
    hosts deny = 0.0.0.0/32
    auth users = backup
    secrets file = /etc/backserver.pas

    [web_user1]
    path = /home/web_user1/
    ignore errors
    read only = true
    list = false
    hosts allow = 202.99.11.121
    hosts deny = 0.0.0.0/32
    uid = web_user1
    gid = web_user1
    auth users = backup
    secrets file = /etc/backserver.pas

    [web_user2]
    path = /home/web_user2/
    ignore errors
    read only = true
    list = false
    hosts allow = 202.99.11.121
    hosts deny = 0.0.0.0/32
    uid = web_user2
    gid = web_user2
    auth users = backup
    secrets file = /etc/backserver.pas

    这里定义有四个三个模块,分别对应于三个需要备份的目录树。这里只允许202.99.11.121备份本机的数据,并且需要认证。三个模块授权的备份用户都为backup,并且用户信息保存在文件/etc/backserver.pas中,其内容如下:

    backup:bk_passwd

    并且该文件只能是root用户可读写的,否则rsyncd启动时会出错。这些文件配置完毕以后,就需要在A服务器上启动rsyncd服务器:

    rsync --daemon

    客户命令示例

    /usr/local/bin/rsync -vzrtopg --delete --exclude "logs/" --exclude "conf/ssl.*/" --progress /backup/www/ --password-file=/etc/rsync.pass

    上面这个命令行中-vzrtopg里的v是verbose,z是压缩,r是recursive,topg都是保持文件原有属性如属主、时间的参数。--progress是指显示出详细的进度情况,--delete是指如果服务器端删除了这一文件,那么客户端也相应把文件删除,保持真正的一致。--exclude "logs/" 表示不对/www/logs目录下的文件进行备份。--exclude "conf/ssl.*/"表示不对/www/conf/ssl.*/目录下的文件进行备份。

    表示对该命令是对服务器202.99.11.120中的www模块进行备份,backup表示使用backup来对该模块进行备份。

    --password-file=/etc/rsync.pass来指定密码文件,这样就可以在脚本中使用而无需交互式地输入验证密码了,这里需要注意的是这份密码文件权限属性要设得只有root可读。

    这里将备份的内容存放在备份机的/backup/www/目录下。

    [root@linuxaid /]# /usr/local/bin/rsync -vzrtopg --delete --exclude "logs/" --exclude "conf/ssl.*/" --progress /backup/www/ --password-file=/etc/rsync.pass
    receiving file list ... done
    ./
    1
    785 (100%)
    1.py
    4086 (100%)
    2.py
    10680 (100%)
    a
    0 (100%)
    ip
    3956 (100%)
    ./
    wrote 2900 bytes read 145499 bytes 576.34 bytes/sec
    total size is 2374927 speedup is 45.34

    对其它两个模块操作的命令分别为:

    /usr/local/bin/rsync -vzrtopg --delete --progress /backup/web_user1/ --password-file=/etc/rsync.pass

    /usr/local/bin/rsync -vzrtopg --delete --progress /backup/web_user2/ --password-file=/etc/rsync.pass

    可以将客户命令通过crontab -e命令来实现自动备份,如crontab -e:

    一些示例脚本

    这里这些脚本都是rsync网站上的例子:

    1、每隔七天将数据往中心服务器做增量备份

    #!/bin/sh

    # This script does personal backups to a rsync backup server. You will end up
    # with a 7 day rotating incremental backup. The incrementals will go
    # into subdirectories named after the day of the week, and the current
    # full backup goes into a directory called "current"
    #

    # directory to backup
    BDIR=/home/$USER

    # excludes file - this contains a wildcard pattern per line of files to exclude
    EXCLUDES=$HOME/cron/excludes

    # the name of the backup machine
    BSERVER=owl

    # your password on the backup server
    export RSYNC_PASSWORD=XXXXXX


    ########################################################################

    BACKUPDIR=`date +%A`
    OPTS="--force --ignore-errors --delete-excluded --exclude-from=$EXCLUDES
    --delete --backup --backup-dir=/$BACKUPDIR -a"

    export PATH=$PATH:/bin:/usr/bin:/usr/local/bin

    # the following line clears the last weeks incremental directory
    [ -d $HOME/emptydir ]@# @#mkdir $HOME/emptydir
    rsync --delete -a $HOME/emptydir/ $BSERVER::$USER/$BACKUPDIR/
    rmdir $HOME/emptydir

    # now the actual transfer
    rsync $OPTS $BDIR $BSERVER::$USER/current

    2、备份至一个空闲的硬盘

    #!/bin/sh

    export PATH=/usr/local/bin:/usr/bin:/bin

    LIST="rootfs usr data data2"

    for d in $LIST; do
    mount /backup/$d
    rsync -ax --exclude fstab --delete /$d/ /backup/$d/
    umount /backup/$d
    done

    DAY=`date "+%A"`

    rsync -a --delete /usr/local/apache /data2/backups/$DAY
    rsync -a --delete /data/solid /data2/backups/$DAY

    3、对vger.rutgers.edu的cvs树进行镜像

    #!/bin/bash

    cd /var/www/cvs/vger/
    PATH=/usr/local/bin:/usr/freeware/bin:/usr/bin:/bin

    RUN=`lps x | grep rsync | grep -v grep | wc -l`
    if [ "$RUN" -gt 0 ]; then
    echo already running
    exit 1
    fi

    rsync -az vger.rutgers.edu::cvs/CVSROOT/ChangeLog $HOME/ChangeLog

    sum1=`sum $HOME/ChangeLog`
    sum2=`sum /var/www/cvs/vger/CVSROOT/ChangeLog`

    if [ "$sum1" = "$sum2" ]; then
    echo nothing to do
    exit 0
    fi

    rsync -az --delete --force vger.rutgers.edu::cvs/ /var/www/cvs/vger/
    exit 0

    FAQ

    Q:如何通过ssh进行rsync,而且无须输入密码?
    A:可以通过以下几个步骤

    1. 通过ssh-keygen在server A上建立SSH keys,不要指定密码,你会在~/.ssh下看到identity和identity.pub文件
    2. 在server B上的home目录建立子目录.ssh
    3. 将A的identity.pub拷贝到server B上
    4. 将identity.pub加到~[user b]/.ssh/authorized_keys
    5. 于是server A上的A用户,可通过下面命令以用户B ssh到server B上了
    e.g. ssh -l userB serverB
    这样就使server A上的用户A就可以ssh以用户B的身份无需密码登陆到server B上了。

    Q:如何通过在不危害安全的情况下通过防火墙使用rsync?
    A:解答如下:

    这通常有两种情况,一种是服务器在防火墙内,一种是服务器在防火墙外。无论哪种情况,通常还是使用ssh,这时最好新建一个备份用户,并且配置sshd仅允许这个用户通过RSA认证方式进入。 如果服务器在防火墙内,则最好限定客户端的IP地址,拒绝其它所有连接。如果客户机在防火墙内,则可以简单允许防火墙打开TCP端口22的ssh外发连接就ok了。

    Q:我能将更改过或者删除的文件也备份上来吗?
    A:当然可以:

    你可以使用如:rsync -other -options -backupdir = ./backup-2000-2-13 ...这样的命令来实现。
    这样如果源文件:/path/to/some/file.c改变了,那么旧的文件就会被移到./backup-2000-2-13/path/to/some/file.c,
    这里这个目录需要自己手工建立起来

    Q:我需要在防火墙上开放哪些端口以适应rsync?
    A:视情况而定

    rsync可以直接通过873端口的tcp连接传文件,也可以通过22端口的ssh来进行文件传递,但你也可以通过下列命令改变它的端口:

    rsync --port 8730 otherhost::
    或者
    rsync -e @#ssh -p 2002@# otherhost:

    Q:我如何通过rsync只复制目录结构,忽略掉文件呢?
    A:rsync -av --include @#*/@# --exclude @#*@# source-dir dest-dir

    Q:为什么我总会出现"Read-only file system"的错误呢?
    A:看看是否忘了设"read only = no"了

    Q:为什么我会出现: invalid gid@#的错误呢?
    A:rsync使用时默认是用uid=nobody;gid=nobody来运行的,如果你的系统不存在nobody组的话,就会出现这样的错误,可以试试gid = nogroup或者其它

    Q:绑定端口873失败是怎么回事?
    A:如果你不是以root权限运行这一守护进程的话,因为1024端口以下是特权端口,会出现这样的错误。你可以用--port参数来改变。

    Q:为什么我认证失败?
    A:从你的命令行看来:

    你用的是:
    > bash$ rsync -a 144.16.251.213::test test
    > Password:
    > @ERROR: auth failed on module test
    >
    > I dont understand this. Can somebody explain as to how to acomplish this.
    > All suggestions are welcome.

    应该是没有以你的用户名登陆导致的问题,试试rsync -a test

    July 10

    事件驱动的理解

    1 我对事件驱动的理解  
    2 作者:axgle  
    3  
    4 引子  
    5  
    6 “事件驱动”这四个字,我是在学习javascript过程中遇到的,例如"onclick事件".  
    7 后来学习visual Basic,也遇到了这四个字----“事件驱动”。  
    8 再后来了解.net以及学习flash脚本语言的过程中,也遇到过...  
    9 甚至在PHP的一个blog程序,名叫wordpress的插件机制中,也见到了“事件驱动”的影子.  
    10 终于,在一个下雨的傍晚,我坐在窗前,双手托住下巴,开始思索“事件驱动到底是什么,为什么要使用事件驱动,以及如何建立事件驱动机制”的问题。  
    11  
    12  
    13 一.事件驱动到底是什么意思?  
    14  
    15 无论是javascript,还是visual Basic,无论是.net系列,还是java语言。。。无论是面向过程也好,面向对象也罢,其共有  
    16 的一个语法结构就是“IF语句”,也叫“条件语句”。其最基本的形式可以表示为“if A then B”.  
    17  
    18 我把“if A then B”语句中的A称呼为‘条件’,而把B称呼为“结果”,希望你不要反对:)  
    19 “如果你反对,那么我誓死捍卫你说话的权利”----你看,条件语句是多么容易出现的事情啊~  
    20  
    21 我把“if A then B”语句中的A称呼为‘事件’,而把B称呼为“响应”,希望你也不要反对:)  
    22 “如果你反对,那么我将煽你一耳光”----其中,‘你反对’是一个事件,而“我将煽你一耳光”是我对该事件作出的“响应”.  
    23  
    24 你看,axgle真是个‘莫名其妙,变化多端’的人,他一会儿'誓死捍卫你说话的权利',一会儿又要"煽你一耳光",真搞不懂他的变化为什么如此的快。  
    25 虽然这里的axgle比较“变态”,但这里也包含了“不变”的成分:一.事件"你反对"常常容易遇到,可以认为是“不变的”;二.if-then的“逻辑关系”是确定的,  
    26 也就是说,"if""then"两者的关系是确定的。简单的说,这里的“事件”和“逻辑关系”是"不变"的。  
    27  
    28 让我们用上面的观点来分析"onclick事件",也就是“鼠标单击”事件:  
    29  
    30 “如果用户用鼠标单击,那么就显示菜单的详细列表”。你看,这里的“鼠标单击”在“如果”里,而后面的“显示菜单的详细列表”是对这个事件的  
    31 “响应”。  
    32 “如果鼠标单击关闭按钮,那么就关机”。你看,这里又有一个“鼠标单击”事件,是不是?可见,“哪里有'如果',哪里就有'事件'”  
    33 “如果鼠标单击关闭按钮,那么就弹出一个新窗口并且给个提示”,你看,同样的“事件”,“响应”却可以有所不同(因为不同的程序员,不同的设计,不同的需求等等)。  
    34  
    35 但无论如何,鼠标单击总是常常遇到的,而鼠标单击与其后的响应之间的“逻辑关系”也是确定的。  
    36 “如果用户进行无数次鼠标单击,那么依然不出现任何反应”。妈的,什么破玩意,靠,是不是死机了??  
    37 可见,就算是“死机”,那也是一种“响应”,只不过是让人讨厌的“响应”而已。但无论如何,这里的"if-then"的逻辑结构是不变的。  
    38 也许,黑客就比较喜欢这一点,因为他想把你的机器搞死。哈哈  
    39  
    40 可见,事件驱动就是“在保持事件及其逻辑关系不变的情况下,根据需要定义事件的响应的机制”。  
    41 其中,'事件'可以用event来表示,'事件的响应'可以用handler来表示,而这里的“逻辑关系”  
    42 是指event和handler两者存在的"If event Then handler"的逻辑关系.  
    43  
    44 二.为什么要使用事件驱动?  
    45  
    46 事件驱动的特点在于“不变与万变”的有机结合。对于给定的“If event Then handler”,实际上包含三个元素:  
    47 1.事件(event);2.响应(handler);3.事件与响应的“逻辑关系”  
    48 其中的'事件'常常是固定的;而“逻辑关系”往往体现的是业务规则或者核心逻辑,也常常是固定不变的。  
    49 只有'响应'是可变的,或者说是可以配置或者需要改变的。  
    50  
    51 软件开发的OCP原则告诉我们:“软件应该对修改关闭,但要对扩展开放”。而事件驱动就是在保持了事件和核心逻辑的稳定性和不被修改  
    52 的前提下,通过定义不同的“响应”从而达到了对“扩展的开放”。  
    53  
    54 因此,事件驱动机制是一种可重用和可扩展性比较强的机制。  
    55  
    56 以上就是理论上的证明。下面有必要进一步“普遍化”:在结构控制方面,顺序,选择(即条件),循环三种结构,理论上都可以用选择结构来理解。  
    57 例如顺序结构,“语句A;语句B;语句C”,按照人类的理解,可以用"如果A出现后,就出现B;如果B出现后,就出现C".  
    58 又如循环结构,依然可以用if-then的语句来描述,这里从略。  
    59  
    60 换句话说,在人类看来,任何程序语句,都可以看作是条件语句。因此,‘事件’在程序中便无处不在,无时不有。这就是“事件驱动的普适性”。  
    61  
    62 因为“事件驱动的普适性”,所以任何程序语言在理论上都可以建立“事件驱动的机制”。  
    63  
    64 事件驱动的机制由于把“响应”作为应付变化的要素,同时保持了“事件和逻辑关系”的稳定性,从而为程序的维护与扩展打下了良好的基础。  
    65  
    66 三.如何建立事件驱动的机制?  
    67  
    68 在面向对象或者基于对象的程序语言中,常常已经建立了明确的事件驱动的机制,例如.net系列或者javascript等等。那么这些语言的内部到底是如何运作的呢?  
    69 我们可以用C语言或者PHP这些没有明显的“事件驱动机制”的语言说起。  
    70  
    71 “回调函数(callback)”可以说是面向过程语言建立‘事件驱动机制’的基础;同样,回调(CALLBACK)的概念也可以解释面向对象语言的"事件驱动"的内部过程。  
    72 你可以在网上搜索"回调函数",看看它是什么意思。下面简单的给一个php的例子.  
    73  
    74 我们知道,php处理错误,调试程序有一个函数,叫做set_error_handler,其原型如下:  
    75 set_error_handler ( callback_error_handler [, int error_types] )  
    76 其中重要的是第一个参数,callback_error_handler,它表示“当php出错的时候,将要调用的自定义的函数名”。  
    77 这样,我们自定义一个函数test_callback(),然后把这个函数的名字test_callback传递给set_error_handler,那么当php出错的时候,test_callback就会执行。  
    78  
    79 这里可以看出其中隐含的‘事件驱动机制’:‘出错’是一个‘事件’,而test_callback()是一种'响应'。通过使用set_error_handler,建立了两者的逻辑关系。  
    80 而这里set_error_handler,本质上就是使用了所谓的"回调函数"的概念。  
    81  
    82 执行php中的回调函数一般使用的是"call_user_func_array或者call_user_method_array"等等,具体你可以查阅手册,看看它们的作用。其他语言例如c语言也有  
    83 回调函数的概念,具体情况请查阅相关资料。  
    84  
    85 因为事件驱动的机制把“响应”作为应付变化的要素,同时保持“事件和逻辑关系”的稳定性,所以'响应'常常是自定义的。  
    86 一个响应常常表现为一个函数,在一段程序中,当事件出现后,就用回调函数的方式调用响应函数,这样,我们只需要修改响应函数,而事件和程序的逻辑关系却可以  
    87 保持稳定,同时把响应独立了出来,作为了可变化和修改的独立部分。  
    88  
    89 考虑如下情形:  
    90 test_callback();语句1;语句2;语句3;...call_user_func('test_callback');...语句N  
    91 注意,其中的语句1到语句N是核心逻辑,所以这些语句的‘位置’是不能修改的,而test_callback部分则是可以自定义的。那么为什么要使用call_user_func('test_callback')  
    92 而不是直接执行test_callback()呢?  
    93  
    94 假如直接执行test_callback(),那么test_callback函数必须是“已定义的函数”。正是因为要在特定的位置执行“未定义的响应函数”,所以才需要使用“回调函数”的方式。  
    95  
    96 把事件后面的响应函数提到前面定义,当事件发生后,就执行回调,也就是执行响应函数。这就是建立事件驱动机制的一般方法。  
    97  
    98 说到这里,也许你还是不明白为什么非要使用回调函数。你可以设想如下情形:  
    99  
    100 function call_user_func(function_name){  
    101   if( function_name函数存在 ) 则执行function_name  
    102 }  
    103  
    104 上面定义的call_user_func回调函数的方式,可以预先检查响应函数是否定义或者是否存在,然后才考虑是否执行以及如何执行,这样就不会出现“函数没有定义”的语法错误。  
    105 并且,使用回调函数的方式,你还可以建立“增加新的回调,删除已有的回调,修改当前的回调,查询所有的回调函数”等等“回调操作”的功能。  
    106  
    107 有兴趣的朋友,可以研究一下php中wordpress程序里的插件机制,主要的几个函数为"add_action,do_action,add_filter...等等".这几个函数,就是wordpress建立  
    108 的回调操作函数,其在整个wordpress中的具体应用,体现的就是这里的事件驱动机制。  
    109  
    110  
    111 以上就是面向过程语言(例如php)建立事件驱动机制的办法。而在面向对象的语言中,依然靠的是回调的方式,只不过传递的不是‘回调函数名’,而是传递的类名,而类中其实  
    112 已经绑定了方法(本质上依然是函数)。因此可以说面向对象的语言依然使用的是回调函数的方式建立的事件驱动的机制。  
    113  
    114  
    115 结语:  
    116  
    117 事件驱动依照“事件-响应”的模式,通过回调的方式执行自定义的响应函数,保持了事件和程序逻辑的稳定性和扩展的开放性,从而为程序的开发和维护提供了有力的帮助。 
    July 04

    定时开机,关机的八个方法

    “你会开机吗?”如果笔者问大家这样的问题,想必会引来一大堆的臭鸡蛋。不过笔者现在是要问“你知道有几种开机方法?”想必没有多少人能完全回答上来。因为除了接上电源,按下主机面板的电源开关进行开机外,还有八种开机方法。如果你不相信的话,就跟着笔者所使用的美达S845E主板来试验一下吧!
      第一招:定时开机  现在大多数人的电脑均可支持定时开机功能。比如笔者每天是8:30上班,设定为每天8:30定时开机之后,只要上班的时间一到就会自动开启电脑。呵呵,这样是不是很方便呀?
      实现条件:首先确认你所使用的电源为ATX电源,然后再查看CMOS设置当中是否有“Resume by Alarm”、“RTC Alarm Resume”或类似的选项(不同的主板,此选项与设置值可能有所不同)。
      实现步骤:开机自检后按“Del”键进入CMOS设置。在主菜单中,进入“Power Management Setup”(电源管理设置)菜单,将“Resume by Alarm”选项设置成“Enabled”,如图1所示。这时下面的“Date(of Month) Alarm”子选项和“Time(hh:mm:ss) Alarm”子选项将激活成高亮显示,也就是可设置的状态。接着用方向键选择到“Date(of Month) Alarm”子选项,此选项一般不用设置,而直接采用默认值“0”,表示每天都适用。如果你不想系统在每天都定时开机,也可以自定义在哪一天启动。再用方向键移动到“Time(hh:mm:ss) Alarm”子选项,通过“Page UP”键或“Page Down”键设置系统在什么时间启动,格式为“时:分:秒”,此时间是以系统时钟为准。最后按“ESC”键退出此菜单,再选择“Save & Quit Setup”菜单(或按“F10”键)并按回车键保存并退出CMOS设置即可。下次关机时只要不断开电源,即可定时开机了。
      第二招:密码开机  热键开机跟在CMOS设置当中设定“Set Supervisor Password(设置超级用户密码)”或“Set User Password(设置用户密码)”是不一样的。前者是ATX电源激活的状态下,不需要按主机前面板的电源开关,就可以直接通过密码开机;后者是必须按主机前面板的电源开关,然后输入“Set Supervisor Password”或“Set User Password”密码进行开机。
      实现条件:要实现热键开机前,必须检查所用的ATX电源的5V待命电流不小于300mA,然后再查看CMOS设置当中是否有“POWER ON Function”、“Keyboard/Mouse Power On”或类似的选项(不同的主板,此选项与设置值可能有所不同)。
      实现步骤:开机自检后按“Del”键进入CMOS设置。在主菜单中,进入“Integrated Peripherals”菜单,将“POWER ON Function”选项设置成 “Password”(如图2所示)。这时下面的“KB Power ON Password”子选项将激活成高亮显示,也就是可设置的状态。用方向键移动到“KB Power ON Password”子选项,并按下回车键。这时输入密码即可,此热键仅限字母键区的26个英文字母和0-9阿拉伯数字,以及数字键区的0-9阿拉伯数字。最后按“ESC”键退出此菜单,再选择“Save & Quit Setup”菜单(或按“F10”键)并按回车键保存并退出CMOS设置即可。下次关机时只要不断开电源,输入之前设置的密码就可以开机了。
     第三招:热键开机  热键开机与密码开机有所不同,热键开机可设定为PS/2键盘的任意键开机或组合键开机。
      实现条件:与“密码开机”小节相同。
      实现步骤:开机自检后按“Del”键进入CMOS设置。在主菜单中,进入“Integrated Peripherals”菜单,将“POWER ON Function”选项设置成“Hot KEY”(热键)或“Any KEY”(任意键),如图3所示。如果选择“Hot KEY”,这时下面的“Hot Key Power On”子选项将激活成高亮显示,用方向键移动到“Hot Key Power On”子选项,将其设置成“Ctrl-F1”~“Ctrl-F12”其中一项;如果选择“Any KEY”,则可以通过任意键来激活电源。最后按“ESC”键退出此菜单,再选择“Save & Quit Setup”菜单(或按“F10”键)并按回车键保存并退出CMOS设置即可。下次关机时只要不断开电源,输入之前设置热键就可以开机了。
      第四招:鼠标开机  很少人听说通过PS/2鼠标也可以开机的吧?其实实现起来很容易,步骤与热键开机是差不多的。
      实现条件:与“密码开机”小节相同。
      实现步骤:开机自检后按“Del”键进入CMOS设置。在主菜单中,进入“Integrated Peripherals”菜单,将“POWER ON Function”选项设置成“Mouse Left”(鼠标左键)或“Mouse Right”(鼠标右键),如图4所示。最后按“ESC”键退出此菜单,再选择“Save & Quit Setup”菜单(或按“F10”键)并按回车键保存并退出CMOS设置即可。下次关机时只要不断开电源,即可通过鼠标左键或鼠标右键开机了。
      小提示:有些主板上还可能提供有启用热键开机和鼠标开机的跳线,如果有的话,必须设置为启用状态。
     第五招:通电自动开机  这次开机方式算是另类的,只要接通主机电源,电脑就自动开机了,而不用按主机前面板的电源开关。
      实现条件:首先确认你所使用的电源为ATX电源,然后再查看CMOS设置当中是否有“Soft-Off by PWR-BTTN”、“System After AC Back”或类似的选项(不同的主板,此选项与设置值可能有所不同)。
      实现步骤:开机自检后按“Del”键进入CMOS设置。在主菜单中,进入“Power Management Setup”菜单,将“Soft-Off by PWR-BTTN”选项设置成“Instant-On”(笔者这块主板无法设置成此项目),如图5所示。最后按“ESC”键退出此菜单,再选择“Save & Quit Setup”菜单(或按“F10”键)并按回车键保存并退出CMOS设置即可。以后只要连接电源(如果机箱后方的电源供应器有开关的话,也可以通过此开关进行开机)即可开机。而一般在正常情形下,电源供应器应在激活前方电源开关才可开机。
      小提示:有些主板接电后需再次激活电源   有些主板(比如:华硕P2B主板)就算你设置好上述设置后,下次接上电源后,计算机会激活约2秒钟,也就是电源灯会亮起一下子,之后必须再按下电源开关,才会正式启动计算机。这是因为华硕P2B主板是可以让计算机拥有服务主机的功能,也可以手动地关掉这个功能。在华硕P2B主板的AGP插槽稍上方,可以看到一个三脚跳线,在这个跳线旁边可以看到R27A、R27B的字样,当短接2、3脚时,则表示电源来时自动开机,短接1、2脚时,则是一般模式。
      第六招:来电开机  “只听说来电显示,还没听说来电开机。”这可能有很多人心中的疑问。的确,现在的电脑基本都可以实现来电开机,只不过大家平时没有用上这功能而已。我们甚至可以在办公室里,利用来电开机功能打开自己家里的计算机并且下载所需要的文件,然后再关闭家里的计算机。也许你还不相信计算机会如此智能化吧?不信的话就跟我一起来试试!当然,这也要一些设置和硬件上的配合才能完成这样的工作。
      实现条件:首先确认你所使用的ATX电源的5V待命电流不小于800mA,然后检查主板上是否提供有WOR(Wake Up on Ring,响铃唤醒)插针(如图6所示),接着再查看CMOS设置当中是否有“Wake-Up by Ring/LAN”或类似的网络唤醒功能选项(不同的主板,此选项与设置值可能有所不同),再下来确认Modem是否具有响铃唤醒功能(我们可以从Modem是否提供WOR接口得知),最后还要买一根二针的WOR连接线,将主板的WOR插针(具体位置请参考主板说明书)与Modem的WOR接口相连接。这五个条件缺一不可。
      实现步骤:开机自检后按“Del”键进入CMOS设置。在主菜单中,进入“Power Management Setup”菜单,将“Wake-Up by Ring/LAN”(由振铃声或网卡唤醒)选项设置成“Enabled”,如图7所示。然后再用方向键移动到“Wake-Up By PCI card”选项,设置成“Enabled”。最后按“ESC”键退出此菜单,再选择“Save & Quit Setup”菜单(或按“F10”键)并按回车键保存并退出CMOS设置即可。
      要实现这个功能,必须保证Modem必须接上电话线,而且不能切断Modem电源和主机电源。以后只要给家里打个电话,主机电源就会自动开启。为了外接成功,还必须有合适的软件在运行(例如:Windows 98的拨号服务器),用户才可以远程访问电脑。
     第七招:网络唤醒开机  对于管理员而言,通过WOL(Wake Up on LAN,网络唤醒)功能可以实现网络远程开机,执行维护任务,再远程关机。也可以自动进行维护工作,极大方便了管理员。
      实现条件:与“来电开机”小节类似,所不同的是将WOR换成WOL。而且WOR接口或连接线是二针,而WOL接口或连接线是三针,如图8所示。
      实现步骤:与“来电开机”小节相同。以后电脑只要在睡眠状态中,通过网络就可以唤配这台电脑。
      小提示:如果你是使用集成网卡或Modem的主板,主板上也已经直接集成了网络唤醒功能,不需要额外的连线。
      第八招:USB键盘开机   最后一种开机方式就是通过USB键盘唤醒开机。没有使用USB键盘的用户可不要眼红了喔^_^
      实现条件:首先确认你所使用的ATX电源的5V待命电流不小于800mA,然后查看CMOS设置当中是否有“USB Controller”和“USB KB Wake-Up From S3”或类似的功能选项(不同的主板,此选项与设置值可能有所不同),最后要确认已连接USB设备。
      实现步骤:开机自检后按“Del”键进入CMOS设置。在主菜单中,进入“Integrated Peripherals”菜单,将“USB Controller”选项设置成“Enabled”,如图9所示。如果你是使用USB键盘,还要将下面的“USB Keyboard Support”选项设置成“Enabled”。
      接着按“ESC”键退回主菜单,进入“Power Management Setup”菜单,将“ACPI Suspend Type”(ACPI待命模式)选项设置成“S3(STR)”或“S1&S3”,如图10所示。这时下面的“USB KB Wake-Up From S3”选项将激活成高亮显示,也就是可设置的状态。将“USB KB Wake-Up From S3”选项设置成“Enabled”。

     

     

     

    定时关机的实现(一次性)

    Windows XP的关机是由Shutdown.exe程序来控制的,位于Windows\System32文件夹中。(如果想让Windows 2000也实现同样的效果,可以把Shutdown.exe复制到系统目录下)

    比如你的电脑要在22:00关机,可以选择“开始→运行”,输入“at 22:00 Shutdown -s”,这样,到了22点电脑就会出现“系统关机”对话框,默认有30秒钟的倒计时并提示你保存工作。

    如果你想以倒计时的方式关机,可以输入“Shutdown.exe -s -t 3600”,这里表示60分钟后自动关机,“3600”的单位默认为秒。

    设置好自动关机后,如果想取消的话,可以在运行中输入“shutdown -a”。

    另外输入“shutdown -i”,则可以打开设置自动关机对话框,对自动关机进行设置。 

    Shutdown.exe的参数,每个都具有特定的用途,执行每一个都会产生不同的效果:

    -s就表示关闭本地计算机

    -a表示取消关机操作

    -f:强行关闭应用程序

    -m \\计算机名:控制远程计算机关闭

    -i:显示图形用户界面,但必须是Shutdown的第一个选项

    -l:注销当前用户

    -r:关机并重启

    -t:时间:设置关机倒计时

    -c "消息内容":输入关机对话框中的消息内容(不能超127个字符)

    这样,定时开机、关机就全部设置完成。

    3、计划定时关机(可重复)

    在步骤2的基础上,单击“开始”—〉“程序”—〉“附件”—〉“系统工具”—〉“计划任务”。这时就打开了“计划任务”窗口。如果步骤2操作正确,这是应当在该窗口中能够看到已经存在一个任务图标。此时,双击这一图标,可以打开该任务的属性——这一任务属性都是灰色显示的,意味着不能修改。

    没关系,双击“添加任务”进入“计划任务”向导。按照提示点击“下一步”后,随便创建一个计划任务。然后,双击该新建好的任务图标。会出现该任务的属性。

    下面就是关键了。这是你的计划任务窗口应该有2个任务图标。把这两个任务图标的属性都打开,其中后面建的那个任务属性是可改动的。共有三个面板(任务、计划、设置)。此时,如实参照不可改的那个任务的属性标志填写新建的(可改的)的那个任务窗口

    ——任务面板中只有“起始于”和“注释”项可自行改动;

    ——计划面板是控制时间的,这个地方你可以填写你希望自动关机执行的周期,比如你希望天天在这个时候实行自动关机,那么周期你就设为每天,上面具体一看就明白了;

    ——设置面板全部设为跟原不可改的那个任务一致。

    至此,可重复的计划关机就完全设置完毕了!

    June 29

    把你的网页装饰为伪静态链接

    <?php
    function mod_rewrite(){
            if(isset($_SERVER['PATH_INFO'])){
                    $url = substr($_SERVER['PATH_INFO'],1);
                    $url = explode('/',$url);
                    foreach ($url as $key =>$value){
                            if($key%2!=1){
                                    if($value!='')$_GET[$value]=$url[$key+1];
                                    $querystring[]=$value.'='.$url[$key+1];
                            }
                    }
                    $_SERVER['QUERY_STRING']=implode("&",$querystring);
                    $_SERVER['PHP_SELF']=substr($_SERVER['PHP_SELF'],0,strpos($_SERVER['PHP_SELF'],'.php')+4);
                    $_SERVER['REQUEST_URI']=$_SERVER['PHP_SELF'].'?'.$_SERVER['QUERY_STRING'];
            }
    }

    mod_rewrite();
    /*例子
    http://qh8.net/test/test.php/a/1/b/2/c/3
    echo '<pre>';
    echo "GET数组如下:<br />";
    print_r($_GET);
    Array
    (
        [a] => 1
        [b] => 2
        [c] => 3
    )
    */


    ?>
    June 27

    APACHE 访问日志统计

    <?php
    /*
    程序:APACHE 访问日志统计
    */
    class myapachelog{
        var $filename;    //日志文件名 完全路径
        function  myapachelog($filename)
        {
      $this->filename=$filename;
        }
        //该函数为格式转换函数,将类似的:$str = "03/Mar/2005:16:53:32"转化为相应的UNIX时间戳。
        function Format2UnixTime ($str)
        {
      $time = $str;
      $time = str_replace("/"," ",$time);
      $time_array = explode( ":",$time,2);
      $time = $time_array[0]." ".$time_array[1];
      return strtotime($time);
        }

        function CompareByTimes ($x,$y)//帮助方法
        {
      if ( $x[0] == $y[0] )
      return 0;
      else if ($x[0] > $y[0])
      return -1;
      else
      return 1;
        }
        function CompareByAccessTime ($x,$y)//帮助方法
        {
      $x[1] = Format2UnixTime($x[1]);  //先格式化为UNIX时间戳
      $y[1] = Format2UnixTime($y[1]); //先格式化为UNIX时间戳
      if ( $x[1] == $y[1] )
      return 0;
      else if ($x[1] > $y[1])
      return -1;
      else
      return 1;
        }
        function mytablestyle(){
      $style=<<<STYLE
      <style type='text/css'>
    .table1 {border-top: #cae0ed solid 1px;}
    .table1 td {   
        height: 16px;
        font-size: 16px;
        border-bottom: #cae0ed solid 1px;
        background-color: expression((this.parentElement.sectionRowIndex%2==0)?'#fff':'#f2f8fb')
    }
    </style>
    STYLE;
      echo $style;
    }
    /*$order为排序方式: 0:按访问次数排序(缺省值) 1:按最近一次访问的时间排序*/
    function GetAccessByLog ($timeformat=1,$order=0)
    {
        $this->mytablestyle();
        if ( file_exists($this->filename) )
        {
      $handle = fopen ($this->filename, "r");
      $ip_times = array();
      while (!feof ($handle)) {//读入日志文件内容
          $buffer = fgets($handle, 999);
          if ((preg_match("#\d{1,2}\/\w{1,3}\/\d{1,4}\:\d{1,2}\:\d{1,2}\:\d{1,2}#",$buffer,$access_time)) && (preg_match("#\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}#",$buffer,$ip)))
          {
        $ip = $ip[0];
        $access_time = $access_time[0];
        $access_time=$this->Format2UnixTime($access_time);
        $access_time=strftime(" %Y-%m-%d %H:%M:%S " ,$access_time);
        if ( in_array($ip,array_keys($ip_times)))
        {
            $ip_times[$ip][0]++;//$ip_times[$ip][0]为访问次数times
            $ip_times[$ip][1]=$access_time;//$ip_times[$ip][1]为访问时间access_time
        }else
        {
            $ip_times[$ip][0] = 1;
            $ip_times[$ip][1]=$access_time;
        }
          }
      }
      fclose ($handle);
        }else
        {
      echo $this->filename;
      echo "<font color=red>日志文件不存在,请检查路径</font>";
      exit;
        }
        if ( $order==1 )
        {
      $compare = "CompareByAccessTime";//按最近一次访问时间排序方法
      $title = "<b>按最近一次访问时间排序</b>";
        }else{
      $compare = "CompareByTimes"; //按访问次数排序方法
      $title = "<b>按访问次数排序</b>";
        }
        //sort($ip);
        //uasort( $ip_times, $compare );
        echo $title;
        echo "<table class=table1><tr><td>IP</td><td><b><font color=green>访问次数</font></b></td><td>最近一次访问时间</td></tr>";
        foreach (  $ip_times as $ip=>$value )
        {
      echo "<tr><td>".$ip."</TD><TD><b><font color=green>".$value[0]."</font></b></TD><TD>".$value[1]."</TD></TR>";
        }
        echo "</table>";
    }
    //查看部分日志记录 //从start到end去件的记录
    function GetAccessByLogPart ($start,$end) //$start开始 $end结束
    {
        $this->mytablestyle();
        if ( file_exists($this->filename) )
        {
      $handle = fopen ($this->filename, "r");
      $ip_times = array();
      $i=0;
      echo $start."---".$end;
      echo "<table  class=table1><tr><td>编号</td><td>访问时间</td><td>来访者IP</td></tr>";
      while (!feof ($handle)) {//读入日志文件内容
          $i++;
          $buffer = fgets($handle, 999);   
          if($i>$start&&$i<$end)    {   
          echo "<tr>";
          if ((preg_match("#\d{1,2}\/\w{1,3}\/\d{1,4}\:\d{1,2}\:\d{1,2}\:\d{1,2}#",$buffer,$access_time)) && (preg_match("#\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}#",$buffer,$ip)))
          {
        $ip = $ip[0];
        $access_time = $access_time[0];
        $access_time=$this->Format2UnixTime($access_time);
        $access_time=strftime(" %Y-%m-%d %H:%M:%S " ,$access_time);   
            echo "<td>".($i)."</td>";//$ip_times[$ip][0]为访问次数times
            echo "<td>".$ip_times[$ip][1]=$access_time;//$ip_times[$ip][1]为访问时间access_time
            echo "</td><td>$ip</td>";   
          }
          echo "</tr>";
          }
      }
      echo "</table>";
      fclose ($handle);
        }else
        {
      echo $this->filename;
      echo "<font color=red>日志文件不存在,请检查路径</font>";
      exit;
        }
    }
    //从$start时间到$end时间的记录
    function GetAccessByLogPart_Bytime ($start,$end) //根据访问时间
    {
        $this->mytablestyle();
        if ( file_exists($this->filename) )
        {
      $handle = fopen ($this->filename, "r");
      $ip_times = array();
      $i=0;
      echo $start."---".$end;
      echo "<table  class=table1><tr><td>编号</td><td>访问时间</td><td>来访者IP</td></tr>";
      while (!feof ($handle)) {//读入日志文件内容
          $i++;
          $buffer = fgets($handle, 999);   
          if($i>$start&&$i<$end)    {   
          if ((preg_match("#\d{1,2}\/\w{1,3}\/\d{1,4}\:\d{1,2}\:\d{1,2}\:\d{1,2}#",$buffer,$access_time)) && (preg_match("#\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}#",$buffer,$ip)))
          {
        $ip = $ip[0];
        $access_time = $access_time[0];
        $access_time=$this->Format2UnixTime($access_time);
        $access_time=strftime(" %Y-%m-%d %H:%M:%S " ,$access_time);   
            echo "<tr><td>".$ip_times[$ip][0]++."</td>";//$ip_times[$ip][0]为访问次数times
            echo "<td>".$ip_times[$ip][1]=$access_time;//$ip_times[$ip][1]为访问时间access_time
            echo "</td><td>$ip</td></tr>";   
          }
          }
      }
      echo "</table>";
      fclose ($handle);
        }else
        {
      echo $this->filename;
      echo "<font color=red>日志文件不存在,请检查路径</font>";
      exit;
        }
    }
    }

    /**
     * **********测试
     */
    $my=new myapachelog("C:/Program Files/PHP Home Edition 2/Apache2/logs/access.log");
    $my->GetAccessByLog();//0:按访问次数排序(缺省值);1:按最近一次访问的时间排序。
    ?>
    June 25

    关于IFRAME 自适应高度的研究

    关于IFRAME 自适应高度的研究——之前自己也碰到过这个问题,为了得到答案去网上搜索,发现有不少人也遇到了这样的问题,现在就把解决方法共享一下。
    --------------------------------------------------------------------------------

      重要提示:src=中你必须填写的网页地址,一定要和本页面在同一个站点上,否则,会抱错,说“拒绝访问!”


      之前自己也碰到过这个问题,为了得到答案去网上搜索,发现有不少人也遇到了这样的问题,现在就把解决方法共享一下
    超简单哦

      1、建立一个bottom.js的文件,然后输入下面的代码(只有两行哦)

    parent.document.all("框架ID名").style.height=document.body.scrollHeight;
    parent.document.all("框架ID名").style.width=document.body.scrollWidth;

    这里的 框架ID名 就是Iframe的ID,比如:
    <IFRAME id="框架ID名" name="left" frameBorder=0 scrolling=no src="XXX.asp" width="100%"></IFRAME>

      2、给你网站里所有的被包含文件里面每个都加入
    <script language = "JavaScript" src = "bottom.js"/></script>

      3、OK,收工!
      我在WINXP、IE6下面测试通过。很简单吧!

    June 15

    用php实现边执行边输出的效果

    1. <?php
    2.  
    3. /*
    4. @author:axgle <axgle at 126 dot com>
    5.  
    6. @note:要决是在每次flush显示前,输出str_pad("",10000)
    7.  
    8. @why:为什么非要10000?呵呵,大于10000也可以,我测试出来的
    9.  
    10. */
    11.  
    12. print "一共5个档案要处理<hr>";
    13. sleep(1);
    14.  
    15. print str_pad("",100000);
    16. flush();
    17.  
    18. for($i=1;$i<=5;$i++)
    19.  
    20. { 
    21.  
    22. sleep(1);
    23.  
    24. print  "#$i 完毕<hr>";
    25.  
    26. print str_pad("",10000);
    27. flush();
    28.  
    29. }
    30.  
    31. print "恭喜,全部处理成功!";
    32.  
    33. ?>
    June 06

    php编写大型网站问题集

     PHP以其易用性得到迅速的推广,但易用并不是说就能用好它,实际上许多程序员用它很容易的立一个个WEB应用系统,但又有多少人仔细的考虑过他们的代码,是否容易维护、是否足够健壮、否效率足够高、是否足够安全,当PHP用于建立大型网站时这些就成为很关键的因素。下面我们从较轻微的问题开始讨论,直至一些致命的错误。共分三部分。
      第一部分、较轻微的错误
       
      一、Printf(),
        该函数主要用来格式化显示数据。当你要改变某个数据的显示格式时才使用。
      例如以不同的精度来显示PI(3.1415926)的值。

    <?php 
       
    /* 
       * The three faces of Π 
       */ 
       
      
     printf ("Pi is: %.2fn<br>n"M_PI
    ); 
      
     printf ("Pi is also: %.3fn<br>n"M_PI
    ); 
      
     printf ("Pi is also: %.4fn<br>n"M_PI
    ); 
      
    ?> 

            但许多程序员仅仅为显示一些变量值和函数返回值使用该函数。因为Printf()在显示数据前要先格式化该数据以速度较慢,因此,仅为了显示数据时应用print和echo,以提高速度。
       
      二、语意检查
        PHP是一种弱类型语言,也就是说在使用一个变量前不用定义,这样给编程带来了很大的方便和灵活,但你自己必须知道该变量到底应该是哪种类型,因为该变量在运行时仍实际对应着某一种类型(各种类型之间可以自由互相转换),没有类型的变量是不存在的。有可能PHP并不能检查出你的语意错误,但由于变量类型的变化,会导致一些潜在的问题的发生。另外一个值得注意的问题是变量的范围,它也可能会导致一些潜在的问题的发生。
      在PHP中有以下几种基本变量:

      Boolean, resource, integer, double, string, array and object。
       
      三、临时变量的使用
        临时变量的滥用会导致程序运行效率的降低。何时使用临时变量可基于以下两点考虑:
      1、该变量是否至少使用两次。
      2、该变量的使用是否会显著提高程序的可读性。
      如果一条也不满足,则省略该变量的使用。例如:
    <?php 
       $tmp 
    date ("F d, h:i a"); 
    /* ie January 3, 2:30 pm */ 
      
     print $tmp

      
    ?> 

    就应该改成:
    <?php 
       print date 
    ("F d, h:i a"
    ); 
      
    ?> 

    又如:

    <?php 
       
      
    // string reverse_characters(string str) 
      // Reverse all of the characters in a string. 
      
    function reverse_characters ($str

      { 
      
     return implode (""array_reverse (preg_split("//"$str
    ))); 
      } 
       
      
    ?>

     的可读性不强,可改成:

    <?php 
       
      
    // string reverse_characters(string str) 
      // Reverse all of the characters in a string. 
      
    function reverse_characters ($str
      { 
      
     $characters preg_split ("//"$str); 
      
     $characters array_reverse ($characters); 
       
      
     return implode (""$characters); 
      } 
       
      
    ?> 
    四、客户端和服务器端代码的分离
       客户端和服务器端代码的在PHP程序中实际上就是HTML代码和PHP语言代码,很多人把HTML和PHP语句混合在一个文件里,使得这文件很大,这种风格对程序的维护和再开发很不利,不适合大型站点的开发。一般有两种方法把HTML和PHP语句分开:
      1、编写专用API,例如:
       
      index.php ? The Client side

    <?php include_once ("site.lib"); ?> 
      <html> 
      <head> 
      <title> <?php print_header (); ?> </title> 
      </head> 
      <body> 
      <h1> <?php print_header (); ?> </h1> 
      <table border="0" cellpadding="0" cellspacing="0"> 
      <tr> 
      <td width="25%"> 
      <?php print_links (); ?> 
      </td> 
      <td> 
      <?php print_body (); ?> 
      </td> 
      </tr> 
      </table> 
      </body> 
      </html> 
    site.lib ? The server side code
    <?php 
       
      $dbh 
    mysql_connect ("localhost""sh""pass"
      or die (
    sprintf ("Cannot connect to MySQL [%s]: %s"
      
    mysql_errno (), mysql_error ())); 
      @
    mysql_select_db ("MainSite"
      or die (
    sprintf ("Cannot select database [%s]: %s"
      
    mysql_errno (), mysql_error ())); 
       
      
    $sth = @mysql_query ("SELECT * FROM site"$dbh
      or die (
    sprintf ("Cannot execute query [%s]: %s"
      
    mysql_errno (), mysql_error ())); 
       
      
    $site_info mysql_fetch_object ($sth); 
       
      function 
    print_header () 
      { 
      
     global $site_info
      
     print $site_info->header
      } 
       
      function 
    print_body () 
      { 
      
     global $site_info
      
     print nl2br ($site_info->body); 
      } 
       
      function 
    print_links () 
      { 
      
     global $site_info
       
      
     $links explode ("n"$site_info->links); 
      
     $names explode ("n"$site_info->link_names); 
       
      for (
    $i 0$i count ($links); $i++) 
      { 
      
     print "ttt 
       <a href="
    $links[$i]">$names[$i]</a> 
       n<br>n"

      } 
      } 
      
    ?> 

    这种方法使得程序看起来比较简洁,而且执行速度也较快。
       
      2、使用模板的方法
      这种方法使得程序看起来更简洁,同样实现上面的功能,可用以下代码:

    <html>
      <head>
      <title>%%PAGE_TITLE%%</title>
      </head>
      <body %%BODY_PROPERTIES%%>
      <h1>%%PAGE_TITLE%%</h1>
      <table border="0" cellpadding="0" cellspacing="0">
      <tr>
      <td width="25%">%%PAGE_LINKS%%</td>
      <td>%%PAGE_CONTENT%%</td>
      </tr>
      </table>
      </body>
      </html>
        用占位符代替要动态生成的内容,然后用一解析程序分析该模板文件,把占位符用际的内容替换。种方法使得即使不会使用PHP的页面制作人员也能修改模板文件。这种方法的缺点是执行效率不高,因为要解释模板文件。同时实现起来也比较复杂。
       
      注: www.thewebmasters.net的 FastTemplate class可方便的实现以上功能。
       
      五、不要用过时的函数 

         作为一种自由软件,PHP发展很快,其中的很多函数都已过时,例如:
       
      while (1):
      print "5";
      if ($idx++ == 5):
      break;
      endif;
      endwhile;
       
        虽然还能用但效率肯定不高,而且可能在以后的版本中会禁用,导致程序不能运行。因此要经常对照最新PHP手册检查那些函数已过时及时修正。

    php控制用户的浏览器

     用PHP控制用户的浏览器--ob*函数的使用
      Output Control 函数可以让你自由控制脚本中数据的输出。它非常地有用,特别是对于:当你想在数据已经输出后,再输出文件头的情况。输出控制函数不对使用 header() 或 setcookie(), 发送的文件头信息产生影响,只对那些类似于 echo() 和 PHP 代码的数据块有作用。

      我们先举一个简单的例子,让大家对Output Control有一个大致的印象:
    Example 1.



    <?php
    ob_start(); //打开缓冲区
    echo "Hellon"; //输出
    header("location:index.php"); //把浏览器重定向到index.php
    ob_end_flush();//输出全部内容到浏览器
    ?>


    所有对header()函数有了解的人都知道,这个函数会发送一段文件头给浏览器,但是如果在使用这个函数之前已经有了任何输出(包括空输出,比如空格,回车和换行)就会提示出错。如果我们去掉第一行的ob_start(),再执行此程序,我们会发现得到了一条错误提示:“Header had all ready send by”!但是加上ob_start,就不会提示出错,原因是当打开了缓冲区,echo后面的字符不会输出到浏览器,而是保留在服务器,直到你使用 flush或者ob_end_flush才会输出,所以并不会有任何文件头输出的错误!

    一、 相关函数简介
    1、Flush:刷新缓冲区的内容,输出。
    函数格式:flush()
    说明:这个函数经常使用,效率很高。

    2、ob_start :打开输出缓冲区
    函数格式:void ob_start(void)
    说明:当缓冲区激活时,所有来自PHP程序的非文件头信息均不会发送,而是保存在内部缓冲区。为了输出缓冲区的内容,可以使用ob_end_flush()或flush()输出缓冲区的内容。

    3 、ob_get_contents :返回内部缓冲区的内容。
    使用方法:string ob_get_contents(void)
    说明:这个函数会返回当前缓冲区中的内容,如果输出缓冲区没有激活,则返回 FALSE 。

    4、ob_get_length:返回内部缓冲区的长度。
    使用方法:int ob_get_length(void)
    说明:这个函数会返回当前缓冲区中的长度;和ob_get_contents一样,如果输出缓冲区没有激活。则返回 FALSE。

    5、ob_end_flush :发送内部缓冲区的内容到浏览器,并且关闭输出缓冲区。
    使用方法:void ob_end_flush(void)
    说明:这个函数发送输出缓冲区的内容(如果有的话)。

    6、ob_end_clean:删除内部缓冲区的内容,并且关闭内部缓冲区
    使用方法:void ob_end_clean(void)
    说明:这个函数不会输出内部缓冲区的内容而是把它删除!

    7、ob_implicit_flush:打开或关闭绝对刷新
    使用方法:void ob_implicit_flush ([int flag])
    说明:使用过Perl的人都知道$|=x的意义,这个字符串可以打开/关闭缓冲区,而ob_implicit_flush函数也和那个一样,默认为关闭缓冲区,打开绝对输出后,每个脚本输出都直接发送到浏览器,不再需要调用 flush()


    二、深入了解

    1. 关于Flush函数:
    这个函数在PHP3中就出现了,是一个效率很高的函数,他有一个非常有用的功能就是刷新browser的cache.我们举一个运行效果非常明显的例子来说明flush.
    Example 2.


    <?php
    for($i = 1; $i <= 300; $i ) print(" ");
    // 这一句话非常关键,cache的结构使得它的内容只有达到一定的大小才能从浏览器里输出
    // 换言之,如果cache的内容不达到一定的大小,它是不会在程序执行完毕前输出的。经
    // 过测试,我发现这个大小的底限是256个字符长。这意味着cache以后接收的内容都会
    // 源源不断的被发送出去。
    for($j = 1; $j <= 20; $j ) {
    echo $j . "
    ";
    flush(); //这一部会使cache新增的内容被挤出去,显示到浏览器上
    sleep(1); //让程序"睡"一秒钟,会让你把效果看得更清楚
    }

    ?>
    具体效果你可以到这里看看http://www.php2000.com/~uc...
    PHP2000的最新的PHP聊天室就是用的这个技术,可惜的是源代码未公开 L
    注:如果在程序的首部加入ob_implicit_flush()打开绝对刷新,就可以在程序中不再使用flush(),这样做的好处是:提高效率!


    2. 关于ob系列函数:
    我想先引用我的好朋友y10k的一个例子:
    Example 3.
    比如你用得到服务器和客户端的设置信息,但是这个信息会因为客户端的不同而不同,如果想要保存phpinfo()函数的输出怎么办呢?在没有缓冲区控制之前,可以说一点办法也没有,但是有了缓冲区的控制,我们可以轻松的解决:



    <?php
    ob_start(); //打开缓冲区
    phpinfo(); //使用phpinfo函数
    $info = ob_get_contents(); //得到缓冲区的内容并且赋值给$info
    $file = fopen('info.txt', 'w'); //打开文件info.txt
    fwrite($file, $info); //写入信息到info.txt
    fclose($file); //关闭文件info.txt

    ?>
    用以上的方法,就可以把不同用户的phpinfo信息保存下来,这在以前恐怕没有办法办到!其实上面就是将一些“过程”转化为“函数”的方法!
    或许有人会问:“难道就这个样子吗?还有没有其他用途?”当然有了,比如笔者论坛的PHP 语法加亮显示就和这个有关(PHP默认的语法加亮显示函数会直接输出,不能保存结果,如果在每次调用都显示恐怕会很浪费CPU,笔者的论坛就把语法加亮函数显示的结果用控制缓冲区的方法保留了),大家如果感兴趣的话可以来看看http://www.zphp.com/bbs/

    可能现在大家对ob_start()的功能有了一定的了解,上面的一个例子看似简单,但实际上已经掌握了使用ob_start()的要点。
    <1>.使用ob_start打开browser的cache,这样可以保证cache的内容在你调用flush(),ob_end_flush()(或程序执行完毕)之前不会被输出。
    <2>.现在的你应该知道你所拥有的优势:可以在任何输出内容后面使用header,setcookie以及session,这是 ob_start一个很大的特点;也可以使用ob_start的参数,在cache被写入后,然后自动运行命令,比如ob_start ("ob_gzhandler");而我们最常用的做法是用ob_get_contents()得到cache中的内容,然后再进行处理……
    <3>.当处理完毕后,我们可以使用各种方法输出,flush(),ob_end_flush(),以及等到程序执行完毕后的自动输出。当然,如果你用的是ob_get_contents(),那么就要你自己控制输出方式了。

    来,让我们看看能用ob系列函数做些什么……


    (一)、 静态模版技术

    简介:所谓静态模版技术就是通过某种方式,使得用户在client端得到的是由PHP产生的html页面。如果这个html页面不会再被更新,那么当另外的用户再次浏览此页面时,程序将不会再调用PHP以及相关的数据库,对于某些信息量比较大的网站,例如sina,163,sohu。类似这种的技术带来的好处是非常巨大的。

    我所知道的实现静态输出的有两种办法:
    <1>.通过y10k修改的phplib的一个叫template.inc.php类实现。
    <2>.使用ob系列函数实现。
    对于第一种方法,因为不是这篇文章所要研究的问题,所以不再赘述。
    我们现在来看一看第二种方法的具体实现:
    Example 4.


    <?php
    ob_start();//打开缓冲区
    ?>

    php页面的全部输出



    <?php
    $content = ob_get_contents(); //取得php页面输出的全部内容
    $fp = fopen("output00001 . html", "w"); //创建一个文件,并打开,准备写入
    fwrite($fp, $content); //把php页面的内容全部写入output00001.html,然后……
    fclose($fp);
    ?>


    这样,所谓的静态模版就很容易的被实现了……


    (二)、 捕捉输出

    以上的Example 4.是一种最简单的情况,你还可以在写入前对$content进行操作……
    你可以设法捕捉一些关键字,然后去对它进行再处理,比如Example 3.所述的PHP语法高亮显示。个人认为,这个功能是此函数最大的精华所在,它可以解决各种各样的问题,但需要你有足够的想象力……
    Example 5.



    <?php
    function run_code($code) {
    If ($code) {
    ob_start();
    eval($code);
    $contents = ob_get_contents();
    ob_end_clean();
    } else {
    echo "错误!没有输出";
    exit();
    }
    return $contents;
    }

    ?>
    以上这个例子的用途不是很大,不过很典型$code的本身就是一个含有变量的输出页面,而这个例子用eval把$code中的变量替换,然后对输出结果再进行输出捕捉,再一次的进行处理……

    Example 6. 加快传输


    <?php
    /*
    ** Title.........: PHP4 HTTP Compression Speeds up the Web
    ** Version.......: 1.20
    ** Author........: catoc <catoc@163.net>
    ** Filename......: gzdoc.php
    ** Last changed..: 18/10/2000
    ** Requirments...: PHP4 >= 4.0.1
    ** PHP was configured with --with-zlib[=DIR]
    ** Notes.........: Dynamic Content Acceleration compresses
    ** the data transmission data on the fly
    ** code by sun jin hu (catoc) <catoc@163.net>
    ** Most newer browsers since 1998/1999 have
    ** been equipped to support the HTTP 1.1
    ** standard known as "content-encoding."
    ** Essentially the browser indicates to the
    ** server that it can accept "content encoding"
    ** and if the server is capable it will then
    ** compress the data and transmit it. The
    ** browser decompresses it and then renders
    ** the page.
    **
    ** Modified by John Lim (jlim@natsoft.com.my)
    ** based on ideas by Sandy McArthur, Jr
    ** Usage........:
    ** No space before the beginning of the first '<?' tag.
    ** ------------Start of file----------
    ** |<?
    ** | include('gzdoc.php');
    ** |? >
    ** |<HTML>
    ** |... the page ...
    ** |</HTML>
    ** |<?
    ** | gzdocout();
    ** |? >
    ** -------------End of file-----------
    */
    ob_start();
    ob_implicit_flush(0);
    function CheckCanGzip() {
    global $HTTP_ACCEPT_ENCODING;
    if (headers_sent() || connection_timeout() || connection_aborted()) {
    return 0;
    }
    if (strpos($HTTP_ACCEPT_ENCODING, 'x-gzip') !== false) return "x-gzip";
    if (strpos($HTTP_ACCEPT_ENCODING, 'gzip') !== false) return "gzip";
    return 0;
    }
    /* $level = compression level 0-9, 0=none, 9=max */
    function GzDocOut($level = 1, $debug = 0) {
    $ENCODING = CheckCanGzip();
    if ($ENCODING) {
    print "n<!-- Use compress $ENCODING -->n";
    $Contents = ob_get_contents();
    ob_end_clean();
    if ($debug) {
    $s = "<p>Not compress length: " . strlen($Contents);
    $s .= "Compressed length: " . strlen(gzcompress($Contents, $level));
    $Contents .= $s;
    }
    header("Content-Encoding: $ENCODING");
    print "x1fx8bx08x00x00x00x00x00";
    $Size = strlen($Contents);
    $Crc = crc32($Contents);
    $Contents = gzcompress($Contents, $level);
    $Contents = substr($Contents, 0, strlen($Contents) - 4);
    print $Contents;
    print pack('V', $Crc);
    print pack('V', $Size);
    exit;
    } else {
    ob_end_flush();
    exit;
    }
    }

    ?>
    这是catoc的一段很早以前的代码,是在weblogs.com看到的,他利用了zlib的函数,对传输的内容进行了压缩,测试表明,对于10k以上的页面,会产生效果,而且页面越大,效果越明显……