本文发布于Cylon的收藏册,转载请著名原文链接~

PHP引擎缓存优化加速

  • eaccelerator
  • zend opcode
  • xcache

使用tmpfs作为缓存加速缓存的文件目录

1
2
mount -t tmpfs tmpfs /dev/shm -o size=256m
mount -t tmpfs /dev/shm/ /tmp/eaccelerator/

利用好tmpfs

1.上传目录缩略图临时处理目录/tmp.

2.其他加速器临时目录/tmp/eaccelerator/

php.ini参数优化

无论是 apache 还是 nginx,php.ini都是适合的。而 php-fpm.conf 适合nginx。而php-fpm.conf更适合 nginx+fcgi 的配置。首选选择产品环境的 php.ini

  • 开发场景:development
  • 生产环境:production

打开php的安全模式

php的安全模式是个非常重要的php内嵌的安全机制,能够控制一些php中的函数执行,比如system() ,同时把很多文件操作的函数进行了权限控制。php5.4后弃用

该参数配置如下:

1
2
3
336 ; Safe Mode
337 ; http://php.net/safe-mode
338 safe_mode = Off

用户和安全组

当safe_mode打开时,safe_mode_gid被关闭,那么php脚本能够对文件进行访问,而且相同组的用户也能够对文件进行访问。建议设置为safe_mode_gid=off;

如果不进行设置,可能我们无法对我们服务器网站目录下的文件进行操作了,比如我们需要对文件进行操作的时候。php5.3默认为 safe_mode_gid=off; (新版弃用)

关闭危险函数

如果打开了安全模式,那么函数禁止是可以不需要的,但是我们为了安全还是考虑进去。比如,我们觉得不希望执行包括 system() 等在那的能够执行命令的php函数,或者能够查看php信息的 phpinfo() 等函数,那么我们就可以禁止他们,方法如下:

1
disable_functions =  system,passthru,exec,shell_exec,popen,phpinfo

如果你要禁止任何文件和目录的操作,那么可以关闭很多文件操作。

1
disable_functions =  chdir,chroot,getcwd,opendir,readdir,scandir,fopen,unlink,delete,copy,mkdir,rmdir,rename,file,file_get_contents,fputs,fwrite,chgrp,chmod,chown

以上只列出部分不叫常用的文件处理函数,你也可以把上面执行命令函数和这个函数结合,就能够地址大部分的phpshell了。该参数默认为 disable_functions=.

关闭PHP版本信息在http头中的泄露

为了防止黑客获取服务器中php版本信息,可以关闭该信息泄露在http头中,该参数默认如下:

1
2
3
4
5
# 在http头中加上其签名,不会有安全上直接威胁,但使客户端知道PHP版本
expose_php = On

# 建议设置为Off
expose_php = Off

建议设置为Off,这样当黑客抓取头信息时,无法看到PHP的信息。

关闭注册全局变量

在PHP中提交的变量,包括使用POST或者GET提交的变量,都将自动注册为全局变量,能够直接访问,这是对服务器非常不安全的,所以我们不能让它注册为全局变量,就把注册全局变量选项关闭(5.4弃用

1
register_globals = Off

打开magic_quotes_gpc来防止SQL注入

SQL注入是非常危险的问题,轻则网站后台被入侵,重则整个服务器沦陷,php.ini 有一个设置,5.4已移除

错误信息控制

一般php在没有连接到数据库或者其他情况下会有提示错误,一般错误信息会包含php脚本当前距离信息或者查询的SQL语句等信息,这类信息提供给黑客后,是不安全的,所以一般服务器建议禁止错误提示

1
2
3
4
5
display_errors = Off
; 是否将错误信息作为输出的一部分显示给终端用户。应用调试时,可以打开,方便查看错误.
; 在最终发布的web站点上,强烈建议你关掉这个特性,并使用错误日志代替(参看下面).
; 在最终发布的web站点打开这个特性可能暴露一些安全信息.
; 例如你的web服务器上的文件路径、数据库规划或别的信息.

设置为

1
display = Off # (php 5.3+默认即为Off)

如果你确实要显示错误信息,一定要设置显示错误级别,比如只显示警告以上的信息,当然最好是关闭错误提示

1
error_reporting = E_WARNING & E_ERROR

错误日志

建议在关闭display_errors后能够把错误信息记录下来,便于查找服务器运行的原因:

1
log_errors = On

同时也要设置错误日志存放的目录,建议和Web日志存放在一起.

1
2
# 文件必须允许web用户和组具有写权限
error_log = /app/logs/php_errors.log

部分资源限制参数优化

设置每个脚本运行的最长时间

当无法上传较大的文件或者后台备份数据经常超时,此时需要调整如下设置:

1
2
3
4
5
6
max_execution_time = 30
; 每个脚本允许最大执行时间(秒),0表示没有限制.
; 这个参数有助于组织劣质脚本无休止占用服务器资源.
; 该指令仅影响脚本本身的运行时间,任何其它华为在脚本运行之外的时间.
; 如用system()/sleep()函数的使用、数据库查询、文件上传等,都不包括在内.
; 在安全模式下,你不能用ini_set()在运行时改变这个位置.

每个脚本使用的最大内存

1
2
3
4
5
6
memory_limit = 128M
; 一个脚本能够申请到的最大内存字节数(可以使用K和M作为单位).
; 这有助于防止劣质脚本消耗完服务器上所有内存.
; 要能够使用该指令碧玺在编译时使用“--enable-memory-limit”配置选项.
; 如果要取消内存限制,则必须将其设为-1.
; 设置了该指令后,memory_get_usage()函数变为可用.

每个脚本等待输入数据最长时间

1
2
3
max_input_time = -1
; 每个脚本解析输入数据(POST,GET,upload)的最大允许时间(秒)
; -1 表示不限制

http://php.net/max-input-time

设置为

1
max_input_time = 60

上载文件的最大许可大小

当上传较大文件时,需要调整如下参数:

1
2
; 上载文件的最大许可大小
upload_max_filesize = 2M

详情:http://php.net/upload-max-filesize

部分安全参数优化

禁止打开远程地址

记得最近出的 php include 的那个漏洞吗?就是在一个php程序中include变量,那么入侵者就可以利用这个控制服务器在本地执行远程的一个php程序,例如phpshell,所以我们关闭这个。

1
2
; Whether to allow the treatment of URLs (like http:// or ftp://) as files.
allow_url_fopen = On

详情:http://php.net/allow-url-fopen

测试远程allow_url_include

www.remote.com/1.php

1
2
3
<?php
	$arr = array(1,2,3,4,5);
?>

www.httpd.com/1.php

1
2
3
4
<?php
	include('http://www.remote.com:81/1.php');
	var_dump($arr);
?>

运行结果

img

测试远程allow_url_fopen

本地读取远端文件的脚本文件内容如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<?php
$file = fopen('http://www.remote.com:81/1.php', 'r');		// 读取远程文件
$i=1; 	//初始化行号
while( !feof($file) ){
    $row = fgets($file);	//读取一行
	echo $i . '--' . $row;	//输出
	$i++;
}
fclose($file);
?>

执行脚本结果如下:

1
2
3
4
$ /app/php/bin/php 2.php
1--<?php
2--$arr = array(1,2,3,4,5);
3--?>

当在禁止后,再重新运行以上脚本文件会报如下错误

1
2
3
Warning: include() [[function.include](http://www.httpd.com/function.include)]: http:// wrapper is disabled in the server configuration by allow_url_fopen=0 

Warning: fopen() [[function.fopen](http://www.httpd.com/function.fopen)]: http:// wrapper is disabled in the server configuration by allow_url_fopen=0 

调整php session信息存放类型和位置

1
2
3
4
5
6
; 存储和检索会话关联的数据的处理器名字。默认为文件“file”
; 如果想要使用自定义的处理器(如基于数据库的处理器),可用“user”
; 设为"memcache"则可以使用memcache作为会话处理器(需要指定"--enable-memcache-session"编译选项)。
session.save_handler = files
; 传递给处理器的参数。对于files处理器,此值是创建会出数据文件的路径。
session.save_path = "/tmp"

web集群session贡献存储设置,默认php.ini中session的类型和配置路径:

1
session.save_handler = "tcp://192.168.2.8:11211"

PHP-FPM参数优化

如果你的高负载网站使用PHP-FPM管理FastCGI,也许下面这些技巧对你有用

  1. 尽量少安装PHP模块,最简单是最好(快)的

  2. 把你的PHP FastCGI子进程数调到100或以上,在4G内存的服务器上200就可以(建议压力测试来得出自己服务器合理的值)

  3. socket连接FastCGI,/dev/shm是内存文件系统,socket放在内存中肯定会快些

  4. Linux下增加文件打开数,命令如下:

    1
    2
    
    ; 增加 PHP-FPM 打开文件描述符的限制,此参数和php-fpm进程数有关
    rlimit_files = 51200
    
  5. 使用php代码加速器,例如 eAccelerator, XCache.在Linux平台上可以把 cache_dir 指向 /dev/shm

php-fpm.conf重要优化参数详解

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
pm = dynamic
; pm参数指定了进程管理方式,有两种可供选择:static或dynamic,从字面意思不难理解,为静态或动态方式。如果是静态方式,那么在php-fpm启动的时候就创建了指定数目的进程,在运行过程中不会再有变化(并不是真的就永远不变);而动态的则在运行过程中动态调整,当然并不是无限制的创建新进程,受pm.max_spare_servers参数影响;动态适合小内存机器,灵活分配进程,省内存。静态适用于大内存机器,动态创建回收进程对服务器资源也是一种消耗

pm.max_children = 24
; static模式下创建的子进程数或dynamic模式下同一时刻允许最大的php-fpm子进程数量

pm.start_servers = 16
; 动态方式下的起始php-fpm进程数量

pm.min_spare_servers = 12
; 动态方式下服务器空闲时最小php-fpm进程数量

pm.max_spare_servers = 24
; 动态方式下服务器空闲时最大php-fpm进程数量

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

error_log = /app/run/log/php-fpm.log
; 错误日志,默认在安装目录中的var/log/php-fpm.log

pid = /app/run/php/php-fpm  #<==一般规划好目录与mysql nginx等在同目录下,方便管理
; pid设置,默认在安装目录中的var/run/php-fpm.pid,建议开启

emergency_restart_threshold = 0 
emergency_restart_interval = 0
; 表示在emergency_restart_interval所设值内出现SIGSEGV或者SIGBUS错误的php-cgi进程数如
; 果超过 emergency_restart_threshold个,php-fpm就会优雅重启。这两个选项一般保持默认值。

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

daemonize = yes
; 后台执行fpm,默认值为yes,如果为了调试可以改为no。在FPM中,可以使用不同的设置来运行多个进程池。 这些设置可以针对每个进程池单独设置.
 
listen = 127.0.0.1:9000
; fpm监听端口,即nginx中php处理的地址,一般默认值即可。可用格式为: 'ip:port', 'port', '/path/to/unix/socket'. 每个进程池都需要设置.
 
listen.backlog = -1
; backlog数,-1表示无限制,由操作系统决定,此行注释掉就行。backlog含义参考http://www.3gyou.cc/?p=41
 
listen.allowed_clients = 127.0.0.1
; 允许访问FastCGI进程的IP,设置any为不限制IP,如果要设置其他主机的nginx也能访问这台FPM进程,listen处要设置成本地可被访问的IP。默认值是any。每个地址是用逗号分隔. 如果没有设置或者为空,则允许任何服务器请求连接
 
listen.owner = www
listen.group = www
listen.mode = 0666
; unix socket设置选项,如果使用tcp方式访问,这里注释即可。
 
user = www
group = www
; 启动进程的帐户和组
  
pm.max_requests = 1000
; 设置每个子进程重生之前服务的请求数. 对于可能存在内存泄漏的第三方模块来说是非常有用的. 如果设置为 '0' 则一直接受请求. 等同于 PHP_FCGI_MAX_REQUESTS 环境变量. 默认值: 0.
 
pm.status_path = /status
; FPM状态页面的网址. 如果没有设置, 则无法访问状态页面. 默认值: none. munin监控会使用到
 
ping.path = /ping
; FPM监控页面的ping网址. 如果没有设置, 则无法访问ping页面. 该页面用于外部检测FPM是否存活并且可以响应请求. 请注意必须以斜线开头 (/)。
 
ping.response = pong
; 用于定义ping请求的返回相应. 返回为 HTTP 200 的 text/plain 格式文本. 默认值: pong.
 
request_terminate_timeout = 0
; 设置单个请求的超时中止时间. 该选项可能会对php.ini设置中的'max_execution_time'因为某些特殊原因没有中止运行的脚本有用. 设置为 '0' 表示 'Off'.当经常出现502错误时可以尝试更改此选项。
 
request_slowlog_timeout = 10s
; 当一个请求该设置的超时时间后,就会将对应的PHP调用堆栈信息完整写入到慢日志中. 设置为 '0' 表示 'Off'
 
slowlog = log/$pool.log.slow
; 慢请求的记录日志,配合request_slowlog_timeout使用
 
rlimit_files = 1024
; 设置文件打开描述符的rlimit限制. 默认值: 系统定义值默认可打开句柄是1024,可使用 ulimit -n查看,ulimit -n 2048修改。

一般 php-fpm 进程占用20~30m左右的内存就按 30m 算。如果单独跑 php-fpm,动态方式起始值可设置物理内存 $\frac{Mem}{30M}$,由于大家一般Nginx, MySQL都在一台机器上,于是预留一半给它们,即php-fpm进程数为 $\frac{mem}{2\times30M}$。

参考文章:

https://jingyan.baidu.com/article/fdbd4277c4dacbb89f3f4855.html

http://www.cnblogs.com/argb/p/3604340.html

本文发布于Cylon的收藏册,转载请著名原文链接~

链接:https://www.oomkill.com/2016/10/php-ini/

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」 许可协议进行许可。