最近遇到了一个问题,所以就把php相关的编码知识整理了一下。本文主要涉及php乱码相关知识
php代码文件的编码
有时候会在一些老代码里面看到乱码的中文注释,还挺抓狂的,索性没影响到代码逻辑。╮( ̄▽ ̄)╭
当然最好不要在具体的代码逻辑里面写中文,不然乱码了就不太好了。
为了团队协作,php代码文件当然最好是是UTF-8编码。在phpstorm等IDE里面都可以设置。
浏览器中文显示乱码
上面说到,为了团队协作,php代码文件最好使用UTF-8编码,尽量减少在代码逻辑里面写中文。
但如果,要使用php输出一个html文件,不可避免里面会有中文。此时这个中文是UTF-8编码的。
举个例子,php输出一个html文件
<?php
$str = '<html><head><title>test中文</title></head></html>';
echo $str;
?>
但是它在浏览器里面却乱码了,效果如下图所示
查看一下网页源代码,如下图:
查看一下Response的header里面的Content-Type
,如下图
解决上方这个乱码有如下几种方法:
方法一、更改浏览器的编码
试想一下,我php里面的中文是utf-8的,但是显示在safari浏览器里面却乱码了,说明浏览器默认不是utf-8编码。
到Safari->Preference->Advanced->Default encoding里面查看一下默认编码。
果然!Safari默认是ISO Latin 1
,把它改成UTF-8
,刷新一下,就能够正常显示了。
但这是治标不治本,不可能让所有普通用户都去改浏览器的编码。
下面请看其他方法。
方法二、php在header里面设置charset
<?php
// 在header里面设置Content-Type以及编码
header('Content-Type: text/html; charset=utf-8');
$str = '<html><head><title>test中文</title></head></html>';
echo $str;
?>
ok,这个时候再显示在浏览器里面的时候就不是乱码了,效果如下:
查看一下网页源代码,如下图:
查看一下Response的header里面的Content-Type
,如下图,可以看到Content-Type
是在php里面设置的text/html; charset=utf-8
方法三、在html里面设置meta标签,里面指定**charset
**
<?php
$str = '<html><head><meta charset="UTF-8"><title>test中文</title></head></html>';
echo $str;
?>
查看一下网页源代码,如下图:
查看一下Response的header里面的Content-Type,如下图
在php的header()里面设置charset
vs html的meta里面设置charset
假如说代码如下:
<?php
$str = '<html><head><meta charset="ISO-8559-1"><title>test中文</title></head></html>';
echo $str;
?>
那么明眼人一看就知道会乱码。因为你设置了meta的charset是ISO-8559-1
,用它来解释UTF-8
编码的中文的时候会乱码。
查看一下网页源代码:
如果在**php的header()里面设置charset
和html的meta里面设置charset
**都设置了,但两者不一样呢?以谁为准?
假如说代码如下:
<?php
header('Content-Type: text/html; charset=utf-8');
$str = '<html><head><meta charset="ISO-8559-1"><title>test中文</title></head></html>';
echo $str;
?>
结果显示不乱码。
查看一下网页源代码:
对比和总结一下上面三个方法:
- php的header()以及html的meta都没有设置charset的时候,由浏览器的默认编码决定是否乱码
- 一般情况下,php的header()里设置的charset的优先级高于html的meta设置的charset的优先级。(具体情况与浏览器的具体实现方式有关)
方法四、修改php.ini里的default_charset
php.ini文件里面有default_charset
这个设置。从php5.6以后,它就被默认设置为UTF-8
了。(default_charset = "UTF-8"
),但是低版本php里面可能没有设置或者默认为iso-8559-1
。
在php.ini里面设置default_charset
之后,就不需要再在代码里面设置header('Content-Type: text/html; charset=utf-8');
了 。
// set default_charset = "UTF-8" in php.ini
<?php
$str = '<html><head><title>test中文</title></head></html>';
echo $str;
?>
Response header里面的Content-Type
默认会被加上charset=utf-8
,效果和手动在php里面写上header('Content-Type: text/html; charset=utf-8');
是一样的。
这样的话也能解决乱码问题。
**注意:**修改过php.ini之后,重启php-fpm后才能生效
(当然,如果不想改动php.ini,也可以在代码里面使用ini_set()
来临时修改里面的值)
方法五、修改服务器的charset
上面提到**方法二、php在header里面设置charset
和方法四、修改php.ini里的
default_charset``**,归根究底是在设置response里面的header。
既然http请求是由服务器给出response的,那么设置服务器的charset也能够达到这个效果。
nginx的charset在nginx.conf
的http{}
模块里面,你可以设置成你想要的值。比如说你想要是GBK,那么就设置charset GBK
。
而我需要的是UTF-8编码,就设置charset UTF-8
。如果并不需要设置服务器的charset的话,可以用#
注释掉。
注意,修改完nginx.conf之后,别忘了重启nginx
下面总结说一下各个方法的优先级
这三个response header里charset的优先级是:php header()
> php.ini charset
> nginx.conf charset
关于Content-Type里面的charset与meta的charset那个优先级更高:一般来说Content-Type的charset高于meta的charset,这样的话可以减少浏览器的嗅探。但具体情况与浏览器有关。