标签 PHP 下的文章

HHVM全称为 HipHop Virtual Machine,它是一个开源虚拟机,用来运行由 Hack(一种编程语言)和 PHP 开发应用。HHVM 在保证了 PHP 程序员最关注的高灵活性的要求下,通过使用最新的编译方式来取得了非凡的性能。到目前为止,相对于 PHP + APC (Alternative PHP Cache) ,HHVM 为 FaceBook 在 HTTP 请求的吞吐量上提高了9倍的性能,在内存的占用上,减少了5倍左右的内存占用。

同时,HHVM 也可以与基于 FastCGI 的 Web 服务器(如 Nginx 或者 Apache )协同工作。

Install HHVM, Nginx and Apache with MariaDB

安装 HHVM,Nginx和 Apache 还有 MariaDB

在本教程中,我们一起来配置 Nginx/Apache web 服务器、 数据库服务器 MariaDB 和 HHVM 。我们将使用 Ubuntu 15.04 (64 位),因为 HHVM 只能运行在64位系统上。同时,该教程也适用于 Debian 和 Linux Mint。

第一步: 安装 Nginx 或者 Apache 服务器

1、首先,先进行一次系统的升级并更新软件仓库列表,命令如下

# apt-get update && apt-get upgrade

System Upgrade

系统升级

2、 正如我之前说的,HHVM 能和 Nginx 和 Apache 进行集成。所以,究竟使用哪个服务器,这是你的自由,不过,我们会教你如何安装这两个服务器。

安装 Nginx

我们通过下面的命令安装 Nginx/Apache 服务器

# apt-get install nginx

Install Nginx Web Server

安装 Nginx 服务器

安装 Apache

# apt-get install apache2

Install Apache Web Server

安装 Apache 服务器

完成这一步,你能通过以下的链接看到 Nginx 或者 Apache 的默认页面

http://localhost
或
http://IP-Address

Nginx Welcome Page

Nginx 默认页面

Apache Default Page

Apache 默认页面

第二步: 安装和配置 MariaDB

3、 这一步,我们将通过如下命令安装 MariaDB,它是一个比 MySQL 性能更好的数据库

# apt-get install mariadb-client mariadb-server

Install MariaDB Database

安装 MariaDB

4、 在 MariaDB 成功安装之后,你可以启动它,并且设置 root 密码来保护数据库:

# systemctl start mysql
# mysql_secure_installation

回答以下问题,只需要按下y或者 n并且回车。请确保你仔细的阅读过说明。

Enter current password for root (enter for none) = press enter
Set root password? [Y/n] = y
Remove anonymous users[y/n] = y
Disallow root login remotely[y/n] = y
Remove test database and access to it [y/n] = y
Reload privileges tables now[y/n] = y

5、 在设置了密码之后,你就可以登录 MariaDB 了。

# mysql -u root -p

第三步: 安装 HHVM

6、 在此阶段,我们将安装 HHVM。我们需要添加 HHVM 的仓库到你的sources.list文件中,然后更新软件列表。

# wget -O - http://dl.hhvm.com/conf/hhvm.gpg.key | apt-key add -
# echo deb http://dl.hhvm.com/ubuntu DISTRIBUTION_VERSION main | sudo tee /etc/apt/sources.list.d/hhvm.list
# apt-get update

重要:不要忘记用你的 Ubuntu 发行版代号替换上述的 DISTRIBUTION\_VERSION (比如:lucid, precise, trusty) 或者是 Debian 的 jessie 或者 wheezy。在 Linux Mint 中也是一样的,不过只支持 petra。

添加了 HHVM 仓库之后,你就可以轻松安装了。

# apt-get install -y hhvm

安装之后,就可以启动它,但是它并没有做到开机启动。可以用如下命令做到开机启动。

# update-rc.d hhvm defaults

第四步: 配置 Nginx/Apache 连接 HHVM

7、 现在,nginx/apache 和 HHVM 都已经安装完成了,并且都独立运行起来了,所以我们需要对它们进行设置,来让它们互相关联。这个关键的步骤,就是需要告知 nginx/apache 将所有的 php 文件,都交给 HHVM 进行处理。

如果你用了 Nginx,请按照如下步骤:

nginx 的配置文件在 /etc/nginx/sites-available/default, 并且这些配置文件会在 /usr/share/nginx/html 中寻找文件执行,不过,它不知道如何处理 PHP。

为了确保 Nginx 可以连接 HHVM,我们需要执行所带的如下脚本。它可以帮助我们正确的配置 Nginx,将 hhvm.conf 放到 上面提到的配置文件 nginx.conf 的头部。

这个脚本可以确保 Nginx 可以对 .hh 和 .php 的做正确的处理,并且将它们通过 fastcgi 发送给 HHVM。

# /usr/share/hhvm/install_fastcgi.sh

Configure Nginx for HHVM

配置 Nginx、HHVM

重要: 如果你使用的是 Apache,这里不需要进行配置。

8、 接下来,你需要使用 hhvm 来提供 php 的运行环境。

# /usr/bin/update-alternatives --install /usr/bin/php php /usr/bin/hhvm 60

以上步骤完成之后,你现在可以启动并且测试它了。

# systemctl start hhvm

第五步: 测试 HHVM 和 Nginx/Apache

9、 为了确认 hhvm 是否工作,你需要在 nginx/apache 的文档根目录下建立 hello.php。

# nano /usr/share/nginx/html/hello.php       [对于 Nginx]
或
# nano /var/www/html/hello.php               [对于 Nginx 和 Apache]

在文件中添加如下代码:

<?php
if (defined('HHVM_VERSION')) {
    echo 'HHVM is working';
    phpinfo();
} else {
    echo 'HHVM is not working';
}
?>

然后访问如下链接,确认自己能否看到 "hello world"

http://localhost/info.php
或
http://IP-Address/info.php

HHVM Page

HHVM 页面

如果 “HHVM” 的页面出现了,那就说明你成功了。

结论

以上的步骤都是非常简单的,希望你能觉得这是一篇有用的教程,如果你在以上的步骤中遇到了问题,给我们留一个评论,我们将全力解决。


via: http://www.tecmint.com/install-hhvm-and-nginx-apache-with-mariadb-on-debian-ubuntu/

作者:Ravi Saive 译者:MikeCoder 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

在上一篇文章“在 Linux 命令行中使用和执行 PHP 代码(一)”中,我同时着重讨论了直接在Linux命令行中运行PHP代码以及在Linux终端中执行PHP脚本文件。

Run PHP Codes in Linux Commandline

本文旨在让你了解一些相当不错的Linux终端中的PHP交互性 shell 的用法特性。

让我们先在PHP 的交互shell中来对php.ini设置进行一些配置吧。

6. 设置PHP命令行提示符

要设置PHP命令行提示,你需要在Linux终端中使用下面的php -a(启用PHP交互模式)命令开启一个PHP交互shell。

$ php -a

然后,设置任何东西(比如说Hi Tecmint ::)作为PHP交互shell的命令提示符,操作如下:

php > #cli.prompt=Hi Tecmint ::

Enable PHP Interactive Shell

启用PHP交互Shell

同时,你也可以设置当前时间作为你的命令行提示符,操作如下:

php > #cli.prompt=`echo date('H:m:s');` >

22:15:43 >

7. 每次输出一屏

在我们上一篇文章中,我们已经在原始命令中通过管道在很多地方使用了less命令。通过该操作,我们可以在那些不能一屏全部输出的地方获得分屏显示。但是,我们可以通过配置php.ini文件,设置pager的值为less以每次输出一屏,操作如下:

$ php -a
php > #cli.pager=less

Fix PHP Screen Output

限制PHP屏幕输出

这样,下次当你运行一个命令(比如说条调试器phpinfo();)的时候,而该命令的输出内容又太过庞大而不能固定在一屏,它就会自动产生适合你当前屏幕的输出结果。

php > phpinfo();

PHP Info Output

PHP信息输出

8. 建议和TAB补全

PHP shell足够智能,它可以显示给你建议和进行TAB补全,你可以通过TAB键来使用该功能。如果对于你想要用TAB补全的字符串而言有多个选项,那么你需要使用两次TAB键来完成,其它情况则使用一次即可。

如果有超过一个的可能性,请使用两次TAB键。

php > ZIP [TAB] [TAB]

如果只有一个可能性,只要使用一次TAB键。

php > #cli.pager [TAB]

你可以一直按TAB键来获得建议的补全,直到该值满足要求。所有的行为都将记录到~/.php-history文件。

要检查你的PHP交互shell活动日志,你可以执行:

$ nano ~/.php_history | less

Check PHP Interactive Shell Logs

检查PHP交互Shell日志

9. 你可以在PHP交互shell中使用颜色,你所需要知道的仅仅是颜色代码。

使用echo来打印各种颜色的输出结果,类似这样:

php > echo "color_code1 TEXT second_color_code";

具体来说是:

php > echo "\033[0;31m Hi Tecmint \x1B[0m";

Enable Colors in PHP Shell

在PHP Shell中启用彩色

到目前为止,我们已经看到,按回车键意味着执行命令,然而PHP Shell中各个命令结尾的分号是必须的。

10. 在PHP shell中用basename()输出路径中最后一部分

PHP shell中的basename函数可以从给出的包含有到文件或目录路径的最后部分。

basename()样例#1和#2。

php > echo basename("/var/www/html/wp/wp-content/plugins");
php > echo basename("www.tecmint.com/contact-us.html");

上述两个样例将输出:

plugins
contact-us.html

Print Base Name in PHP

在PHP中打印基本名称

11. 你可以使用PHP交互shell在你的桌面创建文件(比如说test1.txt),就像下面这么简单

php> touch("/home/avi/Desktop/test1.txt");

我们已经见识了PHP交互shell在数学运算中有多优秀,这里还有更多一些例子会令你吃惊。

12. 使用PHP交互shell打印比如像tecmint.com这样的字符串的长度

strlen函数用于获取指定字符串的长度。

php > echo strlen("tecmint.com");

Print Length String in PHP

在PHP中打印字符串长度

13. PHP交互shell可以对数组排序,是的,你没听错

声明变量a,并将其值设置为array(7,9,2,5,10)。

php > $a=array(7,9,2,5,10);

对数组中的数字进行排序。

php > sort($a);

以排序后的顺序打印数组中的数字,同时打印序号,第一个为[0]。

php > print_r($a);
Array
(
    [0] => 2
    [1] => 5
    [2] => 7
    [3] => 9
    [4] => 10
)

Sort Arrays in PHP

在PHP中对数组排序

14. 在PHP交互Shell中获取π的值

php > echo pi();

3.1415926535898

15. 打印某个数比如32的平方根

php > echo sqrt(150);

12.247448713916

16. 从0-10的范围内挑选一个随机数

php > echo rand(0, 10);

Get Random Number in PHP

在PHP中获取随机数

17. 获取某个指定字符串的md5校验和sha1校验,例如,让我们在PHP Shell中检查某个字符串(比如说avi)的md5校验和sha1校验,并交叉校验bash shell生成的md5校验和sha1校验的结果。

php > echo md5(avi);
3fca379b3f0e322b7b7967bfcfb948ad

php > echo sha1(avi);
8f920f22884d6fea9df883843c4a8095a2e5ac6f

$ echo -n avi | md5sum
3fca379b3f0e322b7b7967bfcfb948ad  -

$ echo -n avi | sha1sum
8f920f22884d6fea9df883843c4a8095a2e5ac6f  -

Check md5sum and sha1sum in PHP

在PHP中检查md5校验和sha1校验

这里只是PHP Shell中所能获取的功能和PHP Shell的交互特性的惊鸿一瞥,这些就是到现在为止我所讨论的一切。保持连线,在评论中为我们提供你有价值的反馈吧。为我们点赞并分享,帮助我们扩散哦。


via: http://www.tecmint.com/execute-php-codes-functions-in-linux-commandline/

作者:Avishek Kumar 译者:GOLinux 校对:wxy

本文由 LCTT 原创翻译,Linux中国 荣誉推出

PHP是一个开源服务器端脚本语言,最初这三个字母代表的是“Personal Home Page”,而现在则代表的是“PHP:Hypertext Preprocessor”,它是个递归首字母缩写。它是一个跨平台脚本语言,深受C、C++和Java的影响。

Run PHP Codes in Linux Command Line

在 Linux 命令行中运行 PHP 代码

PHP的语法和C、Java以及带有一些PHP特性的Perl变成语言中的语法十分相似,它当下大约正被2.6亿个网站所使用,当前最新的稳定版本是PHP版本5.6.10。

PHP是HTML的嵌入脚本,它便于开发人员快速写出动态生成的页面。PHP主要用于服务器端(而Javascript则用于客户端)以通过HTTP生成动态网页,然而,当你知道可以在Linux终端中不需要网页浏览器来执行PHP时,你或许会大为惊讶。

本文将阐述PHP脚本语言的命令行方面。

1. 在安装完PHP和Apache2后,我们需要安装PHP命令行解释器。

# apt-get install php5-cli          [Debian 及类似系统]
# yum install php-cli               [CentOS 及类似系统]

接下来我们通常要做的是,在/var/www/html(这是 Apache2 在大多数发行版中的工作目录)这个位置创建一个内容为 <?php phpinfo(); ?>,名为 infophp.php 的文件来测试(PHP是否安装正确),执行以下命令即可。

# echo '<?php phpinfo(); ?>' > /var/www/html/infophp.php

然后,将浏览器访问 http://127.0.0.1/infophp.php ,这将会在网络浏览器中打开该文件。

Check PHP Info

检查PHP信息

不需要任何浏览器,在Linux终端中也可以获得相同的结果。在Linux命令行中执行/var/www/html/infophp.php,如:

# php -f /var/www/html/infophp.php

Check PHP info from Commandline

从命令行检查PHP信息

由于输出结果太大,我们可以通过管道将上述输出结果输送给 less 命令,这样就可以一次输出一屏了,命令如下:

# php -f /var/www/html/infophp.php | less

Check All PHP Info

检查所有PHP信息

这里,‘-f‘选项解析并执行命令后跟随的文件。

2. 我们可以直接在Linux命令行使用phpinfo()这个十分有价值的调试工具而不需要从文件来调用,只需执行以下命令:

# php -r 'phpinfo();'

PHP Debugging Tool

PHP调试工具

这里,‘-r‘ 选项会让PHP代码在Linux终端中不带<>标记直接执行。

3. 以交互模式运行PHP并做一些数学运算。这里,‘-a‘ 选项用于以交互模式运行PHP。

# php -a

Interactive shell

php > echo 2+3;
5
php > echo 9-6;
3
php > echo 5*4;
20
php > echo 12/3;
4
php > echo 12/5;
2.4
php > echo 2+3-1;
4
php > echo 2+3-1*3;
2
php > exit

输入 ‘exit‘ 或者按下 ‘ctrl+c‘ 来关闭PHP交互模式。

Enable PHP Interactive Mode

启用PHP交互模式

4. 你可以仅仅将PHP脚本作为shell脚本来运行。首先,创建在你当前工作目录中创建一个PHP样例脚本。

# echo -e '#!/usr/bin/php\n<?php phpinfo(); ?>' > phpscript.php

注意,我们在该PHP脚本的第一行使用#!/usr/bin/php,就像在shell脚本中那样(/bin/bash)。第一行的#!/usr/bin/php告诉Linux命令行用 PHP 解释器来解析该脚本文件。

其次,让该脚本可执行:

# chmod 755 phpscript.php

接着来运行它,

# ./phpscript.php

5. 你可以完全靠自己通过交互shell来创建简单函数,这你一定会被惊到了。下面是循序渐进的指南。

开启PHP交互模式。

# php -a

创建一个函数,将它命名为 addition。同时,声明两个变量 $a$b

php > function addition ($a, $b)

使用花括号来在其间为该函数定义规则。

php > {

定义规则。这里,该规则讲的是添加这两个变量。

php { echo $a + $b;

所有规则定义完毕,通过闭合花括号来封装规则。

php {}

测试函数,添加数字4和3,命令如下:

php > var_dump (addition(4,3));

样例输出

7NULL

你可以运行以下代码来执行该函数,你可以测试不同的值,你想来多少次都行。将里头的 a 和 b 替换成你自己的值。

php > var_dump (addition(a,b));

php > var_dump (addition(9,3.3));

样例输出

12.3NULL

Create PHP Functions

创建PHP函数

你可以一直运行该函数,直至退出交互模式(ctrl+z)。同时,你也应该注意到了,上面输出结果中返回的数据类型为 NULL。这个问题可以通过要求 php 交互 shell用 return 代替 echo 返回结果来修复。

只需要在上面的函数的中 ‘echo‘ 声明用 ‘return‘ 来替换

替换

php { echo $a + $b;

php { return $a + $b;

剩下的东西和原理仍然一样。

这里是一个样例,在该样例的输出结果中返回了正确的数据类型。

PHP Functions

PHP函数

永远都记住,用户定义的函数不会从一个shell会话保留到下一个shell会话,因此,一旦你退出交互shell,它就会丢失了。

希望你喜欢此次教程。保持连线,你会获得更多此类文章。保持关注,保持健康。请在下面的评论中为我们提供有价值的反馈。点赞并分享,帮助我们扩散。

还请阅读: 12个Linux终端中有用的的PHP命令行用法——第二部分


via: http://www.tecmint.com/run-php-codes-from-linux-commandline/

作者:Avishek Kumar 译者:GOLinux 校对:wxy

本文由 LCTT 原创翻译,Linux中国 荣誉推出

简介

要提供互联网服务,当你在开发代码的时候必须时刻保持安全意识。可能大部分 PHP 脚本都对安全问题都不在意,这很大程度上是因为有大量的无经验程序员在使用这门语言。但是,没有理由让你因为对你的代码的不确定性而导致不一致的安全策略。当你在服务器上放任何涉及到钱的东西时,就有可能会有人尝试破解它。创建一个论坛程序或者任何形式的购物车,被攻击的可能性就上升到了无穷大。

背景

为了确保你的 web 内容安全,这里有一些常规的安全准则:

别相信表单

攻击表单很简单。通过使用一个简单的 JavaScript 技巧,你可以限制你的表单只允许在评分域中填写 1 到 5 的数字。如果有人关闭了他们浏览器的 JavaScript 功能或者提交自定义的表单数据,你客户端的验证就失败了。

用户主要通过表单参数和你的脚本交互,因此他们是最大的安全风险。你应该学到什么呢?在 PHP 脚本中,总是要验证 传递给任何 PHP 脚本的数据。在本文中,我们向你演示了如何分析和防范跨站脚本(XSS)攻击,它可能会劫持用户凭据(甚至更严重)。你也会看到如何防止会玷污或毁坏你数据的 MySQL 注入攻击。

别相信用户

假定你网站获取的每一份数据都充满了有害的代码。清理每一部分,即便你相信没有人会尝试攻击你的站点。

关闭全局变量

你可能会有的最大安全漏洞是启用了 register\_globals 配置参数。幸运的是,PHP 4.2 及以后版本默认关闭了这个配置。如果打开了 register\_globals,你可以在你的 php.ini 文件中通过改变 register\_globals 变量为 Off 关闭该功能:

register_globals = Off 

新手程序员觉得注册全局变量很方便,但他们不会意识到这个设置有多么危险。一个启用了全局变量的服务器会自动为全局变量赋任何形式的参数。为了了解它如何工作以及为什么有危险,让我们来看一个例子。

假设你有一个称为 process.php 的脚本,它会向你的数据库插入表单数据。初始的表单像下面这样:

<input name="username" type="text" size="15" maxlength="64">

运行 process.php 的时候,启用了注册全局变量的 PHP 会将该参数赋值到 $username 变量。这会比通过 **$\_POST['username']$\_GET['username']** 访问它节省击键次数。不幸的是,这也会给你留下安全问题,因为 PHP 会设置该变量的值为通过 GET 或 POST 的参数发送到脚本的任何值,如果你没有显示地初始化该变量并且你不希望任何人去操作它,这就会有一个大问题。

看下面的脚本,假如 $authorized 变量的值为 true,它会给用户显示通过验证的数据。正常情况下,只有当用户正确通过了这个假想的 authenticated\_user() 函数验证,$authorized 变量的值才会被设置为真。但是如果你启用了 register\_globals,任何人都可以发送一个 GET 参数,例如 authorized=1 去覆盖它:

<?php
// Define $authorized = true only if user is authenticated
if (authenticated_user()) {
    $authorized = true;
}
?>

这个故事的寓意是,你应该从预定义的服务器变量中获取表单数据。所有通过 post 表单传递到你 web 页面的数据都会自动保存到一个称为 $\_POST** 的大数组中,所有的 GET 数据都保存在 **$\_GET 大数组中。文件上传信息保存在一个称为 $\_FILES** 的特殊数据中。另外,还有一个称为 **$\_REQUEST 的复合变量。

要从一个 POST 方法表单中访问 username 字段,可以使用 $\_POST['username']**。如果 username 在 URL 中就使用 **$\_GET['username']。如果你不确定值来自哪里,用 $\_REQUEST['username']

<?php
$post_value = $_POST['post_value'];
$get_value = $_GET['get_value'];
$some_variable = $_REQUEST['some_value']; 
?>  

$\_REQUEST 是 $\_GET、$\_POST、和 $\_COOKIE 数组的结合。如果你有两个或多个值有相同的参数名称,注意 PHP 会使用哪个。默认的顺序是 cookie、POST、然后是 GET。

推荐安全配置选项

这里有几个会影响安全功能的 PHP 配置设置。下面是一些显然应该用于生产服务器的:

  • register\_globals 设置为 off
  • safe\_mode 设置为 off
  • error\_reporting 设置为 off。如果出现错误了,这会向用户浏览器发送可见的错误报告信息。对于生产服务器,使用错误日志代替。开发服务器如果在防火墙后面就可以启用错误日志。(LCTT 译注:此处据原文逻辑和常识,应该是“开发服务器如果在防火墙后面就可以启用错误报告,即 on。”)
  • 停用这些函数:system()、exec()、passthru()、shell\_exec()、proc\_open()、和 popen()。
  • open\_basedir 为 /tmp(以便保存会话信息)目录和 web 根目录,以便脚本不能访问这些选定区域外的文件。
  • expose\_php 设置为 off。该功能会向 Apache 头添加包含版本号的 PHP 签名。
  • allow\_url\_fopen 设置为 off。如果你能够注意你代码中访问文件的方式-也就是你验证所有输入参数,这并不严格需要。
  • allow\_url\_include 设置为 off。对于任何人来说,实在没有明智的理由会想要访问通过 HTTP 包含的文件。

一般来说,如果你发现想要使用这些功能的代码,你就不应该相信它。尤其要小心会使用类似 system() 函数的代码-它几乎肯定有缺陷。

启用了这些设置后,让我们来看看一些特定的攻击以及能帮助你保护你服务器的方法。

SQL 注入攻击

由于 PHP 传递到 MySQL 数据库的查询语句是用强大的 SQL 编程语言编写的,就有了某些人通过在 web 查询参数中使用 MySQL 语句尝试 SQL 注入攻击的风险。通过在参数中插入有害的 SQL 代码片段,攻击者会尝试进入(或破坏)你的服务器。

假如说你有一个最终会放入变量 $product 的表单参数,你使用了类似下面的 SQL 语句:

$sql = "select * from pinfo where product = '$product'";

如果参数是直接从表单中获得的,应该使用 PHP 自带的数据库特定转义函数,类似:

$sql = 'Select * from pinfo where product = '"' 
       mysql_real_escape_string($product) . '"';

如果不这样做的话,有人也许会把下面的代码段放到表单参数中:

39'; DROP pinfo; SELECT 'FOO 

那么 $sql 的结果就是:

select product from pinfo where product = '39'; DROP pinfo; SELECT 'FOO' 

由于分号是 MySQL 的语句分隔符,数据库会运行下面三条语句:

select * from pinfo where product = '39'
DROP pinfo
SELECT 'FOO' 

好了,你丢失了你的表。

注意实际上 PHP 和 MySQL 不会运行这种特殊语法,因为 mysql\_query() 函数只允许每个请求处理一个语句。但是,一个子查询仍然会生效。

要防止 SQL 注入攻击,做这两件事:

  • 总是验证所有参数。例如,如果需要一个数字,就要确保它是一个数字。
  • 总是对数据使用 mysql\_real\_escape\_string() 函数转义数据中的任何引号和双引号。

注意:要自动转义任何表单数据,可以启用魔术引号(Magic Quotes)。

一些 MySQL 破坏可以通过限制 MySQL 用户权限避免。任何 MySQL 账户可以限制为只允许对选定的表进行特定类型的查询。例如,你可以创建只能选择行的 MySQL 用户。但是,这对于动态数据并不十分有用,另外,如果你有敏感的用户信息,可能某些人能访问其中一些数据,但你并不希望如此。例如,一个访问账户数据的用户可能会尝试注入访问另一个人的账户号码的代码,而不是为当前会话指定的号码。

防止基本的 XSS 攻击

XSS 表示跨站脚本。不像大部分攻击,该漏洞发生在客户端。XSS 最常见的基本形式是在用户提交的内容中放入 JavaScript 以便偷取用户 cookie 中的数据。由于大部分站点使用 cookie 和 session 验证访客,偷取的数据可用于模拟该用户-如果是一个常见的用户账户就会深受麻烦,如果是管理员账户甚至是彻底的惨败。如果你不在站点中使用 cookie 和 session ID,你的用户就不容易被攻击,但你仍然应该明白这种攻击是如何工作的。

不像 MySQL 注入攻击,XSS 攻击很难预防。Yahoo、eBay、Apple、以及 Microsoft 都曾经受 XSS 影响。尽管攻击不包含 PHP,但你可以使用 PHP 来剥离用户数据以防止攻击。为了防止 XSS 攻击,你应该限制和过滤用户提交给你站点的数据。正是因为这个原因,大部分在线公告板都不允许在提交的数据中使用 HTML 标签,而是用自定义的标签格式代替,例如 [b][linkto]

让我们来看一个如何防止这类攻击的简单脚本。对于更完善的解决办法,可以使用 SafeHTML,本文的后面部分会讨论到。

function transform_HTML($string, $length = null) {
// Helps prevent XSS attacks
    // Remove dead space.
    $string = trim($string);
    // Prevent potential Unicode codec problems.
    $string = utf8_decode($string);
    // HTMLize HTML-specific characters.
    $string = htmlentities($string, ENT_NOQUOTES);
    $string = str_replace("#", "&#35;", $string);
    $string = str_replace("%", "&#37;", $string);
    $length = intval($length);
    if ($length > 0) {
        $string = substr($string, 0, $length);
    }
    return $string;
} 

这个函数将 HTML 特定的字符转换为 HTML 字面字符。一个浏览器对任何通过这个脚本的 HTML 以非标记的文本呈现。例如,考虑下面的 HTML 字符串:

<STRONG>Bold Text</STRONG>

一般情况下,HTML 会显示为:Bold Text

但是,通过 transform\_HTML() 后,它就像原始输入一样呈现。原因是处理的字符串中的标签字符串转换为 HTML 实体。transform\_HTML() 的结果字符串的纯文本看起来像下面这样:

<STRONG>Bold Text</STRONG> 

该函数的实质是 htmlentities() 函数调用,它会将 <、>、和 & 转换为 <>、和 &。尽管这会处理大部分的普通攻击,但有经验的 XSS 攻击者有另一种把戏:用十六进制或 UTF-8 编码恶意脚本,而不是采用普通的 ASCII 文本,从而希望能绕过你的过滤器。他们可以在 URL 的 GET 变量中发送代码,告诉浏览器,“这是十六进制代码,你能帮我运行吗?” 一个十六进制例子看起来像这样:

<a href="http://host/a.php?variable=%22%3e %3c%53%43%52%49%50%54%3e%44%6f%73%6f%6d%65%74%68%69%6e%67%6d%61%6c%69%63%69%6f%75%73%3c%2f%53%43%52%49%50%54%3e"> 

浏览器渲染这个信息的时候,结果就是:

<a href="http://host/a.php?variable="> <SCRIPT>Dosomethingmalicious</SCRIPT>

为了防止这种情况,transform\_HTML() 采用额外的步骤把 # 和 % 符号转换为它们的实体,从而避免十六进制攻击,并转换 UTF-8 编码的数据。

最后,为了防止某些人用很长的输入超载字符串从而导致某些东西崩溃,你可以添加一个可选的 $length 参数来截取你指定最大长度的字符串。

使用 SafeHTML

之前脚本的问题比较简单,它不允许任何类型的用户标记。不幸的是,这里有上百种方法能使 JavaScript 跳过用户的过滤器,并且要从用户输入中剥离全部 HTML,还没有方法可以防止这种情况。

当前,没有任何一个脚本能保证无法被破解,尽管有一些确实比大部分要好。有白名单和黑名单两种方法加固安全,白名单比较简单而且更加有效。

一个白名单解决方案是 PixelApes 的 SafeHTML 反跨站脚本解析器。

SafeHTML 能识别有效 HTML,能追踪并剥离任何危险标签。它用另一个称为 HTMLSax 的软件包进行解析。

按照下面步骤安装和使用 SafeHTML:

  1. http://pixel-apes.com/safehtml/?page=safehtml 下载最新版本的 SafeHTML。
  2. 把文件放到你服务器的类文件夹。该文件夹包括 SafeHTML 和 HTMLSax 功能所需的所有东西。
  3. 在脚本中 include SafeHTML 类文件(safehtml.php)。
  4. 创建一个名为 $safehtml 的新 SafeHTML 对象。
  5. 用 $safehtml->parse() 方法清理你的数据。

这是一个完整的例子:

<?php
/* If you're storing the HTMLSax3.php in the /classes directory, along
   with the safehtml.php script, define XML_HTMLSAX3 as a null string. */
define(XML_HTMLSAX3, '');
// Include the class file.
require_once('classes/safehtml.php');
// Define some sample bad code.
$data = "This data would raise an alert <script>alert('XSS Attack')</script>";
// Create a safehtml object.
$safehtml = new safehtml();
// Parse and sanitize the data.
$safe_data = $safehtml->parse($data);
// Display result.
echo 'The sanitized data is <br />' . $safe_data;
?>

如果你想清理脚本中的任何其它数据,你不需要创建一个新的对象;在你的整个脚本中只需要使用 $safehtml->parse() 方法。

什么可能会出现问题?

你可能犯的最大错误是假设这个类能完全避免 XSS 攻击。SafeHTML 是一个相当复杂的脚本,几乎能检查所有事情,但没有什么是能保证的。你仍然需要对你的站点做参数验证。例如,该类不能检查给定变量的长度以确保能适应数据库的字段。它也不检查缓冲溢出问题。

XSS 攻击者很有创造力,他们使用各种各样的方法来尝试达到他们的目标。可以阅读 RSnake 的 XSS 教程http://ha.ckers.org/xss.html ,看一下这里有多少种方法尝试使代码跳过过滤器。SafeHTML 项目有很好的程序员一直在尝试阻止 XSS 攻击,但无法保证某些人不会想起一些奇怪和新奇的方法来跳过过滤器。

注意:XSS 攻击严重影响的一个例子 http://namb.la/popular/tech.html,其中显示了如何一步一步创建一个让 MySpace 服务器过载的 JavaScript XSS 蠕虫。

用单向哈希保护数据

该脚本对输入的数据进行单向转换,换句话说,它能对某人的密码产生哈希签名,但不能解码获得原始密码。为什么你希望这样呢?应用程序会存储密码。一个管理员不需要知道用户的密码,事实上,只有用户知道他/她自己的密码是个好主意。系统(也仅有系统)应该能识别一个正确的密码;这是 Unix 多年来的密码安全模型。单向密码安全按照下面的方式工作:

  1. 当一个用户或管理员创建或更改一个账户密码时,系统对密码进行哈希并保存结果。主机系统会丢弃明文密码。
  2. 当用户通过任何方式登录到系统时,再次对输入的密码进行哈希。
  3. 主机系统丢弃输入的明文密码。
  4. 当前新哈希的密码和之前保存的哈希相比较。
  5. 如果哈希的密码相匹配,系统就会授予访问权限。

主机系统完成这些并不需要知道原始密码;事实上,原始密码完全无所谓。一个副作用是,如果某人侵入系统并盗取了密码数据库,入侵者会获得很多哈希后的密码,但无法把它们反向转换为原始密码。当然,给足够时间、计算能力,以及弱用户密码,一个攻击者还是有可能采用字典攻击找出密码。因此,别轻易让人碰你的密码数据库,如果确实有人这样做了,让每个用户更改他们的密码。

加密 Vs 哈希

技术上来来说,哈希过程并不是加密。哈希和加密是不同的,这有两个理由:

不像加密,哈希数据不能被解密。

是有可能(但非常罕见)两个不同的字符串会产生相同的哈希。并不能保证哈希是唯一的,因此别像数据库中的唯一键那样使用哈希。

function hash_ish($string) {
    return md5($string);
}

上面的 md5() 函数基于 RSA 数据安全公司的消息摘要算法(即 MD5)返回一个由 32 个字符组成的十六进制串。然后你可以将那个 32 位字符串插入到数据库中和另一个 md5 字符串相比较,或者直接用这 32 个字符。

破解脚本

几乎不可能解密 MD5 数据。或者说很难。但是,你仍然需要好的密码,因为用一整个字典生成哈希数据库仍然很简单。有一些在线 MD5 字典,当你输入 06d80eb0c50b49a509b49f2424e8c805 后会得到结果 “dog”。因此,尽管技术上 MD5 不能被解密,这里仍然有漏洞,如果某人获得了你的密码数据库,你可以肯定他们肯定会使用 MD5 字典破译。因此,当你创建基于密码的系统的时候尤其要注意密码长度(最小 6 个字符,8 个或许会更好)和包括字母和数字。并确保这个密码不在字典中。

用 Mcrypt 加密数据

如果你不需要以可阅读形式查看密码,采用 MD5 就足够了。不幸的是,这里并不总是有可选项,如果你提供以加密形式存储某人的信用卡信息,你可能需要在后面的某个地方进行解密。

最早的一个解决方案是 Mcrypt 模块,这是一个用于允许 PHP 高速加密的插件。Mcrypt 库提供了超过 30 种用于加密的计算方法,并且提供口令确保只有你(或者你的用户)可以解密数据。

让我们来看看使用方法。下面的脚本包含了使用 Mcrypt 加密和解密数据的函数:

<?php
$data = "Stuff you want encrypted";
$key = "Secret passphrase used to encrypt your data";
$cipher = "MCRYPT_SERPENT_256";
$mode = "MCRYPT_MODE_CBC";
function encrypt($data, $key, $cipher, $mode) {
// Encrypt data
return (string)
            base64_encode
                (
                mcrypt_encrypt
                    (
                    $cipher,
                    substr(md5($key),0,mcrypt_get_key_size($cipher, $mode)),
                    $data,
                    $mode,
                    substr(md5($key),0,mcrypt_get_block_size($cipher, $mode))
                    )
                );
}
function decrypt($data, $key, $cipher, $mode) {
// Decrypt data
    return (string)
            mcrypt_decrypt
                (
                $cipher,
                substr(md5($key),0,mcrypt_get_key_size($cipher, $mode)),
                base64_decode($data),
                $mode,
                substr(md5($key),0,mcrypt_get_block_size($cipher, $mode))
                );
}
?>

mcrypt() 函数需要几个信息:

  • 需要加密的数据
  • 用于加密和解锁数据的口令,也称为键。
  • 用于加密数据的计算方法,也就是用于加密数据的算法。该脚本使用了 MCRYPT\_SERPENT\_256,但你可以从很多算法中选择,包括 MCRYPT\_TWOFISH192MCRYPT\_RC2MCRYPT\_DES、和 MCRYPT\_LOKI97
  • 加密数据的模式。这里有几个你可以使用的模式,包括电子密码本(Electronic Codebook) 和加密反馈(Cipher Feedback)。该脚本使用 MCRYPT\_MODE\_CBC 密码块链接。
  • 一个 初始化向量-也称为 IV 或者种子,用于为加密算法设置种子的额外二进制位。也就是使算法更难于破解的额外信息。
  • 键和 IV 字符串的长度,这可能随着加密和块而不同。使用 mcrypt\_get\_key\_size()mcrypt\_get\_block\_size() 函数获取合适的长度;然后用 substr() 函数将键的值截取为合适的长度。(如果键的长度比要求的短,别担心,Mcrypt 会用 0 填充。)

如果有人窃取了你的数据和短语,他们只能一个个尝试加密算法直到找到正确的那一个。因此,在使用它之前我们通过对键使用 md5() 函数增加安全,就算他们获取了数据和短语,入侵者也不能获得想要的东西。

入侵者同时需要函数,数据和口令,如果真是如此,他们可能获得了对你服务器的完整访问,你只能大清洗了。

这里还有一个数据存储格式的小问题。Mcrypt 以难懂的二进制形式返回加密后的数据,这使得当你将其存储到 MySQL 字段的时候可能出现可怕错误。因此,我们使用 base64encode()base64decode() 函数转换为和 SQL 兼容的字母格式和可检索行。

破解脚本

除了实验多种加密方法,你还可以在脚本中添加一些便利。例如,不用每次都提供键和模式,而是在包含的文件中声明为全局常量。

生成随机密码

随机(但难以猜测)字符串在用户安全中很重要。例如,如果某人丢失了密码并且你使用 MD5 哈希,你不可能,也不希望查找回来。而是应该生成一个安全的随机密码并发送给用户。为了访问你站点的服务,另外一个用于生成随机数字的应用程序会创建有效链接。下面是创建密码的一个函数:

<?php
 function make_password($num_chars) {
    if ((is_numeric($num_chars)) &&
        ($num_chars > 0) &&
        (! is_null($num_chars))) {
        $password = '';
        $accepted_chars = 'abcdefghijklmnopqrstuvwxyz1234567890';
        // Seed the generator if necessary.
        srand(((int)((double)microtime()*1000003)) );
        for ($i=0; $i<=$num_chars; $i++) {
            $random_number = rand(0, (strlen($accepted_chars) -1));
            $password .= $accepted_chars[$random_number] ;
        }
        return $password;
     }
}
?> 

使用脚本

make\_password() 函数返回一个字符串,因此你需要做的就是提供字符串的长度作为参数:

<?php
$fifteen_character_password = make_password(15);
?> 

函数按照下面步骤工作:

  • 函数确保 $num\_chars 是非零的正整数。
  • 函数初始化 $accepted\_chars 变量为密码可能包含的字符列表。该脚本使用所有小写字母和数字 0 到 9,但你可以使用你喜欢的任何字符集合。(LCTT 译注:有时候为了便于肉眼识别,你可以将其中的 0 和 O,1 和 l 之类的都去掉。)
  • 随机数生成器需要一个种子,从而获得一系列类随机值(PHP 4.2 及之后版本中并不需要,会自动播种)。
  • 函数循环 $num\_chars 次,每次迭代生成密码中的一个字符。
  • 对于每个新字符,脚本查看 $accepted\_chars** 的长度,选择 0 和长度之间的一个数字,然后添加 **$accepted\_chars 中该数字为索引值的字符到 $password。
  • 循环结束后,函数返回 $password

许可证

本篇文章,包括相关的源代码和文件,都是在 The Code Project Open License (CPOL) 协议下发布。


via: http://www.codeproject.com/Articles/363897/PHP-Security

作者:SamarRizvi 译者:ictlyh 校对:wxy

本文由 LCTT 原创翻译,Linux中国 荣誉推出

PHP 7.0.0 beta1 发布了,在带来了引人注目的性能提升的同时,也带来了不少语言特性方面的改变。以下由 LCTT 翻译自对官方的升级备注,虽然目前还不是正式发布版,不过想必距离正式发布的特性已经差别不大了。(本文会持续追踪更新)

  1. 向后不兼容的变化

语言变化

变量处理的变化

  • 间接变量、属性和方法引用现在以从左到右的语义进行解释。一些例子:
$$foo['bar']['baz'] // 解释做 ($$foo)['bar']['baz']   
$foo->$bar['baz']   // 解释做 ($foo->$bar)['baz']
$foo->$bar['baz']() // 解释做 ($foo->$bar)['baz']()
Foo::$bar['baz']()  // 解释做 (Foo::$bar)['baz']()

要恢复以前的行为,需要显式地加大括号:

${$foo['bar']['baz']}
$foo->{$bar['baz']}
$foo->{$bar['baz']}()
Foo::{$bar['baz']}()
  • 全局关键字现在只接受简单变量。像以前的
global $$foo->bar;

现在要求如下写法:

global ${$foo->bar};
  • 变量或函数调用的前后加上括号不再有任何影响。例如下列代码,函数调用结果以引用的方式传给一个函数
function getArray() { return [1, 2, 3]; }

$last = array_pop(getArray());
// Strict Standards: 只有变量可以用引用方式传递
$last = array_pop((getArray()));
// Strict Standards: 只有变量可以用引用方式传递

现在无论是否使用括号,都会抛出一个严格标准错误。以前在第二种调用方式下不会有提示。

  • 数组元素或对象属性自动安装引用顺序创建,现在的结果顺序将不同。例如:
$array = [];
$array["a"] =& $array["b"];
$array["b"] = 1;
var_dump($array);

现在结果是 ["a" => 1, "b" => 1],而以前的结果是 ["b" => 1, "a" => 1]。

相关的 RFC:

list() 的变化

  • list() 不再以反序赋值,例如:
list($array[], $array[], $array[]) = [1, 2, 3];
var_dump($array);

现在结果是 $array == [1, 2, 3] ,而不是 [3, 2, 1]。注意仅赋值顺序变化了,而赋值仍然一致(LCTT 译注:即以前的 list()行为是从后面的变量开始逐一赋值,这样对与上述用法就会产生 [3,2,1] 这样的结果了。)。例如,类似如下的常规用法

list($a, $b, $c) = [1, 2, 3];
// $a = 1; $b = 2; $c = 3;

仍然保持当前的行为。

  • 不再允许对空的 list() 赋值。如下全是无效的:
list() = $a;
list(,,) = $a;
list($x, list(), $y) = $a;
  • list() 不再支持对字符串的拆分(以前也只在某些情况下支持)。如下代码:
$string = "xy";
list($x, $y) = $string;

现在的结果是: $x == null 和 $y == null (没有提示),而以前的结果是: $x == "x" 和 $y == "y" 。此外, list() 现在总是可以处理实现了 ArrayAccess 的对象,例如:

list($a, $b) = (object) new ArrayObject([0, 1]);

现在的结果是: $a == 0 和 $b == 1。 以前 $a 和 $b 都是 null。

相关 RFC:

foreach 的变化

  • foreach() 迭代不再影响数组内部指针,数组指针可通过 current()/next() 等系列的函数访问。例如:
$array = [0, 1, 2];
foreach ($array as &$val) {
    var_dump(current($array));
}

现在将指向值 int(0) 三次。以前的输出是 int(1)、int(2) 和 bool(false)。

  • 在对数组按值迭代时,foreach 总是在对数组副本进行操作,在迭代中任何对数组的操作都不会影响到迭代行为。例如:
$array = [0, 1, 2];
$ref =& $array; // Necessary to trigger the old behavior
foreach ($array as $val) {
    var_dump($val);
    unset($array[1]);
}

现在将打印出全部三个元素 (0 1 2),而以前第二个元素 1 会跳过 (0 2)。

  • 在对数组按引用迭代时,对数组的修改将继续会影响到迭代。不过,现在 PHP 在使用数字作为键时可以更好的维护数组内的位置。例如,在按引用迭代过程中添加数组元素:
$array = [0];
foreach ($array as &$val) {
    var_dump($val);
    $array[1] = 1;
}

现在迭代会正确的添加了元素。如上代码输出是 "int(0) int(1)",而以前只是 "int(0)"。

  • 对普通(不可遍历的)对象按值或按引用迭代的行为类似于对数组进行按引用迭代。这符合以前的行为,除了如上一点所述的更精确的位置管理的改进。
  • 对可遍历对象的迭代行为保持不变。

相关 RFC: https://wiki.php.net/rfc/php7_foreach

参数处理的变化

  • 不能定义两个同名的函数参数。例如,下面的方法将会触发编译时错误:
public function foo($a, $b, $unused, $unused) {
    // ...
}

如上的代码应该修改使用不同的参数名,如:

public function foo($a, $b, $unused1, $unused2) {
    // ...
}
  • func\_get\_arg() 和 func\_get\_args() 函数不再返回传递给参数的原始值,而是返回其当前值(也许会被修改)。例如:
function foo($x) {
    $x++;
    var_dump(func_get_arg(0));
}
foo(1);

将会打印 "2" 而不是 "1"。代码应该改成仅在调用 func\_get\_arg(s) 后进行修改操作。

function foo($x) {
    var_dump(func_get_arg(0));
    $x++;
}

或者应该避免修改参数:

function foo($x) {
    $newX = $x + 1;
    var_dump(func_get_arg(0));
}
  • 类似的,异常回溯也不再显示传递给函数的原始值,而是修改后的值。例如:
function foo($x) {
    $x = 42;
    throw new Exception;
}
foo("string");

现在堆栈跟踪的结果是:

Stack trace:
#0 file.php(4): foo(42)
#1 {main}

而以前是:

Stack trace:
#0 file.php(4): foo('string')
#1 {main}

这并不会影响到你的代码的运行时行为,值得注意的是在调试时会有所不同。

同样的限制也会影响到 debug\_backtrace() 及其它检查函数参数的函数。

相关 RFC: https://wiki.php.net/phpng

整数处理的变化

  • 无效的八进制表示(包含大于7的数字)现在会产生编译错误。例如,下列代码不再有效:
$i = 0781; // 8 不是一个有效的八进制数字!

以前,无效的数字(以及无效数字后的任何数字)会简单的忽略。以前如上 $i 的值是 7,因为后两位数字会被悄悄丢弃。

  • 二进制以负数镜像位移现在会抛出一个算术错误:
var_dump(1 >> -1);
// ArithmeticError: 以负数进行位移
  • 向左位移的位数超出了整型宽度时,结果总是 0。
var_dump(1 << 64); // int(0)

以前上述代码的结果依赖于所用的 CPU 架构。例如,在 x86(包括 x86-64) 上结果是 int(1),因为其位移操作数在范围内。

  • 类似的,向右位移的位数超出了整型宽度时,其结果总是 0 或 -1 (依赖于符号):
var_dump(1 >> 64);  // int(0)
var_dump(-1 >> 64); // int(-1)

相关 RFC: https://wiki.php.net/rfc/integer_semantics

字符串处理的变化

  • 包含十六进制数字的字符串不会再被当做数字,也不会被特殊处理。参见例子中的新行为:
var_dump("0x123" == "291");     // bool(false)     (以前是 true)
var_dump(is_numeric("0x123"));  // bool(false)     (以前是 true)
var_dump("0xe" + "0x1");        // int(0)          (以前是 16)

var_dump(substr("foo", "0x1")); // string(3) "foo" (以前是 "oo")
// 注意:遇到了一个非正常格式的数字

filter\_var() 可以用来检查一个字符串是否包含了十六进制数字,或这个字符串是否能转换为整数:

$str = "0xffff";
$int = filter_var($str, FILTER_VALIDATE_INT, FILTER_FLAG_ALLOW_HEX);
if (false === $int) {
    throw new Exception("Invalid integer!");
}
var_dump($int); // int(65535)
  • 由于给双引号字符串和 HERE 文档增加了 Unicode 码点转义格式(Unicode Codepoint Escape Syntax), 所以带有无效序列的 "\u{" 现在会造成错误:
$str = "\u{xyz}"; // 致命错误:无效的 UTF-8 码点转义序列

要避免这种情况,需要转义开头的反斜杠:

$str = "\\u{xyz}"; // 正确

不过,不跟随 { 的 "\u" 不受影响。如下代码不会生成错误,和前面的一样工作:

$str = "\u202e"; // 正确

相关 RFC:

错误处理的变化

  • 现在有两个异常类: Exception 和 Error 。这两个类都实现了一个新接口: Throwable 。在异常处理代码中的类型指示也许需要修改来处理这种情况。
  • 一些致命错误和可恢复的致命错误现在改为抛出一个 Error 。由于 Error 是一个独立于 Exception 的类,这些异常不会被已有的 try/catch 块捕获。

可恢复的致命错误被转换为一个异常,所以它们不能在错误处理里面悄悄的忽略。部分情况下,类型指示失败不再能忽略。

  • 解析错误现在会生成一个 Error 扩展的 ParseError 。除了以前的基于返回值 / errorgetlast() 的处理,对某些可能无效的代码的 eval() 的错误处理应该改为捕获 ParseError 。
  • 内部类的构造函数在失败时总是会抛出一个异常。以前一些构造函数会返回 NULL 或一个不可用的对象。
  • 一些 E\_STRICT 提示的错误级别改变了。

相关 RFC:

其它的语言变化

  • 静态调用一个不兼容的 $this 上下文的非静态调用的做法不再支持。这种情况下,$this 是没有定义的,但是对它的调用是允许的,并带有一个废弃提示。例子:
class A {
    public function test() { var_dump($this); }
}

// 注意:没有从类 A 进行扩展
class B {
    public function callNonStaticMethodOfA() { A::test(); }
}

(new B)->callNonStaticMethodOfA();

// 废弃:非静态方法 A::test() 不应该被静态调用
// 提示:未定义的变量 $this
NULL

注意,这仅出现在来自不兼容上下文的调用上。如果类 B 扩展自类 A ,调用会被允许,没有任何提示。

  • 不能使用下列类名、接口名和特殊名(大小写敏感):
bool
int
float
string
null
false
true

这用于 class/interface/trait 声明、 class\_alias() 和 use 语句中。

此外,下列类名、接口名和特殊名保留做将来使用,但是使用时尚不会抛出错误:

resource
object
mixed
numeric
  • yield 语句结构当用在一个表达式上下文时,不再要求括号。它现在是一个优先级在 “print” 和 “=>” 之间的右结合操作符。在某些情况下这会导致不同的行为,例如:
echo yield -1;
// 以前被解释如下
echo (yield) - 1;
// 现在被解释如下
echo yield (-1);

yield $foo or die;
// 以前被解释如下
yield ($foo or die);
// 现在被解释如下
(yield $foo) or die;

这种情况可以通过增加括号来解决。

  • 移除了 ASP (<%) 和 script (