过滤、验证和转义数据
过滤数据
- 不要相信任何外部数据!
- 常见的有如下几种数据须要过滤:HTML,SQL查询,用户提交的信息(邮件地址、电话号码、身份证)
HTMLphp
- htmlentities()
- HTML Purifier library (https://github.com/ezyang/htmlpurifier)
SQL querieshtml
User profilemysql
- filter_var(), filter_input()
验证数据
转义输出
- htmlentities() ENT_QUOTES UTF-8
- twig/twig 或 smarty/smarty 等模板引擎默认输出转义
密码
- bcrypt
- Password Hashing API: password_hash(), password_verify(), password_needs_rehash()
时间和日期
不建议本身手动处理时间和日期,由于里面有太多要考虑的东西:时间格式,时区,夏令时,闰年,闰秒,以及不一样天数的月份。web
而是,应当使用 DateTime, DateInterval, DateTimeZone 类来处理时间sql
设置默认时区
- php.ini 中设置
date.timezone = 'PRC'
date_default_timezone_set('PRC')数据库
DateTime类
- new DateTime('2014-04-27 5:03 AM'), 传入一个PHP可以理解的时间字符串
DateTime::createFromFormat('Y-m-d H:i:s', '2019-04-02 18:08:00'),从指定的时间格式建立时间浏览器
DateInterval
- DateInterval 表示一段长度的时间,在 DateTime 类的 add() 或 sub() 方法中,能够传入一我的 DateInterval 实例,来修改时间
new DateInterval('P2W2DT5H'),实例化须要传入一个字符串,这个字符串第一个字符是"P",第二个字符表示数量,第三个字符表示单位,合法的单位有:Y(年),M(月),D(天),W(周),H(小时),M(分钟),S(秒)。日期和时间之间使用“T”分隔。好比 “P2W2DT5H” 表示 2周2天5小时安全
DateTimeZone
- 表示时区,new DateTimeZone('PRC')
- 用途:做为 new DateTime() 的第二个参数。若是不指定,则使用默认的时区设置(上面提到)
- setTimezone() 能够用来修改 DateTime() 的时区
在数据库和代码中使用UTC来处理时间很方便,只有当显示给用户看时,再转换为对应的时区。
DatePeriod
- 用于遍历时间(以给定的间隔),用途:日历中重复的事件
- new DatePeriod($datetime, $dateinterval, $number)
DatePeriod 是一个迭代器,每次迭代输出一个 DateTime 对象
- 推荐使用:nesbot/carbon 库来处理时间
数据库
使用PDO来链接数据库,针对不一样的底层数据库,提供了统一的访问方式。但缺点在于不一样的数据库有本身的方言,这是PDO所不能支持的。建议是写标准的SQL。
数据库链接和DSN
- new PDO($dsn, $username, $password),会抛出 PDOException
- DSN 示例:"mysql:host=127.0.0.1;dbname=books;port=3306;charset=utf8",其中 mysql 是驱动名表示 MySQL 数据库驱动
- 安全:(1)不要直接在代码中写用户和密码,应当在web目录以外增长一个配置文件,经过配置获取(2)不要把用户和密码加到版本控制系统中
预处理语句
- 一般咱们使用请求参数来构造SQL语句,这样很危险,幸而 PDO 使用预处理语句和参数绑定帮咱们处理了参数的过滤。
- 预处理语句就是 PDOStatement 实例,可是咱们不多直接实例化它,而是经过 PDO 实例的 prepare() 方法来获取。这个方法第一个参数为一个SQL字符串
- 命名占位符:$sql = "SELECT id FROM users WHERE email = :email";
- 绑定参数:$statement->bindValue(':email', $email),预处理语句会自动过滤 email 参数,从而防止 SQL 注入。
查询结果
- 调用 PDOStatement::execute() 执行语句查询。
- 调用 PDOStetement::fetch(),fetchAll(),fetchColumn(),fetchObject()来获取结果集
- fetch() 方法返回结果集中的下一行,能够用它来遍历比较大的结果集。
- fetch() 和 fetchAll() 接受一个常量来设置获取结果集的形式,有如下:PDO::FETCH_ASSOC, PDO::FETCH_NUM, PDO::FETCH_BOTH, PDO::FETCH_OBJ
- fetchColumn() 获取一行,能够指定一个参数来获取某列
事务
- 添加事务很简单,在执行查询以前,调用 PDO::beginTransaction(),在执行查询结束后 调用 PDO::commit() 便可。
多字节字符串
多字节字符是指ASCII范围以外的字符,PHP默认提供的字符串函数只支持8位的ASCII字符,若是用来处理Unicode字符就会产生错误,为此,能够使用 mbstring 扩展。大部分的PHP字符串处理函数都提供了对应的 mb_* 版本。
字符编码
- 使用 UTF-8,全部现代浏览器都支持
mbstring 还能够转换字符编码:mb_detect_encoding(),mb_convert_encoding()
输出UTF-8数据
- 在 php.ini 中:default_charset = "UTF-8",这个设置会被许多PHP函数使用以及做为PHP默认输出编码
推荐HTML代码中增长:<meta charset="UTF-8"/>
流
- 流是现代PHP中最神奇的、也是使用得最少的一个的功能。
- 流是什么?流是数据在起点和终点之间的传输。也就是提及点和终点,多是一个文件、也多是一个命令行进程,一个网络链接,或者一个ZIP压缩包,临时内存,标准输入输出,或者其余资源。
流提供了许多PHP IO函数的底层实现,好比:file_get_contents(),fopen(),fgets(),fwrite()
流包装器
- 不一样种类的流式数据须要各自的协议来读写数据,这些协议就是流包装器。
- 标识流数据:
<scheme>://<target>
- HTTP流:http://www.baidu.com
- 文件流:file:///etc/hosts,因为它是PHP默认流包装器,因此咱们在使用文件函数时直接输入路径就能够了,于是感觉不到底层其实使用了 file:// 来获取数据的
- php:// 流:命令行脚本会用到,php://stdin, php://stdout, php://memory, php://tmp
- ZIP或TAR流:直接读取写入压缩文件
FTP或FTPS流:ftp://user:pass@ftp.example.com/foo.txt
流上下文
- 流能够接受一个上下文参数,来自定义流的行为。
stream_context_create() 建立上下文参数,返回的流上下文对象,能够被传入大多数的文件函数和流函数。
流过滤器
- 以前使用流来打开、读取、写入数据,可是PHP流的真正用武之处是在数据传输过程当中进行过滤、添加、转换或删除操做。好比:打开一个markdown文件流,当读取到内存中时,自动转换为HTML。
- php提供了几个默认的流过滤器,没什么用,应当使用本身自定义的流过滤器。
stream_filter_append($stream, 'filter.name') 添加过滤器到流中
建立自定义流过滤器
建立一个继承自 php_user_filer 的类,实现 filter(), onCreate(), onClose() 方法,而后使用 stream_filter_register() 注册该过滤器。
错误和异常
PS - 我的博客连接 《modern-php》-阅读笔记-最佳实践