Codeigniter:Better folder setup

Posted on 2012年12月26日 15:07

This guide is for you to have a better folder setup for your codeigniter. Separate your application folder from the core libraries. Have the bulk of your code outside of your public html folder thus improving security. Then create a public folder to separate the images, css and javascripts.

Step 1:Download Codeigniter

I guess first thing to do is download the latest Codeigniter. Once you downloaded the zip. Unzip it and place it to your server. Either you do it in your localhost using WAMP or upload it to a PHP enabled server.

the basic CI installation on most web servers gives you this folder structure:

we want this:

Step 2: Changing structure

As you see the folder structure on top, I created a public folder. You can create your css, images, js folders here. Move the index.php that’s located at the root to here. Then you can actually just delete the user_guide folder and license.txt.

Edit index.php, the one you moved to the public folder from

?
1
$system_path = 'system';

to

?
1
$system_path = '../system';

Then the application path

?
1
$application_folder = "application";

to

?
1
$application_folder = "../application";

Then make a .htaccess file at the root folder to get rid of the annoying index.php out of the url.

?
1
2
3
RewriteEngine on
RewriteCond $1 !^(index\.php|images|robots\.txt)
RewriteRule ^(.*)$ ci/index.php/$1 [L]

 

立即输出缓冲区

Posted on 2012年10月06日 19:19

<?php
set_time_limit(10);
ob_end_clean();     //在循环输出前,要关闭输出缓冲区

echo str_pad('',1024);     //浏览器在接受输出一定长度内容之前不会显示缓冲输出,这个长度值 IE是256,火狐是1024
for($i=1;$i<=100;$i++){
  echo $i.'<br/>';
  flush();    //刷新输出缓冲
  sleep(1);
}
?>

 

PHP 配置服务器crontab

Posted on 2012年8月02日 21:18

<?php

class Ssh2_crontab_manager
{
    private $connection;
    private $path;
    private $handle;
    private $cron_file;

    function __construct($host=NULL, $port=NULL, $username=NULL, $password=NULL)
    {
        $path_length = strrpos(__FILE__, "/");
        $this->path = substr(__FILE__, 0, $path_length) .'/';
        $this->handle = 'crontab.txt';
        $this->cron_file = "{$this->path}{$this->handle}";
        
        try
        {
            if (is_null($host) || is_null($port) || is_null($username) || is_null($password))
                throw new Exception("Please specify the host, port, username and password!");
            
            $this->connection = @ssh2_connect($host, $port);
            if (!$this->connection)
                throw new Exception("The SSH2 connection could not be established.");
            
            $authentication = @ssh2_auth_password($this->connection, $username, $password);
            if (!$authentication)
                throw new Exception("Could not authenticate '{$username}' using password: '{$password}'");            
        }
        catch (Exception $e)
        {
            $this->error_message($e->getMessage());
        }
    }
    
    public function exec()
    {
        $argument_count = func_num_args();
        
        try
        {
            if (!$argument_count)
                throw new Exception("There is nothing to execute, no arguments specified.");
            
            $arguments = func_get_args();
            
            $comment_string = ($argument_count > 1) ? implode(" && ", $arguments) : $arguments[0];
            
            $stream = @ssh2_exec($this->connection, $comment_string);
            if (!$stream)
                throw new Exception("Unable to execute the specified commands: <br>{$comment_string}");
        }
        catch (Exception $e)
        {
            $this->error_message($e->getMessage());
        }
        
        return $this;
    }
    
    public function write_to_file($path=NULL, $handle=NULL)
    {
        if (!$this->crontab_file_exists())
        {
            $this->handle = (is_null($handle)) ? $this->handle : $handle;
            $this->path   = (is_null($path)) ? $this->path     : $path;
            $this->cron_file = "{$this->path}{$this->handle}";
            
            $init_cron = "crontab -l > {$this->cron_file} && [ -f {$this->cron_file} ] || > {$this->cron_file}";
            
            $this->exec($init_cron);
        }
        
        return $this;
    }
    
    public function remove_file()
    {
        if ($this->crontab_file_exists()) $this->exec("rm {$this->cron_file}");
        return $this;
    }
    
    public function append_cronjob($cron_jobs=NULL)
    {
        if (is_null($cron_jobs))
            $this->error_message("Nothing to append! Pleasae specify a cron job or an array of cron jobs.");
        
        $append_cronfile = "echo '";
        $append_cronfile .= (is_array($cron_jobs)) ? implode("\n", $cron_jobs) : $cron_jobs;
        $append_cronfile .= "' >> {$this->cron_file}";
        
        $install_cron = "crontab {$this->cron_file}";
        
        $this->write_to_file()->exec($append_cronfile, $install_cron)->remove_file();
        
        return $this;
    }
    
    public function remove_cronjob($cron_jobs=NULL)
    {
        if (is_null($cron_jobs))
            $this->error_message("Nothing to remove! Please specify a cron job or an array of cron jobs.");
        $this->write_to_file();
        
        $cron_array = file($this->cron_file, FILE_IGNORE_NEW_LINES);
        
        if (empty($cron_array))
            $this->error_message("Nothing to remove! The crontab is already empty.");
        
        $original_count = count($cron_array);
        
        if (is_array($cron_jobs))
        {
            foreach ($cron_jobs as $cron_regex)
                $cron_array = preg_grep($cron_regex, $cron_array, PREG_GREP_INVERT);
        }
        else
        {
            $cron_array = preg_grep($cron_jobs, $cron_array, PREG_GREP_INVERT);
        }
        
        return ($original_count == count($cron_array)) ? $this->remove_file() :
                $this->remove_crontab()->append_cronjob($cron_array);
    }
    
    public function remove_crontab()
    {
        $this->exec("crontab -r")->remove_file();
        return $this;
    }
    
    private function crontab_file_exists()
    {
        return file_exists($this->cron_file);
    }
    
    private function error_message($error)
    {
        die("<pre style='color:#EE2711'>ERROR: {$error}</pre>");
    }
    
}


$crontab = new Ssh2_crontab_manager('localhost', '22', 'hewenxiang', '123456');

$new_cronjobs = array(
    '0 0 1 * * home/path/to/command/the_command.sh',
    '30 8 * * 6 home/path/to/command/the_command.sh >/dev/null 2>&1'
);

$crontab->append_cronjob($new_cronjobs);

$cron_regex = array(
        '/0 0 1 \* \*/',
        '/home\/path\/to\/command\/the_command\.sh/'
);

$crontab->remove_cronjob($cron_regex);
 

让PHP更快的提供文件下载

Posted on 2012年5月08日 16:39

 

一般来说, 我们可以通过直接让URL指向一个位于Document Root下面的文件, 来引导用户下载文件.

但是, 这样做, 就没办法做一些统计, 权限检查, 等等的工作. 于是, 很多时候, 我们采用让PHP来做转发, 为用户提供文件下载.

  1. <?php
  2.     $file = "/tmp/dummy.tar.gz";
  3.     header("Content-type: application/octet-stream");
  4.     header('Content-Disposition: attachment; filename="' . basename($file) . '"');
  5.     header("Content-Length: ". filesize($file));
  6.     readfile($file);

但是这个有一个问题, 就是如果文件是中文名的话, 有的用户可能下载后的文件名是乱码.

于是, 我们做一下修改(参考: :

  1. <?php
  2.     $file = "/tmp/中文名.tar.gz";
  3.  
  4.     $filename = basename($file);
  5.  
  6.     header("Content-type: application/octet-stream");
  7.  
  8.     //处理中文文件名
  9.     $ua = $_SERVER["HTTP_USER_AGENT"];
  10.     $encoded_filename = urlencode($filename);
  11.     $encoded_filename = str_replace("+", "%20", $encoded_filename);
  12.     if (preg_match("/MSIE/", $ua)) {
  13.      header('Content-Disposition: attachment; filename="' . $encoded_filename . '"');
  14.     } else if (preg_match("/Firefox/", $ua)) {
  15.      header("Content-Disposition: attachment; filename*=\"utf8''" . $filename . '"');
  16.     } else {
  17.      header('Content-Disposition: attachment; filename="' . $filename . '"');
  18.     }
  19.  
  20.     header('Content-Disposition: attachment; filename="' . $filename . '"');
  21.     header("Content-Length: ". filesize($file));
  22.     readfile($file);

恩, 现在看起来好多了, 不过还有一个问题, 那就是readfile, 虽然PHP的readfile尝试实现的尽量高效, 不占用PHP本身的内存, 但是实际上它还是需要采用MMAP(如果支持), 或者是一个固定的buffer去循环读取文件, 直接输出.

输出的时候, 如果是Apache + PHP mod, 那么还需要发送到Apache的输出缓冲区. 最后才发送给用户. 而对于Nginx + fpm如果他们分开部署的话, 那还会带来额外的网络IO.

那么, 能不能不经过PHP这层, 直接让Webserver直接把文件发送给用户呢?

今天, 我看到了一个有意思的文章: How I PHP: X-SendFile.

我们可以使用Apache的module mod_xsendfile, 让Apache直接发送这个文件给用户:

  1. <?php
  2.     $file = "/tmp/中文名.tar.gz";
  3.  
  4.     $filename = basename($file);
  5.  
  6.     header("Content-type: application/octet-stream");
  7.  
  8.     //处理中文文件名
  9.     $ua = $_SERVER["HTTP_USER_AGENT"];
  10.     $encoded_filename = urlencode($filename);
  11.     $encoded_filename = str_replace("+", "%20", $encoded_filename);
  12.     if (preg_match("/MSIE/", $ua)) {
  13.      header('Content-Disposition: attachment; filename="' . $encoded_filename . '"');
  14.     } else if (preg_match("/Firefox/", $ua)) {
  15.      header("Content-Disposition: attachment; filename*=\"utf8''" . $filename . '"');
  16.     } else {
  17.      header('Content-Disposition: attachment; filename="' . $filename . '"');
  18.     }
  19.  
  20.     header('Content-Disposition: attachment; filename="' . basename($file) . '"');
  21.  
  22.     //让Xsendfile发送文件
  23.     header("X-Sendfile: $file");

X-Sendfile头将被Apache处理, 并且把响应的文件直接发送给Client.

Lighttpd和Nginx也有类似的模块, 大家有兴趣的可以去找找看 :)

PHP命名空间

Posted on 2012年3月22日 15:46

究竟什么是"命名空间"呢? 看看中文手册是怎么说的:

命名空间概述

什么是命名空间?从广义上来说,命名空间是一种封装事物的方法。在很多地方都可以见到这种抽象概念。

例如,在操作系统中目录用来将相关文件分组,对于目录中的文件来说,它就扮演了命名空间的角色。

具体举个例子,文件 foo.txt 可以同时在目录/home/greg 和 /home/other 中存在,但在同一个目录中

不能存在两个 foo.txt 文件。另外,在目录 /home/greg 外访问 foo.txt 文件时,我们必须将目录名以

及目录分隔符放在文件名之前得到 /home/greg/foo.txt。

这个原理应用到程序设计领域就是命名空间的概念。

在PHP中,命名空间用来解决在编写类库或应用程序时创建可重用的代码如类或函数时碰到的两类问题:

1) 用户编写的代码与PHP内部的类/函数/常量或第三方类/函数/常量之间的名字冲突。 

2) 为很长的标识符名称(通常是为了缓解第一类问题而定义的)创建一个别名(或简短)的名称,提高源代码的可读性。 

看完概述之后有了初步的概念,用生活中例子描述:
甲有一台iphone5,乙也有一个iphone5,但我们能区分清楚,因为他们分别属于两个不同的人。 

命名空间的定义和规则就不多说了,可以看手册介绍。

看看代码是怎么操作的:
创建三个文件分别是file1.ph、file2.php、file3.php、file4.php 他们同属于一个目录级里面。

  1) file1.php

<?php
//这是其中一种定义命名空间的方式
namespace App\Lib1;

const MYCONST = 'App\Lib1\MYCONST';  

function MyFunction() {  
    return __FUNCTION__;  
}  

class MyClass
{
    static function WhoAmI() {  
	return __METHOD__;  
    }  
}
?>

 2) file2.php

<?php
//这是另外一种使用代码块的方式定义命名空间,这方式可以区分开同一个文件里两个不同的命名空间的定义(但是不建议做)。
namespace App\Lib2
{
	const MYCONST = 'App\Lib2\MYCONST';  

	function MyFunction() {  
		return __FUNCTION__;  
	}  

	class MyClass
	{
		static function WhoAmI() {  
			return __METHOD__; 
		}  
	}
} 
?>

file4.php

<?php
//普通的PHP文件,并未定义命名空间
const MYCONST = 'App\Lib4\MYCONST';  

function MyFunction() {  
	return __FUNCTION__;  
}  

class MyClass
{
	static function WhoAmI() {  
		return __METHOD__; 
	}  
}
?>

到这里file1.php和file2.php内容几乎一样, 只有命名空间的名字不同。

另外还要补充一下关于命名空间的一些相关术语:

完全限定名称(Fully-qualified name):

任何PHP代码都可以引用完全限定名称,它是一个以命名空间反斜线开头的标识符,如\App\Lib1\MYCONST,\App\Lib2\MyFunction( )等。

完全限定名称是没有任何歧义的,开头的反斜线和文件路径的作用有点类似,它表示“根”全局空间,如果我们在全局空间中实现了一个不同的MyFunction( ),可以使用\MyFunction( )从lib1.php或lib2.php调用它。

完全限定名称对一次性函数调用或对象初始化非常有用,但当你产生了大量的调用时它们就没有实用价值了,在下面的讨论中我们将会看到,PHP提供了其它选项以解除我们为命名空间打字的烦恼。

限定名称(Qualified name):
至少有一个命名空间分隔符的标识符,如Lib1\MyFunction( )。

非限定名称(Unqualified name):

没有命名空间分隔符的标识符,如MyFunction( )。

看看file3.php是如何使用的命名空间

<?php
/**
 * 若当前PHP文件没有定义命名空间,当require_once('file4.php')时就会发生冲突
 * Fatal error: Cannot redeclare MyFunction()
 */
namespace App\Lib3;

/* 这里下面是file3.php命名空间的一些定义 */
const MYCONST = 'App\Lib3\MYCONST';

function MyFunction() {
	return __FUNCTION__;
}

class MyClass
{
	static function WhoAmI() {  
		return __METHOD__; 
	}
}

/**
 * 把file1.php、file2.php、file4.php包含进来file3.php之后,尝试输出 echo MYCONST; 结果会是App\Lib3\MYCONST,
 * 为什么不是file4.php里面定义的MYCONST常量呢?因为file4.php是属于"根"的全局空间,并且输出时没有指定使用哪个命名
 * 空间(非限定名称),所以默认是当前文件的MYCONST常量,若要输出file4.php的常量,可以这样 echo \MYCONST;
 */
require_once('file1.php');
require_once('file2.php');
require_once('file4.php');

/**
 * 光是把定义了命名空间的文件包含进来,还不能使用各自的定义,需要使用 use 操作符导入命名空间
 * 格式: use 命名空间; ,另外对于很长的命名空间定义还能够使用别名,类似SQL的as, 格式: use 命名空间 as 别名;
 */
use App\Lib1;
use App\Lib2 as B;

/* 开始享受命名空间带来的便利了 */
#完全限定名称
#类似于绝对路劲,从“根”开始.
echo \App\Lib1\MYCONST . "<br/>";
echo \App\Lib1\MyFunction() . "<br/>";
echo \App\Lib1\MyClass::WhoAmI() . "<br/>";

#限定名称
#类似于相对路劲,让系统自己去搜索.
echo B\MYCONST . "<br/>";
echo B\MyFunction() . "<br/>";  
echo B\MyClass::WhoAmI() . "<br/>";

#非限定名称
echo MYCONST . "<br/>";
echo MyFunction() . "<br/>";  
echo MyClass::WhoAmI() . "<br/>";
?>

到这里已经对命名空间有一定的认识,下面再看看一些高级应用:

__NAMESPACE__常量

__NAMESPACE__是一个PHP字符串,它总是返回当前命名空间的名称,在全局空间(file4.php就是属于全局空间)中它是一个空字符串。

 

< ?php  
namespace App\Lib1;  
echo __NAMESPACE__; // outputs: App\Lib1  
?> 

这个值在调试时非常有用,它也可由于动态生成一个完全限定类名,如:

 

< ?php  
namespace App\Lib1;  
 
class MyClass {  
    public function WhoAmI() {  
        return __METHOD__;  
    }  
}  

$c = __NAMESPACE__ . '\\MyClass';  
$m = new $c;  
echo $m->WhoAmI(); // outputs: App\Lib1\MyClass::WhoAmI  
?>  

namespace关键字

namespace关键字可以用于明确引用一个当前命名空间或子命名空间中的项目,它等价于类中的self命名空间:

更多详细的介绍在手册里面,非常多例子。

 

< ?php  
namespace App\Lib1;  
 
class MyClass {  
    public function WhoAmI() {  
        return __METHOD__;  
    }  
}  
 
$m = new namespace\MyClass;  
echo $m->WhoAmI(); // outputs: App\Lib1\MyClass::WhoAmI  
?>  

自动载入命名空间类

PHP 5中最省时省力的特性是自动载入,在全局(非命名空间)PHP代码中,可以写一个标准自动载入函数:

< ?php  
$obj= new MyClass1(); // classes/MyClass1.php is auto-loaded  
$obj= new MyClass2(); // classes/MyClass2.php is auto-loaded  
 
// autoload function  
function __autoload($class_name) {  
    require_once("classes/$class_name.php");  
}  
?>  

在PHP 5.3中,你可以创建一个命名空间类的实例,在这种情况下,完全限定命名空间和类名传递给__autoload函数,例如,$class_name的值可 能是App\Lib1\MyClass。你可以在相同的文件夹下放置所有的PHP类文件,从字符串中提取命名空间,但那样会导致文件名冲突。

另外,你的类文件层次结构会按照命名空间的结构重新组织,例如,MyClass.php文件可以创建在/classes/App/Lib1文件夹下:

/classes/App/Lib1/MyClass.php

< ?php
namespace App\Lib1;  
 
class MyClass {  
    public function WhoAmI() {  
        return __METHOD__;  
    }  
}  
?>  

在根文件夹下的文件就使用下面的代码了:

myapp.php

< ?php
use App\Lib1\MyClass as MC;  
 
$obj = new MC();  
echo $obj->WhoAmI();  
 
// autoload function  
function __autoload($class) {  
 // convert namespace to full file path  
 $class = 'classes/' . str_replace('\\', '/', $class) . '.php';  
 require_once($class);  
}  
?>  

解释:

1.类App\Lib1\MyClass的别名是MC;

2. new MC( )在编译时被翻译成new App\Lib1\MyClass( );

3.字符串App\Lib1\MyClass被传递给__autoload函数,使用文件路径正斜线替换所有命名空间中的反斜线,然后修改字符串,classes\App\Lib1\MyClass.php文件被自动载入;

 

本文努力转自http://my.oschina.net/Jacker/blog/32943

 

 

 

PhpDocumentor中文乱码解决办法

Posted on 2012年3月20日 16:27

根据PEAR手册上所说:

File Formats
All scripts contributed to PEAR must:

Be stored as ASCII text

Use ISO-8859-1 character encoding

Be Unix formatted

“Unix formatted” means two things:

1) Lines must end only with a line feed (LF). Line feeds are represented as ordinal 10, octal 012 and hex 0A. Do not use carriage returns (CR) like Macintosh computers do or the carriage return/line feed combination (CRLF) like Windows computers do.

2) There should be one line feed after the closing PHP tag (?>). This means that when the cursor is at the very end of the file, it should be one line below the closing PHP tag.

解决办法比较机械:
PhpDocumentor/phpDocumentor/Converters/HTML/frames/templates/ 目录下面所有模板文件:
iso-8859-1替换成utf-8

相关编码知识:
ISO 8859-1,正式编号为ISO/IEC 8859-1:1998,又称Latin-1或“西欧语言”,是国际标准化组织内ISO/IEC 8859的第一个8位字符集。

 

本文转自:http://ihacklog.com/software/development-tool/phpdocumentor-chinese-words.html

PHP实现异步调用方法研究

Posted on 2012年3月19日 23:53

浏览器和服务器之间是通过 HTTP 协议进行连接通讯的。这是一种基于请求和响应模型的协议。浏览器通过 URL 向服务器发起请求,Web 服务器接收到请求,执行一段程序,然后做出响应,发送相应的html代码给客户端。

这就有了一个问题,Web 服务器执行一段程序,可能几毫秒就完成,也可能几分钟都完不成。如果程序执行缓慢,用户可能没有耐心等下去,就关闭浏览器了。

而有的时候,我们更本不关心这些耗时的脚本的返回结果,但却还要等他执行完返回,才能继续下一步。
那么有没有什么办法,只是简单的触发调用这些耗时的脚本然后就继续下一步,让这些耗时的脚本在服务端慢慢执行?

经过试验,总结出来几种方法,和大家share:
1. 最简单的办法,就是在返回给客户端的HTML代码中,嵌入AJAX调用,或者,嵌入一个img标签,src指向要执行的耗时脚本。
这种方法最简单,也最快。服务器端不用做任何的调用。
但是缺点是,一般来说Ajax都应该在onLoad以后触发,也就是说,用户点开页面后,就关闭,那就不会触发我们的后台脚本了。
而使用img标签的话,这种方式不能称为严格意义上的异步执行。用户浏览器会长时间等待php脚本的执行完成,也就是用户浏览器的状态栏一直显示还在load。
当然,还可以使用其他的类似原理的方法,比如script标签等等。

2. popen()

resource popen ( string command, string mode );
//打开一个指向进程的管道,该进程由派生给定的 command 命令执行而产生。打开一个指向进程的管道,该进程由派生给定的 command 命令执行而产生。

所以可以通过调用它,但忽略它的输出。

  1. pclose(popen("/home/xinchen/backend.php &", 'r'));

这个方法避免了第一个方法的缺点,并且也很快。但是问题是,这种方法不能通过HTTP协议请求另外的一个WebService,只能执行本地的脚本文件。并且只能单向打开,无法穿大量参数给被调用脚本。 并且如果,访问量很高的时候,会产生大量的进程。如果使用到了外部资源,还要自己考虑竞争。

3. 使用CURL 这个方法,设置CUROPT_TIMEOUT为1(最小为1,郁闷)。也就是说,客户端至少必须等待1秒钟。

  1. $ch = curl_init();
  2.  
  3. $curl_opt = array(CURLOPT_URL, 'http://www.example.com/backend.php',
  4.                             CURLOPT_RETURNTRANSFER, 1,
  5.                             CURLOPT_TIMEOUT, 1,);
  6.  
  7. curl_setopt_array($ch, $curl_opt);
  8.  
  9. curl_exec($ch);
  10.  
  11. curl_close($ch);

4. 使用fsockopen 这个方法应该是最完美的,但是缺点是,你需要自己拼出HTTP的header部分。

  1. $fp = fsockopen("www.example.com", 80, $errno, $errstr, 30);
  2. if (!$fp) {
  3.     echo "$errstr ($errno)<br />\n";
  4. } else {
  5.     $out = "GET /backend.php / HTTP/1.1\r\n";
  6.     $out .= "Host: www.example.com\r\n";
  7.     $out .= "Connection: Close\r\n\r\n";
  8.  
  9.     fwrite($fp, $out);
  10.     /*忽略执行结果
  11. while (!feof($fp)) {
  12. echo fgets($fp, 128);
  13. }*/
  14.     fclose($fp);
  15. }

所以,总体来看,最好用,最简单的还是第一种方法。 最完美的应该是最后一种,但是比较复杂

 

本文转自:http://www.laruence.com/2008/04/14/318.html

PHP读取较大文件的方案

Posted on 2011年9月22日 21:09
<?
/**

* PHP 读取大文件 测试文件大于1G的文本文件
*/

/**

* 文件读取

*

* @param String $filename 文件地址

* @param Int $count 读取得行数

* @param String $sep 每行的分隔标记

* @return String 返回结果

*/

function readBigFile($filename, $count = 20, $tag = “\r\n”) {

    $content = ”;//最终内容

    $_current = ”;//当前读取内容寄存

    $step= 1;//每次走多少字符

    $tagLen = strlen($tag);

    $start = 0;//起始位置

    $i = 0;//计数器

    $handle = fopen($filename,’r+’);//读写模式打开文件,指针指向文件头

    while($i < $count && !feof($handle)) {    //文件没有到结尾和小鱼需要读取得行数时

        fseek($handle, $start, SEEK_SET);//指针设置在文件开头

        $_current = fread($handle,$step);//读取文件

        $content .= $_current;//组合字符串

        $start += $step;//依据步长向前移动

        //依据分隔符的长度截取字符串最后免得几个字符

        $substrTag = substr($content, -$tagLen);

        if ($substrTag == $tag) {    //判断是否为判断是否是换行或其他分隔符

            $i++;

        }

    }

    //关闭文件

    fclose($handle);

    //返回结果

    return $content;

}

$filename = ‘E:/2010log.log’;//需要读取的文件

$tag = “\r\n”;//行分隔符 注意这里必须用双引号

$count = 20;//读取行数

$data = readBigFile($filename,$count,$tag);

echo $data;
?>

 

读取指定开始和结束行

 

<?php
function line_content($filename,$startline,$endline){
        $arr = array();
        $fp=fopen($filename,"r");
        for($i=1;$i<$startline;$i++){
            fgets($fp);
        }
        for($i=$startline;$i<=$endline;$i++){
            array_push($arr, fgetcsv($fp));
        }
        return $arr;
}
print_r(line_content("1.csv",2,4));
?>

php从大文件中读取最后n行

Posted on 2011年9月19日 21:12

在php中,对于文件的读取时,最快捷的方式莫过于使用一些诸如file、 file_get_contents之类的函数,简简单单的几行代码就能很漂亮 的完成我们所需要的功能。但当所操作的文件是一个比较大的文件时,这些函数可能就显的力不从心, 下面将从一个需求入手来说明对于读取大文件时,常用的操作方法。

需求如下:  现有一个1G左右的日志文件,大约有500多万行, 用php返回最后几行的内容。

实现方法:

1. 直接采用file函数来操作


注: 由于 file函数是一次性将所有内容读入内存,而php为了防止一些写的比较糟糕的程序占用太多的内存而导致系统内存不足,使服务器出现宕机,所以默认情况下 限制只能最大使用内存16M,这是通过php.ini里的memory_limit = 16M来进行设置,这个值如果设置-1,则内存使用量不受限制.

下面是一段用file来取出这具文件最后一行的代码.
整个代码执行完成耗时 116.9613 (s).

ini_set('memory_limit','-1');
$file = 'access.log';
$data = file($file);
$line = $data[count($data)-1];
echo $line;

我机器是2个G的内存,当按下F5运行时,系统直接变灰,差不多20分钟后才恢复过来,可见将这么大的文件全部直接读入内存,后果是多少严重,所以不在万不得以,memory_limit这东西不能调得太高,否则只有打电话给机房,让reset机器了.

2.直接调用linux的tail命令来显示最后几行

在linux命令行下,可以直接使用tail -n 10 access.log很轻易的显示日志文件最后几行,可以直接用php来调用tail命令,执行php代码如下.
整个代码执行完成耗时 0.0034 (s)

 
file = 'access.log';
$file = escapeshellarg($file); // 对命令行参数进行安全转义
$line = `tail -n 1 $file`;
echo $line;

3. 直接使用php的fseek来进行文件操作

这种方式是最为普遍的方式,它不需要将文件的内容全部读入内存,而是直接通过指针来操作,所以效率是相当高效的.在使用fseek来对文件进行操作时,也有多种不同的方法,效率可能也是略有差别的,下面是常用的两种方法.

方法一:

首先通过fseek找到文件的最后一位EOF,然后找最后一行的起始位置,取这一行的数据,再找次一行的起始位置,再取这一行的位置,依次类推,直到找到了$num行。
实现代码如下
整个代码执行完成耗时 0.0095 (s)


$fp = fopen($file, "r");
$line = 10;
$pos = -2;
$t = " ";
$data = "";
while ($line > 0) {
    while ($t != "\n") {
        fseek($fp, $pos, SEEK_END);
        $t = fgetc($fp);
        $pos --;
    }
    $t = " ";
    $data .= fgets($fp);
    $line --;
}
fclose ($fp);
echo $data

方法二

还是采用fseek的方式从文件最后开始读,但这时不是一位一位的读,而是一块一块的读,每读一块数据时,就将读取后的数据放在一个buf里,然后通过换行符(\n)的个数来判断是否已经读完最后$num行数据.
实现代码如下
整个代码执行完成耗时 0.0009(s).

 


$fp = fopen($file, "r");
$num = 10;
$chunk = 4096;
$fs = sprintf("%u", filesize($file));
$max = (intval($fs) == PHP_INT_MAX) ? PHP_INT_MAX : filesize($file);
for ($len = 0; $len < $max; $len += $chunk) {     
	$seekSize = ($max - $len &gt; $chunk) ? $chunk : $max - $len;
    fseek($fp, ($len + $seekSize) * -1, SEEK_END);
    $readData = fread($fp, $seekSize) . $readData;
 
    if (substr_count($readData, "\n") &gt;= $num + 1) {
        preg_match("!(.*?\n){".($num)."}$!", $readData, $match);
        $data = $match[0];
        break;
    }
}
fclose($fp);
echo $data;

方法三:

整个代码执行完成耗时 0.0003(s)

 


function tail($fp,$n,$base=5)
{
    assert($n>0);
    $pos = $n+1;
    $lines = array();
    while(count($lines)< =$n){
        try{
            fseek($fp,-$pos,SEEK_END);
        } catch (Exception $e){
            fseek(0);
            break;
        }
        $pos *= $base;
        while(!feof($fp)){
            array_unshift($lines,fgets($fp));
        }
    }
    return array_slice($lines,0,$n);
}
var_dump(tail(fopen("access.log","r+"),10));

PHP分页技术的代码和示例

Posted on 2011年9月13日 16:15

本文来自:10 Helpful PHP Pagination Scripts For Web Developers

分页是目前在显示大量结果时所采用的最好的方式。有了下面这些代码的帮助,开发人员可以在多个页面中显示大量的数据。在互联网上,分​页是一般用于 搜索结果或是浏览全部信息(比如:一个论坛主题)。几乎在每一个Web应用程序都需要划分返回的数据,并按页显示。下面的这个列表给出的代码可以让你的开 发很有帮助。学习这些代码,对于初学者也很有帮助

1) 使用Ajax分页

 

 

下面这个示例使用了jQuery + PHP。 Demo link

 

2) MySql 分页

 

数据库的分页处理。

3) Facebook/Twitter 风格的分页

4) Php & MySql 分页

5) 分页风格

 

一个简单的教程教你如何用CSS定义不同风格的分页。

6) PHP 分页类

 

一个PHP的分页类

7) Easy Pagination

这是一个PHP库,可以让你更容易的做分页。

8 ) 基本分页

 

一个很不错简单易懂的分页教程。

9) Php Page

一个简单的PHP的教程

10) perfect-php-pagination

 

也是一个分页教程。

(全文完)

来至:http://coolshell.cn/articles/5160.html