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/
学习框架图
学习面向过程的编程方式,解决一些常规业务的逻辑,实现表单传值、文件编程、会话技术、图像处理等事项。让自己完全具备建设初级动态的能力。
学会利用OOP思想和MVC设计,实现手写PHP项目框架能力。拥有实现动态网站主流功能的能力,如无限极分类、页面数据检索、内容采集等。能掌握实现页面静态化和邮件处理等较高级的技术。具备建设主流中小型网站的能力。
能够使用 ThinkPHP 框架进行项目的快速开发。可以实现后台的 RBAC 权限管理功能,掌握代码管理、前后台交互、多表连接、数据分析、轮询技术、网站优化技术。通过该阶段学习后,将拥有中大型网站及办公室OA系统的开发能力。
1、掌握PHP开源产品的使用,并能进行快速、深度的二次开发。学完后能掌握各种企业门户网站、政府机关、教育机构、媒体机构、个人站长等网站的快速开发。
2、掌握混合式开发方法开发手机APP,该APP可兼容安卓手机和IOS手机,学完后可实现PC端网站(或企业OA平台)内容在手机端同步观看和更新!
PHP 在线工具:https://www.runoob.com/try/runcode.php?filename=demo_intro&type=php
PHP 配置 Xdebug 调试工具:https://www.cnblogs.com/wcwnina/p/14471379.html
Xdebug 是一个开放源代码的PHP程序调试器,可以帮助开发人员追踪、调试和分析PHP程序的运行状况。
Xdebug 和当前使用的PHP环境版本有密切的关系,在下载时需要选择与之对应的版本
: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 有四种不同的变量作用域:
在函数内声明的变量,是局部变量
在函数外部定义的变量,拥有全局作用域。除了函数外,全局变量可以被脚本中的任何部分访问,要在一个函数中访问一个全局变量,需要使用 global 关键字。在 PHP 函数内部声明的变量是局部变量,仅能在函数内部访问:
测试函数内变量:";
echo "变量 x 为: $x";
echo "
";
echo "变量 y 为: $y";
}
myTest();
echo "
测试函数外变量:
";
echo "变量 x 为: $x";
echo "
";
echo "变量 y 为: $y";
?>
global 关键字用于函数内访问全局变量。在函数内调用函数外定义的全局变量,我们需要在函数中的变量前加上 global 关键字:
PHP 将所有全局变量存储在一个名为 $GLOBALS[index] 的数组中。 index 保存变量的名称。这个数组可以在函数内部访问,也可以直接用来更新全局变量。
当一个函数完成时,它的所有变量通常都会被删除。然而,有时候您希望某个局部变量不要被删除。要做到这一点,需要在声明变量时使用 static 关键字:
PHP 支持以下几种数据类型:
数组示例:创建一个数组, 然后使用 PHP var_dump() 函数返回数组的数据类型和值:
PHP 5 Array 函数:https://www.runoob.com/php/php-ref-array.html
在 PHP 中,array() 函数用于创建数组,count() 函数用于返回数组的长度。
有三种类型的数组:
自动分配 ID 键(ID 键总是从 0 开始):$cars=array("Volvo","BMW","Toyota");
人工分配 ID 键:
$cars[0]="Volvo";
$cars[1]="BMW";
$cars[2]="Toyota";
使用 for 循环,遍历并打印数值数组中的所有值
";
}
?>
"35","Ben"=>"37","Joe"=>"43");
echo "Peter is " . $age['Peter'] . " years old.";
?>
"35","Ben"=>"37","Joe"=>"43");
foreach($age as $x=>$x_value)
{
echo "Key=" . $x . ", Value=" . $x_value;
echo "
";
}
?>
对象数据类型 也可以用于存储数据。在 PHP 中,对象必须声明。
color = $color;
}
function what_color() {
return $this->color;
}
}
?>
PHP 资源 resource 是一种特殊变量,保存了到外部资源的一个引用。常见资源数据类型有 打开文件、数据库连接、图形画布区域等。由于资源类型变量保存有为打开文件、数据库连接、图形画布区域等的特殊句柄,因此将其它类型的值转换为资源没有意义。
使用 get_resource_type() 函数可以返回资源(resource)类型:
虽然 PHP 是弱类型语言,但也需要明白变量类型及它们的意义,因为我们经常需要对 PHP 变量进行比较,包含松散和严格比较。
结果:
1、值相等
3、类型不相等
PHP中 比较 0、false、null
超级全局变量在PHP 4.1.0之后被启用,是PHP系统中自带的变量,在一个脚本的全部作用域中都可用。PHP中预定义了几个超级全局变量(superglobals) ,这意味着它们在一个脚本的全部作用域中都可用。 你不需要特别说明,就可以在函数及类中使用。
PHP 超级全局变量列表:
示例:
";
echo $_SERVER['SERVER_NAME'];
echo "
";
echo $_SERVER['HTTP_HOST'];
echo "
";
echo $_SERVER['HTTP_REFERER'];
echo "
";
echo $_SERVER['HTTP_USER_AGENT'];
echo "
";
echo $_SERVER['SCRIPT_NAME'];
?>
示例:
示例:
示例:
测试 $_GET
PHP 表单和用户输入:https://www.runoob.com/php/php-forms.html
常量在定义后,默认是全局变量,可以在整个运行的脚本的任何地方使用。
设置常量,使用 define() 函数,函数语法如下:
bool define ( string $name , mixed $value [, bool $case_insensitive = false ] )
函数有三个参数:
';
echo greeting; // 输出 "greeting",但是有警告信息,表示该常量未定义
?>
";
echo '该文件位于 ' . __FILE__ . "
";
echo '该文件位于 ' . __DIR__ . "
";
echo '命名空间为: '. __NAMESPACE__ . "
";
function test_func() {
echo '函数名为:' . __FUNCTION__ . "
";
echo '函数名为:' . __METHOD__ . "
";
}
test_func();
class TestClass {
function _print() {
echo '类名为:' . __CLASS__ . "
";
echo '函数名为:' . __FUNCTION__ . "
";
}
}
$t = new TestClass();
$t->_print();
class Base {
public function sayHello() {
echo 'Hello ' . "
";
}
}
trait SayWorld {
public function sayHello() {
parent::sayHello();
echo 'World!'. "
";
}
}
class MyHelloWorld extends Base {
use SayWorld;
}
$o = new MyHelloWorld();
$o->sayHello();
?>
在 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)转换为 。 |
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 取反 | -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 中,提供了下列循环语句:
";
$i++;
}
?>
";
}
while ($i<=5);
?>
数组的 键 值 循环
"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 语句加上大括号括起来,例如:
在声明命名空间之前唯一合法的代码是用于定义源文件编码方式的 declare 语句。所有非 PHP 代码包括空白符都不能出现在命名空间的声明之前。
以下代码会出现语法错误:
” 会致命错误 - 命名空间必须是程序脚本的第一条语句
namespace MyProject;
?>
与目录和文件的关系很像,PHP 命名空间也允许指定层次化的命名空间的名称。因此,命名空间的名字可以使用分层次的方式定义:
上面的例子创建了常量 MyProject\Sub\Level\CONNECT_OK,类 MyProject\Sub\Level\Connection 和函数 MyProject\Sub\Level\Connect。
如果没有定义任何命名空间,所有的类与函数的定义都是在全局空间,与 PHP 引入命名空间概念前一样。在名称前加上前缀 \ 表示该名称是全局空间中的名称,即使该名称位于其它的命名空间中时也是如此。
使用全局空间说明
自从有了命名空间之后,最容易出错的该是使用类的时候,这个类的寻找路径是什么样的了。
可以把
这样可能会更容易理解。
在面向对象的程序设计(英语:Object-oriented programming,缩写:OOP)中,对象是一个由信息及对信息进行处理的描述所组成的整体,是对现实世界的抽象。
比如 Animal(动物) 是一个抽象类,我们可以具体到一只狗跟一只羊,而狗跟羊就是具体的对象,他们有颜色属性,可以写,可以跑等行为状态。
面向对象内容
类 − 定义了一件事物的抽象特点。类的定义包含了数据的形式以及对数据的操作。
对象 − 是类的实例。
成员变量 − 定义在类内部的变量。该变量的值对外是不可见的,但是可以通过成员函数访问,在类被实例化为对象后,该变量即可成为对象的属性。
成员函数 − 定义在类的内部,可用于访问对象的数据。
继承 − 继承性是子类自动共享父类数据结构和方法的机制,这是类之间的一种关系。在定义和实现一个类的时候,可以在一个已经存在的类的基础之上来进行,把这个已经存在的类所定义的内容作为自己的内容,并加入若干新的内容。
父类 − 一个类被其他类继承,可将该类称为父类,或基类,或超类。
子类 − 一个类继承其他类称为子类,也可称为派生类。
多态 − 多态性是指相同的函数或方法可作用于多种类型的对象上并获得不同的结果。不同的对象,收到同一消息可以产生不同的结果,这种现象称为多态性。
重载 − 简单说,就是函数或者方法有同样的名称,但是参数列表不相同的情形,这样的同名不同参数的函数或者方法之间,互相称之为重载函数或者方法。
抽象性 − 抽象性是指将具有一致的数据结构(属性)和行为(操作)的对象抽象成类。一个类就是这样一种抽象,它反映了与应用有关的重要性质,而忽略其他一些无关内容。任何类的划分都是主观的,但必须与具体的应用有关。
封装 − 封装是指将现实世界中存在的某个客体的属性与行为绑定在一起,并放置在一个逻辑单元内。
构造函数 − 主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中。
析构函数 − 析构函数(destructor) 与构造函数相反,当对象结束其生命周期时(例如对象所在的函数已调用完毕),系统自动执行析构函数。析构函数往往用来做"清理善后" 的工作(例如在建立对象时用new开辟了一片内存空间,应在退出前在析构函数中用delete释放)。
下图中通过 Car 类 创建了三个对象:Mercedes, Bmw, 和 Audi。
$mercedes = new Car ();
$bmw = new Car ();
$audi = new Car ();
PHP 定义类通常语法格式如下:
解析如下:
类使用 class 关键字后加上类名定义。
类名后的一对大括号({})内可以定义变量和方法。
类的变量使用 var 来声明, 变量也可以初始化值。
函数定义类似 PHP 函数的定义,但函数只能通过该类及其实例化的对象访问。
url = $par;
}
function getUrl(){
echo $this->url . PHP_EOL;
}
function setTitle($par){
$this->title = $par;
}
function getTitle(){
echo $this->title . PHP_EOL;
}
}
?>
变量 $this 代表自身的对象。PHP_EOL 为换行符。PHP 中创建对象。类创建后,我们可以使用 new 运算符来实例化该类的对象:
$runoob = new Site;
$taobao = new Site;
$google = new Site;
以上代码我们创建了三个对象,三个对象各自都是独立的。在实例化对象后,我们可以使用该对象调用成员方法,该对象的成员方法只能操作该对象的成员变量:
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 [, $... ]] )
带参数的构造函数
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 )
name = "MyDestructableClass";
}
function __destruct() {
print "销毁 " . $this->name . "\n";
}
}
$obj = new MyDestructableClass();
?>
PHP 使用关键字 extends 来继承一个类,PHP 不支持多继承,格式如下:
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;
}
}
示例:
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 方法:
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 定义,则被视为公有。
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; // 未定义 private
echo $obj2->protected; // 这行会产生一个致命错误
$obj2->printHello(); // 输出 Public、Protected2 和 Undefined
?>
方法的访问控制:类中的方法可以被定义为公有,私有或受保护。如果没有设置这些关键字,则该方法默认为公有。
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
?>
示例:
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)。
showConstant();
echo $class::constant . PHP_EOL; // 自 PHP 5.3.0 起
?>
任何一个类,如果它里面至少有一个方法是被声明为抽象的,那么这个类就必须被声明为抽象的。
定义为抽象的类不能被实例化。
被定义为抽象的方法只是声明了其调用方式(参数),不能定义其具体的功能实现。
继承一个抽象类的时候,子类必须定义父类中的所有抽象方法;另外,这些方法的访问控制必须和父类中一样(或者更为宽松)。例如某个抽象方法被声明为受保护的,那么子类中实现的方法就应该声明为受保护的或者公有的,而不能定义为私有的。
示例:
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;
?>
执行以上代码,输出结果为:
ConcreteClass1 FOO_ConcreteClass1 ConcreteClass2 FOO_ConcreteClass2
此外,子类方法可以包含父类抽象方法中不存在的可选参数。
例如,子类定义了一个可选参数,而父类抽象方法的声明里没有,则也是可以正常运行的。
prefixName("Pacman"), "\n";
echo $class->prefixName("Pacwoman"), "\n";
?>
输出结果为:
Mr. Pacman Mrs. Pacwoman
声明类属性或方法为 static(静态),就可以不实例化类而直接访问。
静态属性不能通过一个类已实例化的对象来访问(但静态方法可以)。
由于静态方法不需要通过对象即可调用,所以伪变量 $this 在静态方法中不可用。
静态属性不可以由对象通过 -> 操作符来访问。
自 PHP 5.3.0 起,可以用一个变量来动态调用类。但该变量的值不能为关键字 self,parent 或 static。
staticValue() . PHP_EOL;
?>
执行以上程序,输出结果为:
foo foo
PHP 5 新增了一个 final 关键字。
以下代码执行会报错:
PHP 不会在子类的构造方法中自动的调用父类的构造方法。要执行父类的构造方法,需要在子类的构造方法中调用 parent::__construct() 。
执行以上程序,输出结果为:
BaseClass 类中构造方法 BaseClass 类中构造方法 SubClass 类中构造方法 BaseClass 类中构造方法
PHP 中的 $_GET 和 $_POST 变量用于检索表单中的信息,比如用户输入。PHP 处理 HTML 表单时,能把来自 HTML 页面中的表单元素自动变成可供 PHP 脚本使用。
action 属性值为空表示提交到当前脚本
示例:form.html 文件代码:一个 HTML 表单,带有两个输入框和一个提交按钮。
菜鸟教程(runoob.com)
当用户填写完上面的表单并点击提交按钮时,表单的数据会被送往名为 "welcome.php" 的 PHP 文件:welcome.php 文件代码:
欢迎!
你的年龄是 岁。
通过 select 的 name 属性获取下拉菜单的值:
http://www.runoob.com';
} else if($q =='GOOGLE') {
echo 'Google 搜索
http://www.google.com';
} else if($q =='TAOBAO') {
echo '淘宝
http://www.taobao.com';
}
} else {
?>
如果下拉菜单是多选的( multiple="multiple"),我们可以通过将设置 select name="q[]" 以数组的方式获取,以下使用 POST 方式提交,代码如下所示:
'菜鸟教程: 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 {
?>
PHP 单选按钮表单中 name 属性的值是一致的,value 值是不同的,代码如下所示:
http://www.runoob.com';
} else if($q =='GOOGLE') {
echo 'Google 搜索
http://www.google.com';
} else if($q =='TAOBAO') {
echo '淘宝
http://www.taobao.com';
}
} else {
?>
PHP checkbox 复选框可以选择多个值:
'菜鸟教程: 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 {
?>
$_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
以上的 URL 中,将被解析为如下代码并执行:
"; } ?>上面代码存在的问题是:未经授权的用户可通过输入表单在邮件头部插入数据。
假如用户在表单中的输入框内加入如下文本到电子邮件中,会出现什么情况呢?
[email protected]%0ACc:[email protected]
%0ABcc:[email protected],[email protected],
[email protected],[email protected]
%0ABTo:[email protected]
与往常一样,mail() 函数把上面的文本放入邮件头部,那么现在头部有了额外的 Cc:、Bcc: 和 To: 字段。当用户点击提交按钮时,这封 e-mail 会被发送到上面所有的地址!
防止 e-mail 注入的最好方法是对输入进行验证。
示例:增加了检测表单中 email 字段的输入验证程序:
菜鸟教程(runoob.com)
Email:
Subject:
Message:
";
}
?>
在上面的代码中,我们使用了 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 的一部分) |
示例:
Error: [$errno] $errstr";
}
// 设置错误处理函数
set_error_handler("customError");
// 触发错误
echo($test);
?>
PHP 5 提供了一种新的面向对象的错误处理方法。
异常处理用于在指定的错误(异常)情况发生时改变脚本的正常流程。这种情况称为异常。
当异常被触发时,通常会发生:
我们将展示不同的错误处理方法:
注释:异常应该仅仅在错误情况下使用,而不应该用于在一个指定的点跳转到代码的另一个位置。
当异常被抛出时,其后的代码不会继续执行,PHP 会尝试查找匹配的 "catch" 代码块。
如果异常没有被捕获,而且又没用使用 set_exception_handler() 作相应的处理的话,那么将发生一个严重的错误(致命错误),并且输出 "Uncaught Exception" (未捕获异常)的错误消息。
让我们尝试抛出一个异常,同时不去捕获它:
1)
{
throw new Exception("Value must be 1 or below");
}
return true;
}
// 触发异常
checkNum(2);
?>
要避免上面实例中出现的错误,我们需要创建适当的代码来处理异常。
适当的处理异常代码应该包括:
让我们触发一个异常:
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 类:
getLine().' in '.$this->getFile()
.': '.$this->getMessage().' 不是一个合法的 E-Mail 地址';
return $errorMsg;
}
}
$email = "[email protected]";
try
{
// 检测邮箱
if(filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE)
{
// 如果是个不合法的邮箱地址,抛出异常
throw new customException($email);
}
}
catch (customException $e)
{
//display custom message
echo $e->errorMessage();
}
?>
这个新的类是旧的 exception 类的副本,外加 errorMessage() 函数。正因为它是旧类的副本,因此它从旧类继承了属性和方法,我们可以使用 exception 类的方法,比如 getLine()、getFile() 和 getMessage()。
代码抛出了一个异常,并通过一个自定义的 exception 类来捕获它:
可以为一段脚本使用多个异常,来检测多种情况。
可以使用多个 if..else 代码块,或一个 switch 代码块,或者嵌套多个异常。这些异常能够使用不同的 exception 类,并返回不同的错误消息:
getLine().' in '.$this->getFile()
.': '.$this->getMessage().' 不是一个合法的 E-Mail 地址';
return $errorMsg;
}
}
$email = "[email protected]";
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" 代码块中再次抛出异常。
脚本应该对用户隐藏系统错误。对程序员来说,系统错误也许很重要,但是用户对它们并不感兴趣。为了让用户更容易使用,您可以再次抛出带有对用户比较友好的消息的异常:
getMessage().' 不是一个合法的 E-Mail 地址。';
return $errorMsg;
}
}
$email = "[email protected]";
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() 函数可设置处理所有未捕获异常的用户定义函数。
Exception: " , $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() 函数验证了一个整数:
上面的代码使用了 "FILTER_VALIDATE_INT" 过滤器来过滤变量。
如果我们尝试使用一个非整数的变量(比如 "123abc"),则将输出:"Integer is not valid"。
有两种过滤器:
Validating 过滤器:
Sanitizing 过滤器:
选项和标志用于向指定的过滤器添加额外的过滤选项。
不同的过滤器有不同的选项和标志。
在下面的实例中,我们用 filter_var() 和 "min_range" 以及 "max_range" 选项验证了一个整数:
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 页面:
实例有一个通过 "GET" 方法传送的输入变量 (email):
让我们试着清理一下从表单传来的 URL。
首先,我们要确认是否存在我们正在查找的输入数据。
然后,我们用 filter_input() 函数来净化输入数据。
在下面的实例中,输入变量 "url" 被传到 PHP 页面:
实例有一个通过 "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 地址:
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 之间。
");
}
elseif(!$result["email"])
{
echo("E-Mail 不合法
");
}
else
{
echo("输入正确");
}
?>
实例有三个通过 "GET" 方法传送的输入变量 (name、age 和 email):
filter_input_array() 函数的第二个参数可以是数组或单一过滤器的 ID。
如果该参数是单一过滤器的 ID,那么这个指定的过滤器会过滤输入数组中所有的值。
如果该参数是一个数组,那么此数组必须遵循下面的规则:
通过使用 FILTER_CALLBACK 过滤器,可以调用自定义的函数,把它作为一个过滤器来使用。这样,我们就拥有了数据过滤的完全控制权。
您可以创建自己的自定义函数,也可以使用已存在的 PHP 函数。
将您准备用到的过滤器的函数,按指定选项的规定方法进行规定。在关联数组中,带有名称 "options"。
在下面的实例中,我们使用了一个自定义的函数把所有 "_" 转换为 ".":
"convertSpace"));
?>
实例把所有 "_" 转换成 "." :
实例使用了 filter_var() 函数来检测一个 INT 型的变量是否在 1 到 200 内:
array("min_range"=>$min, "max_range"=>$max))) === false) {
echo("变量值不在合法范围内");
} else {
echo("变量值在合法范围内");
}
?>
实例使用了 filter_var() 函数来检测一个 $ip 变量是否是 IPv6 地址:
使用了 filter_var() 函数来检测 $url 是否包含查询字符串:
实例使用了 filter_var() 函数来移除字符串中 ASCII 值大于 127 的字符,同样它也能移除 HTML 标签:
Hello WorldÆØÅ!";
$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 。
示例:
1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5);
echo json_encode($arr);
?>
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);
?>
'菜鸟教程', 'taobao' => '淘宝网');
echo json_encode($arr); // 编码中文
echo PHP_EOL; // 换行符
echo json_encode($arr, JSON_UNESCAPED_UNICODE); // 不编码中文
?>
示例:
AJAX 基于因特网标准,并使用以下技术组合:
演示当用户在输入框中键入字符时,网页如何与 Web 服务器进行通信:
在输入框中输入一个姓名:
姓名:
返回值:
如果输入框是空的(str.length==0),该函数会清空 txtHint 占位符的内容,并退出该函数。
如果输入框不是空的,那么 showHint() 会执行以下步骤:
上面这段通过 JavaScript 调用的服务器页面是名为 "gethint.php" 的 PHP 文件。
"gethint.php" 中的源代码会检查姓名数组,然后向浏览器返回对应的姓名:
0
if (strlen($q) > 0)
{
$hint="";
for($i=0; $i
解释:如果 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" 事件触发:
菜鸟教程(runoob.com)
网站信息显示在这里……
showSite() 函数会执行以下步骤:
上面这段通过 JavaScript 调用的服务器页面是名为 "getsite_mysql.php" 的 PHP 文件。
"getsite_mysql.php" 中的源代码会运行一次针对 MySQL 数据库的查询,然后在 HTML 表格中返回结果:
ID
网站名
网站 URL
Alexa 排名
国家
";
while($row = mysqli_fetch_array($result))
{
echo "";
echo "" . $row['id'] . " ";
echo "" . $row['name'] . " ";
echo "" . $row['url'] . " ";
echo "" . $row['alexa'] . " ";
echo "" . $row['country'] . " ";
echo " ";
}
echo "";
mysqli_close($con);
?>
解释:当查询从 JavaScript 发送到 PHP 文件时,将发生:
AJAX 可用来与 XML 文件进行交互式通信。
演示网页如何通过 AJAX 从 XML 文件读取信息:
当用户在上面的下拉列表中选择某张 CD 时,会执行名为 "showCD()" 的函数。该函数由 "onchange" 事件触发:
Select a CD:
CD info will be listed here...
showCD() 函数会执行以下步骤:
上面这段通过 JavaScript 调用的服务器页面是名为 "getcd.php" 的 PHP 文件。
PHP 脚本加载 XML 文档,"cd_catalog.xml",运行针对 XML 文件的查询,并以 HTML 返回结果:
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("" . $cd->item($i)->nodeName . ": ");
echo($cd->item($i)->childNodes->item(0)->nodeValue);
echo("
");
}
}
?>
当 CD 查询从 JavaScript 发送到 PHP 页面时,将发生:
演示一个实时的搜索,在您键入数据的同时即可得到搜索结果。
实时的搜索与传统的搜索相比,具有很多优势:
当用户在上面的输入框中键入字符时,会执行 "showResult()" 函数。该函数由 "onkeyup" 事件触发:
如果输入框是空的(str.length==0),该函数会清空 livesearch 占位符的内容,并退出该函数。
如果输入框不是空的,那么 showResult() 会执行以下步骤:
上面这段通过 JavaScript 调用的服务器页面是名为 "livesearch.php" 的 PHP 文件。
"livesearch.php" 中的源代码会搜索 XML 文件中匹配搜索字符串的标题,并返回结果:
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="" .
$y->item(0)->childNodes->item(0)->nodeValue . "";
}
else
{
$hint=$hint . "
" .
$y->item(0)->childNodes->item(0)->nodeValue . "";
}
}
}
}
}
// 如果没找到则返回 "no suggestion"
if ($hint=="")
{
$response="no suggestion";
}
else
{
$response=$hint;
}
// 输出结果
echo $response;
?>
如果 JavaScript 发送了任何文本(即 strlen($q) > 0),则会发生:
演示一个 RSS 阅读器,通过它,来自 RSS 的内容在网页不进行刷新的情况下被载入:
当用户在上面的下拉列表中选择某个 RSS-feed 时,会执行名为 "showRSS()" 的函数。该函数由 "onchange" 事件触发:
菜鸟教程(runoob.com)
RSS-feed 数据列表...
showRSS() 函数会执行以下步骤:
文件 rss_demo.xml。
上面这段通过 JavaScript 调用的服务器页面是名为 "getrss.php" 的 PHP 文件:
load($xml);
// 从 "" 中读取元素
$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;
// 输出 "" 中的元素
echo("" . $channel_title . "");
echo("
");
echo($channel_desc . "
");
// 输出 "- " 中的元素
$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 ("
" . $item_title . "");
echo ("
");
echo ($item_desc . "
");
}
?>
当 RSS feed 的请求从 JavaScript 发送到 PHP 文件时,将发生:
演示一个投票程序,通过它,投票结果在网页不进行刷新的情况下被显示。
当用户选择上面的某个选项时,会执行名为 "getVote()" 的函数。该函数由 "onclick" 事件触发。
poll.html 文件代码如下:
菜鸟教程(runoob.com)
你喜欢 PHP 和 AJAX 吗?
是:
否:
getVote() 函数会执行以下步骤:
上面这段通过 JavaScript 调用的服务器页面是名为 "poll_vote.php" 的 PHP 文件:
结果:
是:
%
否:
%
当所选的值从 JavaScript 发送到 PHP 文件时,将发生:
这很不安全!攻击者能用简短的代码攻破!
//无限循环脚本
var Vote = 0;//你的票。
setInterval(function(){
getVote(Vote);
},2000);
if(empty($_COOKIE["voted"])) {
setcookie("voted","yes!",ime()+60*60*24*365);
} else {
die("您已经投过票!");
}