最近遇到了一个问题,所以就把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,如下图

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()里面设置charsethtml的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;
?>

结果显示不乱码。

查看一下网页源代码:

对比和总结一下上面三个方法:

  1. php的header()以及html的meta都没有设置charset的时候,由浏览器的默认编码决定是否乱码
  2. 一般情况下,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.confhttp{}模块里面,你可以设置成你想要的值。比如说你想要是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,这样的话可以减少浏览器的嗅探。但具体情况与浏览器有关。