lazybios

PHP小偷程序

项目背景

学校图书馆开展某活动,要求设立一个活动网站,使用目的仅为形象展示,展示数据量不小,老师又不愿意手动更新,遂要求一款自动更新数据的网站系统。这样的需求,非小偷程序而不可(其实调用开放平台api也是可以的,奈何没有合适的api且还得分析数据,安排数据展示形式)

开发思路

思路1:客户端js 跨域采集数据再进行数据重整理

思路2:php小偷程序,获取数据、正则捕获目标数据、本地格式化数据、形象展示

思路1固然可行,但出于俩个原因最后放弃了,一是本人js功底薄软,入门小白级别且跨域就是一个难度,二是客户端的配置不同意,有的用户的浏览器屏蔽了js功能,浏览器对js支持层次不齐。于是放弃了思路1,转做思路2

开发环境及关键点

环境:php ci框架、zend studio

关键点:php获取数据、正则格式化数据

细节问题

细节1

数据展示可完全模仿目标站点,但前提是要用firebug将对方的css文件中的关键部位移植到你的系统上来,这里需要注意的就是命名问题,要避免命名冲突带来的杂乱页面

细节2

当待采集页面的格式和本地输出格式不同或需要采集几种格式不同页面的内容展示到一个页面上时,需要事先将编码进行统一,否则会遇到乱码问题,php中使用iconv或mb_convert_encoding函数进行编码的转换,实践中发现前者更强大一些,但当目标程序编码类型不明确的时最好使用后者,后者可以自动识别编码类型后进行转换操作。我要采集的页面编码是gb2312,在使用iconv时遇到一个错误:

Notice: iconv() [function.iconv]: Detected an illegal character in input string in a.php on line ...

该错误是因为内容中有编码超出了gb2312编码范围的字符,解决办法是将源编码类型改为GBK即可,应为GBK与gb2312是包含与被包含的关系,前者表示范围更大,这样就可以有效排除这个错误。iconv(“GBK”,“UTF-8”,$string);

细节3

使用file_get_contents函数读取http协议获取目标站点字符串,该函数获取网站信息时前面必须添加协议名称,同时该函数还有4个可选参数,分别是搜索路径、上下文环境、开始读取位置、最大读取长度。在采集过程中,当目标采集站点服务器访问速度过慢会出现获取数据超时错误,这时并不是php执行超时,而是该函数访问超时,譬如访问国外一些站点就遇到这个问题,解决办法即通过使用context上下文环境设置执行超时时间

$opts = array ( ‘http’ => array ( 'timeout’ => 120 ) ); $context = stream_context_create ( $opts ); $con = file_get_contents ( $url, false, $context );

同时最好将php的执行时间也设置一下,从而避免因为php执行超时而崩溃的问题。这个在将php当作脚本语言执行一些日常操作时特别有用,另外除了这个file_get_contents函数外还有一个功能强大的curl函数,curl是利用URL语法在命令行方式下工作的文件传输工具,该函数可以写出人机互动的脚本url相关脚本,类似与wget命令,但这个需要服务器额外的支持,考虑到通用性就没有使用,标记一下,项目搞完去研究一番!

细节4

正则问题,这个是采集程序的核心所在啊,正则问题,不过这种简单的采集也用不到多少复杂的正则表达式,只要确保获取内容的开始结尾的唯一性一遍都没有问题的,这里与个技巧就是可以打乱标签的意义,单纯性的当做字符来看待,可以任意截断,这样就不怕没有唯一性的标识了,php中的正则函数preg_match和preg_match_all前者匹配到相符的就停止,后者将所有匹配内容全部罗列出来,哦,对了还有一个重要的正则概念就是贪婪匹配和懒惰匹配,前者匹配结尾直到最后一个出现符合条件的匹配,后者只要出现结尾匹配项就停止匹配。preg_match ( $pattern_title, $text, $title );,单个参数分别是正则表达式,匹配内容,返回数组

细节5

字符串截断,该功能没有现成的函数,只能通过explode函数自己写一个,使用这个函数可以使匹配效率更高,思路就是将目标范围圈定的更小,进而再去运用正则,这样就可以使用局部性原理了。函数具体如下:

public function cut_string($file, $start, $end) { $temp_content = explode ( $start, $file ); $real_content = explode ( $end, $temp_content [1] ); $result = array ( $real_content [0], $temp_content [1] ); return $result; }

这样返回的结果中就同时包含目标截取内容及截取剩余内容,可以同时对二者做其它具体处理。

细节6

该问题是ci框架的属于ci的一个问题,不使用ci可以忽略掉,就是以get形式传入url地址,ci中的控制器获取参数以’\'来区分,但url中有许多这样的符号,如果直接传入就会被当作函数参数来处理,达不到传递url的效果,这时只能暂时放弃ci自己的url路由特性,恢复到$_GET功能,具体:

在config.php 中,将‘uri_protocol’ 设置为 ‘PATH_INFO’.

在使用$GET['xxx’]获取参数前,需要先parse_str($_SERVER['QUERYSTRING’],$_GET)下就可以获取到了

此时url可以写成这样index.php/book/?url=“http://lazybios.github.com",parse_str可以写到构造函数中

当然,在ci中也可以直接全局使用这个获取参数的方法,具体方法可以参考官方wiki

以上是在这个项目开发中遇到的一些关键问题,其实还有一些ci和php开发的技巧没有写出来,我会在下一篇关于"基于ci实现的精品课程cms"中去详细罗列,最后贴上一张项目效果图吧(局部)

微信关注「日拱一卒」公众号