存档

文章标签 ‘PHP’

[ZT]利用Curl、socket、file_get_contents POST数据

2009年6月16日 Galaxy 3 条评论

http://hi.baidu.com/qfans/blog/item/33896c81dedc41d0bd3e1e71.html
利用Curl、socket、file_get_contents POST数据

<?php
/**
* Socket版本
* 使用方法:
* $post_string = "app=socket&version=beta";
* request_by_socket('facebook.cn','/restServer.php',$post_string);
*/
function request_by_socket($remote_server,$remote_path,$post_string,$port = 80,$timeout = 30){
    $socket = fsockopen($remote_server,$port,$errno,$errstr,$timeout);
    if (!$socket) die("$errstr($errno)");
 
    fwrite($socket,"POST $remote_path HTTP/1.0\r\n");
    fwrite($socket,"User-Agent: Socket Example\r\n");
    fwrite($socket,"HOST: $remote_server\r\n");
    fwrite($socket,"Content-type: application/x-www-form-urlencoded\r\n");
    fwrite($socket,"Content-length: ".strlen($post_string)+8."\r\n");
    fwrite($socket,"Accept:*/*\r\n");
    fwrite($socket,"\r\n");
    fwrite($socket,"mypost=$post_string\r\n");
    fwrite($socket,"\r\n");
 
    $header = "";
    while ($str = trim(fgets($socket,4096))) {
        $header.=$str;
    }
 
    $data = "";
    while (!feof($socket)) {
        $data .= fgets($socket,4096);
    }
    return $data;
}
 
 
/**
* Curl版本
* 使用方法:
* $post_string = "app=request&version=beta";
* request_by_curl('http://facebook.cn/restServer.php',$post_string);
*/
function request_by_curl($remote_server,$post_string){
    $ch = curl_init();
    curl_setopt($ch,CURLOPT_URL,$remote_server);
    curl_setopt($ch,CURLOPT_POSTFIELDS,'mypost='.$post_string);
    curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
    curl_setopt($ch,CURLOPT_USERAGENT,"Jimmy's CURL Example beta");
    $data = curl_exec($ch);
    curl_close($ch);
    return $data;
}
/**
* 其它版本
* 使用方法:
* $post_string = "app=request&version=beta";
* request_by_other('http://facebook.cn/restServer.php',$post_string);
*/
function request_by_other($remote_server,$post_string){
    $context = array(
        'http'=>array(
            'method'=>'POST',
            'header'=>'Content-type: application/x-www-form-urlencoded'."\r\n".
                      'User-Agent : Jimmy\'s POST Example beta'."\r\n".
                      'Content-length: '.strlen($post_string)+8,
            'content'=>'mypost='.$post_string)
        );
    $stream_context = stream_context_create($context);
    $data = file_get_contents($remote_server,FALSE,$stream_context);
    return $data;
}
?>
分类: PHP 标签: , ,

[ZT]PHP抓取網頁特定div區塊及圖片

2009年4月5日 Galaxy 没有评论

本来是想找个WP插件的,结果只找到个有同样想法的人。只好把找到的资料先塞这了。
* function download_url( $url ) see: http://phpxref.com/xref/wordpress/wp-admin/includes/file.php.source.html#l312
* function wp_upload_dir see: http://phpxref.com/xref/wordpress/wp-includes/functions.php
* function wp_unique_filename see: http://phpxref.com/xref/wordpress/wp-includes/functions.php
阅读全文…

分类: PHP 标签: ,

[ZT]学习 Apache mod_rewrite 13 例

2009年2月6日 Galaxy 1 条评论

http://www.jingzhengli.cn/Blog/zz/855.html
关于PHPmod_rewrite重写模块技术个人觉得最好的一篇文章

最近手里一个PHP项目要用到mod_rewrite模块,很早就听mod_rewrite广泛应用于URL重写,防止盗链,伪静态等各方面,于是怀着激动的心情到网上一阵猛搜,果然很多资料,窃喜…..遗憾的是很多文章看了以后仍旧一团雾水,还是不得要领,甚为苦恼。正当山穷水尽的时候,一篇《Learn Apache mod_rewrite: 13 Real-world Examples》柳暗花明般走进了我的视线,读罢此文,眼前豁然开朗,手里的项目也渐渐有了眉目。由于原文是英文版本,在参考过程中还是费了许多周折,所以本人操起了早已生锈的英语砍刀,斗胆将其翻译过来,英语过关的还是建议看原文。在译文中有很多不恰当的地方,希望大家将就看吧,话不多说,上文。

===================一道华丽的分割线================

原文地址:http://www.sitepoint.com/article/apache-mod_rewrite-examples/

原文作者:DK Lynn(DK Lynn is a former instructor pilot and “rocket scientist” now living in New Zealand where he operates a small business developing and hosting web sites. )

================二道华丽的分割线(以下为本人译文)==========

学习 Apache mod_rewrite 13 例

Apache 以其极高的性价比让越来越多的公司组织选择它作为服务器。其中它有一个很有用的功能就是mod_rewrite模块,一个可将用户请求的URI根据特定规则转换的模块。
这篇文章将引领你学习rewrite 规则,正则表达,rewrite条件,以及提供了一系列的例子。
首先,我假设你已经懂得URI 重写对你网站的意义为前提,如果对这一方面你想了解得更多,这里我向你推荐 mod_rewrite: A Beginner’s Guide to URL Rewriting 这本书。你可以从书中找到关于这方面得更多信息。
测试服务器安装
一些服务器没有开启mod_rewrite模块(服务器默认关闭),你可以键入一行PHP代码来确定你的服务器是否已经开启mod_rewrite模块:
phpinfo();
在浏览器运行这段代码,找到Apache Modules section,如果mod_rewrite没有出现在其列表中,那么你就需要通知你的服务商开启mod_rewrite服务,或者..换另外一个好的服务商。大多数服务商都会开启mod_rewrite模块,所以你很容易找到。
mod_rewrite的魔力
简单举例:创建三个文件,分别命名为 test.html,test.php和.htaccess
test.html 输入:

<h1>This is the HTML file.</h1>

test.php输入:

<h1>This is the php file.</h1>

.htaccess输入:

RewriteEngine on
RewriteRule ^/?test\.html$ test.php [L]

将以上三个文件放test测试文件夹下,在浏览器录入:

http://www.example.com/test/test.html

在浏览器中将 www.example.com替换成你自己的域名。如果运行结果显示“This is the PHP file”,那么运行成功,如果结果显示“This is the Html file”,那么肯定是哪里出了问题,请你再仔细检查下。
如果你测试成功,你是否发现了我们录入了test.html的文件名,确执行了test.php文件,是的,你已经初识了mod_rewrite的神奇。
mod_rewrite 正则表达式
现在我们可以重写URLs了!设想我们有一个显示城市信息的网站。根据URI选择城市:http://www.example.com/display.php?country=USA &state=California&city=San_Diego
这个URL太长并且对用户也不友好,我们更希望写成这样:
http://www.example.com/USA/California/San_Diego
我们需要告诉Apache新的URL会根据一定的格式转化成这样,为了让display.php明白查询的字符,所以我们将用到正则表达式告诉 mod_rewrite匹配我们的URLs。如果你对正则表达式不太熟悉,许多网站提供了优秀的教程供你学习。在本文的末尾,我也会列举出比较好的参考网址。如果你还是不能明白我所讲述的,那么我建议你看看后面链接中的前两篇。
一个最常用的正则就是(.*)。它含有两个元素:一是“点”,表示任意字符;二是“星”,表示以前的全部字符。所以(.*)会匹配{REQUEST_URI}的所有字符。{REQUEST_URI}是URL中出去域名以及“?”符号的所有查询字符,也是Apache 重写技术尝试匹配的字符。
包裹在正则表达式中的元素存放在“原子”内,它是在规则范围内允许被匹配的变量,所以以上正则存储了USA/California/San_Diego在“原子”中,为了解决我们的问题,我们需要三个“原子”,他们可以用左斜杠“/”进行分隔,所以正则表达式成了:
(.*)/(.*)/(.*)
以上正则,在{REQUEST_URI}中通过两个“/”的分割存储了三个值,为了解决我们具体问题,我们得加一点限制――毕竟,第一个和最后一个原子可以匹配任何字符。
开始,我们可以添加一些特殊的字符,比如表示正则“开始”或者“结束”,“^”字符表示正则的开始而“$”表示正则的结束。
^(.*)/(.*)/(.*)$
这个正则表示整个字符串将全部匹配,除去之前后者之后,没有任何例外。
但是,这个方法仍然匹配的范围太广,我们将匹配的字符按照原子形式存放,然后通过他们形成查询字符串,所以我们必须信任我们所匹配的字符。用(.*)匹配字符串,由于允许了太多字符,所以会存在潜在的安全隐患,引用不当会使mod_rewrite运行出故障。
为了避免一些不必要的麻烦,让我们更改一下我们的原子正则,让其更加准确的匹配我们允许的字符。因为这些原子代表了地区地名,所以我们完全可以用A到Z的大小写来表示他们,另外因为地名之间有空格,所以下划线“_”也是被允许的。我们用中括弧明确我们匹配的正则,然后用短横线“-”表示连接的范围,所以被我们允许的正则修改成了[a-zA-Z_],因为我们还要避免匹配到空名字,所以用“+”来匹配在该字符之前的一个或者多个字符,所以我们的正则成了:
^([a-zA-Z_]+)/([a-zA-Z_]+)/([a-zA-Z_]+)$
{REQUEST_URI}是以“/”开头。Apache 在更改版本的时候会更改正则引擎,一代Apache要求有斜杠而二代Apache却不允许!但是我们可以用^/?(?表示匹配字符本身或者前一个字符)来兼容两个版本的Apache,所以我们的正则又成了:
^/?([a-zA-Z_]+)/([a-zA-Z_]+)/([a-zA-Z_]+)$
正则在手,我们就可以将原子标识到URL上了:
display.php?country=$1 &state=$2&city=$3
$1表示国家原子;$2表示省州原子;$3表示城市原子,这里可以加上9个原子,分别用$1到$9表示。
现在我们要做的就是在该目录下创建一个新的.htaccess文件,录入一下代码:
RewriteRule ^/?([a-zA-Z_]+)/([a-zA-Z_]+)/([a-zA-Z_]+)$ display.php?country=$1 &state=$2&city=$3 [L]
然后保存,重写规则必须写在一行并且用一个空格分开每一个参数,我们用[L]或者’last’表示匹配结束。(一会有更多flags介绍)
我们的重写规则已经创建完成, URL请求字符上各原子的值将经过我们匹配的正则,加上查询变量到我们的重写URL上。display.php将从查询字符中解析这些值,然后将他们送入数据库查询或者进行其他数据库操作。
如果你的正则只允许有限的几个国家,为了避免数据库错误,你可以在正则中加入一下被允许条件,例子如下:
^/?(USA|Canada|Mexico)/([a-zA-Z_]+)/([a-zA-Z_]+)$
如果你关心查询字符串的大小写问题,由于你数据库对大写有严格的限制,那么你可以在正则表达式后面加一个[NC]FLAG位来忽略大小写,但是不要忘记在你通过$_GET 获取传递值的时候,把他们转换成小写。
如果你想用数字(0,1…..9)来表示具体的地区,那么需要更改正则中的([a-zA-Z_]+)成([0-9])来匹配单个数字,([0-9]{1,2})匹配两位数字(0到99),([0-9]+)匹配多位数字,这个对匹配数据库ID之类的非常有用。
RewriteCond 指令
现在你已经学会了mod_rewrite的一些基本用法,现在我们来学习下怎样用RewirteCond指令来处理其他各类型的情况。当RewirteCond指令明确声明以后,mod_rewrite将根据它们做出相应的处理。
RewirteCond 指令的形式和RewriteRule有点类似,形式为:RewirteCond 被匹配的字符 正则 FLAG标识。逻辑FLAG标识 [OR],是非常有用的,记住所有RewirteCond 以及RewriteRule指令在[LAST]指令之前,所有的逻辑与关系都会被包含。
你可以用RewirteCond指令测试服务器变量,在this is the best list of server variables一文可以找到相关说明。
举一个列子,假设我们想将“www”放入你的域名中,首先你得测试你的服务器{HTTP_HOST}变量,看www.是否已经存在,如果没有那么定向到期望的主机名:
RewriteCond %{HTTP_HOST} !^www\.example\.com$ [NC]
RewriteRule .? http://www.example.com%{REQUEST_URI} [R=301,L]
这里{HTTP_HOST}是一个Apache服务器变量,我们必须加一个“%”字符再之前。正则表达式以“!”开始表示如果正则不匹配那么条件成立。我们当然也要转义“.”字符,将其作为一个普通字面字符而不是表示所有字符。再最后我们还加了一个忽略大小写的[NC]FLAG。
RewriteRule匹配了零或者任意一个字符,并且定向到 http://www.example.com加上原来{REQUEST_URI}值。R=301向服务器提出301请求,表明这是一个永久转向,最后一个[L]表示已经完成这段正则匹配。
RewriteCond也可以创建原子,在RewriteRule中原子是以$1…..$9表示,但是在RewriteCond中是以%1….%9表示。你可以在稍后的例子中看到具体的原子操作。
mod_rewrite Flags
mod_rewrite用”FLAGS”来建立重写条件以及其他属性。我们用中括弧将FLAGS包起来,放在条件或者是规则的末尾,用逗号将多个FLAGS分隔。以下列表是你需要熟悉的几个主要FLAGS:
last|L -[L]告诉Apache服务器一系列的条件或者是规则将在它出现后结束,换句话说就是[L]不出现,mod_rewrite将会一直执行。
nocase|NC -[NC]告诉Apache服务器忽略正则中的大小写,它经常被用到{HTTP_HOST}服务器参数上,因为域名里面是不会区分大小写的。
redirect|R -[R] 经常引用到触发可见的定向。默认情况下它是一个HTTP 302的临时重定向,但是你可以注明具体的HTTP 代码,比如你可以用[R=301]来表明这是一个永久重定向,这对搜索引擎抓取你重定向后的网页相当有用。
qsappend|QSA -[QSA] 用于添加新的查询参数。你可以在原查询参数后面定义新的查询参数,但命名时注意不要重复已存在的参数名。错误的引用[QSA]将会破坏原来的查询参数导致重定向错误。
forbidden|F -[F]告诉Apache响应请求时不提供页面。其原理就是Apache会发出一个403 HTTP相应,可以保护网站不被未经授权的或者其他盗链访问。
ornext|OR -[OR]作为默认值[AND]的反义词,可以通过逻辑关系将一系列重写条件组合起来。
next|N -[N]可以让你的重写条件循环匹配,当你不知道{REQUEST_URI}有多少字符进行匹配的时候很有用。
你可以在 Apache.org’s mod_rewrite documentation page.了解到其他mod_rewrite FLAGS。
mod_rewrite注释
任何mod_rewrite代码之前都要加上RewriteEngine on这个状态,另外RewriteEngine on还可以用到其他地方。作为一个好的程序员,你知道注释对于程序来说是多么的重要。mod_rewrite允许在RewriteEngine off 与RewriteEngine on之间加上你的注释:
RewriteEngine off
RewriteCond %{HTTP_HOST} !^www\.example\.com$ [NC]
RewriteRule .? http://www.example.com%{REQUEST_URI} [R=301,L]
RewriteEngine on
以上所有的程序代码都不会被执行,RewriteEngine状态值的改变对新的mod_rewrite 代码开发非常有用。像你在PHP里面用/* … */注释一样,好好的运用他们。
mod_rewrite小技巧
作为站长,你要决定怎样提高你网页对访问者的辨识度以及在重写的URI地址里放入适当的信息。在创建新的URI规则的时候务必考虑详细周全一些。另外当你完成新的URI规则以后,必须回去更新以前老的链接来匹配新的规则。
当你在设计新的URI规则的时候,一定注意其唯一性。举一个先前的例子,我用了国家名,州省名,城市名作为URI的元素,因为他们在数据库里面都是唯一的。但是如果建立一个让用户自己更新的数据库,我们没有理由让用户取的文章名字保持唯一性,所以文章一般在数据库里是以一个自动增长的ID作为唯一识别码,这个唯一ID对URL重写规则相当友好,它可以使你的重写规则更加简洁,在URL里面可以用原子非常直接的将其值标识出来。
人们通常想映射数据库里面的值比如标题以及其他字符作为URL的标识,在mod_rewrite中有一个RewriteMap状态专门处理这种情况,但是前提是你必须有修改 Apache配置文件httpd.conf的权限。所以为了根本避免这个问题,还是直接用ID创建你的链接吧。
空格是以%20的形式展示在 URL中的,所以你必须在PHP代码里面将其替换掉,PHP的str_replace函数完全可以胜任这项工作。你只需要在$_GET获取查询值的时候,将其替换就可以了。但是在数据库中空格是难免的,所以我宁愿将空格替换成下划线,一下为PHP代码:
$name = str_replace ( ‘ ‘, ‘_’, $name );
在添加新的URL规则的时候,小心不要打破了原先已存在的链接间的相对关系。开发人员通常会惊讶为什么有时候CSS,JAVASCRIPT,图片等文件出现错误或者不启作用了。记住相对链接只匹配你当前URL的地址,所以你需要将这些相对链接更改成绝对链接地址,或者在你的静态网页加上HTML 标签。
13 个mod_rewrite 应用举例
先前我们举了一个给每个链接加一个www的列子,现在让我们看看用mod_rewrite还可以做哪些工作。
1.给子域名加www标记
RewriteCond %{HTTP_HOST} ^([a-z.]+)?example\.com$ [NC]
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule .? http://www.%1example.com%{REQUEST_URI} [R=301,L]
这个规则抓取二级域名的%1变量,如果不是以www开始,那么就加www,以前的域名以及{REQUEST_URI}会跟在其后。
2.去掉域名中的www标记
RewriteCond %{HTTP_HOST} !^example\.com$ [NC]
RewriteRule .? http://example.com%{REQUEST_URI} [R=301,L]
3.去掉www标记,但是保存子域名
RewriteCond %{HTTP_HOST} ^www\.(([a-z0-9_]+\.)?example\.com)$ [NC]
RewriteRule .? http://%1%{REQUEST_URI} [R=301,L]
这里,当匹配到1%变量以后,子域名才会在%2(内部原子)中抓取到,而我们需要的正是这个%1变量。
4.防止图片盗链
一些站长不择手段的将你的图片盗链在他们网站上,耗费你的带宽。你可以加一下代码阻止这种行为。
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://(www\.)?example\.com/ [NC]
RewriteRule \.(gif|jpg|png)$ – [F]
如果{HTTP_REFERER}值不为空,或者不是来自你自己的域名,这个规则用[F]FLAG阻止以gif|jpg|png 结尾的URL
如果对这种盗链你是坚决鄙视的,你还可以改变图片,让访问盗链网站的用户知道该网站正在盗用你的图片。
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://(www\.)?example\.com/.*$ [NC]
RewriteRule \.(gif|jpg|png)$ http://www.example.com/hotlinked.gif [R=301,L]
除了阻止图片盗链链接,以上规则将其盗链的图片全部替换成了你设置的图片。
你还可以阻止特定域名盗链你的图片:
RewriteCond %{HTTP_REFERER} !^http://(www\.)?leech_site\.com/ [NC]
RewriteRule \.(gif|jpg|png)$ – [F,L]
这个规则将阻止域名黑名单上所有的图片链接请求。
当然以上这些规则都是以{HTTP_REFERER}获取域名为基础的,如果你想改用成IP地址,用{REMOTE_ADDR}就可以了。
5.如果文件不存在重定向到404页面
如果你的主机没有提供404页面重定向服务,那么我们自己创建。
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .? /404.php [L]
这里-f匹配的是存在的文件名,-d匹配的存在的路径名。这段代码在进行404重定向之前,会判断你的文件名以及路径名是否存在。你还可以在404页面上加一个?url=$1参数:
RewriteRule ^/?(.*)$ /404.php?url=$1 [L]
这样,你的404页面就可以做一些其他的事情,例如默认信心,发一个邮件提醒,加一个搜索,等等。
6.重命名目录
如果你想在网站上重命名目录,试试这个:
RewriteRule ^/?old_directory/([a-z/.]+)$ new_directory/$1 [R=301,L]
在规则里我添加了一个“.”(注意不是代表得所有字符,前面有转义符)来匹配文件的后缀名。
7.将.html后缀名转换成.php
前提是.html文件能继续访问的情况下,更新你的网站链接。
RewriteRule ^/?([a-z/]+)\.html$ $1.php [L]
这不是一个网页重定向,所以访问者是不可见的。让他作为一个永久重定向(可见的),将FLAG修改[R=301,L]。
8.创建无文件后缀名链接
如果你想使你的PHP网站的链接更加简洁易记-或者隐藏文件的后缀名,试试这个:
RewriteRule ^/?([a-z]+)$ $1.php [L]
如果网站混有PHP以及HTML文件,你可以用RewriteCond先判断该后缀的文件是否存在,然后进行替换:
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^/?([a-zA-Z0-9]+)$ $1.php [L]
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^/?([a-zA-Z0-9]+)$ $1.html [L]
如果文件是以.php为后缀,这条规则将被执行。
9.检查查询变量里的特定参数
如果在URL里面有一个特殊的参数,你可用RewriteCond鉴别其是否存在:
RewriteCond %{QUERY_STRING} !uniquekey=
RewriteRule ^/?script_that_requires_uniquekey\.php$ other_script.php [QSA,L]
以上规则将检查{QUERY_STRING}里面的uniquekey参数是否存在,如果{REQUEST_URI}值为script_that_requires_uniquekey,将会定向到新的URL。
10.删除查询变量
Apache的mod_rewrite模块会自动辨识查询变量,除非你做了以下改动:
a).分配一个新的查询参数(你可以用[QSA,L]FLAG保存最初的查询变量)
b).在文件名后面加一个“?”(比如index.php?)。符号“?”不会在浏览器的地址栏里显示。
11.用新的格式展示当前URI
如果这就是我们当前正在运行的URLs:/index.php?id=nnnn。我们非常希望将其更改成/nnnn并且让搜索引擎以新格式展现。首先,我们为了让搜索引擎更新成新的,得将旧的URLs重定向到新的格式,但是,我们还得保证以前的index.php照样能够运行。是不是被我搞迷糊了?
实现以上功能,诀窍就在于在查询变量中加了一个访问者看不到的标记符“marker”。我们只将查询变量中没有出现“marker”标记的链接进行重定向,然后将原有的链接替换成新的格式,并且通过[QSA]FLAG在已有的参数加一个“marker”标记。以下为实现的方式:
RewriteCond %{QUERY_STRING} !marker
RewriteCond %{QUERY_STRING} id=([-a-zA-Z0-9_+]+)
RewriteRule ^/?index\.php$ %1? [R=301,L]
RewriteRule ^/?([-a-zA-Z0-9_+]+)$ index.php?marker &id=$1 [L]
这里,原先的URL:http://www.example.com/index.php?id=nnnn,不包含marker,所以被第一个规则永久重定向到http://www.example.com/nnnn,第二个规则将http://www.example.com/nnnn反定向到http: //www.example.com/index.php?marker &id=nnnn,并且加了marker以及id=nnnn两个变量,最后mod_rewrite就开始进行处理过程。
第二次匹配,marker被匹配,所以忽略第一条规则,这里有一个“.”字符会出现在http://www.example.com/index.php?marker &id=nnnn中,所以第二条规则也会被忽略,这样我们就完成了。
注意,这个解决方案要求Apache的一些扩展功能,所以如果你的网站放于在共享主机中会遇到很多障碍。
12.保证安全服务启用
Apache可以用两种方法辨别你是否开启了安全服务,分别引用{HTTPS}和{SERVER_PORT}变量:
RewriteCond %{REQUEST_URI} ^secure_page\.php$
RewriteCond %{HTTPS} !on
RewriteRule ^/?(secure_page\.php)$ https://www.example.com/$1 [R=301,L]
以上规则测试{REQUEST_URI}值是否等于我们的安全页代码,并且{HTTPS}不等于on。如果这两个条件同时满足,请求将被重定向到安全服务URI.另外你可用{SERVER_PORT}做同样的测试,443是常用的安全服务端口
RewriteCond %{REQUEST_URI} ^secure_page\.php$
RewriteCond %{SERVER_PORT} !^443$
RewriteRule ^/?(secure_page\.php)$ https://www.example.com/$1 [R=301,L]
13.在特定的页面上强制执行安全服务
遇到同一个服务器根目录下分别有一个安全服务域名和一个非安全服务域名,所以你就需要用RewriteCond 判断安全服务端口是否占用,并且只将以下列表的页面要求为安全服务:
RewriteCond %{SERVER_PORT} !^443$
RewriteRule ^/?(page1|page2|page3|page4|page5)$ https://www.example.com/%1 [R=301,L]
以下是怎样将没有设置成安全服务的页面返回到80端口:
RewriteCond %{ SERVER_PORT } ^443$
RewriteRule !^/?(page6|page7|page8|page9)$ http://www.example.com%{REQUEST_URI} [R=301,L]
总结
Apache的mod_rewrite模块,不仅会用在SEO以及URLs用户友好方面,还会用到某些重要的重定向工作中,如果你想学习到更多,以下是我找到的一些网上资源:
正则表达:
Great tutorial: http://gnosis.cx/publish/programming/regular_expressions.html
Cheat sheet: http://regexlib.com/CheatSheet.aspx
A regex-capable text editor: http://www.editpadpro.com
Regex Coach: http://weitz.de/regex-coach/
mod_rewrite
Cheat sheet: http://www.ilovejackdaniels.com/cheat-sheets/mod_rewrite-cheat-sheet/

====================最后一道分割线(全文结束)==========

注:如果发现翻译中有什么错误或者需要改进的地方,邮件zhou#jingzhengli.cn (#换成@ )联系吧

* 周钟 发表于 2009-1-19 17:18:20

分类: Programming 标签: , , ,

[ZT]终于倒腾出了一个wordpress 插件 — simpleReply

2008年9月5日 Galaxy 没有评论

http://harryxu.cn/blog/wp-plugin-simplereply
其实这是一个很简单的插件,就是模仿了twitter的回复方式 @name 这种

虽然wordpress有很多类似引用留言,嵌套回复的插件,但是我都觉得不适合我,因为我感觉blog的留言功能大部分是回复给文章作者的,在自己的留言中完全引用别人的留言显的有点太冗余了,那种嵌套的回复方式我个人是不太喜欢,搞得留言区域乱糟糟的。

所以我一直没有装类似这种插件,都是手写类似 @xxx 这样的表示对谁回复,不过单单这样又感觉太简单,在留言很多的情况下,很难找到是回复给那个评论的,所以想要是 @xxx 是一个链接,点一下定位到要回复的那条评论,这样就方便多了,再看看twitter,其实也是这种方式,所以就抽空写了一个这样的插件。

我给他取名为 simpleReply ,因为真的很simple 点击下载

不过这是我第一次写wordpress插件,我php不是太熟悉,也没怎么测试,就试用了那么几次,不确定是不是会有bug,所以如果有朋友发现bug,希望能及时通知我,我会尽力修复。 下面是使用方法:
安装:压缩包里就一个 simpleReply.php 文件,解压后把这个php文件上传到wordpress的plugins目录,然后到后台激活。
用文本编辑器打开 wp-content/themes/当前使用的主题/comments.php
找到遍历评论的循环,类似下面这样的代码:

	<?php foreach ($comments as $comment) : ?>
		<li class="<?php echo $oddcomment; ?>" id="comment-<?php comment_ID() ?>">
<div class="commentnumber"><?php echo $commentcount++;?></div>
			<cite><?php comment_author_link() ?> Says: </cite>
			<?php if ($comment->comment_approved == '0') : ?>
			<em>Your comment is awaiting moderation.</em>
			<?php endif; ?>
 
<?php simpleReply($link_display='Reply') ?>
 
			<br />
<?php comment_text() ?>
<small class="commentmetadata"><a href="#comment-<?php comment_ID() ?>" title=""><?php comment_date('F jS, Y') ?> at <?php comment_time() ?></a> <?php edit_comment_link('e','',''); ?></small>
		</li>
	<?php /* Changes every other comment to a different class */	
		if ('alt' == $oddcomment) $oddcomment = '';
		else $oddcomment = 'alt';
	?>
	<?php endforeach; /* end for each comment */ ?>

在这个循环体内加入下面一段代码,加在哪里就看你的喜好拉,只要是在这个循环体内就行

<?php simpleReply($link_display='Reply') ?>

simpleReply() 函数可以接受一个字符窜参数,就是回复链接的显示内容,默认是 “回复” ,你可以替换成任何你喜欢的html代码,比如放一个img标签,显示成一个图标。这样就行了。
使用:不出意外,你就能在别人的评论区域看到这个 “回复” 连接了,当一个评论者要指定回复给文章中的另一个评论者的时候,他只要点一下那个评论者留言区域的这个”回复”链接,就会在输入评论内容的文本框里出现一窜类似 @xxx#123 这样的字符,这就表示对 xxx回复了,在后面接着输入要写的评论内容,当评论发布后,前面的窜字符会替换成一个 @xxx 这样的链接,点一下这个链接就会定位到 xxx 评论的位置了。

希望这个小插件能对你有所帮助 :)

PHP注释技巧

2008年8月16日 Galaxy 没有评论

http://www.21andy.com/blog/20080605/1155.html

<?php
$a = 1;
$b = 2;
if (1==1) {
    $andy = '帅哥';
}
?>

一般注释的时候,用

<?php
/*
$a = 1;
$b = 2;
*/
if (1==1) {
    $andy = '帅哥';
}
?>

调程序的时候,老要把后面的*/拿到前面去,很麻烦

<?php
/**/
$a = 1;
$b = 2;
 
if (1==1) {
    $andy = '帅哥';
}
?>

现在应该这样写

这样是注释掉

<?php
/**
$a = 1;
$b = 2;
 
if (1==1) {
    $andy = '帅哥';
}
/**/
?>

这样是不注释

<?php
/**/
$a = 1;
$b = 2;
 
if (1==1) {
    $andy = '帅哥';
}
/**/
?>

再附上一个小规范
所有php文件,末尾都不要

 
?>

这样可以避免有空白输出

分类: Programming 标签: ,

Linux服务器系统监控框架与MSN、E-mail、手机短信报警的实现

2008年7月8日 Galaxy 2 条评论

http://blog.s135.com/read.php/354.htm

Linux服务器系统监控框架与MSN、E-mail、手机短信报警的实现[原创]

[文章作者:张宴 本文版本:v1.0 最后修改:2008.06.25]最近,在我原有的“Linux服务器系统监控程序”基础上,完善了HTTP、TCP、MySQL主动监控与MSN、E-mail、手机短信报警。监控程序以shell和PHP程序编写,以下为主要框架与部分代码:

一、系统监控接口程序(interface.php)具有的报警方式
1、MSN实时报警
①、监控程序每次检测到故障存在、或者故障恢复,都会发送短消息到管理员的MSN。
点击在新窗口中浏览此图片

点击在新窗口中浏览此图片

发送MSN短消息用了一个PHP类:sendMsg,使用该PHP类发消息,必须将发送、接收双方的MSN加为联系人,发送中文时,先用iconv将字符集转为UTF-8:

引用
$sendMsg->sendMessage(iconv(“GBK”, “UTF-8″, $message), ‘Times New Roman’, ’008000′);

2、手机短信报警
①、工作日早上10点之前,晚上6点之后,以及周六、周日,监控程序检测到故障,会调用手机短信接口,发送短信给管理员的手机。
②、如果监控程序多次检测到同一台服务器的同一类故障,只会在第一次检测到故障时发送一条“故障报警”短信。服务器故障恢复后,监控程序会再发送一条“故障恢复”短信。

如果没有手机短信网关接口,可以试试中国移动通信的www.139.com邮箱,具有免费的邮件到达手机短信通知功能,可以将收到的邮件标题以短信的形式发送到手机上。


3、电子邮件报警
①、如果监控程序多次检测到同一台服务器的同一类故障,只会在第一次检测到故障时发送一封“故障报警”邮件。服务器故障恢复后,监控程序会再发送一封“故障恢复”邮件。

系统监控接口程序interface.php(核心部分,仅提供部分代码):

  1. <?php
  2. //HTTP服务器监控
  3. if (htmlspecialchars($_POST["menu"]) == “http”)
  4. {
  5. $date = htmlspecialchars($_POST["date"]);
  6. $ip = htmlspecialchars($_POST["ip"]);
  7. $port = htmlspecialchars($_POST["port"]);
  8. $status = htmlspecialchars($_POST["status"]);//状态,0表示无法访问,1表示正常,2表示无法访问但能ping通
  9. //…下一步处理(省略)…
  10. }
  11. //TCP服务器监控
  12. if (htmlspecialchars($_POST["menu"]) == “tcp”)
  13. {
  14. $date = htmlspecialchars($_POST["date"]);
  15. $ip = htmlspecialchars($_POST["ip"]);
  16. $port = htmlspecialchars($_POST["port"]);
  17. $status = htmlspecialchars($_POST["status"]);//状态,0表示无法访问,1表示正常,2表示无法访问但能ping通
  18. //…下一步处理(省略)…
  19. }
  20. //MySQL服务器监控
  21. if (htmlspecialchars($_POST["menu"]) == “mysql”)
  22. {
  23. $date = htmlspecialchars($_POST["date"]);
  24. $ip = htmlspecialchars($_POST["ip"]);
  25. $port = htmlspecialchars($_POST["port"]);
  26. $abstract = htmlspecialchars($_POST["abstract"]);//故障摘要(必须为全角)
  27. $info = htmlspecialchars($_POST["info"]);//故障详细描述
  28. $failback = htmlspecialchars($_POST["failback"]);//如果服务器存活,此处接收的值为active
  29. //…下一步处理(省略)…
  30. }
  31. ?>


二、主动探测监控(“监控机”主动探测“被监控机”)
1、HTTP服务器监控
脚本:/data0/monitor/http.sh

引用
#!/bin/sh
LANG=C

#被监控服务器、端口列表
server_all_list=(\
192.168.1.1:80 \
192.168.1.2:80 \
192.168.1.3:80 \
)

date=$(date -d “today” +”%Y-%m-%d_%H:%M:%S”)

#采用HTTP POST方式发送检测信息给接口程序interface.php,接口程序负责分析信息,决定是否发送报警MSN消息、手机短信、电子邮件。
send_msg_to_interface()
{
/usr/bin/curl -m 600 -d menu=http -d date=$date -d ip=$server_ip -d port=$server_port -d status=$status http://127.0.0.1:8888/interface.php
}

server_all_len=${#server_all_list[*]}
i=0
while [ $i -lt $server_all_len ]
do
server_ip=$(echo ${server_all_list[$i]} | awk -F ‘:’ ‘{print $1}’)
server_port=$(echo ${server_all_list[$i]} | awk -F ‘:’ ‘{print $2}’)
if curl -m 10 -G http://${server_all_list[$i]}/ > /dev/null 2>&1
then
#status: 0,http down 1,http ok 2,http down but ping ok
status=1
echo “服务器${server_ip},端口${server_port}能够正常访问!”
else
if curl -m 30 -G http://${server_all_list[$i]}/ > /dev/null 2>&1
then
status=1
echo “服务器${server_ip},端口${server_port}能够正常访问!”
else
if ping -c 1 $server_ip > /dev/null 2>&1
then
status=2
echo “服务器${server_ip},端口${server_port}无法访问,但是能够Ping通!”
else
status=0
echo “服务器${server_ip},端口${server_port}无法访问,并且无法Ping通!”
fi
fi
fi
send_msg_to_interface
let i++
done


2、TCP服务器监控
脚本:/data0/monitor/tcp.sh

引用
#!/bin/sh
LANG=C

#被监控服务器、端口列表
server_all_list=(\
192.168.1.4:11211 \
192.168.1.5:11211 \
192.168.1.6:25 \
192.168.1.7:25 \
)

date=$(date -d “today” +”%Y-%m-%d_%H:%M:%S”)

#采用HTTP POST方式发送检测信息给接口程序interface.php,接口程序负责分析信息,决定是否发送报警MSN消息、手机短信、电子邮件。
send_msg_to_interface()
{
/usr/bin/curl -m 600 -d menu=tcp -d date=$date -d ip=$server_ip -d port=$server_port -d status=$status http://127.0.0.1:8888/interface.php
}

server_all_len=${#server_all_list[*]}
i=0
while [ $i -lt $server_all_len ]
do
server_ip=$(echo ${server_all_list[$i]} | awk -F ‘:’ ‘{print $1}’)
server_port=$(echo ${server_all_list[$i]} | awk -F ‘:’ ‘{print $2}’)
if nc -vv -z -w 3 $server_ip $server_port > /dev/null 2>&1
then
#status: 0,http down 1,http ok 2,http down but ping ok
status=1
echo “服务器${server_ip},端口${server_port}能够正常访问!”
else
if nc -vv -z -w 10 $server_ip $server_port > /dev/null 2>&1
then
status=1
echo “服务器${server_ip},端口${server_port}能够正常访问!”
else
if ping -c 1 $server_ip > /dev/null 2>&1
then
status=2
echo “服务器${server_ip},端口${server_port}无法访问,但是能够Ping通!”
else
status=0
echo “服务器${server_ip},端口${server_port}无法访问,并且无法Ping通!”
fi
fi
fi
send_msg_to_interface
let i++
done


3、MySQL服务器监控
①、MySQL是否能够连接
②、MySQL是否发生表损坏等错误
③、MySQL活动连接数是否过多
④、MySQL从库是否同步正常
⑤、MySQL从库同步延迟时间是否过大
脚本:/data0/monitor/mysql.php

  1. <?php
  2. //$server_list[]=”服务器地址:端口:帐号:密码”;
  3. $server_list[]=“192.168.1.11:3306:root:password”;
  4. $server_list[]=“192.168.1.12:3306:root:password”;
  5. $server_list[]=“192.168.1.13:3306:root:password”;
  6. $database=“mysql”;
  7. $curl = new Curl_Class();
  8. foreach ($server_list as $server) {
  9. $status=1;//初始化,正常状态
  10. unset($data);
  11. $data["menu"] = “mysql”;
  12. $data["info"] = “”;
  13. list($data["ip"], $data["port"], $username, $password) = explode(“:”, $server);
  14. $connect = @mysql_connect($data["ip"].“:”.$data["port"], $username, $password);
  15. if(! $connect)
  16. {
  17. $status=0;
  18. $data["info"] = $data["info"] . “无法连接MySQL服务器\r\n”;
  19. }
  20. $select = @mysql_select_db($database, $connect);
  21. $result = @mysql_query(“show slave status”);
  22. $rs_slave = @mysql_fetch_array($result);
  23. $result = @mysql_query(“show global status like ‘Threads_running’”);
  24. $rs_threads = @mysql_fetch_array($result);
  25. if($rs_slave["Slave_SQL_Running"] == “No”)
  26. {
  27. $status=0;//故障状态
  28. $data["abstract"] = “从库不同步”;
  29. $data["info"] = $data["info"] . “Slave_SQL_Running = No\r\n”;
  30. }
  31. if($rs_slave["Slave_IO_Running"] == “No”)
  32. {
  33. $status=0;
  34. $data["abstract"] = “从库不同步”;
  35. $data["info"] = $data["info"] . “Slave_IO_Running = No\r\n”;
  36. }
  37. if($rs_slave["Last_Error"] != “”)
  38. {
  39. $status=0;
  40. $data["abstract"] = “从库同步出错”;
  41. $data["info"] = $data["info"] . “Last_Error = “.substr($rs_slave["Last_Error"], 0, 40).“\r\n”;
  42. }
  43. if($rs_slave["Seconds_Behind_Master"] > 180)
  44. {
  45. $status=0;
  46. $data["abstract"] = “从库同步延迟时间高达”.$rs_slave["Seconds_Behind_Master"].“秒”;
  47. $data["info"] = $data["info"] . “Seconds_Behind_Master = “.$rs_slave["Seconds_Behind_Master"].“\r\n”;
  48. }
  49. if($rs_threads["Value"] > 60)
  50. {
  51. $status=0;
  52. $data["abstract"] = “活动连接数多达”.$rs_threads["Value"];
  53. $data["info"] = $data["info"] . “Threads_running = “.$rs_threads["Value"].“\r\n”;
  54. }
  55. $data["date"] = date(“Y-m-d_H:i:s”);
  56. if($status == 0)
  57. {
  58. $post = @$curl->post(“http://127.0.0.1:8888/interface.php”, $data);
  59. echo “MySQL服务器“”.$data["ip"].“:”.$data["port"].“”发生故障!\n”;
  60. print_r($post);
  61. }
  62. else
  63. {
  64. $data["failback"] = “active”;//服务器正常,发送通知信息
  65. $post = @$curl->post(“http://127.0.0.1:8888/interface.php”, $data);
  66. echo “MySQL服务器“”.$data["ip"].“:”.$data["port"].“”运行正常!\n”;
  67. print_r($post);
  68. }
  69. }
  70. /**
  71. *********************************************************************
  72. * Curl_Class :curl 类
  73. *********************************************************************/
  74. class Curl_Class
  75. {
  76. function Curl_Class()
  77. {
  78. return true;
  79. }
  80. function execute($method, $url, $fields = , $userAgent = , $httpHeaders = ,
  81. $username = , $password = )
  82. {
  83. $ch = Curl_Class::create();
  84. if (false === $ch)
  85. {
  86. return false;
  87. }
  88. if (is_string($url) && strlen($url))
  89. {
  90. $ret = curl_setopt($ch, CURLOPT_URL, $url);
  91. }
  92. else
  93. {
  94. return false;
  95. }
  96. //是否显示头部信息
  97. curl_setopt($ch, CURLOPT_HEADER, false);
  98. //
  99. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  100. if ($username != )
  101. {
  102. curl_setopt($ch, CURLOPT_USERPWD, $username . ‘:’ . $password);
  103. }
  104. $method = strtolower($method);
  105. if (‘post’ == $method)
  106. {
  107. curl_setopt($ch, CURLOPT_POST, true);
  108. if (is_array($fields))
  109. {
  110. $sets = array();
  111. foreach ($fields as $key => $val)
  112. {
  113. $sets[] = $key . ‘=’ . urlencode($val);
  114. }
  115. $fields = implode(‘&’, $sets);
  116. }
  117. curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
  118. }
  119. else
  120. if (‘put’ == $method)
  121. {
  122. curl_setopt($ch, CURLOPT_PUT, true);
  123. }
  124. //curl_setopt($ch, CURLOPT_PROGRESS, true);
  125. //curl_setopt($ch, CURLOPT_VERBOSE, true);
  126. //curl_setopt($ch, CURLOPT_MUTE, false);
  127. curl_setopt($ch, CURLOPT_TIMEOUT, 600);
  128. if (strlen($userAgent))
  129. {
  130. curl_setopt($ch, CURLOPT_USERAGENT, $userAgent);
  131. }
  132. if (is_array($httpHeaders))
  133. {
  134. curl_setopt($ch, CURLOPT_HTTPHEADER, $httpHeaders);
  135. }
  136. $ret = curl_exec($ch);
  137. if (curl_errno($ch))
  138. {
  139. curl_close($ch);
  140. return array(curl_error($ch), curl_errno($ch));
  141. }
  142. else
  143. {
  144. curl_close($ch);
  145. if (!is_string($ret) || !strlen($ret))
  146. {
  147. return false;
  148. }
  149. return $ret;
  150. }
  151. }
  152. function post($url, $fields, $userAgent = , $httpHeaders = , $username = ,
  153. $password = )
  154. {
  155. $ret = Curl_Class::execute(‘POST’, $url, $fields, $userAgent, $httpHeaders, $username,
  156. $password);
  157. if (false === $ret)
  158. {
  159. return false;
  160. }
  161. if (is_array($ret))
  162. {
  163. return false;
  164. }
  165. return $ret;
  166. }
  167. function get($url, $userAgent = , $httpHeaders = , $username = , $password =
  168. )
  169. {
  170. $ret = Curl_Class::execute(‘GET’, $url, , $userAgent, $httpHeaders, $username,
  171. $password);
  172. if (false === $ret)
  173. {
  174. return false;
  175. }
  176. if (is_array($ret))
  177. {
  178. return false;
  179. }
  180. return $ret;
  181. }
  182. function create()
  183. {
  184. $ch = null;
  185. if (!function_exists(‘curl_init’))
  186. {
  187. return false;
  188. }
  189. $ch = curl_init();
  190. if (!is_resource($ch))
  191. {
  192. return false;
  193. }
  194. return $ch;
  195. }
  196. }
  197. ?>


4、主动监控守护进程
脚本:/data0/monitor/monitor.sh

引用
#!/bin/sh
while true
do
/bin/sh /data0/monitor/http.sh > /dev/null 2>&1
/bin/sh /data0/monitor/tcp.sh > /dev/null 2>&1
/usr/local/php/bin/php /data0/monitor/mysql.php > /dev/null 2>&1
sleep 10
done

启动主动监控守护进程:

/usr/bin/nohup /bin/sh /data0/monitor/monitor.sh 2>&1 > /dev/null &

三、被动报告监控(“被监控机”采集数据发送给“监控机”)
1、磁盘空间使用量监控
2、磁盘Inode使用量监控
3、Swap交换空间使用量监控
4、系统负载监控
5、Apache进程数监控

被动监控这部分,在我的文章《写完“Linux服务器监控系统 ServMon V1.1” 》中已经实现,就不再详细写出。

分类: Linux 标签: , , , ,

三种遍历树的方法

2008年6月30日 Galaxy 没有评论

http://www.cnblogs.com/niniwzw/archive/2008/06/28/1231410.html

三种遍历树的方法

    树的概念在开发里面是很重要的一部分,xml的文档对象模型(DOM)就是一棵树,文件夹文件的结构也是一棵树。遍历树是开发中经常要遇到的一个问题,比如,要找出DOM里面的img 标签的个数,就要遍历一棵DOM树。要在一个目录里面查找是否有一个文件也要用到遍历这个目录。在这里我们以遍历文件为例,说明遍历树的三种基本的方法:
递归深度优先算法,非递归深度优先算法,非递归广度优先算法。
   
这些算法是我们在项目中经常重复的一些算法,我感觉我写程序以来,我做的大多数算法都用了大二学的那本数据结构,有些时候,只是改装一些一些算法,有些时候也只是把几种算法合并一下,也许这是为什么数据结构这本书这样重要的原因。
先看代码:

<?php
define('DS', DIRECTORY_SEPARATOR);
function rec_list_files($from = '.')
{
    if(!is_dir($from)) {
        return array();
    }
    $files = array();
    if($dh = opendir($from))
    {
        while(false !== ($file = readdir($dh))) {
 
            if($file == '.' || $file == '..') {
                continue;
            }
            $path = $from . DS . $file;
 
            if (is_file($path)) {
                $files[] = $path;
            }
            $files = array_merge($files, rec_list_files($path));
        }
        closedir($dh);
    }
    return $files;
}
 
function deep_first_list_files($from = '.')
{
    if(!is_dir($from)) {
        return false;
    }
    $files = array();
    $dirs = array($from);
    while(NULL !== ($dir = array_pop($dirs))) {
        if( $dh = opendir($dir)) {
            while( false !== ($file = readdir($dh))) {
                if($file == '.' || $file == '..') {
                    continue;
                }
                $path = $dir . DS . $file;
                if(is_dir($path)) {
                    $dirs[] = $path;
                } else {
                    $files[] = $path;
                }
            }
            closedir($dh);
        }
    }
    return $files;
}
 
function breadth_first_files($from = '.') {
    $queue = array(rtrim($from, DS).DS);// normalize all paths
    $files = array();
    while($base = array_shift($queue )) {
        if (($handle = opendir($base))) {
            while (($child = readdir($handle)) !== false) {
               if( $child == '.' || $child == '..') {
                    continue;
                }
                if (is_dir($base.$child)) {
                    $combined_path = $base.$child.DS;
                    array_push($queue, $combined_path);
                } else {
                    $files[] = $base.$child;
                }
            }
            closedir($handle);
        } // else unable to open directory => NEXT CHILD
    }
    return $files; // end of tree, file not found
}
 
function profile($func, $trydir)
{
    $mem1 = memory_get_usage();
    echo '<pre>———————– Test run for '.$func.'() ...';
    flush();
    $time_start = microtime(true);
    $list = $func($trydir);
    //print_r($list);
    $time = microtime(true) - $time_start;
    echo 'Finished : '.count($list).' files</ pre>';
    $mem2 = memory_get_peak_usage();
    printf('<pre>Max memory for '.$func.'() : %0.2f kbytes Running time for '.$func.'() : %0.f s</ pre>',
    ($mem2-$mem1)/1024.0, $time);
    return $list;
}
profile('rec_list_files', "D:\www\server");
profile('deep_first_list_files', "D:\www\server");
profile('breadth_first_files', "D:\www\server");
?>

rec_list_files 是递归的深度优先的算法,这个是用一个简单的函数递归来实现,用array_merge 来合并数组
deep_first_list_files 是非递归的深度优先的算法,用了一个栈来实现。
breadth_first_files 是非递归的广度优先算法,用了一个队列来实现。
顺便说一句,php中的数组,可以做为hashtable,queue,stack,普通数组,甚至做树也是可以的。运行的结果:

-----------------------
Test run for rec_list_files() ...Finished : 1868 files
Max memory for rec_list_files() : 496.93 kbytes Running time for rec_list_files() : 9.231678 s
----------------------- 
Test run for deep_first_list_files() ...Finished : 1868 files
Max memory for deep_first_list_files() : 432.41 kbytes Running time for deep_first_list_files() : 3.940216 s
----------------------- 
Test run for breadth_first_files() ...Finished : 1868 files
Max memory for breadth_first_files() : 432.55 kbytes Running time for breadth_first_files() : 3.749125 s

第二种和第三种方法的效率和内存消耗差别不大,但是第一种递归调用消耗的内存和时间都要大很多,有时候为了效率,可能采用非递归的实现方式比较的好。

分类: Programming 标签: , ,
Locations of visitors to this page