PHP知识总结
-
PHP的认知
-
PHP的语言参考
-
PHP安全考虑
-
PHP的特性
-
PHP实用性考虑
1.PHP的认知
1.1 PHP是什么
PHP(“PHP: Hypertext Preprocessor”,超文本预处理器的字母缩写)是一种被广泛应用的开放源代码的多用途脚本语言,它可嵌入到 HTML中,尤其适合 web 开发。
1.2 PHP的主要用途
-
服务端脚本。开展这项工作需要具备以下三点:PHP 解析器(CGI 或者服务器模块)、web 服务器和 web 浏览器。
-
命令行脚本。仅仅只需要 PHP 解析器来执行。这种用法对于依赖 cron(Unix 或者 Linux 环境)或者 Task Scheduler(Windows 环境)的日常运行的脚本来说是理想的选择。
-
编写桌面应用程序,利用 PHP-GTK 来编写这些程序。
2.PHP语言参考
2.1 基础语法
-
PHP标记:
-
<?php 和 ?>,或者short_open_tag开启后允许使用短标记 <? 和 ?>。
-
分隔符为分号,注释有://, /* * /, / * * */。
-
-
数据类型
-
布尔类型:true或false。整型值0、浮点型值0.0、空字符串,以及字符串 "0"、不包括任何元素的数组、特殊类型NULL、从空标记生成的SimpleXML对象都会当从false。
-
数据类型包括:整型、浮点型、字符串、数组、对象、资源类型、NULL、callback类型。
-
-
变量
-
预定义变量:$GLOBALS、$SERVER、$GET、$POST、$FILES、$REQUEST、$SESSION、$ENV、$COOKIE、$HTTP_RAW_POST_DATA、$http_response_header、$argc、$argv。
-
变量的范围:变量有局部变量和全局变量之分,全局变量用global定义。
-
变量类型:变量类型有可变变量和静态变量,静态变量只会初始化一次并且变量在整个生命过程中有效。
-
-
常量
-
常量的定义方式:define("FOO", "something");
-
魔术常量:LINE、FILE、DIR、FUNCTION、CLASS、TRAIT、METHOD、NAMESPACE
-
-
表达式:复制表达式、比较表达式、三目运算表达式。
-
运算符:
-
运算符优先级:递增/递减, 类型转换, !, * / %, + - ., 比较运算符, 引用符, &&, ||, ? :, 赋值运算符, and, or。
-
错误忽略符号@,如果用 set_error_handler() 设定了自定义的错误处理函数,仍然会被调用。
-
-
流程控制
-
判断控制:if, elseif/else if, else。
-
循环控制:while、do-while、for、foreach、break、continue、switch、return、goto。
-
引入控制:include、include_once、require、require_once。include产生E_COMPILE_ERROR错误时报警告,require产生致命错误。
-
2.2 函数
-
字符串函数:
-
字符串查找:strrpos()最后一次位置、strripos()最后一次位置、strrchr()返回最后一次位置的剩余部分、stristr()返回第一次位置的剩余部分、stripos()第一次出现的位置、strpos()第一次出现的位置。
-
字符串增减:chop()删除指定字符、chunk_split()分割更小部分、explode()分割数组、implode()数组组合字符串、trim移除空格、str_replace()字符串替换、str_split()分割字符块、substr()截取字符串。
-
字符串属性:strlen()字符串长度、strrev()反转字符串、strtolower()字符串小写、strtoupper()字符串大写、ucfirst()首字符大写、lcfirst()首字符小写。
-
-
数组函数:
-
数组比较:array_diff()返回差集(只比较键值)、array_diff_assoc()返回差集(比较键名和键值)、array_diff_key()返回差集(只比较键名)、array_intersect()返回交集(只比较键值)、array_intersect_assoc()返回交集(比较键名和键值)、array_intersect_key()返回交集(只比较键名。
-
数组排序:array_multisort()对多个数组或多维数组进行排序、arsort()按照键值进行降序排序、asort()按照键值进行升序排序、krsort()按照键名逆向排序、ksort()按照键名排序、rsort()数组逆向排序、sort()对数组排序、uasort()使用用户自定义的比较函数对数组中的键值进行排序。
-
数组改变:array_change_key_case()把数组中所有键更改为小写或大写、array_chunk()把一个数组分割为新的数组块、array_column()返回输入数组中某个单一列的值、array_combine()通过合并两个数组来创建一个新数组、array_fill()用给定的键值填充数组、array_filter()用回调函数过滤数组中的元素、array_flip()交换数组中的键和值、array_keys()返回数组中所有的键名、array_pop()出栈、array_push()入栈、array_replace()使用后面数组的值替换第一个数组的值、array_reverse()以相反的顺序返回数组、array_shift()删除数组中首个元素、array_unshift()在数组开头插入一个或多个元素等。
-
2.3 类与对象
-
命名空间
-
用户编写的代码与PHP内部的类/函数/常量或第三方类/函数/常量之间的名字冲突。
-
为很长的标识符名称(通常是为了缓解第一类问题而定义的)创建一个别名(或简短)的名称,提高源代码的可读性。
-
-
类的属性
-
类常量:const,常量的值必须是一个定值,不能是变量,类属性,数学运算的结果或函数调用。
-
访问控制:public(公有),protected(受保护)或 private(私有) 。
-
类自动加载:spl_autoload_register() 函数可以注册任意数量的自动加载器,当使用尚未被定义的类(class)和接口(interface)时自动去加载。
-
构造函数和析构函数:construct、destruct。
-
对象继承:extends,子类就会继承父类所有公有的和受保护的方法。除非子类覆盖了父类的方法,被继承的方法都会保留其原有功能。
-
抽象类:abstract,被定义为抽象的方法只是声明了其调用方式,继承一个抽象类的时候,子类必须定义父类中的所有抽象方法,访问控制只能一样或者更轻松。
-
对象接口:接口是通过 interface 关键字来定义的,就像定义一个标准的类一样,但其中定义所有的方法都是空的。
-
trait:PHP 实现了一种代码复用的方法,称为 trait。Trait 是为类似 PHP 的单继承语言而准备的一种代码复用机制。
-
重载:PHP所提供的重载(overloading)是指动态地创建类属性和方法。我们是通过魔术方法(magic methods)来实现的。
-
魔术方法:construct(), destruct(), call(), callStatic(), get(), set(), isset(), unset(), sleep(), wakeup(), toString(), invoke(), set_state(), clone() 和 __debugInfo() 等方法在 PHP 中被称为魔术方法(Magic methods)。
-
final: 如果父类中的方法被声明为 final,则子类无法覆盖该方法。如果一个类被声明为 final,则不能被继承。
-
2.4 异常处理
-
PHP 7 改变了大多数错误的报告方式。不同于传统(PHP 5)的错误报告机制,现在大多数错误被作为 Error 异常抛出。
-
这种 Error 异常可以像 Exception 异常一样被第一个匹配的 try / catch 块所捕获。如果没有匹配的 catch 块,则调用异常处理函数(事先通过 set_exception_handler() 注册)进行处理。 如果尚未注册异常处理函数,则按照传统方式处理:被报告为一个致命错误(Fatal Error)。
2.5 生成器
-
生成器提供了一种更容易的方法来实现简单的对象迭代,相比较定义类实现 Iterator 接口的方式,性能开销和复杂性大大降低。
-
生成器允许你在 foreach 代码块中写代码来迭代一组数据而不需要在内存中创建一个数组, 那会使你的内存达到上限,或者会占据可观的处理时间。相反,你可以写一个生成器函数,就像一个普通的自定义函数一样, 和普通函数只返回一次不同的是, 生成器可以根据需要 yield 多次,以便生成需要迭代的值。
3.PHP安全考虑
3.1 会话安全
-
会话管理基础
-
安全说明:会话模块无法保证你存储在会话中的信息只能被创建会话的用户本人可见。通常需要付出一定的代价,同时会降低便利性。 例如,如果你需要保护用户免受社会工程学攻击, 你需要启用 session.use_only_cookies 选项。
-
严格会话管理:PHP 是以自适应的方式来管理会话的, 这种方式使用起来很灵活,但是同样也带来了一定的风险。因此需要配置session.use_strict_mode。当启用这个配置项,未经初始化的会话 ID 会被拒绝, 并为其生成一个全新的会话,这可以避免攻击者使用一个已知的会话 ID 来进行攻击。
-
重新生成会话ID:为了确保会话安全,开发者还需要使用 session_regenerate_id() 函数,定期自动重新生成会话ID。
-
CSRF(跨站请求伪造):会话和认证无法避免跨站请求伪造攻击, 开发者需要自己来实现保护应用不受 CSRF 攻击的功能。
-
-
和会话安全相关的配置项
-
session.cookie_lifetime=0 告知浏览器不要持久化存储 cookie 数据。
-
session.use_cookies=On,session.use_only_cookies=On 虽然 HTTP cookie 存在一些问题, 但是它确实是实现会话 ID 管理的优选方案。
-
session.use_strict_mode=On 此设置防止会话模块使用未初始化的会话 ID。
-
session.cookie_httponly=On 禁止JavaScript访问会话cookie。 此设置项可以保护cookie不被JavaScript窃取。
-
session.cookie_secure=On 仅允许在 HTTPS 协议下访问会话ID cookie。 如果你的web站点仅支持HTTPS,那么必须将此配置项设置为On。
-
session.use_trans_sid=Off 禁用会话 ID 透传机制可以 避免会话 ID 被注入以及泄漏, 有效的提高会话安全性。
-
3.2 文件安全
-
PHP遵从大多数服务器系统中关于文件和目录权限的安全机制。这就使管理员可以控制哪些文件在文件系统内是可读的。必须特别注意的是全局的可读文件,并确保每一个有权限的用户对这些文件的读取动作都是安全的。
-
PHP 被设计为以用户级别来访问文件系统,所以完全有可能通过编写一段 PHP 代码来读取系统文件如 /etc/passwd,更改网络连接以及发送大量打印任务等等。因此必须确保 PHP 代码读取和写入的是合适的文件。
-
有两个重要措施来防止此类问题:
-
只给 PHP 的 web 用户很有限的权限。
-
检查所有提交上来的变量。
-
3.3 数据库安全
-
PHP 本身并不能保护数据库的安全。记住一条简单的原则:深入防御。保护数据库的措施越多,攻击者就越难获得和使用数据库内的信息。正确地设计和应用数据库可以减少被攻击的担忧。
-
直接 SQL 命令注入就是攻击者常用的一种创建或修改已有 SQL 语句的技术,从而达到取得隐藏数据,或覆盖关键的值,甚至执行数据库主机操作系统命令的目的。
-
-- 是 SQL 的注释标记,一般可以使用来它告诉 SQL 解释器忽略后面的语句。
-
预防措施
-
永远不要使用超级用户或所有者帐号去连接数据库。要用权限被严格限制的帐号。
-
检查输入的数据是否具有所期望的数据格式。
-
使用数据库特定的敏感字符转义函数(比如 mysql_escape_string() 和 sql_escape_string())把用户提交上来的非数字数据进行转义。
-
也可以选择使用数据库的存储过程和预定义指针等特性来抽象数库访问,使用户不能直接访问数据表和视图。
-
4.PHP的特性
4.1 垃圾回收机制
-
引用计数基本知识
-
每个php变量存在一个叫"zval"的变量容器中。一个zval变量容器,除了包含变量的类型和值,还包括两个字节的额外信息。第一个是"is_ref",是个bool值,用来标识这个变量是否是属于引用集合(reference set)。
-
把一个变量赋值给另一变量将增加引用次数(refcount).
-
变量容器在”refcount“变成0时就被销毁. 当任何关联到某个变量容器的变量离开它的作用域(比如:函数执行结束),或者对变量调用了函数 unset()时,”refcount“就会减1。
-
-
回收周期
-
如果一个引用计数增加,它将继续被使用,当然就不再在垃圾中。如果引用计数减少到零,所在变量容器将被清除(free)。就是说,仅仅在引用计数减少到非零值时,才会产生垃圾周期(garbage cycle)。其次,在一个垃圾周期中,通过检查引用计数是否减1,并且检查哪些变量容器的引用次数是零,来发现哪部分是垃圾。
-
-
性能方面考虑
-
首先,实现垃圾回收机制的整个原因是为了,一旦先决条件满足,通过清理循环引用的变量来节省内存占用。在PHP执行中,一旦根缓冲区满了或者调用gc_collect_cycles() 函数时,就会执行垃圾回收。
-
执行时间增加:垃圾回收影响性能的第二个领域是它释放已泄漏的内存耗费的时间。PHP中的垃圾回收机制,回收算法确实运行时会有时间消耗上的增加。
-
4.2 Fast cgi管理
-
支持平滑停止/启动的高级进程管理功能;
-
可以工作于不同的 uid/gid/chroot 环境下,并监听不同的端口和使用不同的 php.ini 配置文件(可取代 safe_mode 的设置);
-
stdout 和 stderr 日志记录;
-
在发生意外情况的时候能够重新启动并缓存被破坏的 opcode;
-
文件上传优化支持;
-
"慢日志" - 记录脚本(不仅记录文件名,还记录 PHP backtrace 信息,可以使用 ptrace或者类似工具读取和分析远程进程的运行数据)运行所导致的异常缓慢;
-
fastcgi_finish_request() - 特殊功能:用于在请求完成和刷新数据后,继续在后台执行耗时的工作(录入视频转换、统计处理等);
-
动态/静态子进程产生;
-
基本 SAPI 运行状态信息(类似Apache的 mod_status);
-
基于 php.ini 的配置文件。
-
5.PHP实用性考虑
5.1 大量数据的处理
-
足够的批处理
-
记录在业务事务过程中对数据库有影响的所有变化,并在操作结束后,作为一种结果保存到数据库。
-
解决大量规模很小的数据库调用。
-
-
充分的异步处理
-
分而治之的思想:把复杂的业务流程拆分为独立的几个子流程。
-
把不影响主流程的数据加载进行异步处理
-
5.2 内存使用情况
-
使用生成器
-
生成器提供简易的方法实现对象迭代,性能开销和复杂性大大降低。
-
生成器可以避免,大变量导致的内存溢出问题。
-
-
在长时间执行的脚本中,尽可能手动unset()变量。避免PHP垃圾回收机制的耗时,和内存碎片导致的内存增加问题。
5.3 并发处理情况
-
乐观锁机制
-
在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则让返回用户错误的信息,让用户决定如何去做。
-
-
悲观锁机制
-