去年年底的各种网站帐号信息的数据库泄漏,很是给力啊,趁机也下载了几个数据库,准备学学数据分析家来分析一下这些帐号信息。虽然这些数据信息都已经被“整理”过的,不过自己拿来学习也挺有用的,毕竟有这么大的数据量。
数据量大带来的问题就是单个文件很大,能够打开这个文件相当不容易,记事本就不要指望了,果断死机。用MSSQL的客户端也打不开这么大的SQL文件,直接报内存不足,原因据说是MSSQL在读取数据的时候,是一次性地将读取到的数据放在内存中,如果数据量过大,而内存不足,则会直接导致系统瘫掉。
Navicat Premium 这儿推荐一个软件Navicat
Premium,相当给力啊,几百兆的SQL文件轻松就打开了,一点都不卡。而且这个客户端软件支持MSSQL、MYSQL、Oracle……等等各种数据库的连接,其它的很多功能就自己慢慢研究了。
虽然用Navicat可以打开CSDN这个274MB的SQL文件,但是内容却是没意义的,而且也不方便对这些帐号信息进行查询、分类、统计等等操作。唯一的方法就是把这些数据一条一条地读取出来,然后分拆每条记录的不同片段,再将这些片段以数据字段的格式存入数据库,这样就可以方便以后的使用了。
使用PHP读取超大文件
PHP有很多种文件读取的方式,根据目标文件的不同,采取更合适的方法,可有效地提高执行效率。由于CSDN数据库文件很大,所以我们尽量不在短时间内全都读取出来,毕竟每读取一条数据还要对其分拆和写入操作。那么比较合适的方式就是对文件进行分区域地读取,通过使用PHP的fseek和fread相结合,即可做到随意读取文件中的某一部份数据,下面是实例代码:
复制代码 代码如下: function
readBigFile($filename, $count = 20, $tag = “rn”) { $content =
“”;//最终内容 $current = “”;//当前读取内容寄存 $step= 1;//每次走多少字符
$tagLen = strlen; $start = 0;//起始位置 $i = 0;//计数器 $handle =
fopen;//读写模式打开文件,指针指向文件起始位置 while($i < $count &&
!feof { fseek($handle, $start, SEEK_SET);//指针设置在文件开头 $current
= fread;//读取文件 $content .= $current;//组合字符串 $start +=
$step;//依据步长向前移动 //依据分隔符的长度截取字符串最后免得几个字符
$substrTag = substr; if { //判断是否为判断是否是换行或其他分隔符 $i++;
$content .= “
“; } } //关闭文件 fclose; //返回结果 return $content; } $filename =
“csdn.sql”;//需要读取的文件 $tag = “n”;//行分隔符 注意这里必须用双引号
$count = 100;//读取行数 $data = readBigFile($filename,$count,$tag); echo
$data;
关于函数传入的变量$tag的值,根据系统不一样,传入的值也是有区别的:Windows用”rn”,linux/unix用”n”,Mac
OS用”r”。
程序执行的大概流程:先定义读取文件的一些基础变量,然后打开文件,将指针定位在文件的指定位置,并读取指定大小的内容。每读取一次将内容存储在变量中,直到达到读取要求的行数或文件结束。
绝不要假定程序中的一切都将按计划运行。
根据上面的代码,虽然能够得到文件中指定位置、指定大小的数据,但这整个过程只执行了一次,并不能得到所有的数据。其实要得到所有的数据,可以在这个循环的外层再添加判断文件是否结束的循环,但这很浪费系统资源,甚至由于文件过大一直没法读完而导致PHP执行超时。另一种方法就是记录并存储上次读取数据后指针所在的位置,然后再次执行该循环的时候,将指针定位在上次结束的位置,这样就不存在一次循环要把文件从头读到尾的情况。
其实CSDN这个数据库我到现在都还没有导入数据库,因为当时泄漏后没几天CNBETA上就有一个分析了,呵呵,动作太快了。当看到别人已经做了这个事之后,自动就没有多少动力来做了,不过为了学习,还是要抽时间把这个事完成了。

一般读取文件我们用fopen 或者
file_get_contents
,前者可以循环读取,后者可以一次性读取,但都是将文件内容一次性加载来操作。如果加载的文件特别大时,如几百M,上G时,这时性能就降下来了,那么PHP里有没有对大文件的处理函数或者类呢?
答案是:有的。

  一,PHP脚本与动态页面。

PHP真的越来越“面向对象”了,一些原有的基础的SPL方法都开始陆续地实现出class了。

  PHP脚本是一种服务器端脚本程序,可通过嵌入等方法与HTML文件混合,也可以类,函数封装等形式,以模板的方式对用户请求进行处理。无论以何种方式,它的基本原理是这样的。由客户端提出请求,请求某一页面 —–> WEB服务器引入指定相应脚本进行处理 —–> 脚本被载入服务器 —–> 由服务器指定的PHP解析器对脚本进行解析形成HTML语言形式 —-> 将解析后的HTML语句以包的方式传回给浏览器。由此不难看出,在页面发送到浏览器后,PHP就不存在了,已被转化解析为HTML语句。客户请求为一动态文件,事实上并没有真正的文件存在在那里,是PHP解析而成相对应的页面,然后发送回浏览器。这种页面处理方式被称为“动态页面”。

从 PHP 5.1.0 开始,SPL 库增加了 SplFileObject 与 SplFileInfo
两个标准的文件操作类。SplFileInfo 是从 PHP 5.1.2 开始实现的。

  二,静态页面。

从字面意思理解看,可以看出 SplFileObject 要比 SplFileInfo 更为强大。

  静态页面是指在服务器端确实存在的仅含HTML以及JS,CSS等客户端运行脚本的页面。它的处理方式是。由客户端提出请求,请求某一页面 —-> WEB服务器确认并载入某一页面 —-> WEB服务器将该页面以包的形式传递回浏览器。由这一过程,我们对比一下动态页面,即可方现。动态页面需由WEB服务器的PHP解析器进行解析,而且通常还需连接数据库,进行数据库存取操作,然后才能形成HTML语言信息包;而静态页面,无须解析,无须连接数据库,直接发送,可大大减轻服务器压力,提高服务器负载能力,大幅提供页面打开速度和网站整体打开速度。但其缺点是,不能动态地对请求进行处理,服务器上必须确实存在该文件。

不错,SplFileInfo
仅用于获取文件的一些属性信息,如文件大小、文件访问时间、文件修改时间、后缀名等值,而
SplFileObject 是继承 SplFileInfo 这些功能的。

  三,模板及模板解析。

 代码如下

  模板即尚未填充内容html文件。例如:

 /** 返回文件从X行到Y行的内容(支持php5、php4) 
 * @param string $filename 文件名
 * @param int $startLine 开始的行数
 * @param int $endLine 结束的行数
 * @return string
 */
function getFileLines($filename, $startLine = 1, $endLine=50,
$method=’rb’) {
    $content = array();
    $count = $endLine – $startLine; 
    // 判断php版本(因为要用到SplFileObject,PHP>=5.1.0)
    if(version_compare(PHP_VERSION, ‘5.1.0’, ‘>=’)){
        $fp = new SplFileObject($filename, $method);
        $fp->seek($startLine-1);// 转到第N行,
seek方法参数从0开始计数
        for($i = 0; $i <= $count; ++$i) {
            $content[]=$fp->current();// current()获取当前行内容
            $fp->next();// 下一行
        }
    }else{//PHP<5.1
        $fp = fopen($filename, $method);
        if(!$fp) return ‘error:can not read file’;
        for ($i=1;$i<$startLine;++$i) {// 跳过前$startLine行
            fgets($fp);
        }
        for($i;$i<=$endLine;++$i){
            $content[]=fgets($fp);// 读取文件行内容
        }
        fclose($fp);
    }
    return array_filter($content); //
array_filter过滤:false,null,”
}  

   temp.html

 Ps: 上面都没加”读取到末尾的判断”:!$fp->eof() 或者
!feof($fp),加上这个判断影响效率,自己加上测试很多很多很多行的运行时间就晓得了,而且这里加上也完全没必要。

<html>
   <title>{title}</title>
   <body>
    this is a {file} file’s templets
   </body>
</html>

从上面的函数就可以看出来使用SplFileObject比下面的fgets要快多了,特别是文件行数非常多、并且要取后面的内容的时候。fgets要两个循环才可以,并且要循环$endLine次。

    PHP处理:
    templetest.php

此方法花了不少功夫,测试了很多中写法,就是想得出效率最高的方法。哪位觉得有值得改进的欢迎赐教。

图片 1图片 2代码

使用,返回35270行-35280行的内容:

<?php
   $title = “拓迈国际测试模板”;
   $file = “TwoMax Inter test templet,<br>author:Matrix@Two_Max”;

 代码如下

 $fp       = fopen (“temp.html”,”r”);
   $content   = fread ($fp,filesize (“temp.html”));
   $content .= str_replace (“{ file }”,$file,$content);
   $content .= str_replace (“{ title }”,$title,$content);

echo ‘<pre>’;
var_dump(getFileLines(‘test.php’,35270,35280));
echo ‘</pre>’; 

   echo $content;
?>

再看一个实例

 

 代码如下

   模板解析处理,即将经PHP脚本解析处理后得出的结果填充(content)进模板的处理过程。通常借助于模板类。目前较流行的模板解析类有phplib,smarty,fastsmarty等等。模板解析处理的原理通常为替换。也有些程序员习惯将判断,循环等处理放进模板文件中,用解析类处理,典型应用为block概念,简单来说即为一个循环处理。由PHP脚本指定循环次数,如何循环代入等,再由模板解析类具体实施这些操作。

 

  好了,对比过静态页面与动态页面各自的优劣,现在我们就来说说,如何用PHP生成静态文件。

发表评论

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