2014年8月

LNMP服务器安全指南

平时工作中需要维护一些Linux服务器, 有时候也需要自己配置下服务器, 一般主要是配置LNMP服务。整理了一些服务器安装配置方面的知识,现在就总结下。

  • Linux最低权限安全配置
    Nginx、MySQL、PHP-FPM三者都应该是以最低权限用户组运行。
    网站目录的文件用户组和PHP运行用户属主应该区分开, 设置PHP对网站文件只有可执行权限, 对于静态文件都交给Nginx处理。比如PHP-FPM的用户组为php-fpm:php-fpm, 网站目录www.lezhizhe.net其用户组为www:www, 文件属性为644,也就是说php合nginx在网站根目录只有读权限。对于文件上传目录和缓存目录, 可以设置777权限, 生成的文件要设置为644属性, 禁止上传的文件具有可执行权限。
    对于PHP使用open_basedir限制虚拟主机跨目录访问(网上有说在php.ini文件中修改open_basedir, 经测试不生效)。不过可以在nginx的每个站点的con.f文件中设置PHP的open_basedir属性(注意如果在某个站点设置了该属性其它站点未设置, 会造成其它站点打不开的情况):
fastcgi_param  PHP_VALUE  "open_basedir=$document_root:/tmp/";
  • Linux防火墙及端口配置
    1、禁止SSH密码登陆方式, 采用公钥方式登陆。
    2、开启iptables。只开放必要的端口出来。iptable配置如下:
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [46:7024]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -i eth1 -j ACCEPT
-A INPUT -p tcp -m tcp --sport 53 -j ACCEPT //DNS端口
-A INPUT -p udp -m udp --sport 53 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT //HTTP端口
-A INPUT -p tcp -m state --state NEW -m tcp --dport 4000 -j ACCEPT //FTP端口
-A INPUT -p tcp -m state --state NEW -m tcp --dport 4355 -j ACCEPT //SSh端口
-A INPUT -p tcp -m state --state NEW -m tcp --dport 30000:60000 -j ACCEPT //FTP被动模式端口
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT
  • PHP安装配置
    1.禁用不安全PHP函数
    disable_functions = show_source,system,shell_exec,passthru,exec,popen,proc_open,proc_get_status,phpinfo
    2.关闭错误日志防止输出错误信息, 记录log方便程序调试
    display_errors = Off
    log_errors=On
    error_log=/var/log/php-fpm/sie-error.log

    3.关闭远程代码执行。如果启用,PHP可以通过allow_url_fopen,在file_get_contents()、include、require中获取诸如FTP或网页内容这些远程数据。如果忘记了对输入数据进行过滤,而这些函数调用了这些数据,则形成了注入漏洞。
    allow_url_fopen=Off

    4.防止PHP信息泄露, 不轻易透露自己php版本信息,防止黑客针对这个版本的php发动攻击.
    expose_php = Off

    5.禁止动态加载链接库:
    enable_dl = Off

    6.将文件上传到远程服务器, 例如nfs等。当然也可以调用你们写好的php接口。 即使有上传漏洞,那么文件也被传到了静态服务器上。木马等文件根本无法执行。

  • Nginx限制访问
    有些目录存放的是一些类库文件或者模板文件, 不需要用户访问的,可以在该目录访问限制返回404。如lib类文件目录和template模板目录:
    location ~ ^/(lib|template)/ {
    return 404;
    }

    对于静态文件(如js、css、图片等)限制通过PHP执行:
    location ~* \.(js|css|jpg|jpeg|gif|png|swf)$ {
    if (-f $request_filename) {
    expires 0d;
    break;
    }
    }

    对于PHP程序文件,一般都是很少的几个入口文件, 可以直接限制这几个PHP文件的执行。例如现在只有index.php、user.php、admin.php三个入口文件,那我们只把这三个PHP文件交给fast-cgi文件去执行。
    location ~ ^/(index|user|admin)\.php {
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_index index.php;
    fastcgi_split_path_info ^(.+\.php)(/?.+)$;
    fastcgi_param PATH_INFO $fastcgi_path_info;
    fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
    fastcgi_param PHP_VALUE "open_basedir=$document_root:/tmp/";
    include fastcgi_params;
    fastcgi_pass 127.0.0.1:9000;
    }

Linux下的VIM配置及VIM常用命令

话说每次接手新的服务器, 服务器上的VIM配置都是原生的, 每次修改VIM配置都需要重新Google一番, 甚是麻烦。有时候用到一些不常用的VIM命令, 都已经忘了, 都需要搜索资料, 影响工作效率啊。现在自己开通了博客, 就把Linux下的VIM配置相关资料整理下方便以后使用, 没事了自己也可以看看温习一番。

  • VIM安装:
yum -y install vim-enhanced #centos
  • VIM文件位置:
    在目录 /etc/ 下面,有个名为vimrc的文件,这是系统中公共的vim设置文件,对所有用户都有效。而在每个用户的主目录下,都能自己建立私有的设置文件,命名为:“.vimrc”。例如,/root目录下,通常已存在一个.vimrc文件。

  • VIM配置详解

set nocompatible        "去掉讨厌的有关vi一致性模式,避免以前版本的一些bug和局限"
syntax on "语法高亮"
set nummber "显示行号"
filetype on "检测文件类型"
set history=1000 "记录历史的行数"

set tabstop=4 "设置(软)制表符宽度为4"
set softtabstop=4 "设置(软)制表符宽度为4"

set shiftwidth=4 "设置缩进的空格数为4"
set cindent "设置使用 C/C++ 语言的自动缩进方式"

set autoindent "vim使用自动对起,也就是把当前行的对起格式应用到下一行"
set smartindent "依据上面的对起格式,智能的选择对起方式,对于类似C语言编写上很有用"

set hlsearch "高亮查找匹配"
set showmatch "显示匹配"
set ruler "右下角显示光标位置"

#如下设置,可以用空格键直接控制折叠
set foldenable
set foldmethod=marker
  • VIM常用命令
##################基础##########################################
:e filename "打开新文件"
:w "保存文件"
:q "退出VIM"
:q! "不保存退出VIM"
:x "保存并退出"
:sav filename "文件另存为"
:1,10 w outfile "将1-10行写入文件"
:1,10 w >> outfile"将1-10行最近到文件"
:r infile "在当前光标所在行下插入文件infile的内容"
:23r infile "在23行下插入文件infile的内容"
. "重复一次最近一次的VIM命令操作"
5. "重复5次最近一次的VIM命令操作"
u "撤销操作"
Ctrl+r "重做"

##################在文件中移动###################################
k "上移一个字符, 相当于方向键上"
j "下移一个字符, 相当于方向键下"
h "左移一个字符, 相当于方向键左"
l "右移一个字符, 相当于方向键右, 这个命令很少用, 一般用w代替"
#以上四个命令可以配合数字使用,比如20j就是向下移动20行,5h就是向左移动5个字符#

e "移动光标到当前光标所在单词结尾"
E "跳到下一个字尾, 长跳"
b "移动光标到当前光标所在单词开头"
B "跳到上一个字开头, 长跳"
^ "跳至行首的第一个字符"
$ "跳至行尾"
G "移动光标到文件末尾"
gg "移动光标到文件开头"
:num "移动光标到第num行开头"
num| "移动光标到当前行的num列"
% "移动光标到与当前符号(小括号、中括号、大括号)匹配的符号上, 如果当前光标在'('上,它就向前跳转到与它匹配的')'上,如果当前在')'上,它就向后自动跳转到匹配的'('上去."
[[ "移动到当前光标所在函数的开头"
]] "移动到当前光标所在位置下一个函数的开头"
[{ "移动到当前光标所在区块的开头"
}] "移动到当前光标所在区块的结尾"

##################视窗的移动#####################################
Ctrl+f "视窗往下卷一页"
Ctrl+b "视窗往上卷一页"
Ctrl+d "视窗往下卷半页"
Ctrl+u "视窗往上卷半页"
Ctrl+e "视窗往下卷一行"
Ctrl+y "视窗往上卷一行"
L "移动光标到当前视窗口结尾"

##################插入模式#######################################
i "从当前光标处进入插入模式"
I "进入插入模式, 并置光标于行首"
a "追加模式, 置光标于当前光标之后"
A "追加模式, 置光标于行末"
o "在当前行之下新加一行, 并进入插入模式"
O "在当前行之上新加一行,并进入插入模式"

##################可视模式#######################################
v "进入可视模式, 单字符模式"
V "进入可视模式, 行模式"
ctrl+v "进入可视模式, 列模式, 类似于UE的列模式"
o "跳转光标到选中块的另一个端点"
U "将选中块中的内容转成大写"
O "跳转光标到块的另一个端点"
aw "选中一个字"
ab "选中括号中的所有内容,包括括号本身"
aB "选中{}括号中的所有内容"
ib "选中括号中的内容,不含括号"
iB "选中{}中的内容,不含{}"

> "块右移"
< "块左移"
y "复制块"
d "删除块"
~ "切换块中内容的大小写"

##################剪切复制和粘贴#######################################
x "删除字符"
s "删除字符并进入插入模式"
J "删除换行符"
y "复制选中的内容"
p "粘贴剪切板中的内容到光标所在位置之后"
dd "删除当前行"
yy "复制当前行"
y$ "复制到行尾"
D "删除到行尾, 相当于D$"
c "改变命令。它的行为与"d"命令类似,不过在命令执行后会进入Insert模式。比如"cw"改变一个word。或者,更准确地说,它删除一个word并让你置身于Insert模式。
"cc"命令可以改变整行。不过仍保持原来的缩进。
"c$"改变当前光标到行尾的内容。
快捷命令:x 代表dl(删除当前光标下的字符)
X 代表dh(删除当前光标左边的字符)
D 代表d$(删除到行尾的内容)
C 代表c$(修改到行尾的内容)
s 代表cl(修改一个字符)
S 代表cc(修改一整行)
命令"3dw"和"d3w"都是删除3个word。第一个命令"3dw"可以看作是删除一个word的操作执行3次;第二个命令"d3w"是一次删除3个word。这是其中不明显的差异。事实上你可以在两处都放上命令记数,比如,"3d2w"是删除两个word,重复执行3次,总共是6个word。
dj 删除上一行
dk 删除下一行
10d 删除当前行开始的10行。
kdgg 删除当前行之前所有行(不包括当前行)
jdG(jd shift + g) 删除当前行之后所有行(不包括当前行)
:1,10d 删除1-10行
:11,$d 删除11行及以后所有的行
:1,$d 删除所有行
J(shift + j)  删除两行之间的空行,实际上是合并两行。

##################搜索###########################################
/word "从头到尾搜索文字word"
?word "从下往上搜索文字word"
* "搜索当前光标所在位置的单词"
/\cstring "搜索STRING或者string及搜索不区分大小写"
/jo[ha]n "搜索john或joan, 即正则匹配"
/\< the "搜索以the开头的单词"
/the\> "搜索以the结尾的单词"
/\< the\> "搜索 the 单词"
^\n\{3} "查找3行空行"
:bufdo /searchstr/ "在所有打开的文件中搜索"
:bufdo %s/something/replace/g "在所有打开的文件中搜索something并用replace替换"

##################替换###########################################
:%s/old/new/g "把所有的old替换为new"
:%s/sch/rep/gi "把所有的sch替换为rep, 不区分大小写"
:%s/old/new/gc "把所有的old替换为new, 替换前提示确认"
:2,35s/old/new/g "在2-35行把所有的old替换为new"
:5,$s/old/new/g "从第5行替换old到new

:%s/^/hello/g Replace the begining of each line by hello
:%s/$/Harry/g Replace the end of each line by Harry
:%s/onward/forward/gi Replace onward by forward, case unsensitive
:%s/ *$//g Delete all white spaces
:g/string/d Delete all lines containing string
:v/string/d Delete all lines containing which didn’t contain string
:s/Bill/Steve/ Replace the first occurence of Bill by Steve in current line
:s/Bill/Steve/g Replace Bill by Steve in current line
:%s/Bill/Steve/g Replace Bill by Steve in all the file
:%s/^M//g Delete DOS carriage returns (^M)
:%s/\r/\r/g Transform DOS carriage returns in returns
:%s#<[^>]\+>##g Delete HTML tags but keeps text
:%s/^\(.*\)\n\1$/\1/ Delete lines which appears twice
Ctrl+a Increment number under the cursor
Ctrl+x Decrement number under cursor

##################分屏###########################################
:split filename "分屏(横屏)打开文件
:sview file "分屏(横屏)只读模式打开文件
:vsplit file "分屏(竖屏)打开文件
ctrl-w "将光标放在下一个窗口中"
:hide "关闭当前光标所在位置的窗口"
:­nly "关闭除当前窗口外的所有窗口"

##################对齐缩进###########################################
:%!fmt "对齐所有行"
5!!fmt "对齐接下来的5行"
!}fmt "Align all lines at the current position"

>> "缩进"
<< "撤销缩进"
ctrl-t "在插入模式下缩进"
ctrl-d "在插入模式下撤销缩进"

##################文件浏览器###########################################
:e . "打开文件树"
:Sex "分屏(竖屏)方式打开文件树"
:Sex! "分屏(横屏)方式打开文件树"
:ls "列出缓冲内容"
:cd .. "进入上一级目录"

最后来一发中文版VIM键位图
[caption id="attachment_175" align="alignnone" width="300"]VIM键位图 VIM键位图中文banb[/caption]

服务器硬盘损坏宕机

  • 宕机原因:
    服务器已经使用3年多了,前几天一块儿磁盘分区就出现读写数据不完整问题。 因为那块分区是作为备份用的,而且服务器一直也没出现过问题,所以也没有很重视没有很急迫的把那块儿磁盘修复了。本来想着这两天修复的,屋漏偏逢连夜雨,今天下午服务器磁盘终于歇菜了。

  • 解决难点:
    服务器宕机以后就开始联系托管机房的工作人员,机房人员说是系统崩溃需要重新安装系统。但是重新安装系统可能会丢失磁盘文件,关键是这两天刚好因为备份磁盘分区出现问题没有备份,数据是万万不能丢失的。其次有些网银接口等用的是IP,如果更好IP的话,需要更改的东西很多;而且域名解析也需要一段时间的;如果直接加一台新的服务器这样迁移时间太长不划算。

  • 解决办法:
    这台服务器是作为单独的web,还有两台数据库服务器作为主从。主库服务器的配置比较高,然后考虑其作为临时web服务器;然后把宕机服务器的IP也绑定到这太主库服务器上。开始联系机房人员更改IP,同时也开始在配置必须的web环境。不能丢失数据:把原来的硬盘挂到主库服务器上把数据迁移过来。经过一晚上的紧张忙碌,迁移很顺利,工作量相对也较小,网站也恢复正常。

Pure-FTP安装配置

Pure-FTPd 是一款免费(BSD)的,安全的,高质量和符合标准的FTP服务器。 侧重于运行效率和易用性。 这篇文章介绍如何在CentOS下安装Pure-FTP服务, 并且使用MySQL存储虚拟FTP用户。

安装Pure-FTP

  • yum方式安装
yum -y install pure-ftpd
  • 编译安装方式,下载地址,为了方便起见,我在这里使用了几个基本的编译命令来配置编译一个全功能版本的程序
# ./configure --prefix=/usr/local/pure-ftpd/ --with-language=simplified-chinese --with-everything
# make && make check && make install
  • 设置Pure-FTP开机启动
chkconfig --add pure-ftpd
chkconfig --level 2345 pure-ftpd on
  • 配置Pure-FTP
ChrootEveryone              yes         # 启用chroot, 将每个用户限制在自己的home目录下
BrokenClientsCompatibility yes # 兼容不同客户端, 默认:no
Daemonize yes # 后台运行
MaxClientsNumber 20 # 最大用户连接数
MaxClientsPerIP 4 # 每个ip最大连接数
VerboseLog yes # 记录日志
DisplayDotFiles no # 显示隐藏文件
AnonymousOnly no # 只允许匿名用户访问
NoAnonymous yes # 不允许匿名用户连接
SyslogFacility none # 不将日志在syslog日志中显示
DontResolve yes # 不进行客户端DNS解析
MaxIdleTime 5 # 最大空闲时间
LimitRecursion 2048 16 # 浏览限制,文件2000,目录8层
AnonymousCanCreateDirs no # 匿名用户可以创建目录
MaxLoad 4 # 如果系统负载超过下面所给的数字,那么匿名用户将无法下载
PassivePortRange 45000 60000 # 被动模式端口范围
#AnonymousRatio 1 10 # 匿名用户上传/下载比率
#UserRatio 1 10 # 所有用户上传/下载比率
AntiWarez yes # 禁止下载匿名用户上传但未经验证的文件
#AnonymousBandwidth 200 # 匿名用户带宽限制(KB)
UserBandwidth 128 # 所有用户最大带宽(KB)
Umask 133:022 # 创建文件/目录默认掩码
MinUID 100 # 验证登录用户的最小UID
AllowUserFXP no # 仅运行用户进行FXP传输
AllowAnonymousFXP no # 对匿名用户和非匿名用户允许进行匿名 FXP 传输
ProhibitDotFilesWrite no # 不能删除/写入隐藏文件
ProhibitDotFilesRead no # 禁止读取隐藏文件
AutoRename no # 有同名文件时自动重新命名
AnonymousCantUpload yes # 不允许匿名用户上传文件
AltLog clf:/var/log/pureftpd.log # clf格式日志文件位
MySQLConfigFile /etc/pure-ftpd/pureftpd-mysql.conf # 用户数据库文
MaxDiskUsage 99 # 当磁盘使用量打到99%时禁止上传
CreateHomeDir yes # 如果虚拟用户的目录不存在则自动创建#需要ftp根目录权限为755 chmod 775 /data/ftpdata/
CustomerProof yes # 防止命令误操作

安装免费开源的Pure-ftp Web管理工具vftp

  • 下载地址
  • 上传到Web目录以后安装, 执行安装, 根据提示安装相应的PHP模块, 配置/etc/pure-ftpd/pureftpd-mysql.conf 文件即可。配置好以后就可以通过web界面新建FTP虚拟用户了
#php安装php-posix, 安装以后需要重启web服务器
yum -y install php-process

PHP正则表达式之模式修正符

  • i (PCRE_CASELESS) :如果设置了这个修饰符,模式中的字母会进行大小写不敏感匹配。
/**
*result:
Array()
*/
$str = 'AbbbEEs';
$matches = array();
preg_match('/eE/', $str, $matches);
print_r($matches);

/**
*result:
Array([0] => EE)
*/
$str = 'AbbbEEs';
$matches = array();
preg_match('/ee/i', $str, $matches);
print_r($matches);
  • m (PCRE_MULTILINE):默认情况下,PCRE认为目标字符串是由单行字符组成的(然而实际上他可能由多行),“行首”元字符(^)进匹配字符串的开始位置,而“行末”元字符($)仅匹配字符串末尾,或者最后的换行符(除非设置D修饰符)。这个行为和perl相同。当这个修饰符设置以后,“行首”和“行末”就会匹配目标字符串中任意换行符之后或者之前,还分别匹配目标字符串的最开始和最末尾位置。这等同于perl的/m修饰符。如果目标字符串中没有\n字符,或者模式中没有出现^或$,设置这个修饰符不产生任何影响。
/**
*结果输出:
Array
(
[0] => Array
(
[0] => <p>paragraph1</p>
[1] => <p>paragraph2</p>
[2] => <p>paragraph3</p>
)
)
$str = '<p>paragraph1</p>
<p>paragraph2</p>
<p>paragraph3</p>
';
$matches = array();
preg_match_all('/^<p>.*?<\/p>\r$/m', $str, $matches);//在windows系统中要加\r,因为敲回车输入的是\r\n, 在linux下测试去掉\r
print_r($matches);
*/
  • D (PCRE_DOLLAR_ENDONLY):如果设置这个修饰符,模式中的元字符美元符号($)仅仅匹配字符串的末尾。如果没有设置这个修饰符,当字符串以一个换行符结尾时,美元符号($)还会匹配该换行符(但不会匹配之前的任何换行符). 如果设置了修饰符m, D修饰符不起作用。在perl中没有与此修饰符相同效果的修饰符.
/**
*********在windows系统中要加\r,因为敲回车输入的是\r\n, 在linux下测试请去掉\r**********
*/

/**
**未设置修饰符D时, $会匹配字符串末尾的换行符
*retult:
Array
(
[0] => <p>paragraph3</p>
)
*/
$str = '<p>paragraph3</p>
';
$match = array();
preg_match('/<p>.*?<\/p>\r$/', $str, $matches);
print_r($matches);

/**
**设置修饰符D时, $不会匹配字符串末尾的换行符
*retult:
Array()
*/
$str = '<p>paragraph3</p>
';
$match = array();
preg_match('/<p>.*?<\/p>\r$/D', $str, $matches);
print_r($matches);

/**
**设置修饰符D时, $不会匹配字符串末尾的换行符, 需要指明换行符
*retult:
Array([0] => <p>paragraph3</p>)
*/
$str = '<p>paragraph3</p>
';
$match = array();
preg_match('/<p>.*?<\/p>\r\n$/D', $str, $matches);
print_r($matches);
  • s (PCRE_DOTALL):默认情况下元字符(.)是匹配除换行符(\n)的所有字符,当设置了这个修饰符后,元字符(.)匹配包括换行符的所有字符.
/**
*不设置s时,不能匹配换行符
*result:
Array( [0] => sfs)
*/
$str = 'sfsdf
sfdsa';
$matches = array();
preg_match('/sf.*s/', $str, $matches);
print_r($matches);

/**
*设置s后,能匹配换行符
*result:
Array
(
[0] => sfsdf
sfds
)
*/
$str = 'sfsdf
sfdsa';
$matches = array();
preg_match('/sf.*s/s', $str, $matches);
print_r($matches);
  • U (PCRE_UNGREEDY):这个修饰符扭转了量词的贪婪模式,使量词默认为非贪婪的。通过在量词后紧跟?可以使其成为非贪婪的.
/**
*量词*默认为贪婪模式
*result:
Array
(
[0] => <p>paragraph1</p><p>paragraph2</p><p>paragraph3</p>
)
*/
$str = '<p>paragraph1</p><p>paragraph2</p><p>paragraph3</p>';
$matches = array();
preg_match('/<p>.*<\/p>/', $str, $matches);
print_r($matches);

/**
*修饰符U扭转量词的贪婪模式
*result:
Array
(
[0] => <p>paragraph1</p>
)
*/
$str = '<p>paragraph1</p><p>paragraph2</p><p>paragraph3</p>';
$matches = array();
preg_match('/<p>.*<\/p>/U', $str, $matches);
print_r($matches);

/**
*量词后紧跟?变为非贪婪模式
*result:
Array
(
[0] => <p>paragraph1</p>
)
*/
$str = '<p>paragraph1</p><p>paragraph2</p><p>paragraph3</p>';
$matches = array();
preg_match('/<p>.*?<\/p>/', $str, $matches);
print_r($matches);
  • e (PCRE_REPLACE_EVAL):如果设置了这个修饰符,preg_replace在进行了对替换字符串的 后向引用替换之后, 将替换后的字符串作为php代码评估之行(eval函数方式), 并使用之行结果 作为实际参与替换的字符串. 单引号, 双引号, 反斜线()和NULL字符在 后向引用替换时会被用反斜线转义.
/**
*result:
ggggggggggoooo
*/
$str = 'goooo';
echo preg_replace('/(g)/e', 'str_repeat(\\1, 10)', $str);
  • S: 当一个模式需要多次使用的时候, 为了得到匹配速度的提升, 值得花费一些时间 对其进行一些额外的分析. 如果设置了这个修饰符, 这个额外的分析就会执行. 当前, 这种对一个模式的分析仅仅适用于非锚定模式的匹配(即没有单独的固定开始字符).
  • A (PCRE_ANCHORED):如果设置了这个修饰符, 模式被强制为"锚定"模式, 也就是说约束匹配使其仅从 目标字符串的开始位置搜索. 这个效果同样可以使用适当的模式构造出来, 并且 这也是perl种实现这种模式的唯一途径.
/**
*以abc开头的字符串可以被匹配到
Array ( [0] => abc )
*/
$str = "abcdeft";
$matches = array();
preg_match('/abc/A', $str, $matches);
print_r($matches);

/**
*不是以abc开头的字符串不能匹配到
Array ( [0] => )
*/
$str = "dabcdeft";
$matches = array();
preg_match('/abc/A', $str, $matches);
print_r($matches);
  • x (PCRE_EXTENDED):如果设置了这个修饰符, 模式中的没有经过转义的或不在字符类中的空白数据字符总会被忽略, 并且位于一个未转义的字符类外部的#字符和下一个换行符之间的字符也被忽略. 这个修饰符 等同于perl中的/x修饰符, 使被编译模式中可以包含注释. 注意: 这仅用于数据字符. 空白字符 还是不能在模式的特殊字符序列中出现, 比如序列(?(引入了一个条件子组(译注: 这种语法定义的 特殊字符序列中如果出现空白字符会导致编译错误. 比如( ?(就会导致错误.).
/**
*因为模式中的空格被忽略, 匹配不到结果:
Array ( [0] => )
*/
$str = "ab cdeft";
$matches = array();
preg_match('/ab c/x', $str, $matches);
print_r($matches);

/**
*匹配到结果:
Array ( [0] => ab c )
*/
$str = "ab cdeft";
$matches = array();
preg_match('/ab c/', $str, $matches);
print_r($matches);
  • X (PCRE_EXTRA):这个修饰符打开了PCRE与perl不兼容的附件功能. 模式中的任意反斜线后就ingen一个 没有特殊含义的字符都会导致一个错误, 以此保留这些字符以保证向后兼容性. 默认 情况下, 在perl中, 反斜线紧跟一个没有特殊含义的字符被认为是该字符的原文. 当前没有其他特性由这个修饰符控制.