# 字符串函数
[toc]
## 1. 字符串语法
- 字符串上限: 2G
- 字符串中每个字符使用一个字节表示,仅支持 256 个,不支持`Unicode`
- 有四种方式创建字符串
| 序号 | 方式 | 描述 |
| ---- | ------- | ------------------------ |
| 1 | 单引号 | 全部内容视为纯文本 |
| 2 | 双引号 | 可解析变量和转义特殊字符 |
| 3 | heredoc | 与双引号类似 |
| 4 | nowdoc | 与单引号类似 |
### 1.1 单引号
| 单引号 | 转义符 | 特殊字符 | 变量 |
| ------ | ------ | -------- | ------ |
| 转义 | 转义 | 不转义 | 不解析 |
### 1.2 双引号
- 双引号对内容的处理
| 双引号 | 转义符 | 特殊字符 | 变量 |
| ------ | ------ | -------- | ---- |
| 转义 | 转义 | 转义 | 解析 |
- 双引号中的变量, 应该使用大括号`{}`限定标识符识别范围,如: "{\$email}"
- 双引号中的特殊字符列表
| 序号 | 特殊字符 | 描述 |
| ---- | -------------------- | ----------------------------------------------------------------- |
| 1 | `\n` | 换行(ASCII 字符集中的 LF 或 0x0A (10)) |
| 2 | `\r` | 回车(ASCII 字符集中的 CR 或 0x0D(13)) |
| 3 | `\t` | 水平制表符(ASCII 字符集中的 HT 或 0x09 (9)) |
| 4 | `\v` | 垂直制表符(ASCII 字符集中的 VT 或 0x0B (11))(自 PHP 5.2.5 起) |
| 5 | `\e` | Escape(ASCII 字符集中的 ESC 或 0x1B (27))(自 PHP 5.4.0 起) |
| 6 | `\f` | 换页(ASCII 字符集中的 FF 或 0x0C (12))(自 PHP 5.2.5 起) |
| 7 | `\\` | 反斜线 |
| 8 | `\$` | 美元标记 |
| 9 | `\"` | 双引号 |
| 10 | `\[0-7]{1,3}` | 符合该正则表达式序列的是一个以八进制方式来表达的字符 |
| 11 | `\x[0-9A-Fa-f]{1,2}` | 符合该正则表达式序列的是一个以十六进制方式来表达的字符 |
### 1.3 heredoc
| 双引号 | 转义符 | 特殊字符 | 变量 |
| ------ | ------ | -------- | ---- |
| 不转义 | 不转义 | 转义 | 解析 |
### 1.4 nowedoc
| 单引号 | 转义符 | 特殊字符 | 变量 |
| ------ | ------ | -------- | ------ |
| 不转义 | 不转义 | 不转义 | 不解析 |
示例代码: `demo7.html`
```php
<?php
# 字符串
// 1. 单引号
// 转义符反斜线只转义自身和单引号
// 转义符不转义特殊字符
// 不解析内部变量
$str = 'string';
echo 'This \'s a \r\n $str \\';
echo '<hr>';
// 2. 双引号
// 转义符反斜线只转义自身, 双引号, 特殊字符
// 解析内部变量
echo "This \"s a \r\n {$str} \\";
echo '<hr>';
// 3. heredoc
// 功能与双引号定义的字符串类似, 内部双引号不需要转义
// 标识符HELLO起始与结束符后必须换行,不能有任何输出,包括空格
// 标识符HELLO的定界符双引号,可以省略, 默认就是Heredoc
echo <<< "HELLO"
This "s a \r\n $str \\
HELLO;
echo '<hr>';
// heredoc: 特别适合输出大量的html代码,例如html与php混编的模板文件
$book = ['id' => 123, 'name' => 'php开发指南', 'price' => 99];
echo <<< BOOK
<ul style="list-style: none;">
<li>ID: {$book['id']}</li>
<li>书名: {$book['name']}</li>
<li>价格: {$book['price']}</li>
</ul>
BOOK;
echo '<hr>';
// 4. nowdoc
// 功能与单引号字符串类似, 内部单引号不需要转义
// 转义符就是普通字符
echo <<< 'EOT'
This 's a \r\n $str \;
EOT;
echo '<hr>';
// nowdoc非常适合嵌入大段php代码或大段不需要转义特殊字符,也不需要解析变量的文本
// 经常用于初始化类属性和类常量等需要静态数据的场合
class Demo
{
const STR = <<< 'FOO'
mail: admin@php.cn <br>
qq: 498668472 <br>
work-unit: php中文网 <br>
FOO;
}
echo Demo::STR;
```
---
## 2. 打印输出函数
| 序号 | 函数 | 说明 |
| ---- | ------------- | -------------------------------- |
| 1 | echo | 输出一个或多个字符串 |
| 2 | print | 输出字符串 |
| 3 | printf | 输出格式化字符串 |
| 4 | vprintf | 与 printf()区别在于参数在数组中 |
| 5 | sprintf | 返回格式化字符串,存入变量/文件中 |
| 6 | vsprintf | 与 sprintf()区别在于参数在数组中 |
| 7 | fprintf | 将格式化字符串写入文件流中 |
| 8 | vfprintf | 与 fprintf()区别在于参数使用数组 |
| 9 | sscanf | 根据指定格式解析输入的字符 |
| 10 | number_format | 以千位分隔符方式格式化一个数字 |
示例代码: `demo8.php`
```php
# 打印输出函数
// printf(): 输出格式化字符串
printf('SELECT * FROM `%s` LIMIT %d', 'staffs', 5);
echo '<br>';
// vprintf(),与printf()区别在于参数使用数组
vprintf('SELECT * FROM `%s` LIMIT %d', ['staffs', 15]);
echo '<hr>';
// sprintf(): 返回格式化字符串,可存入变量或文件中
echo sprintf('SELECT * FROM `%s` LIMIT %d', 'staffs', 25);
echo '<br>';
// vsprintf(): 与sprintf()区别在于参数使用数组
echo vsprintf('SELECT * FROM `%s` LIMIT %d', ['staffs', 35]);
echo '<hr>';
// fprintf(): 将格式化字符串写入文件流中
$handle = fopen('test.txt', 'w') or die('open file fail');
fprintf($handle, 'SELECT * FROM `%s` LIMIT %d', 'staffs', 45);
echo file_get_contents('test.txt');
echo '<br>';
// vfprintf(): 与fprintf()区别在于参数使用数组,而不是独立变量
$handle = fopen('test1.txt', 'w') or die('open file fail');
vfprintf($handle, 'SELECT * FROM `%s` LIMIT %d', ['staffs', 55]);
echo file_get_contents('test1.txt');
echo '<hr>';
// sscanf(): 按指定格式输入数据
// 返回索引数组, 可通过list()将输入的数据存入变量中
var_dump(sscanf('SN-123456', 'SN-%d'));
list($sn) = sscanf('SN-123456', 'SN-%d');
echo $sn;
echo '<hr>';
// number_format($num, 保留位数, 小数点符, 千位分隔符)
echo number_format(12345.67), '<br>'; // 12.345
echo number_format(12345.67, 2), '<br>'; // 12,345.67
echo number_format(12345.67, 2, '.', ''), '<br>'; // 12345.67
echo number_format(12345.67, 2, '.', ','), '<br>'; // 12,345.67
/**
* SELECT * FROM `staffs` LIMIT 5
* SELECT * FROM `staffs` LIMIT 15
* SELECT * FROM `staffs` LIMIT 25
* SELECT * FROM `staffs` LIMIT 35
* SELECT * FROM `staffs` LIMIT 45
* SELECT * FROM `staffs` LIMIT 55
* array(1) { [0]=> int(123456) } 123456
* 12,346
* 12,345.67
* 12345.67
* 12,345.67
*/
```
---
## 3 分割查询与替换函数
### 3.1 第一组
| 序号 | 函数 | 说明 |
| ---- | -------------- | ------------------------------ |
| 1 | implode | 将一个一维数组的值转化为字符串 |
| 2 | join | 别名 implode |
| 3 | explode | 使用一个字符串分割另一个字符串 |
| 5 | substr | 返回字符串的子串 |
| 6 | substr_count | 计算字串出现的次数 |
| 7 | substr_replace | 替换字符串的子串 |
| 8 | str_split | 将字符串转换为数组 |
| 9 | str_getcsv | 解析 CSV 字符串为一个数组 |
示例代码: `demo9.php`
```php
# 分割查询与替换函数
// implode(),一维数组转字符串
// 用指定字符将数组元素组装成一个字符串返回
echo implode(', ', ['html', 'css', 'js', 'php']), '<br>';
echo join(', ', ['html', 'css', 'js', 'php']), '<br>';
echo '<hr>';
// explode(), 使用一个字符串分隔另一个字符串
print_r(explode(',', 'localhost,root,root,utf8,3306'));
echo '<br>';
// 只要前3个元素,剩下的全部存入第4个元素中
print_r(explode(',', 'localhost,root,root,utf8,3306', 4));
echo '<br>';
// 与list()配合,将数组元素转为变量
list($host, $user, $pass) = explode(',', 'localhost,root,root,utf8,3306');
echo "$host, $user, $pass <br>";
echo '<hr>';
// substr($string, $start, $length): 返回字符串子串
echo substr('abcdef', 0), '<br>'; // abcdef
echo substr('abcdef', 2), '<br>'; // cdef
echo substr('abcdef', 2, 2), '<br>'; // cd
// 从最后一个开始返回到结束,即获取最后一个
echo substr('abcdef', -1), '<br>'; // f
// 从倒数第3个开始,获取到结束,即获取最后三个
echo substr('abcdef', -3), '<br>'; // def
// 从倒数第3个开始,获取2个
echo substr('abcdef', -3, 2), '<br>'; // de
echo '<hr>';
// substr_count($str,$needle, $offset, $length): 统计子串出现的次数
// 'is' 出现2次, 返回2
echo substr_count('This is a test', 'is'), '<br>';
// 从第4个字符开始计算`s is a test`,'is' 只出现1次, 返回1
echo substr_count('This is a test', 'is', 3), '<br>';
// 此时目标字符串中只剩下: `s i`, 'is'不存在了,返回: 0
echo substr_count('This is a test', 'is', 3, 3), '<br>';
echo '<hr>';
// substr_replace($string, $replace,$start,$length): 替换字符串中的子串
// 用子串替换掉原目标字符串
echo substr_replace('html,css,js,java', 'php', 0), '<br>';
// 将子串插入到目标字符串前面
echo substr_replace('html,css,js,java', 'php,', 0, 0), '<br>';
// 替换掉java
echo substr_replace('html,css,js,java', 'php', -4), '<br>';
// 删除掉css
echo substr_replace('html,css,js,java', '', 5, 4), '<br>';
// 该函数支持数组参数
// 将数组中每一个字符串元素做为目标字符串,用子串统一替换
$res = substr_replace(['id:101', 'id:203', 'id:908'], '0', 3, 3);
// 返回数组,可以转为字符串,便于查看
print_r($res);
echo implode('; ', $res), '<br>';
// 可以针对每一个元素内容进行个性化定制替换子串,如第2个替换子串是: '2',
$res = substr_replace(['id:101', 'id:203', 'id:908'], [1, 2, 3], 3, 3);
echo implode(';', $res), '<br>';
// 也可针对数组中每一个字符串元素,替换数量不同的字符
// id:101=>id:a01, id:203=>id:b3,替换2位,id:908=>id:c,3位被替换
$res = substr_replace(['id:101', 'id:203', 'id:908'], ['a', 'b', 'c'], 3, [1, 2, 3]);
echo implode(';', $res), '<br>';
echo '<hr>';
// str_split(): 将字符串转为数组,可指定每个数组元素的宽度
print_r(str_split('php.cn'));
echo '<br>';
print_r(str_split('php.cn', 2));
// 不支持多字符,显示乱码
print_r(str_split('php中文网'));
// 中文用3字节表示,3个一组切割, 实际工作中用mb字符扩展解决
print_r(str_split('php中文网', 3));
echo '<hr>';
// str_getcsv()
// 对于外部csv文件,之前通过文件操作函数:fopen()+fgetcsv()完成
$f = fopen('test2.csv', 'r');
while ($res = fgetcsv($f)) {
print_r($res);
echo '<br>';
}
// 现在可以利用这个str_getcsv()同样可以做到
// str_getcsv(): 返回一个csv字符串各部分内容组成的数组
print_r(str_getcsv('2, peter, peter@php.cn'));
echo '<br>';
// 打开csv将内容全部读到一个字符串
$csvStr = file_get_contents('test2.csv');
// 将读取的csv字符串按换行符分割为数组
$csvArr = explode("\n", $csvStr);
print_r($csvArr);
echo '<hr>';
// 遍历这个csv数组,得到每一个csv数据项
foreach ($csvArr as $csv) {
print_r(str_getcsv($csv));
echo '<br>';
}
// 运行结果
// html, css, js, php
// html, css, js, php
// Array ( [0] => localhost [1] => root [2] => root [3] => utf8 [4] => 3306 )
// Array ( [0] => localhost [1] => root [2] => root [3] => utf8,3306 )
// localhost, root, root
// abcdef
// cdef
// cd
// f
// def
// de
// 2
// 1
// 0
// php
// php,html,css,js,java
// html,css,js,php
// html,js,java
// Array ( [0] => id:0 [1] => id:0 [2] => id:0 ) id:0; id:0; id:0
// id:1;id:2;id:3
// id:a01;id:b3;id:c
// Array ( [0] => p [1] => h [2] => p [3] => . [4] => c [5] => n )
// Array ( [0] => ph [1] => p. [2] => cn ) Array ( [0] => p [1] => h [2] => p [3] => � [4] => � [5] => � [6] => � [7] => � [8] => � [9] => � [10] => � [11] => � ) Array ( [0] => php [1] => 中 [2] => 文 [3] => 网 )
// Array ( [0] => 1 [1] => admin [2] => admin@php.cn )
// Array ( [0] => 2 [1] => peter [2] => peter@php.cn )
// Array ( [0] => 3 [1] => jack [2] => jack@php.cn )
// Array ( [0] => 2 [1] => peter [2] => peter@php.cn )
// Array ( [0] => 1, admin, admin@php.cn [1] => 2, peter, peter@php.cn [2] => 3, jack, jack@php.cn )
// Array ( [0] => 1 [1] => admin [2] => admin@php.cn )
// Array ( [0] => 2 [1] => peter [2] => peter@php.cn )
// Array ( [0] => 3 [1] => jack [2] => jack@php.cn )
```
### 3.2 第二组
| 序号 | 函数 | 说明 |
| ---- | ------------ | ---------------------------------------- |
| 10 | str_pad | 使用另一个字符串填充字符串为指定长度 |
| 11 | str_repeat | 重复一个字符串 |
| 12 | str_replace | 子字符串替换 |
| 13 | str_ireplace | str_replace 的忽略大小写版本 |
| 14 | strtr | 转换指定字符 |
| 15 | str_shuffle | 随机打乱一个字符串 |
| 16 | wordwrap | 打断字符串为指定数量的字串 |
| 17 | trim | 去除字符串首尾处的空白字符(或者其他字符) |
| 18 | rtrim | 删除字符串末端的空白字符(或者其他字符) |
| 19 | ltrim | 删除字符串开头的空白字符(或其他字符) |
| 20 | chop | rtrim 的别名 |
附录 1: `trim()/ltrim()/rtrim()`去除的空白符列表
| 序号 | 空白符 | 描述 |
| ---- | -------- | ------------------------------ |
| 1 | `" "` | `(ASCII 32 (0x20))`,普通空格符 |
| 2 | `"\t"` | `(ASCII 9 (0x09))`,制表符 |
| 3 | `"\n"` | `(ASCII 10 (0x0A))` 换行符 |
| 4 | `"\r"` | `(ASCII 13 (0x0D))`回车符 |
| 5 | `"\0"` | `(ASCII 0 (0x00))`空字节符 |
| 6 | `"\x0B"` | `(ASCII 11 (0x0B))`垂直制表符 |
示例代码: `demo10.php`
```php
# 分割查询与替换函数: 第二部分
// str_pad(): 将字符串填充到指定长度
echo str_pad('php', 10, '='), '<br>';
// 默认填充到右边,使用常量表示
echo str_pad('php', 10, '=', STR_PAD_RIGHT), '<br>';
echo str_pad('php', 10, '=', STR_PAD_LEFT), '<br>';
echo str_pad('php', 10, '=', STR_PAD_BOTH), '<br>';
echo '<hr>';
// str_repeat(): 重复一个字符串,用来做一些内容分隔或装饰
echo str_repeat('-*-|', 10), '<br>';
// str_replace($search,$replace,$subject,$int): 子字符串替换, 非常有用
// 如果命名空间与类文件所有路径形成了映射,可以用它将类文件路径解析出来完成自动加载
echo str_replace('\\', DIRECTORY_SEPARATOR, '\app\home\Index.php') . '<br>';
echo str_replace('php', '*', 'php.cn,php,thinkphp', $count) . '<br>';
echo 'php被替换了 ' . $count . ' 次 <br>';
// 支持数组参数
// 例如设置一个违禁词数组,来替换掉目标字符串的非法内容
// 将第一个参数: 搜索字符串,设置成数组
$search = ['交友', '广告', '直播', '带货'];
echo str_replace($search, '***', '广告代理, 直播教学,免费带货, 异性交友'), '<br>';
// 第二个参数也可以是数组,实现一对一的映射替换
$replace = ['***', '===', '###', '+++'];
echo str_replace($search, $replace, '广告代理, 直播教学,免费带货, 异性交友'), '<br>';
echo '<hr>';
// strtr(): 转换指定的字符,可使用数组批量转换
// 'd'=>'p', 'o'=>'i',字符逐个替换
echo strtr('This is dog', 'do', 'pi'), '<br>';
// 第二个参数可以用数组,但键名必须是原字符,值为新字符
echo strtr('This is dog', ['d' => 'p', 'o' => 'i']), '<br>';
echo '<hr>';
// str_shuffle(): 随机打乱一个字符串, 生成验证码很方便
echo str_shuffle('abcdefg') . '<br>';
echo '<hr>';
// wordwrap(): 打断字符串为指定数量的字符串,true:到到达指定宽度之前打断
echo wordwrap('This is a demo', 4, "<br>\n", true);
echo '<hr>';
// trim() 去掉字符串首尾的空白或指定字符,过滤无效输入很有用
$str = ' This is a string ';
echo '原始字符串(包括空白) : ' . strlen($str) . '<br>';
echo '去掉空白: ' . strlen(trim($str)) . '<br>';
$str = '123898php.cn php中文网 this is site654312';
// 从字符串首尾去掉'12'
echo trim($str, '12') . '<br>';
// 从首尾去掉所有数字,可以使用范围符, 如只去掉1到8之间的
echo trim($str, '1..5') . '<br>';
// 去掉所有数字
echo trim($str, '1..9') . '<br>';
// 和trim()类似功能的还有ltrim()和rtrim(),区域在于去掉空白符的方向不同
// ltrim(): 删除字符串头部的空白或指定字符, 也支持范围符..
echo ltrim($str, '1..9') . '<br>';
// rtrim(): 删除字符串尾部的空白或指定字符
echo rtrim($str, '1..9') . '<br>';
// chop()是rtirm()函数的别名, 只是语义化更强而已,没卵用
echo chop($str, '1..9') . '<br>';
/*
* php=======
* php=======
* =======php
* ===php====
* -*-|-*-|-*-|-*-|-*-|-*-|-*-|-*-|-*-|-*-|
* /app/home/Index.php
* *.cn,*,think*
* php被替换了 3 次
* ***代理, ***教学,免费***, 异性***
* ===代理, ###教学,免费+++, 异性***
* This is pig
* This is pig
* edgcfba
* This
* is a
* demo
* 原始字符串(包括空白) : 21
* 去掉空白: 16
* 3898php.cn php中文网 this is site6543
* 898php.cn php中文网 this is site6
* php.cn php中文网 this is site
* php.cn php中文网 this is site654312
* 123898php.cn php中文网 this is site
* 123898php.cn php中文网 this is site
*/
```
### 3.3 第三组
| 序号 | 函数 | 说明 |
| ---- | ---------- | ------------------------------------------------------------ |
| 21 | strpos | 查找字符串首次出现的位置 |
| 22 | stripos | 查找字符串首次出现的位置(忽略大小写) |
| 23 | strripos | 计算指定字符串在目标字符串中最后一次出现的位置(忽略大小写) |
| 24 | strrpos | 计算指定字符串在目标字符串中最后一次出现的位置) |
| 25 | strstr | 查找字符串的首次出现 |
| 26 | stristr | strstr 函数的忽略大小写版本 |
| 27 | strrchr | 查找指定字符在字符串中的最后一次出现 |
| 28 | strchr | 别名 strstr |
| 29 | strpbrk | 在字符串中查找一组字符的任何一个字符 |
| 30 | strspn | 计算字符串中全部字符都存在于指定字符集合中的第一段子串的长度 |
| 31 | strtolower | 将字符串转化为小写 |
| 32 | strtoupper | 将字符串转化为大写 |
| 33 | lcfirst | 使一个字符串的第一个字符小写 |
| 34 | ucfirst | 将字符串的首字母转换为大写 |
| 35 | ucwords | 将字符串中每个单词的首字母转换为大写 |
| 36 | strlen | 获取字符串长度 |
| 37 | strrev | 反转字符串 |
| 38 | strip_tags | 从字符串中去除 HTML 和 PHP 标记 |
示例代码: `demo11.php`
```php
<?php
# 第三组
// strpos():返回指定字符串首次出现的位置,可指定查找起始索引
// 该函数可以用来快速查询字符串是否存在某个子串
echo strpos('This is a test', 'is'), '<br>';
// 从指定索引位置开始查找,索引3开始,跳过了this
echo strpos('This is a test', 'is', 3), '<br>';
// strpos()大小写敏感,此时应该换成它的忽略大小写的版本
var_dump(strpos('This is a test', 'Is', 3));
echo '<br>';
// stripos()是strpos()的忽略大小写的版本, 依然可以正确查找到
echo stripos('This is a test', 'Is', 3), '<br>';
echo '<hr>';
// strpos():返回指定字符串最后一次次出现的位置, 此时返回5,相当于反向查询
echo strrpos('This is a test', 'is'), '<br>';
echo '<hr>';
// strstr(): 查询字符首次出现的位置并返回它/false
// 返回 "."以及后面内容: ".jpg",用来判断文件类型
echo strstr('images/banner1.jpg', '.'), '<br>';
// true: 返回"."之前的内容"images/banner1"
echo strstr('images/banner1.jpg', '.', true), '<br>';
// 如果只是判断某个字符是否存在,推荐使用strpos()更快更方便
echo '<hr>';
// strpbrk(): 在字符串中查找一组字符的任何一个字符,返回该字符开始的子字符串
// "es"中, 先匹配到"s",所以返回以"s"起始的字符串
echo strpbrk('This is a test', 'es'), '<br>';
echo '<hr>';
// strspn()计算字符串中全部字符都存在于指定字符集合中的第一段子串的长度
echo strspn("42 is the answer to the 128th question.", "1234567890"), '<br>';
echo strspn("foo", "o", 1, 2), '<br>';
echo strspn('this is a test 0551-6688789', 'this is a') . '<br>';
echo '<hr>';
// strtolower(): 字符串全部转小写
// 这个很有用, 例如在switch()判断,验证码转换等,更多案例在开发实战讲解
echo strtolower('PHP.CN是国内最大的PHP开发资源分享平台') . '<br>';
echo strtoupper('Hello World') . '<br>';
echo '<hr>';
// lcfirst(): 首字符小写, 转换标识符命名风格时会用到
echo lcfirst('UserName') . '<br>';
// ucfirst(): 首字母大写, 动态生成类名称时会用到
echo ucfirst('userController') . '.php' . '<br>';
echo '<hr>';
// strrev()反转字符串
echo strrev('admin888') . '<br>';
// 生成密码时可以增加复杂度,例如
echo md5(strrev('this is a password')) . '<br>';
echo '<hr>';
// strip_tags(): 删除html和php标签,仅保留纯文本内容
echo strip_tags('<h2>Hello</h2><?php echo "World";?>');
/*
* 2
* 5
* bool(false)
* 5
* 5
* .jpg
* images/banner1
* s is a test
* 2
* 2
* 11
* php.cn是国内最大的php开发资源分享平台
* HELLO WORLD
* userName
* UserController.php
* 888nimda
* 6a7b93da1adce2c2c314395f51ba3725
* Hello
*/
```
---
## 4. URL 处理函数
| 序号 | 函数 | 说明 |
| ---- | ---------------- | -------------------------------- |
| 1 | parse_str | 将字符串解析成多个变量,处理 url |
| 2 | parse_url | 解析 URL,返回其组成部分 |
| 3 | http_build_query | 生成 URL-encode 之后的请求字符串 |
| 4 | urldecode | 解码已编码的 URL 字符串 |
| 5 | urlencode | 编码 URL 字符串 |
| 6 | base64_encode | MIME base64 数据解码 |
| 7 | base64_decode | MIME base64 数据编码 |
### 附录 1: `$_SERVER`预定义变量
以 URL 为例: `http://php.io/case/demo12.php/m/admin/c/add?id=5&name=admin`
| 序号 | 变量 | 描述 | 示例 |
| ---- | ---------------------- | ----------------------------------- | ---------------------------------------- |
| 1 | `UNIQUE_ID` | HTTP 请求的唯一标识符 | Xn4DhH8AAAEAAAWiEO0AAAAB |
| 2 | `HTTP_HOST` | HTTP 主机名/域名 | php.io |
| 3 | `SERVER_ADDR` | HTTP 主机名 IP 地址 | 127.0.0.1 / 0:0:0:1 / ::1 |
| 4 | `SERVER_PORT` | Web 服务器使用的端口 | 80 |
| 5 | `REMOTE_PORT` | 用户机器连接到 Web 服务器的端口号 | 52706 |
| 6 | `SERVER_NAME` | Appcha 配置的 ServerName | php.io |
| 7 | `DOCUMENT_ROOT` | 当前脚本所在的根目录(配置文件中) | /Documents/web/php/case |
| 8 | `SCRIPT_FILENAME` | 当前执行脚本的绝对路径 | /Documents/web/php/case/demo1.php |
| 9 | `SCRIPT_NAME` | 当前执行脚本的路径与文件名 | /case/demo1.php |
| 10 | `PHP_SELF` | 当前脚本名(含 pathinfo) | /case/demo1.php/m/admin/c/add |
| 11 | `PATH_INFO` | 执行脚本与查询字符串之间的路径信息 | /m/admin/c/add |
| 12 | `PATH_TRANSLATED` | 脚本所在文件系统路径(限 pathinfo) | /Documents/web/php/m/admin/c/add |
| 13 | `REQUEST_URI` | 当前访问的 URL(pathinfo,查询字符串) | case/demo1.php/m/admin/c/add?id=5&... |
| 14 | `QUERY_STRING` | 查询字符串(不含前导问号`?`) | id=5&name=admin |
| 15 | `REQUEST_METHOD` | HTTP 请求类型 | POST / GET |
| 16 | `HTTP_REFERER` | 引导用户进入当前页面的 URL | 如果是直接进入当前页,则不存在该值 |
| 17 | `HTTP_USER_AGENT` | 客户端/浏览器信息`get_browser()` | Mozilla/5.0 (Macintosh; Intel Mac ... |
| 18 | `SERVER_SOFTWARE` | web 服务器软件 | Apache |
| 19 | `SERVER_PROTOCOL` | web 服务器 HTTP 协议 | HTTP/1.1 |
| 20 | `GATEWAY_INTERFACE` | 网关接口:服务器使用 CGI 规范 | CGI/1.1 |
| 21 | `REQUEST_TIME` | HTTP 请求开始的时间戳 | 1585320730 |
| 22 | `REQUEST_TIME_FLOAT` | HTTP 请求开始的时间戳(微秒级) | 1585320730.803 |
| 23 | `argv` | 传递给脚本的参数数组 | Array ( [0] => id=5&name=admin ) |
| 24 | `argc` | 传递给脚本的参数数量 | 1 |
| 25 | `HTTP_ACCEPT` | 客户端请求/接受文档类型 | text/html,application/xhtml+xml,appli... |
| 26 | `HTTP_ACCEPT_ENCODING` | HTTP 压缩 HTML 的编码方式 | gzip, deflate |
| 27 | `HTTP_ACCEPT_LANGUAGE` | HTTP 接受的语言 | zh-CN,zh;q=0.9,en;q=0.8,ja;q=0.7 |
### 附录 2: `urlencode()`:对 url 变量值进行编码
| 除了`-\_.`之外的所有字符 | 空格 | 编码方式 |
| ------------------------ | ---- | ----------------------------------- |
| `%`+2 位 16 进制数 | `+` | `application/x-www-form-urlencoded` |
### 附录 3: `base64_encode()`:用 base64 对 data 进行编码
- 为了使二进制数据可以通过非纯 8-bit 的传输层传输,例如电子邮件的主体
- 下载链接, 图片等都可以使用它进行加密处理
- 加密之后的数据比原始数据要多占据 33%的空间大小
### 附录 4: Data URI Scheme(协议)
形如:`data:text/jpeg;base64,/9j/4AAQSkZJRgABA...` 这样的资源链接
| 序号 | 协议 | 说明 |
| ---- | ------------------------------ | --------------------------- |
| 1 | `data:` | 文本数据 |
| 2 | `data:text/plain,` | 文本数据 |
| 3 | `data:text/html,` | HTML 代码 |
| 4 | `data:text/css;base64,` | css 代码 |
| 5 | `data:text/javascript;base64,` | javascript 代码 |
| 6 | `data:image/x-icon;base64,` | base64 编码的 icon 图片数据 |
| 7 | `data:image/gif;base64,` | base64 编码的 gif 图片数据 |
| 8 | `data:image/png;base64,` | base64 编码的 png 图片数据 |
| 9 | `data:image/jpeg;base64,` | base64 编码的 jpeg 图片数据 |
示例代码: `demo12.php`
```php
<?php
# URL处理函数
// parse_str($querystring,$array): 解析出查询字符串的变量键值对
// http://php.io/demo12.php?id=5&name=admin&role=1
echo $querystring = $_SERVER['QUERY_STRING'] . '<br>';
parse_str($querystring, $queryArr);
print_r($queryArr);
echo '<hr>';
// parse_url():解析URL地址,返回协议,主机,脚本路径和查询字符串等信息
$url = 'http://php.io/demo12.php/m/admin/c/add?id=5&name=admin';
// echo '<pre>' . print_r($_SERVER, true) . '</pre>';
print_r(parse_url($url));
// Array ( [scheme] => http [host] => php.io [path] => /demo12.php [query] => id=5&name=admin )
echo '<hr>';
// http_build_query(): 生成经过urlencode()处理之后的查询字符串
echo http_build_query(['name' => 'peter zhu', 'age' => 30]) . '<br>';
// 支持对象中的属性, 仅转换public公共属性
echo http_build_query((new class
{
public $name = 'admin';
public $email = 'admin@php.cn';
private $gender = 'male';
protected $salary = 98989;
})) . '<br>';
echo '<hr>';
// urlencode(): 对url变量值进行编码后,便于传到下一页面
// 除了 -_. 之外的所有非字母数字字符都将被替换成百分号(%)后跟两位十六进制数
// 因历史原因, 空格单独编码, 用加号"+"表示
// 编码方式与post中的application/x-www-form-urlencoded一样
$post = ['name' => 'peter zhu', 'email' => 'peter@php.cn'];
$name = urlencode($post['name']);
$email = urlencode($post['email']);
// 通常转码之后, 建议再用htmlentities(), 将html标签和引号等转为实体则更安全
$input = htmlentities("name={$name}&email={$email}");
echo $input . '<br>';
echo "<a href=\"register.php?{$input}\">注册</a>";
// 输出到控制台查看一下URL编码后的结果
echo '<script>console.log(document.querySelector("a").href)</script>';
// http://php.io/case/register.php?name=peter+zhu&email=peter%40php.cn
echo '<hr>';
// urldecode():对已编码的URL解码,将%+16进制数和"+"替换成原义字符
echo urldecode($input) . '<br>';
// base64_encode(): 二进制数据进行编码后加密传输, 图片是典型的2进制,以此为例
echo $img = base64_encode(file_get_contents('girl.jpg'));
// 显示图片
// 如果要在<img>标签中显示base编码数据,需要使用HTTP URI Scheme资源链接协议
// 这种协议通过用在<a href="">....</a>或者<img src="...>
echo "<img src='data:image/jpeg;base64,{$img}'>" . '<br>';
// 对图片进行 base64 编码后,图片能随 HTML 一起传输到浏览器,可以减少 HTTP 请求
// 缺点是文档体积变大,并且原图修改后需要重新编码不利于浏览器缓存加速,不利图片复用等
// 如果一些古老的浏览器不支持DataURI,可以使用base64_decode()解码
file_put_contents('girl2.jpg', base64_decode($img));
echo "<img src='girl2.jpg'>" . '<br>';
echo '<hr>';
```
---
## 5. HTML 相关
| 序号 | 函数 | 说明 |
| ---- | ----------------------- | -------------------------------------- |
| 1 | htmlspecialchars | 将特殊字符转换为 HTML 实体 |
| 2 | htmlspecialchars_decode | 将特殊的 HTML 实体转换回普通字符 |
| 3 | htmlentities | 将字符转换为 HTML 转义字符 |
| 4 | html_entity_decode | 将 HTML 实体转换为它们相应的字符 |
| 5 | nl2br | 在字符串所有新行之前插入 HTML 换行标记 |
### 附录 1: html 实体字符
- 某些字符在 html 文档中有特殊意义,如`<>`用表示元素标签,这些都是预留字符,不能直接使用
- 如果要在 html 文档中正确显示他们,需要将它们转为**html 实体字符**,如`<`转为`<`
- html 实体字符有二种表示方法: 1. 命名表示法,如`<`, 2. 编码表示法, 如`&60;`
- 常用实体字符列表:
| 序号 | 描述 | 实体名称 | 实体编码 |
| ---- | ----- | ----------------- | ---------- |
| 1 | `' '` | 空格 | ` ` | ` ` |
| 2 | `<` | 小于号 | `<` | `<` |
| 3 | `>` | 大于号 | `>` | `>` |
| 4 | `&` | 和号 | `&` | `&` |
| 5 | `"` | 双引号 | `"` | `"` |
| 6 | `'` | 单引号 | `'` | `'` |
| 7 | `¢` | 分(cent) | `¢` | `¢` |
| 8 | `£` | 镑(pound) | `£` | `£` |
| 9 | `¥` | 元(yen) | `¥` | `¥` |
| 10 | `€` | 欧元(euro) | `€` | `€` |
| 11 | `§` | 小节 | `§` | `§` |
| 12 | `©` | 版权(copyright) | `©` | `©` |
| 13 | `®` | 注册商标 | `®` | `®` |
| 14 | `™` | 商标 | `™` | `™` |
| 15 | `×` | 乘号 | `×` | `×` |
| 16 | `÷` | 除号 | `÷` | `÷` |
### 附录 2: htmlspecialchars()转换字符列表
| 序号 | 原字符 | 替换成 |
| ---- | ------ | -------- |
| 1 | `&` | `&` |
| 2 | `"` | `"` |
| 3 | `'` | `'` |
| 4 | `<` | `<` |
| 5 | `>` | `>` |
> 如果要转换的字符超出以上列表,请使用: `htmlentities()`
### 附录 3: 转换时的 FLAG 常量
| 序号 | 常量 | 描述 |
| ---- | ---------------- | --------------------------------------- |
| 1 | `ENT_COMPAT` | 会转换双引号,不转换单引号 |
| 2 | `ENT_QUOTES` | 既转换双引号也转换单引号 |
| 3 | `ENT_NOQUOTES` | 单/双引号都不转换 |
| 4 | `ENT_SUBSTITUTE` | 替换无效的代码单元序列为 Unicode 代替符 |
| 5 | `ENT_DISALLOWED` | 为文档的无效代码点替换为 Unicode 代替符 |
| 6 | `ENT_HTML401` | 以 HTML 4.01 处理代码 |
| 7 | `ENT_XML1` | 以 XML 1 处理代码 |
| 8 | `ENT_XHTML` | 以 XHTML 处理代码 |
| 9 | `ENT_HTML5` | 以 HTML 5 处理代码 |
示例代码: `demo13.php`
```php
# html相关函数
// htmlspecialchars(): 将html标签和引号等转为html实体字符
$link = "<a href='edit.php?id=1&p=2'>\"编辑\"</a>";
echo htmlspecialchars($link) . '<br>';
// 默认只转换双引号, 不转换单引号, 和下面语句等效
echo htmlspecialchars($link, ENT_COMPAT) . '<br>';
// <a href='edit.php?id=1&p=2'>"编辑"</a>
// 双引号, 单引号都转换,添加常量标志: ENT_QUOTES
echo htmlspecialchars($link, ENT_QUOTES) . '<br>';
// <a href='edit.php?id=1&p=2'>"编辑"</a>
echo '<hr>';
// htmlspecialchars_decode(),执行与 htmlspecialchars()反操作,实体符还原
// 注意, 中间单引号转义一下,或者外层用双引号也可以
$entities = '<a href=\'edit.php?id=1&p=2\'>"编辑"</a>';
echo htmlspecialchars_decode($entities);
// 不转换双引号: "编辑" (必须打开源代码查看)
echo htmlspecialchars_decode($entities, ENT_NOQUOTES);
echo '<hr>';
// htmlentities(): 对比 htmlspecialchars()可以转义更多的html特殊字符,如版权符
// 发现双引号被转换成了实体, 而单引号仍被忽略
echo htmlentities('<h3>\'10 × 5\' = 50</h3>"€" ©版权所有') . '<br>';
// <h3>'10 × 5' = 50</h3>"€" ©版权所有
// 与htmlspecialchars()一样, 添加一个转换常量就可以
echo htmlentities('<h3>\'10 × 5\' = 50</h3>"€" ©版权所有', ENT_QUOTES) . '<br>';
// <h3>'10 × 5' = 50</h3>"€" ©版权所有
echo '<hr>';
// 同样, htmlentities()也有一个反操作函数: html_entity_decode();
$html = "<h3>'10 × 5' = 50</h3>"€" ©版权所有";
echo html_entity_decode($html) . '<hr>';
// nl2br()
// php字符串中的换行符\n,会被浏览器页面解析成一个空格,起不到换行的显示效果
// nl2br()可以将字符串的换行符"\n",替换成"<br>"标签,起到视觉上的换行效果
$str = "html\ncss\njs\nphp";
// 全部显示在一行, "\n"用空格代替了,并没有换行效果
echo $str . '<br>';
// 换行符"\n",替换成了"<br>"标签,可以正常显示换行效果了 到源代码中可以查看到
echo nl2br($str);
```
---
## 6. 转码相关函数
| 序号 | 函数 | 说明 |
| ---- | ---------------- | ----------------------------------------------------- |
| 1 | chr | 返回指定的字符 |
| 2 | ord | 转换字符串第一个字节为 0-255 之间的值 |
| 3 | chunk_split | 将字符串分割成小块 |
| 4 | bin2hex | 函数把包含数据的二进制字符串转换为十六进制值 |
| 5 | hex2bin | 转换十六进制字符串为二进制字符串 |
| 7 | convert_uuencode | 将所有(含 2 进制)字符串转为可打印字符便于网络安全传输 |
| 6 | convert_uudecode | 将 convert_uuencode 编码的字符串解析还原(反操作) |
| 8 | count_chars | 返回字符串所用字符的信息(每个字符出现的次数) |
| 9 | quotemeta | 转义元字符集: `. \ + * ? [ ^ ] ( $ )` |
- `count_chars()` 的模式符:
| 序号 | 模式符 | 说明 |
| ---- | ------ | ------------------------------------------------ |
| 1 | `0` | 以所有的每个字节值作为键名, 出现次数作为值的数组 |
| 2 | `1` | 与 0 相同,但只列出出现次数**大于零**的字节值 |
| 3 | `2` | 与 0 相同,但只列出出现次数**等于零**的字节值 |
| 4 | `3` | 返回由所有使用了的字节值组成的字符串 |
| 5 | `4` | 返回由所有未使用的字节值组成的字符串 |
- `quotemeta()`: 预定义的字符前添加反斜线`\`
- 预定义字符列表(在正则中具有特殊语义)
| 序号 | 字符 | 说明 |
| ---- | ------------ | ------ |
| 1 | `.` | 圆点 |
| 2 | `\` | 反斜线 |
| 3 | `+` | 加号 |
| 4 | `*` | 星号 |
| 5 | `?` | 问号 |
| 6 | `[]` | 方括号 |
| 7 | `^` | 脱字符 |
| 8 | `$` | 美元符 |
| 9 | `()` | 圆括号 |
示例代码: `demo8.php`
```php
<?php
# 转码相关的字符串函数
// chr(): 输出整数ACSII码对应的字符
echo chr(80) . chr(72) . chr(80) . '<br>';
// ord(): 输出字符对应的ASCII码
echo ord('P') . ord('H') . ord('P') . '<br>';
// 随机产生一个随机字符串可以用到它,生成一些演示用户名称等
function rand_str(int $length): string
{
$str = '';
for ($i = 0; $i < $length; $i++) {
$str .= chr(random_int(97, 122));
}
return $str;
}
echo rand_str(10) . '<hr>';
// chunk_split(): 将字符串分割成指定大小的块,并插入自定义字符串
// 默认每行76个字符, 未尾自动添加\r\n
// \r: 回到行首, \n: 到下一行,即新行
$str = chunk_split('abcdefghigklmnopqrstuvwxyz', 5);
// 分成5行显示,
echo $str . '<br>';
// 浏览器页面中看不到换行效果, 可以用nl2br()处理一下
echo nl2br($str);
// 这个函数经常用来将base64_encode()编码转成RFC 2045语义字符串
// echo chunk_split(base64_encode(file_get_contents('girl.jpg')));
echo '<hr>';
// bin2hex(): 包含数据的二进制字符串转换为十六进制值
echo $hex = bin2hex('php.cn') . '<br>';
// 输出: 7068702e636e
// 可以用pack()还原: H*: 表示高位在前
echo pack("H*", bin2hex('php.cn')) . '<br>';
// hex2bin(): 是bin2hex()反操作, 与pack()功能一样
echo hex2bin('7068702e636e') . '<hr>';
// convert_uuencode():将所有(含 2 进制)字符串转为可打印字符便于网络安全传输
echo convert_uuencode("Hello World") . '<br>';
// +2&5L;&\@5V]R;&0` `
// convert_uudecode: convert_uuencode()反操作,还原数据
echo convert_uudecode("+2&5L;&\@5V]R;&0` `") . '<br>';
// convert_uudecode()参数建议使用变量而不是字面量, 以防止来回转义出现语法错误
$url = convert_uuencode("https://www.php.cn");
echo convert_uudecode($url) . '<br>';
echo '<hr>';
// count_chars()
$str = 'this is a test';
// 模式1: 只列出字符串, 出现次数大于0的字节的值
// 键名:字符字节值(ASCII或其它编码)
// 值: 字符出现的次数
echo '原始字符串: ' . $str . ' : <br>';
foreach (count_chars($str, 1) as $code => $count) {
echo chr($code) . ' 出现的次数是 : ' . $count . '<br>';
}
// quotemeta(): 转义元字符集, `. \ + * ? [ ^ ] ( $ )`, 常用在正则操作中
// 此函数转义在正则表达式中具有特殊含义的字符, preg_quote()
$id = $id ?? 1;
$salary = $salary ?? 10000;
// 转义sql语句的元字符
$sql = "SELECT * FROM `staffs` WHERE (`id` > '{$id}' ) AND (`salary` < '{$salary}') LIMIT 5";
echo quotemeta($sql);
```
---
## 7. 哈希相关函数
| 序号 | 函数 | 说明 |
| ---- | --------- | ----------------------------- |
| 1 | md5_file | 计算指定文件的 MD5 散列值 |
| 2 | md5 | 计算字符串的 MD5 散列值 |
| 3 | sha1_file | 计算文件的 sha1 散列值 |
| 4 | sha1 | 计算字符串的 sha1 散列值 |
| 5 | crypt | 单向字符串散列 |
| 6 | crc32 | 计算一个字符串的 crc32 多项式 |
| 7 | str_rot13 | 对字符串执行 ROT13 转换 |
示例代码:
```php
// 字符串: 哈希相关函数
// md5_file(): 只要文件被修改过,这个值就会发生变化
echo 'demo8.php的md5 = ' . md5_file('demo8.php') . '<br>';
// md5_file(): 文件唯一标识符
// md5_file(): 判断文件是否被修改过
// 获取demo8.php文件的md5
// file_put_contents('md5file.txt', md5_file('demo8.php'));
// 检查demo8.php是否被修改过,只要修改过,它的md5一定会发生变化
if (md5_file('demo8.php') === file_get_contents('md5File.txt')) {
echo '文件没有被修改过';
} else {
echo '文件被修改过';
}
// 每个文件的md5完全不同的,所以在处理文件上传时,可以检查这个值,判断是否重复上传
```
---
## 8. 统计与比较函数
| 序号 | 函数 | 说明 |
| ---- | -------------- | -------------------------------------------------- |
| 1 | strspn | 返回字符串与掩码中字符串匹配的字符数量 |
| 2 | strcspn | 返回第一个字符串中, 找到与掩码字符之前的字符数量 |
| 3 | str_word_count | 返回字符串中单词的使用情况 |
| 4 | substr_compare | 二进制安全比较字符串(从偏移位置比较指定长度) |
| 5 | strcmp | 二进制安全字符串比较 |
| 6 | strncmp | 二进制安全比较字符串开头的若干个字符 |
| 7 | strcasecmp | 二进制安全比较字符串(不区分大小写) |
| 8 | strncasecmp | 二进制安全比较字符串开头的若干个字符(不区分大小写) |
示例代码:
```php
<?php
// 统计与比较函数
// strspn() 返回字符串与掩码中字符串匹配的字符数量
// 第一段`hello`与掩码字符集`hello`连续匹配上5个, 返回: 5, 'hello' === 'hello'
// 匹配过程
// 第一次, 'hello'中取出'h',在掩码'hello'中查询,是否存在,存在返回1
// 第二次, 'hello'中取出'e',在掩码'hello'中查询,是否存在,存在返回1, 并累加到前一个结果上
// 直到遇到"第一个掩码中不存在的字符"(例如空格),则立即终止查询,并返回与掩码匹配到字符数量
echo strspn('hello world', 'hello'), '<br>';
// 'hello'中第一个字符'h'在掩码就匹配失败, 返回0, 直接退出
echo strspn('hello world', 'weoll'), '<br>';
// 返回5, 为什么?因为'hello'中的'll'与掩码中的'l'连续匹配2次
echo strspn('hello world', 'aahelo'), '<br>';
// 看上去似乎应该匹配上,实际上却返回0, 因为第一字符串中的第一个字符'h'在掩码中就不存丰,直接退出
echo strspn('helloworld', 'world'), '<br>';
// 从第一个字符串的第3个字符开始与掩码匹配,'l'匹配2次,'o'匹配1次,返回3
echo strspn('hello world', 'lo', 2), '<br>';
// 小案例: 验证手机号字符合法性,手机号码必须是"0-9"之间的一个数字字符,只要有一个不满足就匹配失败
// 利用第一个字符全部匹配则返回当前字符串长度的特征,做为条件进行判断
$phone = '13845673456a';
if (strlen($phone) !== strspn($phone, '0123456789')) echo '号码非法';
echo '<hr>';
// strcspn() 返回第一个字符串中, 找到与掩码字符之前的字符数量
// 将第一个字符串中的字符依次取出与掩码比对, 第一次h不匹配,第二次e不匹配, 第三次l匹配成功
// 前此, 在第一个字符串中找到匹配掩码的'l'之前, 已经查询过了2次,所以返回2
echo strcspn('hello world', 'l'), '<br>';
// 仍返回2, 原因是'hello world'中, 只比较二次到'l'时, 就在掩码中找到了'l'匹配完成
echo strcspn('hello world', 'orl'), '<br>';
// 返回4, 在第一个字符串, 检查到'o'时, 在掩码字符串匹配成功, 于是返回'o'之前检测过的字符数量
echo strcspn('hello world', 'wor'), '<br>';
// 也支持索引参数,设置从第一个字符串的起始索引与数量
// 因为在第一个字符串, 索引6就是'w',直接匹配成功,前面没有比较过其它字符,返回0
echo strcspn('hello world', 'wor', 6), '<br>';
// 咱们稍微修改一下掩码,去掉w, 此时返回1,是因为在掩码中找到'o'时,已经检查过了'w'一个字符
echo strcspn('hello world', 'or', 6), '<br>';
echo '<hr>';
// str_word_count(): 统计字符串单词使用情部,忽略标点
$str = 'This is a demo.';
echo $str, '<br>';
// 第二个参数默认为0,返回单词数量
echo '单词数量: ' . str_word_count($str, 0) . '个. <br>';
echo '单词数量: ' . str_word_count($str) . '个. <br>';
// 第二个参数:1, 返回单词组成的索引数组
echo '<pre>' . print_r(str_word_count($str, 1), true) . '</pre>';
// 第二个参数:2, 返回单词组成的关联数组, 键名是单词在字符串中的起始索引
echo '<pre>' . print_r(str_word_count($str, 2), true) . '</pre>';
// substr_compare(): 子串比较,检查第一个字符串参数中是否存在第二个子串, 从偏移位置比较指定长度
// 注意, 一定要在第一个被比较的字符串中取出一定范围的子串, 与第二个参数进行比较
// 如果第二个参数子串, 存在于第一个主串中, 则返回0, 通常我们只对返回0的结果感兴趣
echo substr_compare('hello world', 'hello', 0, 3); // 0
echo substr_compare('hello world', 'hello', 0, 5); // 0
// 从主串索引6开始, 取前3位,与子串进行比较, 当然取5位进行完全匹配也可以
echo substr_compare('hello world', 'world', 6, 3); // 0
echo substr_compare('hello world', 'World', 6, 3); // 32,匹配失败,因为大小写敏感
echo substr_compare('hello world', 'World', 6, 3, true); // 参数true, 忽略大小写比较
echo '<hr>';
// strcmp(): 字符串简单比较
// 相等, 返回 0
echo strcmp('php', 'php') === 0 ? '相等<br>' : '不相等<br>';
// 大小写敏感
echo strcmp('php', 'Php') === 0 ? '相等<br>' : '不相等<br>';
echo '<hr>';
// strncmp(): 与strcmp()功能一样,只不过可以设置比较长度,注意中间多了一个`n`,可理解为`num`
// 只比较前3个字符,当然相等,当然比较前2个也是相等的
echo strncmp('php', 'php.cn', 3) === 0 ? '相等<br>' : '不相等<br>';
echo '<hr>';
// strcasecmp(): 忽略大小写比较字符串
echo strcasecmp('php', 'Php') === 0 ? '相等<br>' : '不相等<br>';
echo '<hr>';
// strncasecmp(): 忽略大小写比较字符串, 可以指定比较的字符串长度,与strncmp类似
echo strncasecmp('php', 'Php.cn', 2) === 0 ? '相等<br>' : '不相等<br>';
echo '<hr>';
```