发布时间:2025-12-09 20:45:22 浏览次数:3
PHP 官网文档(中文):https://www.php.net/manual/zh/langref.php
ThinkPhp (官方手册、入门教程):https://sites.thinkphp.cn/1556331
W3School PHP 教程:http://www.w3school.com.cn/php/index.asp
w3cschool (在线教程&技术文档):https://www.w3cschool.cn
菜鸟教程:https://www.runoob.com/php/php-tutorial.html
php教程,php学习路线图:https://www.zhihu.com/question/60882384
在线工具:https://c.runoob.com/
:https://blog.csdn.net/m0_46641521/article/details/120107786
在 phpStorm 中使用 Xdebug。
首先修改配置信息。编辑 D:\Sofware\php\php7.4.30-nts\php.ini 文件,增加如下调试配置信息并重启Apache服务(路径信息根据实际情况做调整)。
添加配置
[Xdebug]
;指定 Xdebug 扩展文件的绝对路径
extension_dir = "ext"
zend_extension = php_xdebug.dll
;zend_extension = "D:\Software\php\php-7.4.30-nts\php_xdebug.dll"
;指定log存放目录
xdebug.output_dir = "D:\Software\php\php_xdebug_log"
;开启远程调试
xdebug.mode = debug,trace
;指定远程调试的处理协议
xdebug.remote_handler = dbgp
;指定远程调试的主机名。也可以设置成本地解析的域名
;xdebug.client_host = www.demo.com
;xdebug.client_host = localhost
xdebug.client_host=127.0.0.1
;指定远程调试的端口号, 可自己定义
xdebug.client_port = 9100
;在 PHP 请求开始时激活函数跟踪、垃圾收集统计信息、分析或步骤调试。
xdebug.start_with_request = yes
;指定传递给DBGp调试器处理程序的IDE Key(多用户调式下使用)
xdebug.idekey = PHPSTORM
;允许收集函数调用的返回值
;重写var_dump(),当这个参数被设置为1时,即使捕捉到异常,xdebug仍将强制执行异常跟踪当一个异常出现时
xdebug.collect_return = 1
;启用代码自动跟踪
xdebug.auto_trace = Off
;--------------------------xdebug3 配置信息 --------------------------
;[xdebug]
;zend_extension ="\ext\php_xdebug-3.0.4-7.3-vc15-nts-x86_64.dll"
;[Xdebug]
;
;xdebug.output_dir = "tmp\xdebug"
;xdebug.log=xdebug.log
;;开启debug
;xdebug.mode=debug,trace
;xdebug.start_with_request = yes
;xdebug.client_port = 9003
;xdebug.client_host=127.0.0.1
;xdebug.remote_handler=dbgp
;xdebug.idekey=PHPSTORM
;--------------------------xdebug3 配置信息 --------------------------
配置 PHPStorm 的 PHP。配置 xdebug 的端口号,需要和php.ini中的端口号一致
单用户调试步骤到此结束,点击右上角的电话图标来开启监听,打断点启动debug模式即可,但如果是多用户调试模式需要配置 DBGp Proxy 和 Server,首先配置 DBGp Proxy,填写php.ini中的IDEKEY和端口号
配置 DBGp Proxy。在 “Settings” 对话框中,选择 “PHP” ----> “Debug” ----> “DBGp Proxy” 选项,在对话框中填写 “IDE Key” ( 和xdebug.idekey=PHPSTORM 保持一致)和 “Host” (和xdebug.remote_host = www.demo.com 保持一致),“Port” 默认为9001可以不修改,单击"Apply" 按钮.
配置完成,点击应用。
然后再配置 Servers。
网上很多教程没有讲明白啥意思,首先要在 phpenv 等软件里面设置 127.0.0.1(可以自定义)网站指向的目录为你要 debug 的文件目录【记得重启服务】。( 其实这里就是填写已经搭好的php环境 127.0.0.1,这样 phpstorm 就知道通过 127.0.0.1 可以访问到当前目录所对应的网站 )
步骤:在 “Settings” 对话框中,选择 “PHP” ----> “Servers” 选项,创建本地调试服务器,点击应用即可。操作步骤如下:
配置测试项目。选择 “Run” ----> “ Edit Configurations” 命令,新建一个运行调试配置。操作步骤如下:
断点测试。在项目中新建一个名为“test.php”的文件,单击代码视图行号的位置新增一个断点。在窗口右上角选择 “testDebug" 的调试配置,单击 “Start | Stop Listening for PHP Debug Connections” 按钮,如下图所示:
PHP(全称:PHP:Hypertext Preprocessor,即 "PHP:超文本预处理器")是一种创建动态交互性站点、通用开源的服务器端脚本语言。
PHP 文件
PHP 能做什么
PHP 安装
如果不想自己安装 PHP,可以使用 集成服务器
PHP 脚本可以放在文档中的任何位置。PHP 脚本以 <?php 开始,以 ?> 结束:
<?php// PHP 代码?>PHP 是一门弱类型语言,不需要声明变量的数据类型,PHP 会根据变量的值,自动把变量转换为正确的数据类型。在强类型的编程语言中,必须在使用变量前先声明(定义)变量的类型和名称。
PHP 没有声明变量的命令。变量在第一次给它赋值的时候被创建。
<?php$txt="Hello world!";$x=5;$y=10.5;echo "$txt";?>PHP 有四种不同的变量作用域:
在函数内声明的变量,是局部变量
在函数外部定义的变量,拥有全局作用域。除了函数外,全局变量可以被脚本中的任何部分访问,要在一个函数中访问一个全局变量,需要使用 global 关键字。在 PHP 函数内部声明的变量是局部变量,仅能在函数内部访问:
<?php$x=5; // 全局变量function myTest(){$y=10; // 局部变量echo "<p>测试函数内变量:<p>";echo "变量 x 为: $x";echo "<br>";echo "变量 y 为: $y";} myTest();echo "<p>测试函数外变量:<p>";echo "变量 x 为: $x";echo "<br>";echo "变量 y 为: $y";?>global 关键字用于函数内访问全局变量。在函数内调用函数外定义的全局变量,我们需要在函数中的变量前加上 global 关键字:
<?php$x=5;$y=10;function myTest(){global $x,$y;$y=$x+$y;}myTest();echo $y; // 输出 15?>PHP 将所有全局变量存储在一个名为 $GLOBALS[index] 的数组中。 index 保存变量的名称。这个数组可以在函数内部访问,也可以直接用来更新全局变量。
<?php$x=5;$y=10;function myTest(){$GLOBALS['y']=$GLOBALS['x']+$GLOBALS['y'];} myTest();echo $y;?>当一个函数完成时,它的所有变量通常都会被删除。然而,有时候您希望某个局部变量不要被删除。要做到这一点,需要在声明变量时使用 static 关键字:
<?phpfunction myTest(){static $x=0;echo $x;$x++;echo PHP_EOL; // 换行符}myTest();myTest();myTest();?>PHP 支持以下几种数据类型:
数组示例:创建一个数组, 然后使用 PHP var_dump() 函数返回数组的数据类型和值:
<?php $cars=array("Volvo","BMW","Toyota");var_dump($cars);?>PHP 5 Array 函数:https://www.runoob.com/php/php-ref-array.html
在 PHP 中,array() 函数用于创建数组,count() 函数用于返回数组的长度。
有三种类型的数组:
使用 for 循环,遍历并打印数值数组中的所有值
<?php$cars=array("Volvo","BMW","Toyota");$arrlength=count($cars);for($x=0;$x<$arrlength;$x++){echo $cars[$x];echo "<br>";}?><?php$age=array("Peter"=>"35","Ben"=>"37","Joe"=>"43");echo "Peter is " . $age['Peter'] . " years old.";?><?php$age=array("Peter"=>"35","Ben"=>"37","Joe"=>"43");foreach($age as $x=>$x_value){echo "Key=" . $x . ", Value=" . $x_value;echo "<br>";}?>对象数据类型 也可以用于存储数据。在 PHP 中,对象必须声明。
PHP 资源 resource 是一种特殊变量,保存了到外部资源的一个引用。常见资源数据类型有 打开文件、数据库连接、图形画布区域等。由于资源类型变量保存有为打开文件、数据库连接、图形画布区域等的特殊句柄,因此将其它类型的值转换为资源没有意义。
使用 get_resource_type() 函数可以返回资源(resource)类型:
虽然 PHP 是弱类型语言,但也需要明白变量类型及它们的意义,因为我们经常需要对 PHP 变量进行比较,包含松散和严格比较。
结果:
1、值相等
3、类型不相等
PHP中 比较 0、false、null
<?phpecho '0 == false: ';var_dump(0 == false);echo '0 === false: ';var_dump(0 === false);echo PHP_EOL;echo '0 == null: ';var_dump(0 == null);echo '0 === null: ';var_dump(0 === null);echo PHP_EOL;echo 'false == null: ';var_dump(false == null);echo 'false === null: ';var_dump(false === null);echo PHP_EOL;echo '"0" == false: ';var_dump("0" == false);echo '"0" === false: ';var_dump("0" === false);echo PHP_EOL;echo '"0" == null: ';var_dump("0" == null);echo '"0" === null: ';var_dump("0" === null);echo PHP_EOL;echo '"" == false: ';var_dump("" == false);echo '"" === false: ';var_dump("" === false);echo PHP_EOL;echo '"" == null: ';var_dump("" == null);echo '"" === null: ';var_dump("" === null);超级全局变量在PHP 4.1.0之后被启用,是PHP系统中自带的变量,在一个脚本的全部作用域中都可用。PHP中预定义了几个超级全局变量(superglobals) ,这意味着它们在一个脚本的全部作用域中都可用。 你不需要特别说明,就可以在函数及类中使用。
PHP 超级全局变量列表:
示例:
<?php $x = 75; $y = 25;function addition() { $GLOBALS['z'] = $GLOBALS['x'] + $GLOBALS['y']; }addition(); echo $z; ?><?php echo $_SERVER['PHP_SELF'];echo "<br>";echo $_SERVER['SERVER_NAME'];echo "<br>";echo $_SERVER['HTTP_HOST'];echo "<br>";echo $_SERVER['HTTP_REFERER'];echo "<br>";echo $_SERVER['HTTP_USER_AGENT'];echo "<br>";echo $_SERVER['SCRIPT_NAME'];?>示例:
<!DOCTYPE html><html><body><form method="post" action="<?php echo $_SERVER['PHP_SELF'];?>">Name: <input type="text" name="fname"><input type="submit"></form><?php $name = htmlspecialchars($_REQUEST['fname']); echo $name; ?></body></html>示例:
<!DOCTYPE html><html><body><form method="post" action="<?php echo $_SERVER['PHP_SELF'];?>">Name: <input type="text" name="fname"><input type="submit"></form><?php $name = htmlspecialchars($_POST['fname']); echo $name; ?></body></html>示例:
<!DOCTYPE html><html><body><a href="test_get.php?subject=PHP&web=runoob.com">测试 $_GET</a></body></html>PHP 表单和用户输入:https://www.runoob.com/php/php-forms.html
常量在定义后,默认是全局变量,可以在整个运行的脚本的任何地方使用。
设置常量,使用 define() 函数,函数语法如下:
bool define ( string $name , mixed $value [, bool $case_insensitive = false ] )
函数有三个参数:
在 PHP 中,只有一个字符串运算符。
PHP String 函数是 PHP 核心的组成部分。无需安装即可使用这些函数。
| addcslashes() | 返回在指定的字符前添加反斜杠的字符串。 |
| addslashes() | 返回在预定义的字符前添加反斜杠的字符串。 |
| bin2hex() | 把 ASCII 字符的字符串转换为十六进制值。 |
| chop() | 移除字符串右侧的空白字符或其他字符。 |
| chr() | 从指定 ASCII 值返回字符。 |
| chunk_split() | 把字符串分割为一连串更小的部分。 |
| convert_cyr_string() | 把字符串由一种 Cyrillic 字符集转换成另一种。 |
| convert_uudecode() | 对 uuencode 编码的字符串进行解码。 |
| convert_uuencode() | 使用 uuencode 算法对字符串进行编码。 |
| count_chars() | 返回字符串所用字符的信息。 |
| crc32() | 计算一个字符串的 32 位 CRC(循环冗余校验)。 |
| crypt() | 单向的字符串加密法(hashing)。 |
| echo() | 输出一个或多个字符串。 |
| explode() | 把字符串打散为数组。 |
| fprintf() | 把格式化的字符串写入到指定的输出流。 |
| get_html_translation_table() | 返回 htmlspecialchars() 和 htmlentities() 使用的翻译表。 |
| hebrev() | 把希伯来(Hebrew)文本转换为可见文本。 |
| hebrevc() | 把希伯来(Hebrew)文本转换为可见文本,并把新行(\n)转换为 <br>。 |
| hex2bin() | 把十六进制值的字符串转换为 ASCII 字符。 |
| html_entity_decode() | 把 HTML 实体转换为字符。 |
| htmlentities() | 把字符转换为 HTML 实体。 |
| htmlspecialchars_decode() | 把一些预定义的 HTML 实体转换为字符。 |
| htmlspecialchars() | 把一些预定义的字符转换为 HTML 实体。 |
| implode() | 返回一个由数组元素组合成的字符串。 |
| join() | implode() 的别名。 |
| lcfirst() | 把字符串中的首字符转换为小写。 |
| levenshtein() | 返回两个字符串之间的 Levenshtein 距离。 |
| localeconv() | 返回本地数字及货币格式信息。 |
| ltrim() | 移除字符串左侧的空白字符或其他字符。 |
| md5() | 计算字符串的 MD5 散列。 |
| md5_file() | 计算文件的 MD5 散列。 |
| metaphone() | 计算字符串的 metaphone 键。 |
| money_format() | 返回格式化为货币字符串的字符串。 |
| nl_langinfo() | 返回指定的本地信息。 |
| nl2br() | 在字符串中的每个新行之前插入 HTML 换行符。 |
| number_format() | 通过千位分组来格式化数字。 |
| ord() | 返回字符串中第一个字符的 ASCII 值。 |
| parse_str() | 把查询字符串解析到变量中。 |
| print() | 输出一个或多个字符串。 |
| printf() | 输出格式化的字符串。 |
| quoted_printable_decode() | 把 quoted-printable 字符串转换为 8 位字符串。 |
| quoted_printable_encode() | 把 8 位字符串转换为 quoted-printable 字符串。 |
| quotemeta() | 引用元字符。 |
| rtrim() | 移除字符串右侧的空白字符或其他字符。 |
| setlocale() | 设置地区信息(地域信息)。 |
| sha1() | 计算字符串的 SHA-1 散列。 |
| sha1_file() | 计算文件的 SHA-1 散列。 |
| similar_text() | 计算两个字符串的相似度。 |
| soundex() | 计算字符串的 soundex 键。 |
| sprintf() | 把格式化的字符串写入一个变量中。 |
| sscanf() | 根据指定的格式解析来自一个字符串的输入。 |
| str_getcsv() | 把 CSV 字符串解析到数组中。 |
| str_ireplace() | 替换字符串中的一些字符(大小写不敏感)。 |
| str_pad() | 把字符串填充为新的长度。 |
| str_repeat() | 把字符串重复指定的次数。 |
| str_replace() | 替换字符串中的一些字符(大小写敏感)。 |
| str_rot13() | 对字符串执行 ROT13 编码。 |
| str_shuffle() | 随机地打乱字符串中的所有字符。 |
| str_split() | 把字符串分割到数组中。 |
| str_word_count() | 计算字符串中的单词数。 |
| strcasecmp() | 比较两个字符串(大小写不敏感)。 |
| strchr() | 查找字符串在另一字符串中的第一次出现。(strstr() 的别名。) |
| strcmp() | 比较两个字符串(大小写敏感)。 |
| strcoll() | 比较两个字符串(根据本地设置)。 |
| strcspn() | 返回在找到任何指定的字符之前,在字符串查找的字符数。 |
| strip_tags() | 剥去字符串中的 HTML 和 PHP 标签。 |
| stripcslashes() | 删除由 addcslashes() 函数添加的反斜杠。 |
| stripslashes() | 删除由 addslashes() 函数添加的反斜杠。 |
| stripos() | 返回字符串在另一字符串中第一次出现的位置(大小写不敏感)。 |
| stristr() | 查找字符串在另一字符串中第一次出现的位置(大小写不敏感)。 |
| strlen() | 返回字符串的长度。中文字符串的处理使用 mb_strlen() 函数。 |
| strnatcasecmp() | 使用一种"自然排序"算法来比较两个字符串(大小写不敏感)。 |
| strnatcmp() | 使用一种"自然排序"算法来比较两个字符串(大小写敏感)。 |
| strncasecmp() | 前 n 个字符的字符串比较(大小写不敏感)。 |
| strncmp() | 前 n 个字符的字符串比较(大小写敏感)。 |
| strpbrk() | 在字符串中搜索指定字符中的任意一个。 |
| strpos() | 返回字符串在另一字符串中第一次出现的位置(大小写敏感)。 |
| strrchr() | 查找字符串在另一个字符串中最后一次出现。 |
| strrev() | 反转字符串。 |
| strripos() | 查找字符串在另一字符串中最后一次出现的位置(大小写不敏感)。 |
| strrpos() | 查找字符串在另一字符串中最后一次出现的位置(大小写敏感)。 |
| strspn() | 返回在字符串中包含的特定字符的数目。 |
| strstr() | 查找字符串在另一字符串中的第一次出现(大小写敏感)。 |
| strtok() | 把字符串分割为更小的字符串。 |
| strtolower() | 把字符串转换为小写字母。 |
| strtoupper() | 把字符串转换为大写字母。 |
| strtr() | 转换字符串中特定的字符。 |
| substr() | 返回字符串的一部分。 |
| mb_substr() | 返回中文字符串的一部分。 |
| substr_compare() | 从指定的开始位置(二进制安全和选择性区分大小写)比较两个字符串。 |
| substr_count() | 计算子串在字符串中出现的次数。 |
| substr_replace() | 把字符串的一部分替换为另一个字符串。 |
| trim() | 移除字符串两侧的空白字符和其他字符。 |
| ucfirst() | 把字符串中的首字符转换为大写。 |
| ucwords() | 把字符串中每个单词的首字符转换为大写。 |
| vfprintf() | 把格式化的字符串写到指定的输出流。 |
| vprintf() | 输出格式化的字符串。 |
| vsprintf() | 把格式化字符串写入变量中。 |
| wordwrap() | 按照指定长度对字符串进行折行处理。 |
| x + y | 加 | x 和 y 的和 | 2 + 2 | 4 |
| x - y | 减 | x 和 y 的差 | 5 - 2 | 3 |
| x * y | 乘 | x 和 y 的积 | 5 * 2 | 10 |
| x / y | 除 | x 和 y 的商 | 15 / 5 | 3 |
| x % y | 模(除法的余数) | x 除以 y 的余数 | 5 % 2 10 % 8 10 % 2 | 1 2 0 |
| - x | 取反 | x 取反 | <?php$x =2;echo -$x;?> | -2 |
| a . b | 并置 | 连接两个字符串 | "Hi" . "Ha" | HiHa |
| x = y | x = y | 左操作数被设置为右侧表达式的值 |
| x += y | x = x + y | 加 |
| x -= y | x = x - y | 减 |
| x *= y | x = x * y | 乘 |
| x /= y | x = x / y | 除 |
| x %= y | x = x % y | 模(除法的余数) |
| a .= b | a = a . b | 连接两个字符串 |
| ++ x | 预递增 | x 加 1,然后返回 x |
| x ++ | 后递增 | 返回 x,然后 x 加 1 |
| -- x | 预递减 | x 减 1,然后返回 x |
| x -- | 后递减 | 返回 x,然后 x 减 1 |
| x == y | 等于 | 如果 x 等于 y,则返回 true | 5==8 返回 false |
| x === y | 绝对等于 | 如果 x 等于 y,且它们类型相同,则返回 true | 5==="5" 返回 false |
| x != y | 不等于 | 如果 x 不等于 y,则返回 true | 5!=8 返回 true |
| x <> y | 不等于 | 如果 x 不等于 y,则返回 true | 5<>8 返回 true |
| x !== y | 绝对不等于 | 如果 x 不等于 y,或它们类型不相同,则返回 true | 5!=="5" 返回 true |
| x > y | 大于 | 如果 x 大于 y,则返回 true | 5>8 返回 false |
| x < y | 小于 | 如果 x 小于 y,则返回 true | 5<8 返回 true |
| x >= y | 大于等于 | 如果 x 大于或者等于 y,则返回 true | 5>=8 返回 false |
| x <= y | 小于等于 | 如果 x 小于或者等于 y,则返回 true | 5<=8 返回 true |
| x and y | 与 | 如果 x 和 y 都为 true,则返回 true | x=6 y=3 (x < 10 and y > 1) 返回 true |
| x or y | 或 | 如果 x 和 y 至少有一个为 true,则返回 true | x=6 y=3 (x==6 or y==5) 返回 true |
| x xor y | 异或 | 如果 x 和 y 有且仅有一个为 true,则返回 true | x=6 y=3 (x==6 xor y==3) 返回 false |
| x && y | 与 | 如果 x 和 y 都为 true,则返回 true | x=6 y=3 (x < 10 && y > 1) 返回 true |
| x || y | 或 | 如果 x 和 y 至少有一个为 true,则返回 true | x=6 y=3 (x==5 || y==5) 返回 false |
| ! x | 非 | 如果 x 不为 true,则返回 true | x=6 y=3 !(x==y) 返回 true |
| x + y | 集合 | x 和 y 的集合 |
| x == y | 相等 | 如果 x 和 y 具有相同的键/值对,则返回 true |
| x === y | 恒等 | 如果 x 和 y 具有相同的键/值对,且顺序相同类型相同,则返回 true |
| x != y | 不相等 | 如果 x 不等于 y,则返回 true |
| x <> y | 不相等 | 如果 x 不等于 y,则返回 true |
| x !== y | 不恒等 | 如果 x 不等于 y,则返回 true |
三元运算符:"?:"(或三元)运算符 。语法格式:(expr1) ? (expr2) : (expr3)
| 无 | clone new | clone 和 new |
| 左 | [ | array() |
| 右 | ++ -- ~ (int) (float) (string) (array) (object) (bool) @ | 类型和递增/递减 |
| 无 | instanceof | 类型 |
| 右 | ! | 逻辑运算符 |
| 左 | * / % | 算术运算符 |
| 左 | + – . | 算术运算符和字符串运算符 |
| 左 | << >> | 位运算符 |
| 无 | == != === !== <> | 比较运算符 |
| 左 | & | 位运算符和引用 |
| 左 | ^ | 位运算符 |
| 左 | | | 位运算符 |
| 左 | && | 逻辑运算符 |
| 左 | || | 逻辑运算符 |
| 左 | ? : | 三元运算符 |
| 右 | = += -= *= /= .= %= &= |= ^= <<= >>= => | 赋值运算符 |
| 左 | and | 逻辑运算符 |
| 左 | xor | 逻辑运算符 |
| 左 | or | 逻辑运算符 |
| 左 | , | 多处用到 |
在 PHP 中,提供了下列条件语句:
switch 示例:
<?php$favcolor="red";switch ($favcolor){case "red":echo "你喜欢的颜色是红色!";break;case "blue":echo "你喜欢的颜色是蓝色!";break;case "green":echo "你喜欢的颜色是绿色!";break;default:echo "你喜欢的颜色不是 红, 蓝, 或绿色!";}?>在 PHP 中,提供了下列循环语句:
数组的 键 值 循环
<?php$x=array(1=>"Google", 2=>"Runoob", 3=>"Taobao");foreach ($x as $key => $value){echo "key 为 " . $key . ",对应的 value 为 ". $value . PHP_EOL;}?>:https://www.runoob.com/php/php-namespace.html
PHP 命名空间(namespace)是在PHP 5.3中加入的,如果你学过C#和Java,那命名空间就不算什么新事物。 不过在PHP当中还是有着相当重要的意义。
PHP 命名空间与其它语言有个不同:同一个命名空间可以定义在多个文件中,即允许将同一个命名空间的内容分割存放在不同的文件中。
字符串 作为 php 对象,并直接使用:https://www.php.net/manual/zh/language.namespaces.dynamic.php
在实际的编程实践中,非常不提倡在同一个文件中定义多个命名空间。这种方式的主要用于将多个 PHP 脚本合并在同一个文件中。将全局的非命名空间中的代码与命名空间中的代码组合在一起,只能使用大括号形式的语法。全局代码必须用一个不带名称的 namespace 语句加上大括号括起来
PHP 命名空间可以解决以下两类问题:
将全局的非命名空间中的代码与命名空间中的代码组合在一起,只能使用大括号形式的语法。全局代码必须用一个不带名称的 namespace 语句加上大括号括起来,例如:
<?phpnamespace MyProject {const CONNECT_OK = 1;class Connection { /* ... */ }function connect() { /* ... */ }}namespace { // 全局代码session_start();$a = MyProject\connect();echo MyProject\Connection::start();}?>在声明命名空间之前唯一合法的代码是用于定义源文件编码方式的 declare 语句。所有非 PHP 代码包括空白符都不能出现在命名空间的声明之前。
<?phpdeclare(encoding='UTF-8'); //定义多个命名空间和不包含在命名空间中的代码namespace MyProject {const CONNECT_OK = 1;class Connection { /* ... */ }function connect() { /* ... */ }}namespace { // 全局代码session_start();$a = MyProject\connect();echo MyProject\Connection::start();}?>以下代码会出现语法错误:
<html><?php// 命名空间前出现了“<html>” 会致命错误 - 命名空间必须是程序脚本的第一条语句namespace MyProject; ?>与目录和文件的关系很像,PHP 命名空间也允许指定层次化的命名空间的名称。因此,命名空间的名字可以使用分层次的方式定义:
<?phpnamespace MyProject\Sub\Level; //声明分层次的单个命名空间const CONNECT_OK = 1;class Connection { /* ... */ }function Connect() { /* ... */ }?>上面的例子创建了常量 MyProject\Sub\Level\CONNECT_OK,类 MyProject\Sub\Level\Connection 和函数 MyProject\Sub\Level\Connect。
如果没有定义任何命名空间,所有的类与函数的定义都是在全局空间,与 PHP 引入命名空间概念前一样。在名称前加上前缀 \ 表示该名称是全局空间中的名称,即使该名称位于其它的命名空间中时也是如此。
使用全局空间说明
<?phpnamespace A\B\C;/* 这个函数是 A\B\C\fopen */function fopen() { /* ... */$f = \fopen(...); // 调用全局的fopen函数return $f;} ?>自从有了命名空间之后,最容易出错的该是使用类的时候,这个类的寻找路径是什么样的了。
<?phpnamespace A;use B\D, C\E as F;// 函数调用foo(); // 首先尝试调用定义在命名空间"A"中的函数foo()// 再尝试调用全局函数 "foo"\foo(); // 调用全局空间函数 "foo" my\foo(); // 调用定义在命名空间"A\my"中函数 "foo" F(); // 首先尝试调用定义在命名空间"A"中的函数 "F" // 再尝试调用全局函数 "F"// 类引用new B(); // 创建命名空间 "A" 中定义的类 "B" 的一个对象// 如果未找到,则尝试自动装载类 "A\B"new D(); // 使用导入规则,创建命名空间 "B" 中定义的类 "D" 的一个对象// 如果未找到,则尝试自动装载类 "B\D"new F(); // 使用导入规则,创建命名空间 "C" 中定义的类 "E" 的一个对象// 如果未找到,则尝试自动装载类 "C\E"new \B(); // 创建定义在全局空间中的类 "B" 的一个对象// 如果未发现,则尝试自动装载类 "B"new \D(); // 创建定义在全局空间中的类 "D" 的一个对象// 如果未发现,则尝试自动装载类 "D"new \F(); // 创建定义在全局空间中的类 "F" 的一个对象// 如果未发现,则尝试自动装载类 "F"// 调用另一个命名空间中的静态方法或命名空间函数B\foo(); // 调用命名空间 "A\B" 中函数 "foo"B::foo(); // 调用命名空间 "A" 中定义的类 "B" 的 "foo" 方法// 如果未找到类 "A\B" ,则尝试自动装载类 "A\B"D::foo(); // 使用导入规则,调用命名空间 "B" 中定义的类 "D" 的 "foo" 方法// 如果类 "B\D" 未找到,则尝试自动装载类 "B\D"\B\foo(); // 调用命名空间 "B" 中的函数 "foo" \B::foo(); // 调用全局空间中的类 "B" 的 "foo" 方法// 如果类 "B" 未找到,则尝试自动装载类 "B"// 当前命名空间中的静态方法或函数A\B::foo(); // 调用命名空间 "A\A" 中定义的类 "B" 的 "foo" 方法// 如果类 "A\A\B" 未找到,则尝试自动装载类 "A\A\B"\A\B::foo(); // 调用命名空间 "A" 中定义的类 "B" 的 "foo" 方法// 如果类 "A\B" 未找到,则尝试自动装载类 "A\B"?>可以把
这样可能会更容易理解。
<?php //创建空间Blognamespace Blog;class Comment { }//非限定名称,表示当前Blog空间//这个调用将被解析成 Blog\Comment();$blog_comment = new Comment();//限定名称,表示相对于Blog空间//这个调用将被解析成 Blog\Article\Comment();$article_comment = new Article\Comment(); //类前面没有反斜杆\//完全限定名称,表示绝对于Blog空间//这个调用将被解析成 Blog\Comment();$article_comment = new \Blog\Comment(); //类前面有反斜杆\//完全限定名称,表示绝对于Blog空间//这个调用将被解析成 Blog\Article\Comment();$article_comment = new \Blog\Article\Comment(); //类前面有反斜杆\//创建Blog的子空间Articlenamespace Blog\Article;class Comment { }?>在面向对象的程序设计(英语:Object-oriented programming,缩写:OOP)中,对象是一个由信息及对信息进行处理的描述所组成的整体,是对现实世界的抽象。
比如 Animal(动物) 是一个抽象类,我们可以具体到一只狗跟一只羊,而狗跟羊就是具体的对象,他们有颜色属性,可以写,可以跑等行为状态。
面向对象内容
类 − 定义了一件事物的抽象特点。类的定义包含了数据的形式以及对数据的操作。
对象 − 是类的实例。
成员变量 − 定义在类内部的变量。该变量的值对外是不可见的,但是可以通过成员函数访问,在类被实例化为对象后,该变量即可成为对象的属性。
成员函数 − 定义在类的内部,可用于访问对象的数据。
继承 − 继承性是子类自动共享父类数据结构和方法的机制,这是类之间的一种关系。在定义和实现一个类的时候,可以在一个已经存在的类的基础之上来进行,把这个已经存在的类所定义的内容作为自己的内容,并加入若干新的内容。
父类 − 一个类被其他类继承,可将该类称为父类,或基类,或超类。
子类 − 一个类继承其他类称为子类,也可称为派生类。
多态 − 多态性是指相同的函数或方法可作用于多种类型的对象上并获得不同的结果。不同的对象,收到同一消息可以产生不同的结果,这种现象称为多态性。
重载 − 简单说,就是函数或者方法有同样的名称,但是参数列表不相同的情形,这样的同名不同参数的函数或者方法之间,互相称之为重载函数或者方法。
抽象性 − 抽象性是指将具有一致的数据结构(属性)和行为(操作)的对象抽象成类。一个类就是这样一种抽象,它反映了与应用有关的重要性质,而忽略其他一些无关内容。任何类的划分都是主观的,但必须与具体的应用有关。
封装 − 封装是指将现实世界中存在的某个客体的属性与行为绑定在一起,并放置在一个逻辑单元内。
构造函数 − 主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中。
析构函数 − 析构函数(destructor) 与构造函数相反,当对象结束其生命周期时(例如对象所在的函数已调用完毕),系统自动执行析构函数。析构函数往往用来做"清理善后" 的工作(例如在建立对象时用new开辟了一片内存空间,应在退出前在析构函数中用delete释放)。
下图中通过 Car 类 创建了三个对象:Mercedes, Bmw, 和 Audi。
$mercedes = new Car ();$bmw = new Car ();$audi = new Car ();PHP 定义类通常语法格式如下:
<?phpclass phpClass {var $var1;var $var2 = "constant string";function myfunc ($arg1, $arg2) {[..]}[..]}?>解析如下:
类使用 class 关键字后加上类名定义。
类名后的一对大括号({})内可以定义变量和方法。
类的变量使用 var 来声明, 变量也可以初始化值。
函数定义类似 PHP 函数的定义,但函数只能通过该类及其实例化的对象访问。
变量 $this 代表自身的对象。PHP_EOL 为换行符。PHP 中创建对象。类创建后,我们可以使用 new 运算符来实例化该类的对象:
$runoob = new Site;$taobao = new Site;$google = new Site; <?phpclass Site {/* 成员变量 */var $url;var $title;/* 成员函数 */function setUrl($par){$this->url = $par;}function getUrl(){echo $this->url . PHP_EOL;}function setTitle($par){$this->title = $par;}function getTitle(){echo $this->title . PHP_EOL;}}$runoob = new Site;$taobao = new Site;$google = new Site;// 调用成员函数,设置标题和URL$runoob->setTitle( "菜鸟教程" );$taobao->setTitle( "淘宝" );$google->setTitle( "Google 搜索" );$runoob->setUrl( 'www.runoob.com' );$taobao->setUrl( 'www.taobao.com' );$google->setUrl( 'www.google.com' );// 调用成员函数,获取标题和URL$runoob->getTitle();$taobao->getTitle();$google->getTitle();$runoob->getUrl();$taobao->getUrl();$google->getUrl();?>构造函数是一种特殊的方法,并且一个类中只能存在一个构造函数。主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,在创建对象的语句中与 new 运算符一起使用。PHP 5 允许开发者在一个类中定义一个方法作为构造函数,语法格式如下:void __construct ([ mixed $args [, $... ]] )
带参数的构造函数
<?phpclass Site {/* 成员变量 */var $url;var $title;function __construct( $par1, $par2 ) {$this->url = $par1;$this->title = $par2;}function getUrl(){echo $this->url . PHP_EOL;}function getTitle(){echo $this->title . PHP_EOL;}}$runoob = new Site('www.runoob.com', '菜鸟教程');$taobao = new Site('www.taobao.com', '淘宝');$google = new Site('www.google.com', 'Google 搜索');// 调用成员函数,获取标题和URL$runoob->getTitle();$taobao->getTitle();$google->getTitle();$runoob->getUrl();$taobao->getUrl();$google->getUrl();?>析构函数(destructor) 与构造函数相反,当对象结束其生命周期时(例如对象所在的函数已调用完毕),系统自动执行析构函数。
PHP 5 引入了析构函数的概念,其语法格式如下:void __destruct ( void )
<?phpclass MyDestructableClass {function __construct() {print "构造函数\n";$this->name = "MyDestructableClass";}function __destruct() {print "销毁 " . $this->name . "\n";}}$obj = new MyDestructableClass();?>PHP 使用关键字 extends 来继承一个类,PHP 不支持多继承,格式如下:
<?php class Site {/* 成员变量 */var $url;var $title;/* 成员函数 */function setUrl($par){$this->url = $par;}function getUrl(){echo $this->url . PHP_EOL;}function setTitle($par){$this->title = $par;}function getTitle(){echo $this->title . PHP_EOL;}}// 子类扩展站点类别class Child_Site extends Site {var $category;function setCate($par){$this->category = $par;}function getCate(){echo $this->category . PHP_EOL;}}示例:
<?phpclass students{var $name,$age,$sex;function __construct($name,$age,$sex){$this->name = $name;$this->age = $age;$this->sex = $sex;}}class master extends students{var $hobby,$address;function __construct($name, $age, $sex,$hobby,$address){parent::__construct($name, $age, $sex);$this->hobby = $hobby;$this->address = $address;}function print_info(){echo $this->name;echo $this->age;echo $this->sex;echo $this->hobby;echo $this->address;}}$mm = new master("king", 99, "男", "play" ,"地球");$mm->print_info();?>如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
实例中重写了 getUrl 与 getTitle 方法:
<?php class Site {/* 成员变量 */var $url;var $title;/* 成员函数 */function setUrl($par){$this->url = $par;}function getUrl(){echo $this->url . PHP_EOL;}function setTitle($par){$this->title = $par;}function getTitle(){echo $this->title . PHP_EOL;}}// 子类扩展站点类别class Child_Site extends Site {var $category;function setCate($par){$this->category = $par;}function getCate(){echo $this->category . PHP_EOL;}function getUrl() {echo $this->url . PHP_EOL;return $this->url;}function getTitle(){echo $this->title . PHP_EOL;return $this->title;}}PHP 对属性或方法的访问控制,是通过在前面添加关键字 public(公有),protected(受保护)或 private(私有)来实现的。
属性的访问控制:类属性必须定义为公有,受保护,私有之一。如果用 var 定义,则被视为公有。
<?php/*** Define MyClass*/class MyClass{public $public = 'Public';protected $protected = 'Protected';private $private = 'Private';function printHello(){echo $this->public;echo $this->protected;echo $this->private;}}$obj = new MyClass();echo $obj->public; // 这行能被正常执行echo $obj->protected; // 这行会产生一个致命错误echo $obj->private; // 这行也会产生一个致命错误$obj->printHello(); // 输出 Public、Protected 和 Private/*** Define MyClass2*/class MyClass2 extends MyClass{// 可以对 public 和 protected 进行重定义,但 private 而不能protected $protected = 'Protected2';function printHello(){echo $this->public;echo $this->protected;echo $this->private;}}$obj2 = new MyClass2();echo $obj2->public; // 这行能被正常执行echo $obj2->private; // 未定义 privateecho $obj2->protected; // 这行会产生一个致命错误$obj2->printHello(); // 输出 Public、Protected2 和 Undefined?>方法的访问控制:类中的方法可以被定义为公有,私有或受保护。如果没有设置这些关键字,则该方法默认为公有。
<?php/*** Define MyClass*/class MyClass{// 声明一个公有的构造函数public function __construct() { }// 声明一个公有的方法public function MyPublic() { }// 声明一个受保护的方法protected function MyProtected() { }// 声明一个私有的方法private function MyPrivate() { }// 此方法为公有function Foo(){$this->MyPublic();$this->MyProtected();$this->MyPrivate();}}$myclass = new MyClass;$myclass->MyPublic(); // 这行能被正常执行$myclass->MyProtected(); // 这行会产生一个致命错误$myclass->MyPrivate(); // 这行会产生一个致命错误$myclass->Foo(); // 公有,受保护,私有都可以执行/*** Define MyClass2*/class MyClass2 extends MyClass{// 此方法为公有function Foo2(){$this->MyPublic();$this->MyProtected();$this->MyPrivate(); // 这行会产生一个致命错误}}$myclass2 = new MyClass2;$myclass2->MyPublic(); // 这行能被正常执行$myclass2->Foo2(); // 公有的和受保护的都可执行,但私有的不行class Bar {public function test() {$this->testPrivate();$this->testPublic();}public function testPublic() {echo "Bar::testPublic\n";}private function testPrivate() {echo "Bar::testPrivate\n";}}class Foo extends Bar {public function testPublic() {echo "Foo::testPublic\n";}private function testPrivate() {echo "Foo::testPrivate\n";}}$myFoo = new foo();$myFoo->test(); // Bar::testPrivate // Foo::testPublic?>示例:
<?php// 声明一个'iTemplate'接口interface iTemplate{public function setVariable($name, $var);public function getHtml($template);}// 实现接口class Template implements iTemplate{private $vars = array();public function setVariable($name, $var){$this->vars[$name] = $var;}public function getHtml($template){foreach($this->vars as $name => $value) {$template = str_replace('{' . $name . '}', $value, $template);}return $template;}}可以把在类中始终保持不变的值定义为常量。在定义和使用常量的时候不需要使用 $ 符号。
常量的值必须是一个定值,不能是变量,类属性,数学运算的结果或函数调用。
自 PHP 5.3.0 起,可以用一个变量来动态调用类。但该变量的值不能为关键字(如 self,parent 或 static)。
<?phpclass MyClass{const constant = '常量值';function showConstant() {echo self::constant . PHP_EOL;}}echo MyClass::constant . PHP_EOL;$classname = "MyClass";echo $classname::constant . PHP_EOL; // 自 5.3.0 起$class = new MyClass();$class->showConstant();echo $class::constant . PHP_EOL; // 自 PHP 5.3.0 起?>任何一个类,如果它里面至少有一个方法是被声明为抽象的,那么这个类就必须被声明为抽象的。
定义为抽象的类不能被实例化。
被定义为抽象的方法只是声明了其调用方式(参数),不能定义其具体的功能实现。
继承一个抽象类的时候,子类必须定义父类中的所有抽象方法;另外,这些方法的访问控制必须和父类中一样(或者更为宽松)。例如某个抽象方法被声明为受保护的,那么子类中实现的方法就应该声明为受保护的或者公有的,而不能定义为私有的。
示例:
<?phpabstract class AbstractClass{// 强制要求子类定义这些方法abstract protected function getValue();abstract protected function prefixValue($prefix);// 普通方法(非抽象方法)public function printOut() {print $this->getValue() . PHP_EOL;}}class ConcreteClass1 extends AbstractClass{protected function getValue() {return "ConcreteClass1";}public function prefixValue($prefix) {return "{$prefix}ConcreteClass1";}}class ConcreteClass2 extends AbstractClass{public function getValue() {return "ConcreteClass2";}public function prefixValue($prefix) {return "{$prefix}ConcreteClass2";}}$class1 = new ConcreteClass1;$class1->printOut();echo $class1->prefixValue('FOO_') . PHP_EOL;$class2 = new ConcreteClass2;$class2->printOut();echo $class2->prefixValue('FOO_') . PHP_EOL;?>执行以上代码,输出结果为:
ConcreteClass1FOO_ConcreteClass1ConcreteClass2FOO_ConcreteClass2此外,子类方法可以包含父类抽象方法中不存在的可选参数。
例如,子类定义了一个可选参数,而父类抽象方法的声明里没有,则也是可以正常运行的。
<?phpabstract class AbstractClass{// 我们的抽象方法仅需要定义需要的参数abstract protected function prefixName($name);}class ConcreteClass extends AbstractClass{// 我们的子类可以定义父类签名中不存在的可选参数public function prefixName($name, $separator = ".") {if ($name == "Pacman") {$prefix = "Mr";} elseif ($name == "Pacwoman") {$prefix = "Mrs";} else {$prefix = "";}return "{$prefix}{$separator} {$name}";}}$class = new ConcreteClass;echo $class->prefixName("Pacman"), "\n";echo $class->prefixName("Pacwoman"), "\n";?>输出结果为:
Mr. PacmanMrs. Pacwoman声明类属性或方法为 static(静态),就可以不实例化类而直接访问。
静态属性不能通过一个类已实例化的对象来访问(但静态方法可以)。
由于静态方法不需要通过对象即可调用,所以伪变量 $this 在静态方法中不可用。
静态属性不可以由对象通过 -> 操作符来访问。
自 PHP 5.3.0 起,可以用一个变量来动态调用类。但该变量的值不能为关键字 self,parent 或 static。
<?phpclass Foo {public static $my_static = 'foo';public function staticValue() {return self::$my_static;}}print Foo::$my_static . PHP_EOL;$foo = new Foo();print $foo->staticValue() . PHP_EOL;?>执行以上程序,输出结果为:
foofooPHP 5 新增了一个 final 关键字。
以下代码执行会报错:
<?phpclass BaseClass {public function test() {echo "BaseClass::test() called" . PHP_EOL;}final public function moreTesting() {echo "BaseClass::moreTesting() called" . PHP_EOL;}}class ChildClass extends BaseClass {public function moreTesting() {echo "ChildClass::moreTesting() called" . PHP_EOL;}}// 报错信息 Fatal error: Cannot override final method BaseClass::moreTesting()?>PHP 不会在子类的构造方法中自动的调用父类的构造方法。要执行父类的构造方法,需要在子类的构造方法中调用 parent::__construct() 。
<?phpclass BaseClass {function __construct() {print "BaseClass 类中构造方法" . PHP_EOL;}}class SubClass extends BaseClass {function __construct() {parent::__construct(); // 子类构造方法不能自动调用父类的构造方法print "SubClass 类中构造方法" . PHP_EOL;}}class OtherSubClass extends BaseClass {// 继承 BaseClass 的构造方法}// 调用 BaseClass 构造方法$obj = new BaseClass();// 调用 BaseClass、SubClass 构造方法$obj = new SubClass();// 调用 BaseClass 构造方法$obj = new OtherSubClass();?>执行以上程序,输出结果为:
BaseClass 类中构造方法BaseClass 类中构造方法SubClass 类中构造方法BaseClass 类中构造方法PHP 中的 $_GET 和 $_POST 变量用于检索表单中的信息,比如用户输入。PHP 处理 HTML 表单时,能把来自 HTML 页面中的表单元素自动变成可供 PHP 脚本使用。
action 属性值为空表示提交到当前脚本
示例:form.html 文件代码:一个 HTML 表单,带有两个输入框和一个提交按钮。
<html><head><meta charset="utf-8"><title>菜鸟教程(runoob.com)</title></head><body><form action="welcome.php" method="post">名字: <input type="text" name="fname">年龄: <input type="text" name="age"><input type="submit" value="提交"></form></body></html>当用户填写完上面的表单并点击提交按钮时,表单的数据会被送往名为 "welcome.php" 的 PHP 文件:welcome.php 文件代码:
欢迎<?php echo $_POST["fname"]; ?>!<br>你的年龄是 <?php echo $_POST["age"]; ?> 岁。通过 select 的 name 属性获取下拉菜单的值:
<?php$q = isset($_GET['q'])? htmlspecialchars($_GET['q']) : '';if($q) {if($q =='RUNOOB') {echo '菜鸟教程<br>http://www.runoob.com';} else if($q =='GOOGLE') {echo 'Google 搜索<br>http://www.google.com';} else if($q =='TAOBAO') {echo '淘宝<br>http://www.taobao.com';}} else {?><form action="" method="get"> <select name="q"><option value="">选择一个站点:</option><option value="RUNOOB">Runoob</option><option value="GOOGLE">Google</option><option value="TAOBAO">Taobao</option></select><input type="submit" value="提交"></form><?php}?>如果下拉菜单是多选的( multiple="multiple"),我们可以通过将设置 select name="q[]" 以数组的方式获取,以下使用 POST 方式提交,代码如下所示:
<?php$q = isset($_POST['q'])? $_POST['q'] : '';if(is_array($q)) {$sites = array('RUNOOB' => '菜鸟教程: http://www.runoob.com','GOOGLE' => 'Google 搜索: http://www.google.com','TAOBAO' => '淘宝: http://www.taobao.com',);foreach($q as $val) {// PHP_EOL 为常量,用于换行echo $sites[$val] . PHP_EOL;}} else {?><form action="" method="post"> <select multiple="multiple" name="q[]"><option value="">选择一个站点:</option><option value="RUNOOB">Runoob</option><option value="GOOGLE">Google</option><option value="TAOBAO">Taobao</option></select><input type="submit" value="提交"></form><?php}?>PHP 单选按钮表单中 name 属性的值是一致的,value 值是不同的,代码如下所示:
<?php$q = isset($_GET['q'])? htmlspecialchars($_GET['q']) : '';if($q) {if($q =='RUNOOB') {echo '菜鸟教程<br>http://www.runoob.com';} else if($q =='GOOGLE') {echo 'Google 搜索<br>http://www.google.com';} else if($q =='TAOBAO') {echo '淘宝<br>http://www.taobao.com';}} else {?><form action="" method="get"> <input type="radio" name="q" value="RUNOOB" />Runoob<input type="radio" name="q" value="GOOGLE" />Google<input type="radio" name="q" value="TAOBAO" />Taobao<input type="submit" value="提交"></form><?php}?>PHP checkbox 复选框可以选择多个值:
<?php$q = isset($_POST['q'])? $_POST['q'] : '';if(is_array($q)) {$sites = array('RUNOOB' => '菜鸟教程: http://www.runoob.com','GOOGLE' => 'Google 搜索: http://www.google.com','TAOBAO' => '淘宝: http://www.taobao.com',);foreach($q as $val) {// PHP_EOL 为常量,用于换行echo $sites[$val] . PHP_EOL;}} else {?><form action="" method="post"> <input type="checkbox" name="q[]" value="RUNOOB"> Runoob<br> <input type="checkbox" name="q[]" value="GOOGLE"> Google<br> <input type="checkbox" name="q[]" value="TAOBAO"> Taobao<br><input type="submit" value="提交"></form><?php}?>$_SERVER["PHP_SELF"]是超级全局变量,返回当前正在执行脚本的文件名,与 document root相关。
$_SERVER["PHP_SELF"] 变量有可能会被黑客使用!当黑客使用跨网站脚本的HTTP链接来攻击时,$_SERVER["PHP_SELF"]服务器变量也会被植入脚本。原因就是跨网站脚本是附在执行文件的路径后面的,因此$_SERVER["PHP_SELF"]的字符串就会包含HTTP链接后面的JavaScript程序代码
http://www.runoob.com/test_form.php/%22%3E%3Cscript%3Ealert('hacked')%3C/script%3E
代码中添加了 script 标签,并添加了alert命令。 当页面载入时会执行该Javascript代码(用户会看到弹出框)。 这仅仅只是一个简单的实例来说明PHP_SELF变量会被黑客利用。
请注意, 任何JavaScript代码可以添加在<script>标签中! 黑客可以利用这点重定向页面到另外一台服务器的页面上,页面 代码文件中可以保护恶意代码,代码可以修改全局变量或者获取用户的表单数据。
$_SERVER["PHP_SELF"] 可以通过 htmlspecialchars() 函数来避免被利用。
form 代码如下所示:<form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>">
htmlspecialchars() 把一些预定义的字符转换为 HTML 实体。现在如果用户想利用 PHP_SELF 变量, 结果将输出如下所示:<form method="post" action="test_form.php/"><script>alert('hacked')</script>">
尝试该漏洞失败!
<html><head><meta charset="utf-8"><title>菜鸟教程(runoob.com)</title></head><body><form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>">名字: <input type="text" name="fname">年龄: <input type="text" name="age"><input type="submit" value="提交"></form><?php// echo phpinfo();echo "PHP 代码在服务器上执行,结果以纯 HTML 形式返回给浏览器";?></body></html>htmlspecialchars() 函数把一些预定义的字符转换为 HTML 实体。
预定义的字符是:
对用户所有提交的数据都通过 PHP 的 htmlspecialchars() 函数处理。
当我们使用 htmlspecialchars() 函数时,在用户尝试提交以下文本域:
<script>location.href('http://www.runoob.com')</script>
该代码将不会被执行,因为它会被保存为HTML转义代码,如下所示:
<script>location.href('http://www.runoob.com')</script>
当用户提交表单时,我们将做以下两件事情:
接下来让我们将这些过滤的函数写在一个我们自己定义的函数中,这样可以大大提高代码的复用性。
将函数命名为 test_input()。
现在,我们可以通过test_input()函数来检测 $_POST 中的所有变量, 脚本代码如下所示:
<!DOCTYPE HTML> <html><head><meta charset="utf-8"><title>菜鸟教程(runoob.com)</title></head><body> <?php// 定义变量并默认设置为空值$name = $email = $gender = $comment = $website = "";if ($_SERVER["REQUEST_METHOD"] == "POST"){$name = test_input($_POST["name"]);$email = test_input($_POST["email"]);$website = test_input($_POST["website"]);$comment = test_input($_POST["comment"]);$gender = test_input($_POST["gender"]);}function test_input($data){$data = trim($data);$data = stripslashes($data);$data = htmlspecialchars($data);return $data;}?><h2>PHP 表单验证实例</h2><form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>"> 名字: <input type="text" name="name"><br><br>E-mail: <input type="text" name="email"><br><br>网址: <input type="text" name="website"><br><br>备注: <textarea name="comment" rows="5" cols="40"></textarea><br><br>性别:<input type="radio" name="gender" value="female">女<input type="radio" name="gender" value="male">男<br><br><input type="submit" name="submit" value="Submit"> </form><?phpecho "<h2>您输入的内容是:</h2>";echo $name;echo "<br>";echo $email;echo "<br>";echo $website;echo "<br>";echo $comment;echo "<br>";echo $gender;?></body>在执行上面脚本时,会通过 $_SERVER["REQUEST_METHOD"] 来检测表单是否被提交 。如果 REQUEST_METHOD 是 POST, 表单将被提交 - 数据将被验证。如果表单未提交将跳过验证并显示空白。
在以上实例中使用输入项都是可选的,即使用户不输入任何数据也可以正常显示。
在接下来的章节中我们将介绍如何对用户输入的数据进行验证。
<!DOCTYPE HTML> <html><head><meta charset="utf-8"><title>菜鸟教程(runoob.com)</title><style>.error {color: #FF0000;}</style></head><body> <?php// 定义变量并默认设为空值$nameErr = $emailErr = $genderErr = $websiteErr = "";$name = $email = $gender = $comment = $website = "";if ($_SERVER["REQUEST_METHOD"] == "POST") {if (empty($_POST["name"])) {$nameErr = "名字是必须的。";} else {$name = test_input($_POST["name"]);}if (empty($_POST["email"])) {$emailErr = "邮箱是必须的。";} else {$email = test_input($_POST["email"]);}if (empty($_POST["website"])) {$website = "";} else {$website = test_input($_POST["website"]);}if (empty($_POST["comment"])) {$comment = "";} else {$comment = test_input($_POST["comment"]);}if (empty($_POST["gender"])) {$genderErr = "性别是必须的。";} else {$gender = test_input($_POST["gender"]);}}function test_input($data) {$data = trim($data);$data = stripslashes($data);$data = htmlspecialchars($data);return $data;}?><h2>PHP 表单验证实例</h2><p><span class="error">* 必填字段。</span></p><form method="post" action="<?php echo htmlspecialchars($_SERVER['PHP_SELF']);?>"> 名字: <input type="text" name="name"><span class="error">* <?php echo $nameErr;?></span><br><br>E-mail: <input type="text" name="email"><span class="error">* <?php echo $emailErr;?></span><br><br>网址: <input type="text" name="website"><span class="error"><?php echo $websiteErr;?></span><br><br>备注: <textarea name="comment" rows="5" cols="40"></textarea><br><br>性别:<input type="radio" name="gender" value="female">女<input type="radio" name="gender" value="male">男<span class="error">* <?php echo $genderErr;?></span><br><br><input type="submit" name="submit" value="Submit"> </form><?phpecho "<h2>您的输入:</h2>";echo $name;echo "<br>";echo $email;echo "<br>";echo $website;echo "<br>";echo $comment;echo "<br>";echo $gender;?></body></html>示例:
<!DOCTYPE HTML> <html><head><meta charset="utf-8"><title>菜鸟教程(runoob.com)</title><style>.error {color: #FF0000;}</style></head><body> <?php// 定义变量并默认设置为空值$nameErr = $emailErr = $genderErr = $websiteErr = "";$name = $email = $gender = $comment = $website = "";if ($_SERVER["REQUEST_METHOD"] == "POST") {if (empty($_POST["name"])) {$nameErr = "Name is required";} else {$name = test_input($_POST["name"]);// 检测名字是否只包含字母跟空格if (!preg_match("/^[a-zA-Z ]*$/",$name)) {$nameErr = "只允许字母和空格"; }}if (empty($_POST["email"])) {$emailErr = "Email is required";} else {$email = test_input($_POST["email"]);// 检测邮箱是否合法if (!preg_match("/([\w\-]+\@[\w\-]+\.[\w\-]+)/",$email)) {$emailErr = "非法邮箱格式"; }}if (empty($_POST["website"])) {$website = "";} else {$website = test_input($_POST["website"]);// 检测 URL 地址是否合法if (!preg_match("/\b(?:(?:https?|ftp):\/\/|www\.)[-a-z0-9+&@#\/%?=~_|!:,.;]*[-a-z0-9+&@#\/%=~_|]/i",$website)) {$websiteErr = "非法的 URL 的地址"; }}if (empty($_POST["comment"])) {$comment = "";} else {$comment = test_input($_POST["comment"]);}if (empty($_POST["gender"])) {$genderErr = "性别是必需的";} else {$gender = test_input($_POST["gender"]);}}function test_input($data) {$data = trim($data);$data = stripslashes($data);$data = htmlspecialchars($data);return $data;}?><h2>PHP 表单验证实例</h2><p><span class="error">* 必需字段。</span></p><form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>"> 名字: <input type="text" name="name"><span class="error">* <?php echo $nameErr;?></span><br><br>E-mail: <input type="text" name="email"><span class="error">* <?php echo $emailErr;?></span><br><br>网址: <input type="text" name="website"><span class="error"><?php echo $websiteErr;?></span><br><br>备注: <textarea name="comment" rows="5" cols="40"></textarea><br><br>性别:<input type="radio" name="gender" value="female">女<input type="radio" name="gender" value="male">男<span class="error">* <?php echo $genderErr;?></span><br><br><input type="submit" name="submit" value="Submit"> </form><?phpecho "<h2>您输入的内容是:</h2>";echo $name;echo "<br>";echo $email;echo "<br>";echo $website;echo "<br>";echo $comment;echo "<br>";echo $gender;?></body></html>预定义的 $_GET 变量用于收集来自 method="get" 的表单中的值。
在 HTML 表单中使用 method="get" 时,所有的变量名和值都会显示在 URL 中。
注释:所以在发送密码或其他敏感信息时,不应该使用这个方法!HTTP GET 的值不能超过 2000 个字符,所以不适合大型的变量值。
预定义的 $_POST 变量用于收集来自 method="post" 的表单中的值。
从带有 POST 方法的表单发送的信息,对任何人都是不可见的(不会显示在浏览器的地址栏),并且对发送信息的量也没有限制。
注释:默认情况下,POST 方法的发送信息的量最大值为 8 MB(可通过设置 php.ini 文件中的 post_max_size 进行更改)。
预定义的 $_REQUEST 变量包含了 $_GET、$_POST 和 $_COOKIE 的内容。
$_REQUEST 变量可用来收集通过 GET 和 POST 方法发送的表单数据。
<html><head><meta charset="utf-8"><title>菜鸟教程(runoob.com)</title></head><body><form action="welcome.php" method="post">名字: <input type="text" name="fname">年龄: <input type="text" name="age"><input type="submit" value="提交"></form></body></html>welcome.php
欢迎 <?php echo $_REQUEST["fname"]; ?>!<br>你的年龄是 <?php echo $_REQUEST["age"]; ?> 岁。示例:
<pre><?php// 二维数组:$cars = array(array("Volvo",100,96),array("BMW",60,59),array("Toyota",110,100));print_r($cars);?></pre><?php$sites = array("runoob"=>array("菜鸟教程","http://www.runoob.com"),"google"=>array("Google 搜索","http://www.google.com"),"taobao"=>array("淘宝","http://www.taobao.com"));print("<pre>"); // 格式化输出数组print_r($sites);print("</pre>");?>PHP date() 函数可把时间戳格式化为可读性更好的日期和时间。
语法:string date ( string $format [, int $timestamp ] )
| format | 必需。规定时间戳的格式。 |
| timestamp | 可选。规定时间戳。默认是当前的日期和时间。 |
完整的 PHP Date 参考手册:https://www.runoob.com/php/php-ref-date.html
在 PHP 中,在服务器执行 PHP 文件之前,可以在该文件中插入一个文件的内容。
include 和 require 语句用于在执行流中插入写在其他文件中的有用的代码。
include 和 require 除了处理错误的方式不同之外,在其他方面都是相同的:
因此,如果您希望继续执行,并向用户输出结果,即使包含文件已丢失,那么请使用 include。否则,在框架、CMS 或者复杂的 PHP 应用程序编程中,请始终使用 require 向执行流引用关键文件。这有助于提高应用程序的安全性和完整性,在某个关键文件意外丢失的情况下。
包含文件省去了大量的工作。这意味着您可以为所有网页创建标准页头、页脚或者菜单文件。然后,在页头需要更新时,您只需更新这个页头包含文件即可。
语法
include 'filename';或者require 'filename';示例:假设有一个标准的页头文件,名为 "header.php"。如需在页面中引用这个页头文件,请使用 include/require:
<html><head><meta charset="utf-8"><title>菜鸟教程(runoob.com)</title></head><body><?php include 'header.php'; ?><h1>欢迎来到我的主页!</h1><p>一些文本。</p></body></html>示例 :假设我们有一个在所有页面中使用的标准菜单文件。"menu.php":
echo '<a href="/">主页</a><a href="/html">HTML 教程</a><a href="/php">PHP 教程</a>';网站中的所有页面均应引用该菜单文件。以下是具体的做法:
<html><head><meta charset="utf-8"><title>菜鸟教程(runoob.com)</title></head><body><p class="leftmenu"><?php include 'menu.php'; ?></p><h1>欢迎来到我的主页!</h1><p>一些文本。</p></body></html>示例:假设我们有一个定义变量的包含文件("vars.php"):
<?php$color='red';$car='BMW';?>这些变量可用在调用文件中:
<html><head><meta charset="utf-8"><title>菜鸟教程(runoob.com)</title></head><body><h1>欢迎来到我的主页!</h1><?php include 'vars.php';echo "I have a $color $car"; // I have a red BMW?></body></html>PHP Filesystem 参考手册:https://www.runoob.com/php/php-ref-filesystem.html
fopen() 函数用于在 PHP 中打开文件。此函数的第一个参数含有要打开的文件的名称,第二个参数规定了使用哪种模式来打开文件:
<html><body><?php$file=fopen("welcome.txt","r");?></body></html>文件可能通过下列模式来打开:
| r | 只读。在文件的开头开始。 |
| r+ | 读/写。在文件的开头开始。 |
| w | 只写。打开并清空文件的内容;如果文件不存在,则创建新文件。 |
| w+ | 读/写。打开并清空文件的内容;如果文件不存在,则创建新文件。 |
| a | 追加。打开并向文件末尾进行写操作,如果文件不存在,则创建新文件。 |
| a+ | 读/追加。通过向文件末尾写内容,来保持文件内容。 |
| x | 只写。创建新文件。如果文件已存在,则返回 FALSE 和一个错误。 |
| x+ | 读/写。创建新文件。如果文件已存在,则返回 FALSE 和一个错误。 |
示例:
<html><body><?php$file=fopen("welcome.txt","r") or exit("Unable to open file!");?>//执行一些代码fclose($file);</body></html>feof() 函数检测是否已到达文件末尾(EOF)。在循环遍历未知长度的数据时,feof() 函数很有用。注释:在 w 、a 和 x 模式下,您无法读取打开的文件!
if (feof($file)) echo "文件结尾";fgets() 函数用于从文件中逐行读取文件。注释:在调用该函数之后,文件指针会移动到下一行。
示例:下面的实例逐行读取文件,直到文件末尾为止:
<?php$file = fopen("welcome.txt", "r") or exit("无法打开文件!");// 读取文件每一行,直到文件结尾while(!feof($file)){echo fgets($file). "<br>";}fclose($file);?>fgetc() 函数用于从文件中逐字符地读取文件。
注释:在调用该函数之后,文件指针会移动到下一个字符。
示例:下面的实例逐字符地读取文件,直到文件末尾为止:
<?php$file=fopen("welcome.txt","r") or exit("无法打开文件!");while (!feof($file)){echo fgetc($file);}fclose($file);?>本章节实例在 test 项目下完成,目录结构为:
test|-----upload # 文件上传的目录|-----form.html # 表单文件|-----upload_file.php # php 上传代码源码下载:https://www.runoob.com/wp-content/uploads/2013/08/runoob-file-uplaod-demo.zip
将以上代码保存到 form.html 文件中。
有关上面的 HTML 表单的一些注意项列举如下:
注释:允许用户上传文件是一个巨大的安全风险。请仅仅允许可信的用户执行文件上传操作。
"upload_file.php" 文件含有供上传文件的代码:
<?phpif ($_FILES["file"]["error"] > 0){echo "错误:" . $_FILES["file"]["error"] . "<br>";}else{echo "上传文件名: " . $_FILES["file"]["name"] . "<br>";echo "文件类型: " . $_FILES["file"]["type"] . "<br>";echo "文件大小: " . ($_FILES["file"]["size"] / 1024) . " kB<br>";echo "文件临时存储的位置: " . $_FILES["file"]["tmp_name"];}?>通过使用 PHP 的全局数组 $_FILES,你可以从客户计算机向远程服务器上传文件。
第一个参数是表单的 input name,第二个下标可以是 "name"、"type"、"size"、"tmp_name" 或 "error"。如下所示:
这是一种非常简单文件上传方式。基于安全方面的考虑,您应当增加有关允许哪些用户上传文件的限制。
在这个脚本中,我们增加了对文件上传的限制。用户只能上传 .gif、.jpeg、.jpg、.png 文件,文件大小必须小于 200 kB:
<?php// 允许上传的图片后缀$allowedExts = array("gif", "jpeg", "jpg", "png");$temp = explode(".", $_FILES["file"]["name"]);$extension = end($temp); // 获取文件后缀名if ((($_FILES["file"]["type"] == "image/gif")|| ($_FILES["file"]["type"] == "image/jpeg")|| ($_FILES["file"]["type"] == "image/jpg")|| ($_FILES["file"]["type"] == "image/pjpeg")|| ($_FILES["file"]["type"] == "image/x-png")|| ($_FILES["file"]["type"] == "image/png"))&& ($_FILES["file"]["size"] < 204800) // 小于 200 kb&& in_array($extension, $allowedExts)){if ($_FILES["file"]["error"] > 0){echo "错误:: " . $_FILES["file"]["error"] . "<br>";}else{echo "上传文件名: " . $_FILES["file"]["name"] . "<br>";echo "文件类型: " . $_FILES["file"]["type"] . "<br>";echo "文件大小: " . ($_FILES["file"]["size"] / 1024) . " kB<br>";echo "文件临时存储的位置: " . $_FILES["file"]["tmp_name"];}}else{echo "非法的文件格式";}?>上面的实例在服务器的 PHP 临时文件夹中创建了一个被上传文件的临时副本。
这个临时的副本文件会在脚本结束时消失。要保存被上传的文件,我们需要把它拷贝到另外的位置:
<?php// 允许上传的图片后缀$allowedExts = array("gif", "jpeg", "jpg", "png");$temp = explode(".", $_FILES["file"]["name"]);echo $_FILES["file"]["size"];$extension = end($temp); // 获取文件后缀名if ((($_FILES["file"]["type"] == "image/gif")|| ($_FILES["file"]["type"] == "image/jpeg")|| ($_FILES["file"]["type"] == "image/jpg")|| ($_FILES["file"]["type"] == "image/pjpeg")|| ($_FILES["file"]["type"] == "image/x-png")|| ($_FILES["file"]["type"] == "image/png"))&& ($_FILES["file"]["size"] < 204800) // 小于 200 kb&& in_array($extension, $allowedExts)){if ($_FILES["file"]["error"] > 0){echo "错误:: " . $_FILES["file"]["error"] . "<br>";}else{echo "上传文件名: " . $_FILES["file"]["name"] . "<br>";echo "文件类型: " . $_FILES["file"]["type"] . "<br>";echo "文件大小: " . ($_FILES["file"]["size"] / 1024) . " kB<br>";echo "文件临时存储的位置: " . $_FILES["file"]["tmp_name"] . "<br>";// 判断当前目录下的 upload 目录是否存在该文件// 如果没有 upload 目录,你需要创建它,upload 目录权限为 777if (file_exists("upload/" . $_FILES["file"]["name"])){echo $_FILES["file"]["name"] . " 文件已经存在。 ";}else{// 如果 upload 目录不存在该文件则将文件上传到 upload 目录下move_uploaded_file($_FILES["file"]["tmp_name"], "upload/" . $_FILES["file"]["name"]);echo "文件存储在: " . "upload/" . $_FILES["file"]["name"];}}}else{echo "非法的文件格式";}?>上面的脚本检测了文件是否已存在,如果不存在,则把文件拷贝到名为 "upload" 的目录下。
<form enctype="multipart/form-data" action="upload.php" method="post"> <input type="hidden" name="MAX_FILE_SIZE" value="1000"> <input name="myFile" type="file"> <input type="submit" value="上传文件"> </form>$_FILES 数组内容如下:
文件被上传结束后,默认地被存储在了临时目录中,这时您必须将它从临时目录中删除或移动到其它地方,如果没有,则会被删除。也就是不管是否上传成功,脚本执行完后临时目录里的文件肯定会被删除。所以在删除之前要用PHP的 copy() 函数将它复制到其它位置,此时,才算完成了上传文件过程。
cookie 常用于识别用户。cookie 是一种服务器留在用户计算机上的小文件。每当同一台计算机通过浏览器请求页面时,这台计算机将会发送 cookie。通过 PHP,您能够创建并取回 cookie 的值。
setcookie() 函数用于设置 cookie。
语法:setcookie(name, value, expire, path, domain);
<?php$expire=time()+60*60*24*30;setcookie("user", "runoob", $expire);?><html>.....注释:setcookie() 函数必须位于 <html> 标签之前。在发送 cookie 时,cookie 的值会自动进行 URL 编码,在取回时进行自动解码。(为防止 URL 编码,请使用 setrawcookie() 取而代之。)
$_COOKIE 变量用于取回 cookie 的值。
在下面的实例中,我们取回了名为 "user" 的 cookie 的值,并把它显示在了页面上:
<?php// 输出 cookie 值echo $_COOKIE["user"];// 查看所有 cookieprint_r($_COOKIE);?> <html><head><meta charset="utf-8"><title>菜鸟教程(runoob.com)</title></head><body><?phpif (isset($_COOKIE["user"]))echo "欢迎 " . $_COOKIE["user"] . "!<br>";elseecho "普通访客!<br>";?></body></html>当删除 cookie 时,您应当使过期日期变更为过去的时间点。
删除的实例:
<?php// 设置 cookie 过期时间为过去 1 小时setcookie("user", "", time()-3600);?>如果应用程序需要与不支持 cookie 的浏览器打交道,那么不得不使用其他的办法在应用程序中的页面之间传递信息。一种方式是通过表单传递数据(有关表单和用户输入的内容,在前面已经介绍过了)。
下面的表单在用户单点击 "Submit" 按钮时,向 "welcome.php" 提交了用户输入:
<html><head><meta charset="utf-8"><title>菜鸟教程(runoob.com)</title></head><body><form action="welcome.php" method="post">名字: <input type="text" name="name">年龄: <input type="text" name="age"><input type="submit"></form></body></html>取回 "welcome.php" 文件中的值,如下所示:
<html><head><meta charset="utf-8"><title>菜鸟教程(runoob.com)</title></head><body>欢迎 <?php echo $_POST["name"]; ?>.<br>你 <?php echo $_POST["age"]; ?> 岁了。</body></html>在计算机上操作某个应用程序时,您打开它,做些更改,然后关闭它。这很像一次对话(Session)。计算机知道您是谁。它清楚您在何时打开和关闭应用程序。然而,在因特网上问题出现了:由于 HTTP 地址无法保持状态,Web 服务器并不知道您是谁以及您做了什么。
session 解决了这个问题,它通过在服务器上存储用户信息以便随后使用(比如用户名称、购买商品等)。然而,会话信息是临时的,在用户离开网站后将被删除。如果您需要永久存储信息,可以把数据存储在数据库中。session 变量用于存储关于用户会话(session)的信息,或者更改用户会话(session)的设置。Session 变量存储单一用户的信息,并且对于应用程序中的所有页面都是可用的。
Session 的工作机制是:为每个访客创建一个唯一的 id (UID),并基于这个 UID 来存储变量。UID 存储在 cookie 中,或者通过 URL 进行传导。
在您把用户信息存储到 PHP session 中之前,首先必须启动会话。
注释:session_start() 函数必须位于 <html> 标签之前:
<?php session_start(); ?><html><body></body></html>上面的代码会向服务器注册用户的会话,以便您可以开始保存用户信息,同时会为用户会话分配一个 UID。
存储和取回 session 变量的正确方法是使用 PHP 的 $_SESSION 变量:
<?phpsession_start();// 存储 session 数据$_SESSION['views']=1;?><html><head><meta charset="utf-8"><title>菜鸟教程(runoob.com)</title></head><body><?php// 检索 session 数据echo "浏览量:". $_SESSION['views'];?></body></html>示例:
<?phpsession_start();if(isset($_SESSION['views'])){$_SESSION['views']=$_SESSION['views']+1;}else{$_SESSION['views']=1;}echo "浏览量:". $_SESSION['views'];?>如果希望删除某些 session 数据,可以使用 unset() 或 session_destroy() 函数。
unset() 函数用于释放指定的 session 变量:
<?phpsession_start();if(isset($_SESSION['views'])){unset($_SESSION['views']);}?>可以通过调用 session_destroy() 函数彻底销毁 session:
<?phpsession_destroy();?>注释:session_destroy() 将重置 session,您将失去所有已存储的 session 数据。
关于验证登陆用户是否有 admin 权限的例子。
如果用户成功登陆的话,储存一个登陆成功的凭证的 session,即admin=true:
示例:
<?php// 表单提交后...$posts = $_POST;// 清除一些空白符号foreach ($posts as $key => $value) {$posts[$key] = trim($value);}$password = md5($posts["password"]);$username = $posts["username"]; $query = "SELECT `username` FROM `user` WHERE `password` = '$password' AND `username` = '$username'";// 取得查询结果$userInfo = $DB->getRow($query); if (!empty($userInfo)) {// 当验证通过后,启动 Seindex.html> 验证 session里的`admin`是否为 `true`<?php// 防止全局变量造成安全隐患$admin = false;// 启动会话,这步必不可少session_start();// 判断是否登陆if (isset($_SESSION["admin"]) && $_SESSION["admin"] === true) {echo "您已经成功登陆";} else {// 验证失败,将 $_SESSION["admin"] 置为 false$_SESSION["admin"] = false;die("您无权访问");}?>mail() 函数用于从脚本中发送电子邮件。
语法:mail(to,subject,message,headers,parameters)
| to | 必需。规定 email 接收者。 |
| subject | 必需。规定 email 的主题。注释:该参数不能包含任何新行字符。 |
| message | 必需。定义要发送的消息。应使用 LF (\n) 来分隔各行。每行应该限制在 70 个字符内。 |
| headers | 可选。规定附加的标题,比如 From、Cc 和 Bcc。应当使用 CRLF (\r\n) 分隔附加的标题。 |
| parameters | 可选。对邮件发送程序规定额外的参数。 |
通过 PHP 发送电子邮件的最简单的方式是发送一封文本 email。
在下面的实例中,我们首先声明变量($to, $subject, $message, $from, $headers),然后我们在 mail() 函数中使用这些变量来发送了一封 E-mail:
<?php$to = "someone@example.com"; // 邮件接收者$subject = "参数邮件"; // 邮件标题$message = "Hello! 这是邮件的内容。"; // 邮件正文$from = "someonelse@example.com"; // 邮件发送者$headers = "From:" . $from; // 头部信息设置mail($to,$subject,$message,$headers);echo "邮件已发送";?>注释:这个简易发送 e-mail 不安全
通过 PHP,您能够在自己的站点制作一个反馈表单。下面的实例向指定的 e-mail 地址发送了一条文本消息:
<html><head><meta charset="utf-8"><title>菜鸟教程(runoob.com)</title></head><body><?phpif (isset($_REQUEST['email'])) { // 如果接收到邮箱参数则发送邮件// 发送邮件$email = $_REQUEST['email'] ;$subject = $_REQUEST['subject'] ;$message = $_REQUEST['message'] ;mail("someone@example.com", $subject,$message, "From:" . $email);echo "邮件发送成功";} else { // 如果没有邮箱参数则显示表单echo "<form method='post' action='mailform.php'>Email: <input name='email' type='text'><br>Subject: <input name='subject' type='text'><br>Message:<br><textarea name='message' rows='15' cols='40'></textarea><br><input type='submit'></form>";}?></body></html>上面代码存在的问题是:未经授权的用户可通过输入表单在邮件头部插入数据。
假如用户在表单中的输入框内加入如下文本到电子邮件中,会出现什么情况呢?
someone@example.com%0ACc:person2@example.com%0ABcc:person3@example.com,person3@example.com,anotherperson4@example.com,person5@example.com%0ABTo:person6@example.com与往常一样,mail() 函数把上面的文本放入邮件头部,那么现在头部有了额外的 Cc:、Bcc: 和 To: 字段。当用户点击提交按钮时,这封 e-mail 会被发送到上面所有的地址!
防止 e-mail 注入的最好方法是对输入进行验证。
示例:增加了检测表单中 email 字段的输入验证程序:
<html><head><meta charset="utf-8"><title>菜鸟教程(runoob.com)</title></head><body><?phpfunction spamcheck($field){// filter_var() 过滤 e-mail// 使用 FILTER_SANITIZE_EMAIL$field=filter_var($field, FILTER_SANITIZE_EMAIL);//filter_var() 过滤 e-mail// 使用 FILTER_VALIDATE_EMAILif(filter_var($field, FILTER_VALIDATE_EMAIL)){return TRUE;}else{return FALSE;}}if (isset($_REQUEST['email'])){// 如果接收到邮箱参数则发送邮件// 判断邮箱是否合法$mailcheck = spamcheck($_REQUEST['email']);if ($mailcheck==FALSE){echo "非法输入";}else{ // 发送邮件$email = $_REQUEST['email'] ;$subject = $_REQUEST['subject'] ;$message = $_REQUEST['message'] ;mail("someone@example.com", "Subject: $subject",$message, "From: $email" );echo "Thank you for using our mail form";}}else{ // 如果没有邮箱参数则显示表单echo "<form method='post' action='mailform.php'>Email: <input name='email' type='text'><br>Subject: <input name='subject' type='text'><br>Message:<br><textarea name='message' rows='15' cols='40'></textarea><br><input type='submit'></form>";}?></body></html>在上面的代码中,我们使用了 PHP 过滤器来对输入进行验证:
不同的错误处理方法:
创建一个自定义的错误处理器非常简单。创建一个专用函数,在 发生错误时调用该函数。该函数必须有能力处理至少两个参数 (error level 和 error message),但是可以接受最多五个参数(可选的:file, line-number 和 error context):
语法
error_function(error_level,error_message,error_file,error_line,error_context)| error_level | 必需。为用户定义的错误规定错误报告级别。必须是一个数字。参见下面的表格:错误报告级别。 |
| error_message | 必需。为用户定义的错误规定错误消息。 |
| error_file | 可选。规定错误发生的文件名。 |
| error_line | 可选。规定错误发生的行号。 |
| error_context | 可选。规定一个数组,包含了当错误发生时在用的每个变量以及它们的值。 |
错误报告级别。这些错误报告级别是用户自定义的错误处理程序处理的不同类型的错误:
| 2 | E_WARNING | 非致命的 run-time 错误。不暂停脚本执行。 |
| 8 | E_NOTICE | run-time 通知。在脚本发现可能有错误时发生,但也可能在脚本正常运行时发生。 |
| 256 | E_USER_ERROR | 致命的用户生成的错误。这类似于程序员使用 PHP 函数 trigger_error() 设置的 E_ERROR。 |
| 512 | E_USER_WARNING | 非致命的用户生成的警告。这类似于程序员使用 PHP 函数 trigger_error() 设置的 E_WARNING。 |
| 1024 | E_USER_NOTICE | 用户生成的通知。这类似于程序员使用 PHP 函数 trigger_error() 设置的 E_NOTICE。 |
| 4096 | E_RECOVERABLE_ERROR | 可捕获的致命错误。类似 E_ERROR,但可被用户定义的处理程序捕获。(参见 set_error_handler()) |
| 8191 | E_ALL | 所有错误和警告。(在 PHP 5.4 中,E_STRICT 成为 E_ALL 的一部分) |
示例:
<?php// 错误处理函数function customError($errno, $errstr){echo "<b>Error:</b> [$errno] $errstr";}// 设置错误处理函数set_error_handler("customError");// 触发错误echo($test);?>PHP 5 提供了一种新的面向对象的错误处理方法。
异常处理用于在指定的错误(异常)情况发生时改变脚本的正常流程。这种情况称为异常。
当异常被触发时,通常会发生:
我们将展示不同的错误处理方法:
注释:异常应该仅仅在错误情况下使用,而不应该用于在一个指定的点跳转到代码的另一个位置。
当异常被抛出时,其后的代码不会继续执行,PHP 会尝试查找匹配的 "catch" 代码块。
如果异常没有被捕获,而且又没用使用 set_exception_handler() 作相应的处理的话,那么将发生一个严重的错误(致命错误),并且输出 "Uncaught Exception" (未捕获异常)的错误消息。
让我们尝试抛出一个异常,同时不去捕获它:
<?php// 创建一个有异常处理的函数function checkNum($number){if($number>1){throw new Exception("Value must be 1 or below");}return true;}// 触发异常checkNum(2);?>要避免上面实例中出现的错误,我们需要创建适当的代码来处理异常。
适当的处理异常代码应该包括:
让我们触发一个异常:
<?php// 创建一个有异常处理的函数function checkNum($number){if($number>1){throw new Exception("变量值必须小于等于 1");}return true;}// 在 try 块 触发异常try{checkNum(2);// 如果抛出异常,以下文本不会输出echo '如果输出该内容,说明 $number 变量';}// 捕获异常catch(Exception $e){echo 'Message: ' .$e->getMessage();}?>上面的代码抛出了一个异常,并捕获了它:
然而,为了遵循 "每个 throw 必须对应一个 catch" 的原则,可以设置一个顶层的异常处理器来处理漏掉的错误。
创建自定义的异常处理程序非常简单。我们简单地创建了一个专门的类,当 PHP 中发生异常时,可调用其函数。该类必须是 exception 类的一个扩展。
这个自定义的 customException 类继承了 PHP 的 exception 类的所有属性,您可向其添加自定义的函数。
我们开始创建 customException 类:
<?phpclass customException extends Exception{public function errorMessage(){// 错误信息$errorMsg = '错误行号 '.$this->getLine().' in '.$this->getFile().': <b>'.$this->getMessage().'</b> 不是一个合法的 E-Mail 地址';return $errorMsg;}}$email = "someone@example...com";try{// 检测邮箱if(filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE){// 如果是个不合法的邮箱地址,抛出异常throw new customException($email);}}catch (customException $e){//display custom messageecho $e->errorMessage();}?>这个新的类是旧的 exception 类的副本,外加 errorMessage() 函数。正因为它是旧类的副本,因此它从旧类继承了属性和方法,我们可以使用 exception 类的方法,比如 getLine()、getFile() 和 getMessage()。
代码抛出了一个异常,并通过一个自定义的 exception 类来捕获它:
可以为一段脚本使用多个异常,来检测多种情况。
可以使用多个 if..else 代码块,或一个 switch 代码块,或者嵌套多个异常。这些异常能够使用不同的 exception 类,并返回不同的错误消息:
<?phpclass customException extends Exception{public function errorMessage(){// 错误信息$errorMsg = '错误行号 '.$this->getLine().' in '.$this->getFile().': <b>'.$this->getMessage().'</b> 不是一个合法的 E-Mail 地址';return $errorMsg;}}$email = "someone@example.com";try{// 检测邮箱if(filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE){// 如果是个不合法的邮箱地址,抛出异常throw new customException($email);}// 检测 "example" 是否在邮箱地址中if(strpos($email, "example") !== FALSE){throw new Exception("$email 是 example 邮箱");}}catch (customException $e){echo $e->errorMessage();}catch(Exception $e){echo $e->getMessage();}?>代码测试了两种条件,如果其中任何一个条件不成立,则抛出一个异常:
如果 customException 类抛出了异常,但没有捕获 customException,仅仅捕获了 base exception,则在那里处理异常。
有时,当异常被抛出时,您也许希望以不同于标准的方式对它进行处理。可以在一个 "catch" 代码块中再次抛出异常。
脚本应该对用户隐藏系统错误。对程序员来说,系统错误也许很重要,但是用户对它们并不感兴趣。为了让用户更容易使用,您可以再次抛出带有对用户比较友好的消息的异常:
<?phpclass customException extends Exception{public function errorMessage(){// 错误信息$errorMsg = $this->getMessage().' 不是一个合法的 E-Mail 地址。';return $errorMsg;}}$email = "someone@example.com";try{try{// 检测 "example" 是否在邮箱地址中if(strpos($email, "example") !== FALSE){// 如果是个不合法的邮箱地址,抛出异常throw new Exception($email);}}catch(Exception $e){// 重新抛出异常throw new customException($email);}}catch (customException $e){// 显示自定义信息echo $e->errorMessage();}?>代码检测在邮件地址中是否含有字符串 "example"。如果有,则再次抛出异常:
如果在当前的 "try" 代码块中异常没有被捕获,则它将在更高层级上查找 catch 代码块。
set_exception_handler() 函数可设置处理所有未捕获异常的用户定义函数。
<?phpfunction myException($exception){echo "<b>Exception:</b> " , $exception->getMessage();}set_exception_handler('myException');throw new Exception('Uncaught Exception occurred');?>在上面的代码中,不存在 "catch" 代码块,而是触发顶层的异常处理程序。应该使用此函数来捕获所有未被捕获的异常。
简而言之:如果抛出了异常,就必须捕获它。
PHP Filter 参考手册:https://www.runoob.com/php/php-ref-filter.html
过滤器用于验证和过滤来自非安全来源的数据,比如用户的输入。测试、验证和过滤用户输入或自定义数据是任何 Web 应用程序的重要组成部分。过滤器扩展的设计目的是使数据过滤更轻松快捷。
几乎所有的 Web 应用程序都依赖外部的输入。这些数据通常来自用户或其他应用程序(比如 web 服务)。通过使用过滤器,您能够确保应用程序获得正确的输入类型。
应该始终对外部数据进行过滤!输入过滤是最重要的应用程序安全课题之一。
什么是外部数据?
如需过滤变量,请使用下面的过滤器函数之一:
实例中,我们用 filter_var() 函数验证了一个整数:
<?php$int = 123;if(!filter_var($int, FILTER_VALIDATE_INT)){echo("不是一个合法的整数");}else{echo("是个合法的整数");}?>上面的代码使用了 "FILTER_VALIDATE_INT" 过滤器来过滤变量。
如果我们尝试使用一个非整数的变量(比如 "123abc"),则将输出:"Integer is not valid"。
有两种过滤器:
Validating 过滤器:
Sanitizing 过滤器:
选项和标志用于向指定的过滤器添加额外的过滤选项。
不同的过滤器有不同的选项和标志。
在下面的实例中,我们用 filter_var() 和 "min_range" 以及 "max_range" 选项验证了一个整数:
<?php$var=300;$int_options = array("options"=>array("min_range"=>0,"max_range"=>256));if(!filter_var($var, FILTER_VALIDATE_INT, $int_options)){echo("不是一个合法的整数");}else{echo("是个合法的整数");}?>就像上面的代码一样,选项必须放入一个名为 "options" 的相关数组中。如果使用标志,则不需在数组内。由于整数是 "300",它不在指定的范围内,
让我们试着验证来自表单的输入。
我们需要做的第一件事情是确认是否存在我们正在查找的输入数据。
然后我们用 filter_input() 函数过滤输入的数据。
在下面的实例中,输入变量 "email" 被传到 PHP 页面:
<?phpif(!filter_has_var(INPUT_GET, "email")){echo("没有 email 参数");}else{if (!filter_input(INPUT_GET, "email", FILTER_VALIDATE_EMAIL)){echo "不是一个合法的 E-Mail";}else{echo "是一个合法的 E-Mail";}}?>实例有一个通过 "GET" 方法传送的输入变量 (email):
让我们试着清理一下从表单传来的 URL。
首先,我们要确认是否存在我们正在查找的输入数据。
然后,我们用 filter_input() 函数来净化输入数据。
在下面的实例中,输入变量 "url" 被传到 PHP 页面:
<?phpif(!filter_has_var(INPUT_GET, "url")){echo("没有 url 参数");}else{$url = filter_input(INPUT_GET, "url", FILTER_SANITIZE_URL);echo $url;}?>实例有一个通过 "GET" 方法传送的输入变量 (url):
假如输入变量是一个类似这样的字符串:"http://www.ruåånoøøob.com/",则净化后的 $url 变量如下
表单通常由多个输入字段组成。为了避免对 filter_var 或 filter_input 函数重复调用,我们可以使用 filter_var_array 或 the filter_input_array 函数。
在本例中,我们使用 filter_input_array() 函数来过滤三个 GET 变量。接收到的 GET 变量是一个名字、一个年龄以及一个 e-mail 地址:
<?php$filters = array("name" => array("filter"=>FILTER_SANITIZE_STRING),"age" => array("filter"=>FILTER_VALIDATE_INT,"options"=>array("min_range"=>1,"max_range"=>120)),"email"=> FILTER_VALIDATE_EMAIL);$result = filter_input_array(INPUT_GET, $filters);if (!$result["age"]){echo("年龄必须在 1 到 120 之间。<br>");}elseif(!$result["email"]){echo("E-Mail 不合法<br>");}else{echo("输入正确");}?>实例有三个通过 "GET" 方法传送的输入变量 (name、age 和 email):
filter_input_array() 函数的第二个参数可以是数组或单一过滤器的 ID。
如果该参数是单一过滤器的 ID,那么这个指定的过滤器会过滤输入数组中所有的值。
如果该参数是一个数组,那么此数组必须遵循下面的规则:
通过使用 FILTER_CALLBACK 过滤器,可以调用自定义的函数,把它作为一个过滤器来使用。这样,我们就拥有了数据过滤的完全控制权。
您可以创建自己的自定义函数,也可以使用已存在的 PHP 函数。
将您准备用到的过滤器的函数,按指定选项的规定方法进行规定。在关联数组中,带有名称 "options"。
在下面的实例中,我们使用了一个自定义的函数把所有 "_" 转换为 ".":
<?phpfunction convertSpace($string){return str_replace("_", ".", $string);}$string = "www_runoob_com!";echo filter_var($string, FILTER_CALLBACK,array("options"=>"convertSpace"));?>实例把所有 "_" 转换成 "." :
实例使用了 filter_var() 函数来检测一个 INT 型的变量是否在 1 到 200 内:
<?php$int = 122;$min = 1;$max = 200;if (filter_var($int, FILTER_VALIDATE_INT, array("options" => array("min_range"=>$min, "max_range"=>$max))) === false) {echo("变量值不在合法范围内");} else {echo("变量值在合法范围内");}?>实例使用了 filter_var() 函数来检测一个 $ip 变量是否是 IPv6 地址:
<?php$ip = "2001:0db8:85a3:08d3:1319:8a2e:0370:7334";if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) {echo("$ip 是一个 IPv6 地址");} else {echo("$ip 不是一个 IPv6 地址");}?>使用了 filter_var() 函数来检测 $url 是否包含查询字符串:
<?php// 检测 $url 是否包含查询字符串$url = "http://www.runoob.com";if (!filter_var($url, FILTER_VALIDATE_URL, FILTER_FLAG_QUERY_REQUIRED) === false) {echo("$url 是一个合法的 URL");} else {echo("$url 不是一个合法的 URL");}?>实例使用了 filter_var() 函数来移除字符串中 ASCII 值大于 127 的字符,同样它也能移除 HTML 标签:
<?php$str = "<h1>Hello WorldÆØÅ!</h1>";$newstr = filter_var($str, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_HIGH);echo $newstr;?>在 php5.2.0 及以上版本已经内置 JSON 扩展。
| json_encode | 对变量进行 JSON 编码 |
| json_decode | 对 JSON 格式的字符串进行解码,转换为 PHP 变量 |
| json_last_error | 返回最后发生的错误 |
语法:string json_encode ( $value [, $options = 0 ] )
options:由以下常量组成的二进制掩码 JSON_HEX_QUOT, JSON_HEX_TAG, JSON_HEX_AMP, JSON_HEX_APOS, JSON_NUMERIC_CHECK, JSON_PRETTY_PRINT, JSON_UNESCAPED_SLASHES, JSON_FORCE_OBJECT, JSON_PRESERVE_ZERO_FRACTION, JSON_UNESCAPED_UNICODE, JSON_PARTIAL_OUTPUT_ON_ERROR。
要注意的是 JSON_UNESCAPED_UNICODE 选项,如果我们不希望中文被编码,可以添加该选项。语法:mixed json_decode ($json_string [,$assoc = false [, $depth = 512 [, $options = 0 ]]])
json_string: 待解码的 JSON 字符串,必须是 UTF-8 编码数据
assoc: 当该参数为 TRUE 时,将返回数组,FALSE 时返回对象。
depth: 整数类型的参数,它指定递归深度
options: 二进制掩码,目前只支持 JSON_BIGINT_AS_STRING 。
示例:
<?php$arr = array('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5);echo json_encode($arr);?><?phpclass Emp {public $name = "";public $hobbies = "";public $birthdate = "";}$e = new Emp();$e->name = "sachin";$e->hobbies = "sports";$e->birthdate = date('m/d/Y h:i:s a', "8/5/1974 12:20:03 p");$e->birthdate = date('m/d/Y h:i:s a', strtotime("8/5/1974 12:20:03"));echo json_encode($e);?><?php$arr = array('runoob' => '菜鸟教程', 'taobao' => '淘宝网');echo json_encode($arr); // 编码中文echo PHP_EOL; // 换行符echo json_encode($arr, JSON_UNESCAPED_UNICODE); // 不编码中文?>示例:
<?php$json = '{"a":1,"b":2,"c":3,"d":4,"e":5}';var_dump(json_decode($json));var_dump(json_decode($json, true));?>AJAX 基于因特网标准,并使用以下技术组合:
演示当用户在输入框中键入字符时,网页如何与 Web 服务器进行通信:
<html><head><script>function showHint(str){if (str.length==0){ document.getElementById("txtHint").innerHTML="";return;}if (window.XMLHttpRequest){// IE7+, Firefox, Chrome, Opera, Safari 浏览器执行的代码xmlhttp=new XMLHttpRequest();}else{ //IE6, IE5 浏览器执行的代码xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");}xmlhttp.onreadystatechange=function(){if (xmlhttp.readyState==4 && xmlhttp.status==200){document.getElementById("txtHint").innerHTML=xmlhttp.responseText;}}xmlhttp.open("GET","gethint.php?q="+str,true);xmlhttp.send();}</script></head><body><p><b>在输入框中输入一个姓名:</b></p><form> 姓名: <input type="text" onkeyup="showHint(this.value)"></form><p>返回值: <span id="txtHint"></span></p></body></html>如果输入框是空的(str.length==0),该函数会清空 txtHint 占位符的内容,并退出该函数。
如果输入框不是空的,那么 showHint() 会执行以下步骤:
上面这段通过 JavaScript 调用的服务器页面是名为 "gethint.php" 的 PHP 文件。
"gethint.php" 中的源代码会检查姓名数组,然后向浏览器返回对应的姓名:
<?php// 将姓名填充到数组中$a[]="Anna";$a[]="Brittany";$a[]="Cinderella";$a[]="Diana";$a[]="Eva";$a[]="Fiona";$a[]="Gunda";$a[]="Hege";$a[]="Inga";$a[]="Johanna";$a[]="Kitty";$a[]="Linda";$a[]="Nina";$a[]="Ophelia";$a[]="Petunia";$a[]="Amanda";$a[]="Raquel";$a[]="Cindy";$a[]="Doris";$a[]="Eve";$a[]="Evita";$a[]="Sunniva";$a[]="Tove";$a[]="Unni";$a[]="Violet";$a[]="Liza";$a[]="Elizabeth";$a[]="Ellen";$a[]="Wenche";$a[]="Vicky";//从请求URL地址中获取 q 参数$q=$_GET["q"];//查找是否由匹配值, 如果 q>0if (strlen($q) > 0){$hint="";for($i=0; $i<count($a); $i++){if (strtolower($q)==strtolower(substr($a[$i],0,strlen($q)))){if ($hint==""){$hint=$a[$i];}else{$hint=$hint." , ".$a[$i];}}}}// 如果没有匹配值设置输出为 "no suggestion" if ($hint == ""){$response="no suggestion";}else{$response=$hint;}//输出返回值echo $response;?>解释:如果 JavaScript 发送了任何文本(即 strlen($q) > 0),则会发生:
AJAX 可用来与数据库进行交互式通信。
实例中,我们使用的数据库表如下所示:
mysql> select * from websites;+----+--------------+---------------------------+-------+---------+| id | name | url | alexa | country |+----+--------------+---------------------------+-------+---------+| 1 | Google | https://www.google.cm/ | 1 | USA || 2 | 淘宝 | https://www.taobao.com/ | 13 | CN || 3 | 菜鸟教程 | http://www.runoob.com/ | 4689 | CN || 4 | 微博 | http://weibo.com/ | 20 | CN || 5 | Facebook | https://www.facebook.com/ | 3 | USA |+----+--------------+---------------------------+-------+---------+5 rows in set (0.01 sec)用户在上面的下拉列表中选择某位用户时,会执行名为 "showSite()" 的函数。该函数由 "onchange" 事件触发:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>菜鸟教程(runoob.com)</title> <script>function showSite(str){if (str==""){document.getElementById("txtHint").innerHTML="";return;} if (window.XMLHttpRequest){// IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码xmlhttp=new XMLHttpRequest();}else{// IE6, IE5 浏览器执行代码xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");}xmlhttp.onreadystatechange=function(){if (xmlhttp.readyState==4 && xmlhttp.status==200){document.getElementById("txtHint").innerHTML=xmlhttp.responseText;}}xmlhttp.open("GET","getsite_mysql.php?q="+str,true);xmlhttp.send();}</script></head><body><form><select name="users" onchange="showSite(this.value)"><option value="">选择一个网站:</option><option value="1">Google</option><option value="2">淘宝</option><option value="3">菜鸟教程</option><option value="4">微博</option><option value="5">Facebook</option></select></form><br><p id="txtHint"><b>网站信息显示在这里……</b></p></body></html>showSite() 函数会执行以下步骤:
上面这段通过 JavaScript 调用的服务器页面是名为 "getsite_mysql.php" 的 PHP 文件。
"getsite_mysql.php" 中的源代码会运行一次针对 MySQL 数据库的查询,然后在 HTML 表格中返回结果:
<?php$q = isset($_GET["q"]) ? intval($_GET["q"]) : '';if(empty($q)) {echo '请选择一个网站';exit;}$con = mysqli_connect('localhost','root','123456');if (!$con){die('Could not connect: ' . mysqli_error($con));}// 选择数据库mysqli_select_db($con,"test");// 设置编码,防止中文乱码mysqli_set_charset($con, "utf8");$sql="SELECT * FROM Websites WHERE id = '".$q."'";$result = mysqli_query($con,$sql);echo "<table border='1'><tr><th>ID</th><th>网站名</th><th>网站 URL</th><th>Alexa 排名</th><th>国家</th></tr>";while($row = mysqli_fetch_array($result)){echo "<tr>";echo "<td>" . $row['id'] . "</td>";echo "<td>" . $row['name'] . "</td>";echo "<td>" . $row['url'] . "</td>";echo "<td>" . $row['alexa'] . "</td>";echo "<td>" . $row['country'] . "</td>";echo "</tr>";}echo "</table>";mysqli_close($con);?>解释:当查询从 JavaScript 发送到 PHP 文件时,将发生:
AJAX 可用来与 XML 文件进行交互式通信。
演示网页如何通过 AJAX 从 XML 文件读取信息:
当用户在上面的下拉列表中选择某张 CD 时,会执行名为 "showCD()" 的函数。该函数由 "onchange" 事件触发:
<html><head><script>function showCD(str){if (str==""){document.getElementById("txtHint").innerHTML="";return;} if (window.XMLHttpRequest){// IE7+, Firefox, Chrome, Opera, Safari 浏览器执行xmlhttp=new XMLHttpRequest();}else{// IE6, IE5 浏览器执行xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");}xmlhttp.onreadystatechange=function(){if (xmlhttp.readyState==4 && xmlhttp.status==200){document.getElementById("txtHint").innerHTML=xmlhttp.responseText;}}xmlhttp.open("GET","getcd.php?q="+str,true);xmlhttp.send();}</script></head><body><form>Select a CD:<select name="cds" onchange="showCD(this.value)"><option value="">Select a CD:</option><option value="Bob Dylan">Bob Dylan</option><option value="Bonnie Tyler">Bonnie Tyler</option><option value="Dolly Parton">Dolly Parton</option></select></form><p id="txtHint"><b>CD info will be listed here...</b></p></body></html>showCD() 函数会执行以下步骤:
上面这段通过 JavaScript 调用的服务器页面是名为 "getcd.php" 的 PHP 文件。
PHP 脚本加载 XML 文档,"cd_catalog.xml",运行针对 XML 文件的查询,并以 HTML 返回结果:
<?php$q=$_GET["q"];$xmlDoc = new DOMDocument();$xmlDoc->load("cd_catalog.xml");$x=$xmlDoc->getElementsByTagName('ARTIST');for ($i=0; $i<=$x->length-1; $i++){// 处理元素节点if ($x->item($i)->nodeType==1){if ($x->item($i)->childNodes->item(0)->nodeValue == $q){$y=($x->item($i)->parentNode);}}}$cd=($y->childNodes);for ($i=0;$i<$cd->length;$i++){ // 处理元素节点if ($cd->item($i)->nodeType==1){echo("<b>" . $cd->item($i)->nodeName . ":</b> ");echo($cd->item($i)->childNodes->item(0)->nodeValue);echo("<br>");}}?>当 CD 查询从 JavaScript 发送到 PHP 页面时,将发生:
演示一个实时的搜索,在您键入数据的同时即可得到搜索结果。
实时的搜索与传统的搜索相比,具有很多优势:
当用户在上面的输入框中键入字符时,会执行 "showResult()" 函数。该函数由 "onkeyup" 事件触发:
<html><head><script>function showResult(str){if (str.length==0){ document.getElementById("livesearch").innerHTML="";document.getElementById("livesearch").style.border="0px";return;}if (window.XMLHttpRequest){// IE7+, Firefox, Chrome, Opera, Safari 浏览器执行xmlhttp=new XMLHttpRequest();}else{// IE6, IE5 浏览器执行xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");}xmlhttp.onreadystatechange=function(){if (xmlhttp.readyState==4 && xmlhttp.status==200){document.getElementById("livesearch").innerHTML=xmlhttp.responseText;document.getElementById("livesearch").style.border="1px solid #A5ACB2";}}xmlhttp.open("GET","livesearch.php?q="+str,true);xmlhttp.send();}</script></head><body><form><input type="text" size="30" onkeyup="showResult(this.value)"><p id="livesearch"></p></form></body></html>如果输入框是空的(str.length==0),该函数会清空 livesearch 占位符的内容,并退出该函数。
如果输入框不是空的,那么 showResult() 会执行以下步骤:
上面这段通过 JavaScript 调用的服务器页面是名为 "livesearch.php" 的 PHP 文件。
"livesearch.php" 中的源代码会搜索 XML 文件中匹配搜索字符串的标题,并返回结果:
<?php$xmlDoc=new DOMDocument();$xmlDoc->load("links.xml");$x=$xmlDoc->getElementsByTagName('link');// 从 URL 中获取参数 q 的值$q=$_GET["q"];// 如果 q 参数存在则从 xml 文件中查找数据if (strlen($q)>0){$hint="";for($i=0; $i<($x->length); $i++){$y=$x->item($i)->getElementsByTagName('title');$z=$x->item($i)->getElementsByTagName('url');if ($y->item(0)->nodeType==1){// 找到匹配搜索的链接if (stristr($y->item(0)->childNodes->item(0)->nodeValue,$q)){if ($hint==""){$hint="<a href='" . $z->item(0)->childNodes->item(0)->nodeValue . "' target='_blank'>" . $y->item(0)->childNodes->item(0)->nodeValue . "</a>";}else{$hint=$hint . "<br /><a href='" . $z->item(0)->childNodes->item(0)->nodeValue . "' target='_blank'>" . $y->item(0)->childNodes->item(0)->nodeValue . "</a>";}}}}}// 如果没找到则返回 "no suggestion"if ($hint==""){$response="no suggestion";}else{$response=$hint;}// 输出结果echo $response;?>如果 JavaScript 发送了任何文本(即 strlen($q) > 0),则会发生:
演示一个 RSS 阅读器,通过它,来自 RSS 的内容在网页不进行刷新的情况下被载入:
当用户在上面的下拉列表中选择某个 RSS-feed 时,会执行名为 "showRSS()" 的函数。该函数由 "onchange" 事件触发:
<html><head><meta charset="utf-8"><title>菜鸟教程(runoob.com)</title><script>function showRSS(str){if (str.length==0){ document.getElementById("rssOutput").innerHTML="";return;}if (window.XMLHttpRequest){// IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码xmlhttp=new XMLHttpRequest();}else{// IE6, IE5 浏览器执行代码xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");}xmlhttp.onreadystatechange=function(){if (xmlhttp.readyState==4 && xmlhttp.status==200){document.getElementById("rssOutput").innerHTML=xmlhttp.responseText;}}xmlhttp.open("GET","getrss.php?q="+str,true);xmlhttp.send();}</script></head><body><form><select onchange="showRSS(this.value)"><option value="">选择一个 RSS-feed:</option><option value="rss">读取 RSS 数据</option></select></form><br><p id="rssOutput">RSS-feed 数据列表...</p></body></html>showRSS() 函数会执行以下步骤:
文件 rss_demo.xml。
上面这段通过 JavaScript 调用的服务器页面是名为 "getrss.php" 的 PHP 文件:
<?php// rss 文件$xml="rss_demo.xml";$xmlDoc = new DOMDocument();$xmlDoc->load($xml);// 从 "<channel>" 中读取元素$channel=$xmlDoc->getElementsByTagName('channel')->item(0);$channel_title = $channel->getElementsByTagName('title')->item(0)->childNodes->item(0)->nodeValue;$channel_link = $channel->getElementsByTagName('link')->item(0)->childNodes->item(0)->nodeValue;$channel_desc = $channel->getElementsByTagName('description')->item(0)->childNodes->item(0)->nodeValue;// 输出 "<channel>" 中的元素echo("<p><a href='" . $channel_link. "'>" . $channel_title . "</a>");echo("<br>");echo($channel_desc . "</p>");// 输出 "<item>" 中的元素$x=$xmlDoc->getElementsByTagName('item');for ($i=0; $i<=1; $i++) {$item_title=$x->item($i)->getElementsByTagName('title')->item(0)->childNodes->item(0)->nodeValue;$item_link=$x->item($i)->getElementsByTagName('link')->item(0)->childNodes->item(0)->nodeValue;$item_desc=$x->item($i)->getElementsByTagName('description')->item(0)->childNodes->item(0)->nodeValue;echo ("<p><a href='" . $item_link. "'>" . $item_title . "</a>");echo ("<br>");echo ($item_desc . "</p>");}?>当 RSS feed 的请求从 JavaScript 发送到 PHP 文件时,将发生:
演示一个投票程序,通过它,投票结果在网页不进行刷新的情况下被显示。
当用户选择上面的某个选项时,会执行名为 "getVote()" 的函数。该函数由 "onclick" 事件触发。
poll.html 文件代码如下:
<html><head><meta charset="utf-8"><title>菜鸟教程(runoob.com)</title><script>function getVote(int) {if (window.XMLHttpRequest) {// IE7+, Firefox, Chrome, Opera, Safari 执行代码xmlhttp=new XMLHttpRequest();} else {// IE6, IE5 执行代码xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");}xmlhttp.onreadystatechange=function() {if (xmlhttp.readyState==4 && xmlhttp.status==200){document.getElementById("poll").innerHTML=xmlhttp.responseText;}}xmlhttp.open("GET","poll_vote.php?vote="+int,true);xmlhttp.send();}</script></head><body><p id="poll"><h3>你喜欢 PHP 和 AJAX 吗?</h3><form>是:<input type="radio" name="vote" value="0" onclick="getVote(this.value)"><br>否:<input type="radio" name="vote" value="1" onclick="getVote(this.value)"></form></p></body></html>getVote() 函数会执行以下步骤:
上面这段通过 JavaScript 调用的服务器页面是名为 "poll_vote.php" 的 PHP 文件:
<?php$vote = htmlspecialchars($_REQUEST['vote']);// 获取文件中存储的数据$filename = "poll_result.txt";$content = file($filename);// 将数据分割到数组中$array = explode("||", $content[0]);$yes = $array[0];$no = $array[1];if ($vote == 0){$yes = $yes + 1;}if ($vote == 1){$no = $no + 1;}// 插入投票数据$insertvote = $yes."||".$no;$fp = fopen($filename,"w");fputs($fp,$insertvote);fclose($fp);?><h2>结果:</h2><table><tr><td>是:</td><td><span style="display: inline-block; background-color:green;width:<?php echo(100*round($yes/($no+$yes),2)); ?>px;height:20px;" ></span><?php echo(100*round($yes/($no+$yes),2)); ?>%</td></tr><tr><td>否:</td><td><span style="display: inline-block; background-color:red;width:<?php echo(100*round($no/($no+$yes),2)); ?>px;height:20px;"></span><?php echo(100*round($no/($no+$yes),2)); ?>%</td></tr></table>当所选的值从 JavaScript 发送到 PHP 文件时,将发生:
这很不安全!攻击者能用简短的代码攻破!
//无限循环脚本var Vote = 0;//你的票。setInterval(function(){getVote(Vote);},2000); if(empty($_COOKIE["voted"])) {setcookie("voted","yes!",ime()+60*60*24*365);} else {die("您已经投过票!");} <?php//根据浏览器抓包得知,投票地址是如下:$api_url = "https://www.runoob.com/try/demo_source/poll_vote.php?vote=0";for($i=0; $i<1000; $i++){//循环 1000 次用 file_get_contents 函数访问 投票地址 进行刷票file_get_contents($api_url);}