2. 单引号只转义 单引号和 \ 而双引号转义很多,如果不加引号,会当作常量去处理。
3. GBK转车ascii码 -- 2个字节 UTF8 -- 3个字节 汉字的处理一样平常都用 mbstring来处理
4. 字符串操作 - 常见任务
=================================
提取/查找
更换/截断
大小写转换
转义/转编码
substr()
=========================
字符串截取是最根本的操作之一,substr函数功能强大,常日利用substr即可完成所有所需操作。
substr_compare() 函数从指定的开始长度比较两个字符串。
该函数返回:
0 - 如果两字符串相等<0 - 如果 string1 (从开始位置)小于 string2>0 - 如果 string1 (从开始位置)大于 string2实战 - 获取URL的协议名1
===========================
<?php
$url = 39;http://weibo.com/rodin';
$url_https = 'https://login.sina.com.cn';
function is_https($url){
return substr($url, 0, 5) === 'https';
}
echo is_https($url) ? 'is secure' : 'not secure';
echo is_https($url_https) ? 'is secure' : 'not secure';
实战 - 获取URL的协议名2
===========================
<?php
function is_https2($url){
return substr_compare($url, 'https', 0, 5) === 0;
}
实战 - 获取URL的协议名3
===========================
parse_url(); -- 判断url的格式,是否加了协议名称
<?php
function is_https3($url){
$url_components = parse_url($url);
return $url_components['scheme'] === 'https';
}
实战 - 获取URL的协议名4
===========================
<?php
function is_https4($url){
return $url{0} === 'h'
&& $url{1} === 't'
&& $url{2} === 't'
&& $url{3} === 'p'
&& $url{4} === 's';
}
substr_replace() - 方法解释 -- 函数把字符串的一部分更换为另一个字符串
=========================
substr_replace(string,replacement,start,length)
参数描述string必需。规定要检讨的字符串。replacement必需。规定要插入的字符串。start必需。规定在字符串的何处开始更换。
正数 - 在第 start 个偏移量开始更换负数 - 在从字符串结尾的第 start 个偏移量开始更换0 - 在字符串中的第一个字符处开始更换charlist可选。规定要更换多少个字符。
正数 - 被更换的字符串长度负数 - 从字符串末端开始的被更换字符数0 - 插入而非更换str_ireplace -- 函数利用一个字符串更换字符串中的另一些字符,忽略大小写
str_replace -- 函数利用一个字符串更换字符串中的另一些字符,该函数对大小写敏感
preg_replace -- 实行正则表达式的搜索和更换
preg_replace_callback -- 用回调函数实行正则表达式的搜索和更换
实战 - 过滤危险字符1
==========================
<?php
$dangerous='This<script src="http://x.cn/xss.js"></script> is dangerous!';
$unsafe = str_replace('>', '>', $dangerous);
$safe = str_replace('<', '<', $unsafe);
echo $safe;
//一次更换多个
echo str_replace(
array('<', '>'), array('<', '>'), $dangerous
);
strpos()
=========================
字符串查找是最根本的操作之一。
系列函数中,默认为从左往右以及大小写敏感(二进制安全)。
加i的是大小写忽略(case-insenstive)
加r的是从右往左找,但返回的位置仍旧是从左往右。
strpos/stripos 忽略大小写
strrpos 从后向前 /strripos 忽略大小写
<?php
int|false strpos($haystack, $needle, $offset = null);
//如果在$haystack字符串中查找到了第一个$needle的存在,返回其起始位置;
//否则返回false。
//如果指定了$offset,则会从$offset的位置开始查找,否则从$haystack
//的第一个字符开始查找。
strpos()
=========================
<?php
for($i = 0; $i <= 9; $i ++){
echo strpos('9876543210', "$i");
}
explode()
======================
字符串分离,split() 是 explode() 的别名函数
explode/split
implode/join
实战 - 检讨是否有危险字符存在1
================================
.. code-block:: php
<?php
$sql_injection_str = "abcde' or 1=1";
if(strpos($sql_injection_str, "'") !== false){
echo 'suspected sql injection';
}else{
echo 'safe sql string';
}
实战 - 检讨是否有危险字符存在2
================================
<?php
$sql_injection_str = "abcde' or 1=1";
if(count(explode("'", $sql_injection_str)) > 1){
echo 'suspected sql injection';
}else{
echo 'safe sql string';
}
实战 - 提取文件名1
===========================
<?php
$file_name = 'a.rar.zip.html';
$dot_pos = strpos($file_name, '.');
$file_basename = ($dot_pos !== false)
? substr($file_name, 0, $dot_pos)
: $file_name;
echo $file_basename;
实战 - 提取文件名2
===========================
<?php
$file_name = 'a.rar.zip.html';
$file_basename = strstr('.', $file_name, true);
echo $file_basename;
实战 - 提取文件名3
===========================
.. code-block:: php
<?php
$file_name = 'a.rar.zip.html';
list($file_basename,) = explode('.', $file_name, 2);
echo $file_basename;
实战 - 提取文件名4
===========================
<?php
$file_name = 'a.rar.zip.html';
$file_basename = strtok($file_name, '.');
echo $file_basename;
实战 - 提取文件扩展名1
===========================
<?php
//只要末了一个“.“后面的
$file_name = 'a.rar.zip.html';
$dot_pos = strrpos($file_name, '.');
$file_extname = ($dot_pos !== false)
? substr($file_name, $dot_pos + 1) : '';
echo $file_extname;
实战 - 提取文件扩展名2
===========================
<?php
$file_name = 'a.rar.zip.html';
$last_slice = strstr($file_name, '.');
$file_extname = '';
while($last_slice !== false){
$file_extname = substr($last_slice, 1);
$last_slice = strstr($file_extname, '.');
}
echo $file_extname;
实战 - 提取文件扩展名3
===========================
<?php
$file_name = 'a.rar.zip.html';
$file_name_slices = explode('.', $file_name);
$file_extname = count($file_name_slices) > 1
? array_pop($file_name_slices) : '';
echo $file_extname;
实战 - 提取文件扩展名4
===========================
<?php
$file_name = 'a.rar.zip.html';
$token = strtok($file_name, '.');
$file_extname = '';
while($token !== false){
$file_extname = $token;
$token = strtok('.');
}
echo $file_extname;
trim() - Usage
=====================
截掉字符串首尾的回车、换行、Tab(16)、垂直Tab(17)、空格等或者手动指定的字符。
可以用来调度字符串格式、判断造孽字符等功能
trim
ltrim -- 去除左侧空格
rtrim/chop -- 去除右侧空格
实战 - 过滤字符串扫尾空格
=================================
<?php
$a = $_GET['param']; // $_GET['param'] = ' asdf ';
$trimmed_a = trim($a);
$ltrimmed_a = ltrim($a);
$rtrimmed_a = rtrim($a);
echo $trimmed_a; // output: "asdf"
echo $ltrimmed_a; // output: "asdf "
echo $rtrimmed_a; // output: " asdf"
实战 - 去掉首尾不想要的字符
====================================
<?php
$jsonp_string = <<<JSON
var data = {
"code" : 1, "error" : "System error", "data" : {null}
};
JSON;
var_dump(json_decode($jsonp_string, 1)); // null
$valid_json_string = trim($jsonp_string, 'var data = ;');
var_dump(json_decode($valid_json_string, 1)); // an array
实战 - 检测是否只包含想要的字符
========================================
<?php
$file_path = 'sina\..\..\weibo';
$trimmed_path = trim(strtolower($file_path),
"abcdefghijklmnopqrstuvwxyz1234567890\\");// ..\..
if($trimmed_path){
echo '不屈安的路径!
';
}
//对付此例更易读的实现是
if(!preg_match('/^[a-z0-9\\\\]+$/iD', $file_path)){
echo '不屈安的路径!
';
}
大小写转换 - Usage
===========================
strtolower -- 转化成小写
strtoupper -- 转换成大写
ucfirst -- 让第一个字符串大写
ucwords
实战 - 忽略大小写比对字符串
======================================
<?php
$a = 'Hello World!';
if(strtolower($a) === 'hello world!'){
echo 'Same!';
}else{
echo 'Different!';
}
实战 - 忽略大小写比对字符串2
=======================================
<?php
$a = 'Hello worlD!';
if(strcasecmp($a, 'hello world!') === 0){
echo 'Same!';
}else{
echo 'Different!';
}
实战 - 命名风格转换
=======================================
<?php
$class_name = 'sina_weibo_class';
echo implode('', array_map(
'ucfirst',
explode('_', $class_name)
));
//SinaWeiboClass
实战 - 命名风格转换2
=======================================
<?php
$class_name = 'sina_weibo_class';
function cb_camel_style($match){
return ucfirst($match[2]);
}
echo preg_replace_callback('/(^|_)(\w)/i',
'cb_camel_style', $class_name);
//SinaWeiboClass
各种转义 - Usage
=====================
HTML转义:
- htmlentities / html_entity_decode --- 转移所有字符
- htmlspecialchars / htmlspecialchars_decode --- 转义个别字符 单引号等等。。。。
URL转义:
- urlencode / urldecode
- rawurlencode / rawurldecode(Form兼容)
各种转义 - Usage
=====================
JSON转义:
- json_encode / json_decode(把稳溢出)
SQL转义:
- addslashes / stripslashes(不推举)
- PDO::quote (推举)
数组操作
======================
数组是
.. class:: takahashi3
PHP精髓
http://cn.php.net/manual/en/ref.array.php
.. container:: handout
PHP Web开拓利用频率最高的操作类型
数组常见任务
==================
访问
遍历,过滤,排重,映射
排序
栈/行列步队
凑集
通过SPL扩展
实战 - 索引数组普通操作
==========================
.. code-block:: php
<?php
//Index数组
$a = array(5, 4, 3, 2, 1); // 利用前必须先初始化!
$a[] = 0; // 追加
$a[count($a)] = 1; // Index数组追加
$a[0] === 0; // True
if(isset($a[2])) { //判断一个index是否存在,或可以考验数组长度
echo "Array \$a's length is bigger or equals to 3";
}
unset($a[1]); // 删除一个key/index
实战 - 关联数组普通操作
==========================
.. code-block:: php
<?php //关联数组
$a = array('a' => 'a_value', 'b' => 'b_value'); // 初始化
$a['c'] = 'c_value';
$a[] = 1; // 追加到当前索引序列的末了一个
if(isset($a['b'])) // 判断一个key是否已经存在且不为null值
echo "\$a['b'] is exist and not null";
if(array_key_exists('b', $a))
echo "\$a['b'] is exist and maybe null";
unset($a['b']); //删除一个值(或值的引用)
$a['b'] === null; //通过array_key_exists判断仍旧为真
实战 - 更人性化的逗号1
=========================
.. code-block:: php
<?php
$fruits = array('bananas', 'apples', 'pears');
$result = 'I love to eat';
foreach($fruits as $fruit){
$result .= ' ' . $fruit . ',';
}
$result = substr($result, 0, -1) . '.';
echo $result;// I love to eat bananas, apples, pears.
实战 - 更人性化的逗号2
=========================
.. code-block:: php
<?php
$fruits = array('bananas', 'apples', 'pears');
$result = 'I love to eat';
$result .= ' ' . implode(', ', $fruits) . '.';
echo $result;
实战 - 函数多返回值
=======================
.. code-block:: php
<?php // !
!
!
强烈不推举!
!
!
function ugly(&$error_desc){
$error_code = 0;
if(error_detected()){
$error_code = 1;
$error_desc = 'not correct';
}
return $error_code;
}
if(ugly($error_desc)){
echo $error_desc;
}
实战 - 函数多返回值2
=========================
.. code-block:: php
<?php
function beauty(){
$error_code = 0;
if(error_detected()){
$error_code = 1;
$error_desc = 'not correct';
}
return array($error, $error_desc);
}
list($error, $error_detail) = beauty();
if($error) echo $error_detail;
数组 - 凑集常见操作
=============================
- 合并数组 array_combine array_merge
- 遍历: array_walk
- 过滤/排重: array_filter
- 映射: array_map
- 聚合: array_reduce
.. class:: takahashi3
foreach
实战 - 过滤列表空内容并按id排重
================================
.. code-block:: php
<?php
$list = array(
array(
'id' => 12345,
'content' => 'something',
'is_deleted' => false,
),
);
实战 - 过滤列表空内容并按id排重2
================================
.. code-block:: php
<?php
$result = array();
foreach($list as $v){
if($v['is_deleted']){
continue;
}
$result[$v['id']] = $v;
}
实战 - 过滤列表空内容并按id排重3
====================================
.. code-block:: php
<?php
function cb_filter_deleted($item){
static $map;
if($map === null) $map = array();
return !(isset($map[$item['id']])||$item['is_deleted']);
}
$result = array_filter($list, 'cb_filter_deleted');
数组操作 - 排序
=======================
.. class:: takahashi3
sort/usort
asort/uasort
ksort/uksort
...
数组操作 - 栈/行列步队
========================
.. class:: takahashi2
array_pop / []
array_shift / array_unshift
数组操作 - 凑集
======================
.. class:: takahashi3
array_merge / +
array_intersect
array_diff
...
实战 - 数据合并
=====================
.. code-block:: php
<?php
$a = array('a' => '1', 'b' => '2');
$b = array('a' => 'a', 'c' => 'c');
var_export(array_merge($a, $b));
// array('a'=>'a','b'=>'2','c'=>'c');
var_export($a + $b);
// array('a'=>'1','b'=>'2','c'=>'c');
实战 - 取交集/差集
=========================
.. code-block:: php
<?php
$a = array('a' => '1', 'b' => '2');
$b = array('a' => '1', 'c' => 'c');
var_export(array_intersect($a, $b));
// array('a' => '1');
var_export(array_diff($a, $b));
// array('b' => '2');
数组操作 - SPL扩展
===========================
.. code-block:: php
<?php
class SinaArray implements ArrayAccess{
public function offsetSet($key, $value){
echo "array's \"{$key}\" set to \"{$value}\".";
}
//须要实现offsetGet, offsetExists, offsetUnset...
}
$a = new SinaArray();
$a['sina'] = 'weibo';
// output: array's "sina" set to "weibo".
大纲
=====================
.. class:: said
字符串常用操作
-----------------
.. class:: said
数组常用操作
------------------
.. class:: next
Cookie和Session
------------------
.. class:: wait
文件上传
------------------
.. class:: wait
PHP.ini
------------------
Cookie和Session机制
=========================
.. class:: takahashi4
用户数据传输
Cookie
===============
+ 数据在用户手中
- 易跨做事器共享
+ 花费带宽而非做事器运算和存储资源
+ 长度有限定
+ 过期韶光基本由用户浏览器掌握
Cookie
===============
+ 数据 不可信赖
- 但可通过署名达到数据信赖
+ 随意马虎遭受各种攻击
- 随意马虎被盗取 XSS
- 随意马虎被挟制会话 CSRF
- 随意马虎被注入 Cookie injection
Session
================
+ 可基于Cookie实现
- 通过识别cookie中的session id实现
+ 数据在做事器上
- 须要公共存储方可实现跨做事器共享
+ 花费做事器运算/存储资源而非带宽
+ 数据 基本 可信任
- 须要防止session id泄露
+ 不随意马虎遭受攻击
- 在session id被盗或者被预测的情形下,仍可能被挟制
Session (2)
================
+ 长度取决于做事器资源
+ PHP代码中须要开启 session 支持
+ 默认的Session机制中的过期韶光不甚靠谱
+ 存储机制可 扩展_
.. _扩展: http://cn.php.net/manual/en/book.session.php
大纲
=====================
.. class:: said
字符串常用操作
-----------------
.. class:: said
数组常用操作
------------------
.. class:: said
Cookie和Session
------------------
.. class:: next
文件上传
------------------
.. class:: wait
PHP.ini
------------------
文件上传
=======================
.. class:: takahashi3
漏洞篓子
完备版: http://cn.php.net/manual/en/features.file-upload.php
RFC-1867: http://www.ietf.org/rfc/rfc1867.txt
文件上传 - Usage
======================
.. code-block:: html
<form action="__URL__" method="POST" enctype="multipart/form-data">
<!-- MAX_FILE_SIZE 可以限定文件大小-->
<input type="hidden" name="MAX_FILE_SIZE" value="30000" />
<!-- $_FILES 数组中用来识别的名字-->
Send this file: <input name="userfile" type="file" />
<input type="submit" value="上传文件" />
</form>
文件上传 - Usage
======================
.. code-block:: php
<?php
$uploaddir = '/var/www/uploads/';
$uploadfile = $uploaddir . basename($_FILES['userfile']['name']);
//TODO 须要做更多的安全检测,包括文件大小限定
if(move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)){
echo "File is valid, and was successfully uploaded.\n";
} else {
echo "Possible file upload attack!\n";
}
文件上传 - Usage - 安全检讨
================================
.. code-block:: php
<?php //更安全的文件类型检测
$dot_pos = strrpos($_FILES['userfile']['name'], '.');
$file_extname = ($dot_pos !== false)
? strtolower(substr($file_name, $dot_pos + 1))
: '';
$avail_exts = array('jpg', 'jpeg', 'gif', 'png');
if(!in_array($file_extname, $avail_exts)){
echo 'wrong file type';
return;
}
//可能须要对上传的文件的二进制内容做更进一步判断
//如gif必须以ascii:gif89a 开头等
文件上传 - Usage - 安全检讨2
================================
.. code-block:: php
<?php //更安全的文件名检测
$file_basename = basename($_FILES['userfile']['name']);
if(preg_match('/^\w+$/iD', $file_basename){
$uploadfile = "{$file_basename}.{$file_extname}";
}
//大略粗暴的方法:
$uploadfile = microtime(1).random(1, 999).".{$file_extname}";
文件上传 - 限定
============================
+ 运行时限定(Post/Request/Memory)
+ 要求实行韶光
+ 长连接导致随意马虎受DOS攻击
+ 易涌现安全问题
+ 多做事器/跨IDC同步以及备份
+ 带宽与连接密集型须要专门优化web做事器
+ 需仔细方案上传目录权限和访问方法
文件上传 - 限定
============================
.. class:: takahashi2
Cloud is the God!
+ 云打算可以办理大部分问题
+ 仍有要求实行韶光限定
+ 备份同样成问题(S3除外)
+ 易遭受DOS攻击(资源限额耗尽)
大纲
=====================
.. class:: said
字符串常用操作
-----------------
.. class:: said
数组常用操作
------------------
.. class:: said
Cookie和Session
------------------
.. class:: said
文件上传
------------------
.. class:: next
PHP.ini
------------------
PHP.ini
========================
.. class:: takahashi3
PHP的闸门
完备参考: http://cn.php.net/manual/en/ini.php
PHP.ini - 设置方法
==========================
.. container:: handout
PHP.ini对付CGI/CLI可分开,个中CGI打了fpm补丁时可以再次指定其位置;而CLI可以在运行时指定
+ 位置:
- 常日为安装目录,详细需看编译选项
+ 格式:
- INI
+ 生效:
- 一样平常需重启PHP进程,但如果以fcgi模式且打了fpm补丁,则可以不重启,reload即可
PHP.ini - 设置方法
==========================
+ 其他:
- 命令行下可以通过php -c 来指定ini位置或php -d 来设置某一项的值
- 运行时可以利用 ini_set() / ini_get()
- 也可以利用 `Apache httpd.conf中设置`_
.. _apache httpd.conf中设置: http://ca3.php.net/manual/en/configuration.changes.php
PHP.ini - 格式
==========================
.. code-block:: ini
; allow_call_time_pass_reference
; Default Value: On
; Development Value: Off
; Production Value: Off
allow_call_time_pass_reference = Off
PHP.ini - 常用选项
========================
.. code-block:: ini
expose_php = On
; 大多数情形下,生产做事器该当设置为Off
error_reporting = E_ALL & ~E_DEPRECATED & ~E_NOTICE
; 生产模式一样平常可以关闭E_NOTICE以防止log过大
display_errors = Off
log_errors = On
error_log = /var/log/php_errors.log
include_path = ".:/usr/share/php"
; 没有把 . 加入include_path导致在程序里无法按照相对路径require
PHP.ini - 常用选项
===============================
.. code-block:: ini
max_execution_time = 30
memory_limit = 128M
; 如果128M还不足用,请检讨程序逻辑
post_max_size = 8M
register_globals = Off
magic_quotes_gpc = Off
magic_quotes_runtime = Off
PHP.ini - 常用选项
===============================
.. code-block:: ini
allow_url_fopen = On
allow_url_include = Off
default_socket_timeout = 60
date.timezone = Asia/Chongqing
extension=msql.so
课后作业
===================
1. 通读字符串所有函数手册;
#. 通读数组函数所有手册;
#. 实际操作字符串所有的函数及考试测验其参数组合(可选参数可以忽略);
#. 实际操作数组所有的函数及考试测验其参数组合(可选参数可以忽略);
#. 完成一个文件上传页面示例;
#. 修正php.ini中的error_reporting参数进行缺点掌握;
#. 安装一个php扩展,如memcache或者 pdo_mysql,然后通过php_info()/php -i检讨是否安装成功。
Thanks
=================
.. class:: takahashi4
Thanks!
Q & A
=================
.. class:: takahashi4
Questions?
str_replace() 过滤危险字符
list() 函数的学习
调试追踪 debug_backtrace debug_print_backtrace
mysql5.1 的一个bug, select from user where id in(1,'2'); 这样的语句在5.1里面就相称于没有索引了 会全文检索,效率可就差了,修正 in (1,2) 或者('1','2')
var_export()
文件上传的时候 input type=file form的type enctype ...形式
=== 比较的是两个变量的本身字符 和 类型
__call() __callStatic() 做冗错机制比较好
================
PHP运用技巧(二)
================
:作者: @李枨煊 (4061)
:Email: chengxuan@staff.sina.com.cn
调查
===========================================
- 知道PHP中INT的最大值
- 理解GBK和UTF8
- 利用过mbstring
- PHP中非常与缺点的差异
目录
===========================================
- PHP版本比较及分外流程语句写法
- 数据类型
- 手册的利用
- 多字节(中文)字符串处理
- PHP缺点处理
- 常见缺点
PHP版本比较
===========================================
============ ===== ======= =======
项目 PHP4 PHP5.2 PHP5.3
============ ===== ======= =======
面向工具支持 差 好 极好
类与工具 是 是 是
访问掌握 否 是 是
析构方法 否 是 是
工具迭代 否 是 是
工具自动加载 否 是 是
命名空间 否 否 是
匿名函数 否 否 是
CGI进程名称 php php-cgi php-cgi
============ ===== ======= =======
如何选择PHP版本
===========================================
x.y.z
---------------------------
- x.y 只管即便与生做事器同等或高于做事器版本
- z 尽可能的选择最高版本(非RC/Beta)
有问题的PHP版本
---------------------------
- PHP5.3.5 源代码被入侵
- ver < PHP5.2.5 json_decode BUG严重
PHP分外的流程掌握写法
===========================================
- switch...case 中可以利用运算语句
- break x 可以跳出多层循环
- if...endif(while/for/foreach等同样适用) 写法
- 可变变量 $$a
- 中文变量 $用户名 = 'xxx';
数据类型
==========================================
弱类型 不即是 无类型
---------------------
======== =========================
int $var = 1;
float $var = 1.0;
string $var = '1';
boolean $var = true;
array $var = array(1,2,3);
Object $var = new stdClass;
NULL $var = null;
Resource $var = fopen('xxx', 'r');
======== =========================
数据类型间的转换
==========================================
- (int), (integer) - 转换为 整型(integer)
- (bool), (boolean) - 转换为 布尔型(boolean)
- (float), (double), (real) - 转换为 浮点型(float)
- (string) - 转换为 字符串(string)
- (binary) - 转换为二进制 字符串(string) (PHP 6)
- (array) - 转换为 数组(array)
- (object) - 转换为 工具(object)
- (unset) - 转换为 NULL (PHP 5)
例:$var = (int)$var;
INT长度限定
==========================================
- 查看INT的最大值可以利用常量(PHP_INT_MAX)
- 32位操作系统INT的最大值为:2147483647
- 64位操作系统INT的最大值为:9223372036854775807
- 面对巨大的整型数字(如UID/微博ID),建议利用字符串表示
数据的比较
==========================================
$a == $b 即是
$a === $b 全等(PHP 4 引进,同时比较类型)
PHP弱类型的底层实现
==========================================
- Zend/zend.h
- struct _zval_struct
- typedef union _zvalue_value
手册的利用
==========================================
- 手册是工具
- 手册是最好的学习资料
- PHP手册在线/下载地址: http://php.net/docs.php
如何利用手册查找函数
==========================================
#) 利用索引 猜
#) 利用干系函数和索引定位目录 找
#) 利用目录分类一层一层 找
多字节编码
===========================================
为什么要用多字节编码?
-------------------------------------------
处理多字节编码的字符串需把稳些什么?
-------------------------------------------
如何方便的处理多字节编码字符串?
-------------------------------------------
多字节编码(GBK)
===========================================
字符有一字节和双字节,00–7F(0-127)范围是一位,和ASCII保持同等,此范围内严格上说有96个笔墨和32个掌握符号。
之后的双字节中,前一字节是双字节的第一位。
总体上说第一字节的范围是81–FE(也便是不含80和FF),第二字节的一部分领域在40–FE,其他领域在80–FE。
参考资料: http://zh.wikipedia.org/wiki/GBK
多字节编码(UTF-8)
===========================================
- 0xxxxxxx
- 110xxxxx 10xxxxxx
- 1110xxxx 10xxxxxx 10xxxxxx
- 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
- 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
- 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
参考资料: http://zh.wikipedia.org/wiki/UTF8
多字节(中文)字符串处理
==========================================
- 设置默认字符集: mb_internal_encoding('utf-8');
- 获取字数: mb_strlen();
- 按字数截取字符串: mb_substr();
- 获取字符宽度: mb_strwidth();
- 按字符宽度截取: mb_strimwidth();
- 按字节数截取: mb_strcut();
- 编码转换:mb_convert_encoding();
PHP缺点处理
==========================================
掌握缺点的输出
----------------------------------
自定义缺点处理程序
----------------------------------
出错后如何定位出出错的地方
----------------------------------
PHP的缺点级别
==========================================
影响PHP缺点输出的干系配置
--------------------------
#) php.ini
#) error_reporting
#) display_errors
#) runtime php code
#) error_reporting()
#) ini_set()
error_reporting 配置
==========================================
- 配置值参考: http://hk.php.net/manual/zh/errorfunc.constants.php
- 配置方法参考:
- E_ALL
- E_ALL & ~E_NOTICE
- E_ALL | E_STRICT
- E_ALL | E_STRICT & ~E_NOTICE
自定义缺点处理程序
==========================================
- 自定义缺点函数 set_error_handler
- 自定义非常处理 set_exception_handler
- 还原系统默认处理缺点函数 restore_error_handler
- 还原系统默认处理非常 restore_exception_handler
- 抛出用户自定义缺点 trigger_error (E_USER_)
调试追踪
==========================================
- 究竟外层是怎么调用到底层方法的?
- debug_backtrace
- debug_print_backtrace
- 有没有更好的办法?
- 结合 set_error_handler,出错后自动追踪
常见缺点
==========================================
措辞本身的误导性
--------------------------------
写错的语句仍可解析为精确语句
--------------------------------
手册的不完全性
--------------------------------
编写PHP代码不严谨
--------------------------------
……
--------------------------------
常见缺点(头已输出)
==========================================
Cannot modify header information - headers already sent by xxx
- 发送header(含cookie)前不要有任何输出
- 把稳 <?php 前有没有空格
- 如果当前文件只有PHP代码,可不写 ?>
- 把稳是否有utf8 BOM头
常见缺点(==)
==========================================
.. code-block:: php
<?php
$a = 'weibo';
if($a = 't') {
echo 'true';
} else {
echo 'false';
}
//结果输出true
常见缺点(优先级)
==========================================
.. code-block:: php
<?php
$result = (int) 0.1+0.9;
echo $result;
//结果输出0.9
常见缺点(分号)
==========================================
.. code-block:: php
<?php
$var = false;
if($var);
{
echo 'ok';
}
//以上程序会输出ok
常见缺点(类型转换后的值)
==========================================
.. code-block:: php
<?php
$a = false;
$a = (array)$a;
if($a) {
echo 'true';
} else {
echo 'false';
}
//结果输出true
常见缺点(丢失的数组KEY)
==========================================
.. code-block:: php
<?php
$arr = array(
110 => 'weibo',
111 => 'event',
112 => 'q',
113 => 'screen',
114 => 'service',
);
$result = array_slice($arr, 1, 3);
print_r($result);
常见缺点(PHP BUG)
==========================================
PHP BUG: http://bugs.php.net/
感激大家
============
:Author: @李枨煊 (4061)
:Email: chengxuan@staff.sina.com.cn
作业
==========================================
- 阅读手册mbstring部分
- 考试测验利用mbstring函数
- 考试测验调节各种缺点级别设置
- 理解 https://bugs.php.net/
- 理解UTF8编码 http://zh.wikipedia.org/wiki/UTF8 (可选)
- 编写一个自定义缺点函数,将缺点转换为非常 (可选)