想必 iconv 这个扩展的相关函数大家多少都接触过,做为 PHP 的默认扩展它已经存在了很久,也是我们在操作字符编码时经常会使用的函数。不过除了 iconv() 这个函数外,你还知道它的其它函数吗?今天,我们就来学习一下 iconv 扩展中的各种好玩的函数。

iconv 设置及获取信息

首先,就是我们可以设置 iconv 扩展中默认定义的输出和输出字符编码格式。

iconv_set_encoding("internal_encoding", "UTF-8");
// Deprecated: iconv_set_encoding(): Use of iconv.internal_encoding is deprecated
iconv_set_encoding("output_encoding", "ISO-8859-1");
// Deprecated: iconv_set_encoding(): Use of iconv.output_encoding is deprecated
var_dump(iconv_get_encoding());
// array(3) {
// ["input_encoding"]=>
// string(5) "UTF-8"
// ["output_encoding"]=>
// string(10) "ISO-8859-1"
// ["internal_encoding"]=>
// string(5) "UTF-8"
// }

iconv_set_encoding() 接收两个参数,一个是设置的属性类型,一个是设置的编码格式。属性类型包括 internal_encoding 、 input_encoding 和 output_encoding ,分别代表内部的、输入的、输出的编码格式。在这段测试代码中,我们将 internal_encoding 设置为 UTF8 ,将 output_encoding 设置为 ISO-8859-1 ,然后使用 iconv_get_encoding() 打印出当前环境中相关的 iconv 属性设置信息,可以看到,在默认情况下当前环境中的 input_encoding 也是 UTF8 格式。

不过需要说明的是,iconv_set_encoding() 已经是不推荐使用的函数了,或者说不推荐使用这个函数来设置上面的三种属性类型,它们会报出过时警告信息。现在更推荐直接使用 php.ini 中的 default_charset 来进行设置。

iconv 根据编码获取字符长度、指定位置及截取字符串

在面对中文字符串的操作时,我们使用默认的 strlen() 之类的函数返回的中文字符长度是不正确的,这就牵涉到编码的问题。一般情况下,UTF8 是占三个字节,而 GBK 是占两个字节,所以说一个汉字对于 strlen() 来说如果是在 UTF8 环境中会返回 3 。当然,现在大多数情况下我们会使用 MB 库扩展的相关函数来处理这种问题,不过 iconv 也为我们提供了几个用于字符串操作的函数。

echo iconv_strlen("测试长度测试长度"), PHP_EOL; // 8
echo iconv_strlen("测试长度测试长度", 'ISO-8859-1'), PHP_EOL; // 24
echo iconv_strlen("测试长度测试长度", 'GBK'), PHP_EOL; // 12 echo '======', PHP_EOL; echo iconv_strpos("测试长度测试长度", "长"), PHP_EOL; // 2
echo iconv_strpos("测试长度测试长度", "长", 0, 'ISO-8859-1'), PHP_EOL; // 6
echo iconv_strpos("测试长度测试长度", "长", 0, 'GBK'), PHP_EOL; // echo '======', PHP_EOL; echo iconv_strrpos("测试长度测试长度", "长"), PHP_EOL; // 6
echo iconv_strrpos("测试长度测试长度", "长", 'ISO-8859-1'), PHP_EOL; // 18 echo '======', PHP_EOL; echo iconv_substr("测试长度测试长度", 2, 4), PHP_EOL; // 长度测试
echo iconv_substr("测试长度测试长度", 6, 12, 'ISO-8859-1'), PHP_EOL; // 长度测试
echo iconv_substr("测试长度测试长度", 3, 6, 'GBK'), PHP_EOL; // 长度测试

iconv_strlen() 就是获取字符串长度的,如果不给第二个参数就按默认的字符集编码来获取字符串长度。在测试代码中可以看出,同样八个中文字的内容,使用不同的编码返回的数量是不相同的。在这里,我们发现 iconv 中对于 GBK 的中文是 1.5 个字节,也就是 8 个中文字占用了 12 个字节的长度。

iconv_strpos() 和 iconv_strrpos() 和 strpos() 的作用一样,返回某个字符第一次出现的位置,一个是从前往后(从左往右),另一个是从后往前(从右往左)。它们的第三个参数是偏移量,也就是查找到指定字符后再偏移几个单位。从这里我们可以看出,对于 GBK 编码的操作是有问题的,因为在 iconv 中,GBK 是 1.5 个字节,这样会带来单个字符无法定位的问题。

iconv_substr() 很明显地就是截取字符串的函数了,同样我们要根据编码格式来指定它的截取位置。

iconv 转换字符编码

接下来就是本尊 iconv() 函数的使用的了,其实它反而没什么可讲的,将指定的编码转换成另外一种编码而已,相信这个函数大家都不陌生。

$phone = file_get_contents('https://tcc.taobao.com/cc/json/mobile_tel_segment.htm?tel=13888888888');

print_r($phone);
// __GetZoneResult_ = {
// mts:'1388888',
// province:'����',
// catName:'�й��ƶ�',
// telString:'13888888888',
// areaVid:'30515',
// ispVid:'3236139',
// carrier:'�����ƶ�'
// } print_r(iconv('GBK', 'UTF-8', $phone));
// __GetZoneResult_ = {
// mts:'1388888',
// province:'云南',
// catName:'中国移动',
// telString:'13888888888',
// areaVid:'30515',
// ispVid:'3236139',
// carrier:'云南移动'
// } print_r(iconv('GBK', 'ISO-8859-1//IGNORE', $phone));
// __GetZoneResult_ = {
// mts:'1388888',
// province:'',
// catName:'',
// telString:'13888888888',
// areaVid:'30515',
// ispVid:'3236139',
// carrier:''
// }

我们找到的这个淘宝用于查找手机号相关信息的开放接口,返回的正好是 GBK 类型的数据。当我们直接打印结果时,在 UTF8 环境下它就会输出乱码信息。这时,我们通过 iconv() 函数就能够轻松地将编码转换成 UTF8 格式,并正确打印出了结果。第三个测试中,我们在要转换到的字符集编码类型后面加上了 //IGNORE ,目的就是忽略无法转换的内容,所以可以看出在最后我们转换到错误的 ISO-8859-1 时,中文信息就全都没有了,因为它们无法转换就被忽略掉了。

mime 邮件头操作

最后我们再看一个非常不常用的内容,那就是 iconv 还可以直接转换 mime 头中的编码内容信息。这个 mime 头信息其实就是标示当前文件或者内容的 mime 类型。平常我们会根据它来判断上传的文件是否正确,除些之外,在邮件发送中,这个 mime 头的使用也非常广泛。如果做过邮件发送接收相关的开发并且抓过包的同学一定见过下面的内容。

headers_string = <<<EOF
Subject: =?UTF-8?B?UHLDvGZ1bmcgUHLDvGZ1bmc=?=
To: example@example.com
Date: Thu, 1 Jan 1970 00:00:00 +0000
Message-Id: <example@example.com>
Received: from localhost (localhost [127.0.0.1]) by localhost
with SMTP id example for <example@example.com>;
Thu, 1 Jan 1970 00:00:00 +0000 (UTC)
(envelope-from example-return-0000-example=example.com@example.com)
Received: (qmail 0 invoked by uid 65534); 1 Thu 2003 00:00:00 +0000
EOF;

Subject 字符就是邮件的标题,To 就是发送人的邮件地址。在这里我们主要看一下 Subject 的内容,它的开头就有一段描述这个字段使用的编码信息的内容,?UTF-8 ,然后后面是一堆看不懂的东西。其实我们简单地能看出来这是一个 base64 编码的内容,如果将它解码在对应的编码内容下就能看到原文信息。不过,这个时候我们也可以使用 iconv 来直接转换它的编码。

$headers =  iconv_mime_decode_headers($headers_string, 0, "ISO-8859-1");
var_dump($headers);
// array(5) {
// ["Subject"]=>
// string(15) "Pr�fung Pr�fung"
// ["To"]=>
// string(19) "example@example.com"
// ["Date"]=>
// string(30) "Thu, 1 Jan 1970 00:00:00 +0000"
// ["Message-Id"]=>
// string(21) "<example@example.com>"
// ["Received"]=>
// array(2) {
// [0]=>
// string(204) "from localhost (localhost [127.0.0.1]) by localhost with SMTP id example for <example@example.com>; Thu, 1 Jan 1970 00:00:00 +0000 (UTC) (envelope-from example-return-0000-example=example.com@example.com)"
// [1]=>
// string(57) "(qmail 0 invoked by uid 65534); 1 Thu 2003 00:00:00 +0000"
// }
// }

看到了么?不仅直接转了编码,而且还将 mime 头格式转换成了 PHP 中的数组格式。当然,我们这里测试的代码是将正常的内容转换到 ISO-8859-1 了,反而是出现了乱码。下面我们再拿一个中文邮件的例子来看下。

$headers_string = <<<EOF
Return-Path: <bluesky7810@163.com>
Delivered-To: bhw98@sina.com
Received: (qmail 75513 invoked by alias); 20 May 2002 02:19:53 -0000
Received: from unknown (HELO bluesky) (61.155.118.135)
by 202.106.187.143 with SMTP; 20 May 2002 02:19:53 -0000
Message-ID: <007f01c3111c$742fec00$0100007f@bluesky>
From: "=?gb2312?B?wLbAtrXEzOwNCg==?=" <bluesky7810@163.com>
To: "bhw98" <bhw98@sina.com>
Cc: <bhwang@jlonline.com>
Subject: =?gb2312?B?ztK1xLbgtK6/2rPM0PI=?=
Date: Sat, 20 May 2002 10:03:36 +0800
MIME-Version: 1.0
Content-Type: multipart/mixed;
boundary="----=_NextPart_000_007A_01C3115F.80DFC5E0" EOF;
$headers = iconv_mime_decode_headers($headers_string, 0, "UTF-8");
var_dump($headers);
// array(11) {
// ["Return-Path"]=>
// string(21) "<bluesky7810@163.com>"
// ["Delivered-To"]=>
// string(14) "bhw98@sina.com"
// ["Received"]=>
// array(2) {
// [0]=>
// string(58) "(qmail 75513 invoked by alias); 20 May 2002 02:19:53 -0000"
// [1]=>
// string(101) "from unknown (HELO bluesky) (61.155.118.135) by 202.106.187.143 with SMTP; 20 May 2002 02:19:53 -0000"
// }
// ["Message-ID"]=>
// string(40) "<007f01c3111c$742fec00$0100007f@bluesky>"
// ["From"]=>
// string(38) ""蓝蓝的天
// " <bluesky7810@163.com>"
// ["To"]=>
// string(24) ""bhw98" <bhw98@sina.com>"
// ["Cc"]=>
// string(21) "<bhwang@jlonline.com>"
// ["Subject"]=>
// string(21) "我的多串口程序"
// ["Date"]=>
// string(31) "Sat, 20 May 2002 10:03:36 +0800"
// ["MIME-Version"]=>
// string(3) "1.0"
// ["Content-Type"]=>
// string(16) "multipart/mixed;"
// }

这个中文邮件 mime 头的 Subject 指定的是 GB2312 。通过 iconv_mime_decode_headers() 函数我们将整个头信息中的内容都转换成了 UTF8 ,这时就可以正常显示所有的内容信息了。当然,我们也可以对单个的 mime 字段进行转码。

echo iconv_mime_decode("Subject: =?gb2312?B?ztK1xLbgtK6/2rPM0PI=?=", 0, 'UTF-8'), PHP_EOL; // Subject: 我的多串口程序

除了对于接收的信息进行编码转换之外,我们还可以自己编码相关的内容进行发送使用。

$preferences = array(
"input-charset" => "UTF-8",
"output-charset" => "GBK",
"line-length" => 76,
"line-break-chars" => "\n"
);
$preferences["scheme"] = "Q";
echo iconv_mime_encode("Subject", "测试头", $preferences), PHP_EOL;
// Subject: =?GBK?Q?=B2=E2=CA=D4=CD=B7?=
$preferences["scheme"] = "B";
echo iconv_mime_encode("Subject", "测试头", $preferences), PHP_EOL;
// Subject: =?GBK?B?suLK1M23?=

iconv_mime_encode() 函数就是用于进行 mime 头编码的函数。第一个参数是 mime 字段名,第二个参数是字段值,第三个函数就是我们进行编码的参数了。编码参数的内容通过字段名就可以看出来,从什么编码转换成什么编码,行的长度多少,换行符是什么。另外它还有一个 scheme 字段,就是用于指定编码结果的类型,如果设置的是 B ,那么编码结果就会再加一层 base64 操作。

总结

是不是感觉奇怪的小姿势又增加了呀?没错,在没刷文档之前我也只知道一个 iconv 而已。甚至在学习了这些内容之后我才发现了邮件信息原来是这样编码的,自己都感觉自己一下子高大上了。好了,不说废话了,自己动手试试吧!

测试代码:

https://github.com/zhangyue0503/dev-blog/blob/master/php/202011/source/2.学习PHP中的iconv扩展相关函数.php

参考文档:

https://www.cnblogs.com/onelikeone/p/7865596.html

https://www.php.net/manual/zh/book.iconv.php

关注公众号:【硬核项目经理】获取最新文章

添加微信/QQ好友:【xiaoyuezigonggong/149844827】免费得PHP、项目管理学习资料

知乎、公众号、抖音、头条搜索【硬核项目经理】

B站ID:482780532

学习PHP中的iconv扩展相关函数的更多相关文章

  1. 学习PHP中Fileinfo扩展的使用

    今天来学习的这个扩展其实现在也已经是标配的一个扩展了,为什么呢?因为 Laravel 框架在安装的时候它就是必须的一个扩展,没有打开它的话,连 Laravel 框架都是无法使用的. Fileinfo ...

  2. 深入学习PHP中的JSON相关函数

    在我们当年刚刚上班的那个年代,还全是 XML 的天下,但现在 JSON 数据格式已经是各种应用传输的事实标准了.最近几年开始学习编程开发的同学可能都完全没有接触过使用 XML 来进行数据传输.当然,时 ...

  3. 学习PHP中好玩的Gmagick图像操作扩展的使用

    在 PHP 的图像处理领域,要说最出名的 GD 库为什么好,那就是因为它不需要额外安装的别的什么图像处理工具,而且是随 PHP 源码一起发布的,只需要在安装 PHP 的时候添加上编译参数就可以了. G ...

  4. 学习PHP中的高精度计时器HRTime扩展

    不知道大家还记得在学校的时候体育测试时老师带的秒表吗?当枪声想起时,我们开始跑步,这时秒表启动,当我们跑过终点后,老师会按下按扭记录我们的成绩,这就是一个典型的定时器的应用.今天我们要学习的内容其实就 ...

  5. PHP中的MySQLi扩展学习(六)MySQLI_result对象操作

    在之前的文章中,我们就已经接触过 MYSQLI_result 相关的内容.它的作用其实就是一个查询的结果集.不过在 PDO 中,一般直接通过 query() 或者 PDOStatement 对象进行查 ...

  6. PHP中的MySQLi扩展学习(五)MySQLI_STMT对象操作

    就像 PDO 中的 PDO_Statment 对象一样,MySQLI_STMT 对象也是一个预处理语句所形成的对象,专门用来操作 MySQLi 所生成的预处理语句的.其实操作方式之类也都比较相似,不外 ...

  7. PHP中的MySQLi扩展学习(四)mysqli的事务与预处理语句

    对于 MySQLi 来说,事务和预处理语句当然是它之所以能够淘汰 MySQL(原始) 扩展的资本.我们之前也已经学习过了 PDO 中关于事务和预处理语句相关的内容.所以在这里,我们就不再多讲理论方面的 ...

  8. PHP中的MySQLi扩展学习(三)mysqli的基本操作

    我们继续 MySQLi 扩展的学习,上篇文章中提到过,MySQLi 的扩展相对于 PDO 来说功能更加的丰富,所以我们依然还会在学习过程中穿插各种 MySQLi 中好玩的方法函数.不过,今天的主角是 ...

  9. PHP中的MySQLi扩展学习(二)mysqli类的一些少见的属性方法

    虽说是少见的一些属性方法,但是可能还是有不少同学在日常的开发中使用过,这里只是学习了可能相对来说我们用得比较少的一些 mysqli 的属性或方法.就当是扩展一下自己的知识体系. 切换用户 首先就是切换 ...

随机推荐

  1. Linux中的DNS反解析

    安装bind软件包 yum -y install bind 查找配置文件路径 修改系统配置文件 配置反向解析文件 修改网卡信息,关闭防火墙 测试实验

  2. Python语言系列-07-面向对象2

    重构父类__init__方法 #!/usr/bin/env python3 # author:Alnk(李成果) # 需求:Dog类要新增一个实例属性,但是Cat类不需要 class Animal(o ...

  3. 【笔记】初探KNN算法(1)

    KNN算法(1) 全称是K Nearest Neighbors k近邻算法: 思想简单 需要的数学知识很少 效果不错 可以解释机器学习算法使用过程中的很多细节问题 更加完整的刻画机器学习应用的流程 其 ...

  4. brew换源

    转自:https://blog.csdn.net/gorwayne/article/details/107359912 第一步,替换brew.git cd "$(brew --repo)&q ...

  5. CTFre-getit-WP

    攻防世界getit-WP 日子忙起来人也就忙,CTF慢慢刷,慢就是快. 下载之后,也没管别的直接就IDA打开:下载之后,也没管别的直接就IDA打开: 随便点点看得到三个可以字符串.F5看看: 懂个大概 ...

  6. zookeeper同一台服务器创建伪集群

    下载zk wget https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/zookeeper-3.7.0/apache-zookeeper-3.7 ...

  7. null的坑 和 比较运算符、相等运算符的隐式转换问题 (在javascript中,null>=0 为真,null<=0 为真,null==0却为假,null到底是什么?)

    null在关系运算中的坑 & 关系运算符的隐式转换问题 注意: 比较运算符 和 相等运算符 的 ECMAscript 语法实现不同. 比较运算符 和 相等运算符 对数据进行了隐式转换, 相当于 ...

  8. Collectors.reducing总结

    Collectors.reducing总结 1. 方法签名 一个参数 public static <T> Collector<T, ?, Optional<T>> ...

  9. WPF 中的 路由事件

    public class ReportTimeEventArgs:RoutedEventArgs { public ReportTimeEventArgs(RoutedEvent routedEven ...

  10. 【转】ps命令详解与使用

    ps 概述 Linux中的ps命令是Process Status的缩写.ps命令用来列出系统中当前运行的那些进程.ps命令列出的是当前那些进程的快照,就是执行ps命令的那个时刻的那些进程,如果想要动态 ...