分类 php 下的文章

php的::class


今天看laravel框架,看到这样一个语法 类::class

经过一番查找,在手册中找到这个

The special ::class constant are available as of PHP 5.5.0, and allows for fully qualified class name resolution at compile, this is useful for namespaced classes:

在php5.5.0中添加了一个特殊的常量::class,它允许完全限定的类在编译的时候调用,这对命名空间类是非常有用的。


php-fpm配置说明


1.php-fpm是什么?

php-fpm是FastCGI进程管理器,用于替换 PHP FastCGI 的大部分附加功能,对于高负载网站是非常有用的。
如果需要了解FastCGI是个什么含义请看搞不清FastCgi与PHP-fpm之间是个什么样的关系

2.FPM 配置

FPM 配置文件为 php-fpm.conf。
他的配置项如下:

pid   string
PID文件的位置。默认为空。

error_log string
错误日志的位置。默认:安装路径 #INSTALL_PREFIX#/log/php-fpm.log。

log_level string
错误级别。可用级别为:alert(必须立即处理),error(错误情况),warning(警告情况),notice(一般重要信息),            
debug(调试信息)。默认:notice。

emergency_restart_threshold int
如果子进程在 emergency_restart_interval 设定的时间内收到该参数设定次数的 SIGSEGV 或者 SIGBUS退出信息号,则FPM会重新启动。0 表示“关闭该功能”。默认值:0(关闭)。

emergency_restart_interval mixed
emergency_restart_interval 用于设定平滑重启的间隔时间。这么做有助于解决加速器中共享内存的使用问题。可用单位:s(秒),m(分),h(小时)或者 d(天)。默认单位:s(秒)。默认值:0(关闭)。

process_control_timeout mixed
设置子进程接受主进程复用信号的超时时间。可用单位:s(秒),m(分),h(小时)或者 d(天)。默认单位:s(秒)。默认值:0(关闭)。

daemonize boolean
设置 FPM 在后台运行。设置“no”将 FPM 保持在前台运行用于调试。默认值:yes。

在FPM中,可以使用不同的设置来运行多个进程池。 这些设置可以针对每个进程池单独设置。

listen string
设置接受 FastCGI 请求的地址。可用格式为:'ip:port','port','/path/to/unix/socket'。每个进程池都需要设置。

listen.backlog int
设置 listen(2) 的半连接队列长度。“-1”表示无限制。默认值:-1。

listen.allowed_clients string
设置允许连接到 FastCGI 的服务器 IPV4 地址。等同于 PHP FastCGI (5.2.2+) 中的 FCGI_WEB_SERVER_ADDRS 环境变量。仅对 TCP 监听起作用。每个地址是用逗号分隔,如果没有设置或者为空,则允许任何服务器请求连接。默认值:any。

listen.owner string
如果使用,表示设置 Unix 套接字的权限。在Linux中,读写权限必须设置,以便用于 WEB 服务器连接。在很多 BSD 派生的系统中可以忽略权限允许自由连接。默认值:运行所使用的用户和组,权限为 0666。

listen.group string
参见 listen.owner。

listen.mode string
参见 listen.owner。

user string
FPM 进程运行的Unix用户。必须设置。

group string
FPM 进程运行的 Unix 用户组。如果没有设置,则默认用户的组被使用。

pm string
设置进程管理器如何管理子进程。可用值:static,ondemand,dynamic。必须设置。

static - 子进程的数量是固定的(pm.max_children)。

ondemand - 进程在有需求时才产生(当请求时,与 dynamic 相反,pm.start_servers 在服务启动时即启动。

dynamic - 子进程的数量在下面配置的基础上动态设置:pm.max_children,pm.start_servers,    pm.min_spare_servers,pm.max_spare_servers。

pm.max_children int
pm 设置为 static 时表示创建的子进程的数量,pm 设置为 dynamic 时表示最大可创建的子进程的数量。必须设置。

该选项设置可以同时提供服务的请求数限制。类似 Apache 的 mpm_prefork 中 MaxClients 的设置和 普通PHP FastCGI中的 PHP_FCGI_CHILDREN 环境变量。

pm.start_servers in
设置启动时创建的子进程数目。仅在 pm 设置为 dynamic 时使用。默认值:min_spare_servers + (max_spare_servers - min_spare_servers) / 2。

pm.min_spare_servers int
设置空闲服务进程的最低数目。仅在 pm 设置为 dynamic 时使用。必须设置。

pm.max_spare_servers int
设置空闲服务进程的最大数目。仅在 pm 设置为 dynamic 时使用。必须设置。

pm.max_requests int
设置每个子进程重生之前服务的请求数。对于可能存在内存泄漏的第三方模块来说是非常有用的。如果设置为 '0' 则一直接受请求,等同于 PHP_FCGI_MAX_REQUESTS 环境变量。默认值:0。

pm.status_path string
FPM 状态页面的网址。如果没有设置,则无法访问状态页面,默认值:无。

ping.path string
FPM 监控页面的 ping 网址。如果没有设置,则无法访问 ping 页面。该页面用于外部检测 FPM 是否存活并且可以响应请求。请注意必须以斜线开头(/)。

ping.response string
用于定义 ping 请求的返回响应。返回为 HTTP 200 的 text/plain 格式文本。默认值:pong。

request_terminate_timeout mixed
设置单个请求的超时中止时间。该选项可能会对 php.ini 设置中的 'max_execution_time' 因为某些特殊原因没有中止运行的脚本有用。设置为 '0' 表示 'Off'。可用单位:s(秒),m(分),h(小时)或者 d(天)。默认单位:s(秒)。默认值:0(关闭)。

request_slowlog_timeout mixed
当一个请求该设置的超时时间后,就会将对应的 PHP 调用堆栈信息完整写入到慢日志中。设置为 '0' 表示 'Off'。可用单位:s(秒),m(分),h(小时)或者 d(天)。默认单位:s(秒)。默认值:0(关闭)。

slowlog string
慢请求的记录日志。默认值:#INSTALL_PREFIX#/log/php-fpm.log.slow。

rlimit_files int
设置文件打开描述符的 rlimit 限制。默认值:系统定义值。

rlimit_core int
设置核心 rlimit 最大限制值。可用值:'unlimited',0 或者正整数。默认值:系统定义值。

chroot string
启动时的 Chroot 目录。所定义的目录需要是绝对路径。如果没有设置,则 chroot 不被使用。

chdir string
设置启动目录,启动时会自动 Chdir 到该目录。所定义的目录需要是绝对路径。默认值:当前目录,或者根目录(chroot时)。

catch_workers_output boolean
重定向运行过程中的 stdout 和 stderr 到主要的错误日志文件中。如果没有设置,stdout 和 stderr 将会根据 FastCGI 的规则被重定向到 /dev/null。默认值:无。

这面是我的配置

[global]
pid = /usr/local/php/var/run/php-fpm.pid
error_log = /usr/local/php/var/log/php-fpm.log
log_level = notice

[www]
listen = /tmp/php-cgi.sock
listen.backlog = -1
listen.allowed_clients = 127.0.0.1
listen.owner = www
listen.group = www
listen.mode = 0666
user = www
group = www
pm = dynamic
pm.max_children = 10
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 6
request_terminate_timeout = 100
request_slowlog_timeout = 0
slowlog = var/log/slow.log

文件下载


1.得到文件路径

从$_GET['file']得到文件路径

$path_parts = pathinfo($_GET['file']);
$file_name  = $path_parts['basename'];
$file_path  = '/mysecretpath/' . $file_name;

务必使用上面这种方法得到路径,不能简单的字符串拼接得到路径
$mypath = '/mysecretpath/' . $_GET['file'];
如果输入的是../../,就可以访问任何路径

2. 设置header信息

header('Content-Description: File Transfer'); //描述页面返回的结果
header('Content-Type: application/octet-stream'); //返回内容的类型,此处只知道是二进制流。具体返回类型可参考http://tool.oschina.net/commons
header('Content-Disposition: attachment; filename='.basename($file));//可以让浏览器弹出下载窗口
header('Content-Transfer-Encoding: binary');//内容编码方式,直接二进制,不要gzip压缩
header('Expires: 0');//过期时间
header('Cache-Control: must-revalidate');//缓存策略,强制页面不缓存,作用与no-cache相同,但更严格,强制意味更明显
header('Pragma: public');
header('Content-Length: ' . filesize($file));//文件大小,在文件超过2G的时候,filesize()返回的结果可能不正确

3. 输出文件之file_get_contents()方法

file_get_contents()把文件内容读取到字符串,也就是要把文件读到内存中,再输出内容

$str = file_get_contents($file);
echo $str;

这种方式,只要文件稍微一大,就会超过内存限制

4. 输出文件之file()方法

与file_get_contents()差不多,只不过是file()会把内容按行读取到数组中,也是需要占用内存

$f = file($file);
while(list($line, $cnt) = each($f)) {
   echo $cnt;
}

文件大的时候也会超出内存限制

5. 输出文件之readfile()方法

readfile()方法:读入一个文件并写入到输出缓冲
这种方式可以直接输出到缓冲,不会整个文件占用内存
前提要先清空缓冲,先要让用户看到下载文件的对话框

while (ob_get_level()) ob_end_clean();
//设置完header以后
ob_clean();
flush();  //清空缓冲区
readfile($file);

这种方法可以输出大文件,读取单个文件不会超出内存限制,但下面的情况除外。
readfile()在多人读取文件的时候同样会造成PHP内存耗尽:http://stackoverflow.com/questions/6627952/why-does-readfile-exhaust-php-memory

PHP has to read the file and it writes to the output buffer. So, for 300Mb file, no matter what the implementation you wrote (by many small segments, or by 1 big chunk) PHP has to read through 300Mb of file eventually.
If multiple user has to download the file, >there will be a problem. (In one server, hosting providers will limit memory given to each hosting user. With such limited memory, using buffer is not going to be a good idea. )
I think using the direct link to download a file is a much better approach for big files.

大意:PHP需要读文件,再输出到缓冲。对于一个300M的文件,PHP最终还是要读300M内存。因此在多个用户同时下载的时候,缓冲也会耗尽内存。(不对还请指正)

例如100个用户在下载,就需要100*buffer_size大小的内存

6. 输出文件之fopen()方法

set_time_limit(0);
$file = @fopen($file_path,"rb");
while(!feof($file))
{
    print(@fread($file, 1024*8));
    ob_flush();
    flush();
}

fopen()可以读入大文件,每次可以指定读取一部分的内容。在操作大文件的时候也很有用

7. 总结

利用PHP下载文件时,应该要注重场景。如果本身只是几个小文件被下载,那么使用PHP下载比较好;但是如果PHP要承受大量下载请求,这时下载文件就不该交给PHP做。

对于Apache,有mod_xsendfile可以帮助完成下载任务,更简单也更快速

当文件是远程文件时,filesize,file_exist函数不能正确获取文件的存在。

原文


初学者理解生成器


理解php生成器并不是一个艰巨的事情。希望你能在看完这篇文章之后完全理解他。那么,让我们开始吧。

什么是PHP生成器?

我们都知道内存管理是所有编程模块当中最难处理的。小巧,轻便和快速的应用总是人们所喜爱的。在PHP5.5当中,我们引入PHP生成器的概念。这个概念非常有用他能是我们的应用运行的更快。总的来说,这个概念就是不在内存当中创建数组。首先让我们用一个例子来解释它。创建一个generator.php在你本地,粘贴如下代码,执行代码并查看。

<?php
    function getLimit ($max = 10) {
        $array = [];

        for ($i = 1; $i < $max; $i++) {
            $array[] = $i;
        }

        return $array;
    }

    foreach (getLimit(15) as $range) {
        echo "Dataset {$range} <br>";
    }

输入结果


php编码技巧


  1. 如果一个方法能被定义成静态的static,那么定义成静态的速度可快25%
  1. echo的效率高于print,因为echo没有返回值
  1. 在循环之前设置最大的次数,而不是在循环之中
  1. 销毁变量去释放内存,特别是大的数组
    a) unset()只能销毁超过256个字节的变量内存,否则空间是不被释放的
    b) 结论一、unset()函数只能在变量值占用内存空间超过256字节时才会释放内存空间。
    c) 结论二、只有当指向该变量的所有变量(如引用变量)都被销毁后,才会释放内存。
  1. 避免使用__construct,__destruct,__call,__callStatic,__get,__set,__isset,__unset,__sleep,__wakeup,__toString,__set_state,__cloneand__autoload等魔术方法
  1. 避免require_once()比较耗资源
  1. 在include,或者是require中尽量使用绝对路径,减少分析时间
  1. 如果你需要得到脚本的执行时间那么用$_SERVER['REQUEST_TIME']要优于time();
  1. 用@掩盖错误会降低运行速度
  1. 养成对数组健加引号的习惯,这样速度会快7倍如:$_row['id']与$_row[id];
  1. 错误信息很有用
  1. 在循环里别用函数,如count()在外面先计算
  1. 在方法里面建立局部变量速度快
  1. 全局变量几乎要比局部变量慢2倍
  1. 对象属性要双局部变量慢3倍
  1. 初始化的局部变量要比未定义的局部变量快9-10倍
  1. 子类的方法性能优于基类方法
  1. 只调用一个参数并且函数体为空的函数运行花费的时间等于7-8次$localvar++运算,而一个类似的方法(类里的函数)运行等于大约15次$localvar++运算;
  1. 当用echo输出字符串时用逗号代替点运行快些
  1. 在apache服务器里一个php脚本页面比相应的HTML静态页面生成至少要多花2-10倍的时间,建议多用些静态HTML页面和少量的脚步;
  1. 除非你的安装了缓存,不然你的php脚本每次被访问都需要被重编译。建议安装个php缓存程序,这样通过去除一些重复的编译来很明显的提高你20-100%的性能;
  1. 建议用memcached,高性能的分布式内存对象缓存系统,提高动态网络应用程序性能,减轻数据库的负担;
  1. 使用long2ip()或者是ip2long()函数将IP地址转换成整型存入数据库,能降低25%的存储空间,同时也可以很容易对IP进行排序和快速查找
  1. 尽量优先使用三元运算符(a?a:b;)
  1. 使用gzcompress()和gzuncompress()对容量大的字符串进行压缩和解压再存进和取出数据库时,这种内置函数使用gzip算法能压缩到90%;\
  1. 如果你想查看文件的完整路径那么可以用realpath();
  1. 魔术常量

    __LINE__ __FILE__ __DIR__ __FUNCTION__ __CLASS__ __METHOD__ __NAMESPACE__

  2. left(text,20)只取出text文本的前20个字

  1. 在mysql插入语句中如果是自增字段要用NULL代替
  1. 尽量使用PHP内置函数
  1. str_replace函数比preg_replace函数快,但strtr函数的效率是str_replace函数的四倍。
  1. PHP在windows和LINUX下的路径分隔符DIRECTORY_SEPARATOR(windows下的是\和/,而LINUX下的是/)