文件对比这个扩展现在用得比较少,因为大部分情况下我们都在使用一些代码管理工具,比如 Git 或者 Svn 之类的,其实它的作用就非常类似这类工具,另外还有一个非常常用的 Beyond Compare 工具也能方便地让我们能够进行文件的对比。

安装及准备工作

在 PHP 中的这个文件扩展叫做 xdiff 扩展,我们可以直接在 pecl 中下载并安装。

需要注意的是,安装这个扩展需要操作系统安装 libxdiff 工具,在文章最下方的参考链接中有这个工具的官网地址。libxdiff 无法使用默认的 yum 安装,所以需要下载之后自行安装。和其它的 Linux 工具一样,安装过程非常简单,这里就不多赘述了。

xdiff 扩展支持字符串和文件两种形式的差异对比以及一些相关的操作,这里我们以字符串的操作为主进行讲解,文件相关的操作将在最后给出全部的操作函数用法。首先,我们需要定义一些字符串以及相关的文件便于后续的操作。

$old_article = "我本无为野客,飘飘浪迹人间。
一时被命住名山。未免随机应变。
识破尘劳扰扰,何如乐取清闲。
流霞细酌咏诗篇。且与白云为伴。";
$new_article = "我本无为野客,飘飘浪迹人间。
一时被命住名山。未免随机应变。
识破尘劳扰扰,何如乐取清闲。一
流霞细酌咏诗篇。且与白云为伴。";
$new_article1 = "我本无为野客,飘飘浪迹人间。
一时被命住名山。未免随机应变。二
识破尘劳扰扰,何如乐取清闲。
流霞细酌咏诗篇。且与白云为伴。
三一四一"; file_put_contents('old_file.txt', $old_article);
file_put_contents('new_file.txt', $new_article);
file_put_contents('new_file1.txt', $new_article1);

字符串差别

$diff = xdiff_string_diff($old_article, $new_article);
var_dump($diff);
// string(273) "@@ -1,4 +1,4 @@
// 我本无为野客,飘飘浪迹人间。
// 一时被命住名山。未免随机应变。
// -识破尘劳扰扰,何如乐取清闲。
// +识破尘劳扰扰,何如乐取清闲。一
// 流霞细酌咏诗篇。且与白云为伴。
// \ No newline at end of file
// "

使用 xdiff_string_diff() 函数就可以获得两段字符串中的差异信息。可以看到它的内容结构和 Git 的文件差异对比返回的内容非常相似。像用 + 、 - 号表示的那一行的差异,我们只要使用过 Git 或 Svn 就一定不会陌生。

合并字符串

var_dump(xdiff_string_merge3($old_article, $new_article, $new_article1, $error));
// string(180) "我本无为野客,飘飘浪迹人间。
// 一时被命住名山。未免随机应变。
// 识破尘劳扰扰,何如乐取清闲。一
// 流霞细酌咏诗篇。且与白云为伴。"
var_dump($error); // NULL

xdiff_string_merge3() 函数用于将三个字符串合并到一起,也是类似于 Git 中的 merge 功能。不过这个函数需要三个字符串,但是通过测试我们发现只有第一个 \$new_article 和原始的 $old_article 合并成功了。第三个 $new_article1 并没有合并到最后返回的字符串中。关于这个函数的功能和实际的效果并不一致的问题并没有找到任何相关的参考资料,官方文档的介绍也非常地简单,所以如果大家如果有知道这个函数的真实具体情况的,可以留言一起讨论哦!

$error 参数是一个可选的引用参数,如果合并过程中出现任何问题它将返回错误信息。

修补数据(补丁)

var_dump(xdiff_string_patch($old_article, $diff, XDIFF_PATCH_NORMAL, $errors));
// string(180) "我本无为野客,飘飘浪迹人间。
// 一时被命住名山。未免随机应变。
// 识破尘劳扰扰,何如乐取清闲。一
// 流霞细酌咏诗篇。且与白云为伴。"
var_dump($errors); // NULL

从函数的名称中的 patch 就能看出,这个 xdiff_string_patch() 是为差异字符串打补丁用的。在曾经的桌面时代,不管是操作系统还是各种游戏,都经常会更新各种补丁。这里的补丁其实和合并差异比较类似。它的第一个参数是原始的字符串,第二个参数是 xdiff_string_diff() 生成的差异数据,打补丁的结果就是返回正式的全并差异之后的字符串。

第三个参数是可选的,它还可以定义成 XDIFF_PATCH_REVERSE ,也就是反转补丁,只返回原始的数据,不返回差异合并后的结果。反过来说,使用这个参数我们可以将第一个参数设置为修改后的 $new_article ,然后反转回原始的数据,大家可以自行尝试一下。最后的参数同样是可选的引用类型的错误变量。

二进制修补数据

$patchBinary = xdiff_string_bdiff($old_article, $new_article);
var_dump($patchBinary);
// string(44) "�{�N��一
// 流霞细酌�!" var_dump(xdiff_string_bdiff_size($patchBinary)); // int(180)
var_dump(xdiff_string_bpatch($old_article, $patchBinary));
// string(180) "我本无为野客,飘飘浪迹人间。
// 一时被命住名山。未免随机应变。
// 识破尘劳扰扰,何如乐取清闲。一
// 流霞细酌咏诗篇。且与白云为伴。"

除了原文的字符串操作之外,我们还可以使用 xdiff_string_bdiff() 返回二进制的字符串差异结果。同样地,使用 xdiff_string_bpatch() 可以对这个二进制的字符串操作结果打补丁,也就是合并差异。另外在二进制操作中还有一个函数 xdiff_string_bdiff_size() 用于返回二进制差异函数所返回的结果中的字符长度。

$raPatchBinary = xdiff_string_rabdiff($old_article, $new_article1);
var_dump($raPatchBinary);
// string(46) "�{�N�X二XY
// 三一四一" var_dump(xdiff_string_bdiff_size($raPatchBinary)); // int(193)
var_dump(xdiff_string_bpatch($old_article, $raPatchBinary));
// string(193) "我本无为野客,飘飘浪迹人间。
// 一时被命住名山。未免随机应变。二
// 识破尘劳扰扰,何如乐取清闲。
// 流霞细酌咏诗篇。且与白云为伴。
// 三一四一"

最后还有一个 xdiff_string_rabdiff() ,也是返回二进制的数据差异信息的。它和 xdiff_string_bdiff() 的区别主要是使用的算法不同。

文件操作

上面我们详细地介绍了 xdiff 扩展对于字符串的操作。它同时还提供了一系列的针对文件的操作,使用这些直接操作文件的函数就真的和我们的 Git 之类的工具非常类似了。

$old_file = 'old_file.txt';
$new_file = 'new_file.txt';
$new_file1 = 'new_file1.txt';
$diff_file = 'file.diff';
$merge_file = 'merge.txt';
$patch_file = 'patch.diff'; echo "File Diff: ", PHP_EOL;
$patch = xdiff_file_diff($old_file, $new_file, $diff_file);
var_dump($patch); // bool(true)
var_dump(file_get_contents($diff_file));
// string(273) "@@ -1,4 +1,4 @@
// 我本无为野客,飘飘浪迹人间。
// 一时被命住名山。未免随机应变。
// -识破尘劳扰扰,何如乐取清闲。
// +识破尘劳扰扰,何如乐取清闲。一
// 流霞细酌咏诗篇。且与白云为伴。
// \ No newline at end of file
// " echo 'File Merge: ', PHP_EOL;
var_dump(xdiff_file_merge3($old_file, $new_file, $new_file1, $merge_file));
// string(307) "@@ -1,4 +1,5 @@
// 我本无为野客,飘飘浪迹人间。
// -一时被命住名山。未免随机应变。
// +一时被命住名山。未免随机应变。二
// 识破尘劳扰扰,何如乐取清闲。
// -流霞细酌咏诗篇。且与白云为伴。+流霞细酌咏诗篇。且与白云为伴。
// +三一四一"
var_dump(file_get_contents($merge_file));
// string(180) "我本无为野客,飘飘浪迹人间。
// 一时被命住名山。未免随机应变。
// 识破尘劳扰扰,何如乐取清闲。一
// 流霞细酌咏诗篇。且与白云为伴。" echo "File Patch: ", PHP_EOL;
var_dump(xdiff_file_patch($old_file, $diff_file, $patch_file, XDIFF_PATCH_NORMAL)); // bool(true)
var_dump(file_get_contents($patch_file));
// string(180) "我本无为野客,飘飘浪迹人间。
// 一时被命住名山。未免随机应变。
// 识破尘劳扰扰,何如乐取清闲。一
// 流霞细酌咏诗篇。且与白云为伴。" echo "File Binary Diff: ", PHP_EOL;
$patchBinary = xdiff_file_bdiff($old_file, $new_file, $diff_file);
var_dump($patchBinary); // bool(true)
var_dump(file_get_contents($diff_file));
// string(44) "�{�N��一
// 流霞细酌�!" var_dump(xdiff_file_bdiff_size($diff_file)); // int(180)
var_dump(xdiff_file_bpatch($old_file,$patchBinary, $patch_file)); // bool(false)
var_dump(file_get_contents($patch_file));
// string(180) "我本无为野客,飘飘浪迹人间。
// 一时被命住名山。未免随机应变。
// 识破尘劳扰扰,何如乐取清闲。一
// 流霞细酌咏诗篇。且与白云为伴。" echo "File RA Binary Diff: ", PHP_EOL;
$raPatchBinary = xdiff_file_rabdiff($old_file, $new_file1, $diff_file);
var_dump($raPatchBinary); // bool(true)
var_dump(file_get_contents($diff_file));
// string(46) "�{�N�X二XY
// 三一四一" var_dump(xdiff_file_bdiff_size($diff_file)); // int(193)
var_dump(xdiff_file_bpatch($old_file, $raPatchBinary, $patch_file)); // bool(false)
var_dump(file_get_contents($patch_file));
// string(193) "我本无为野客,飘飘浪迹人间。
// 一时被命住名山。未免随机应变。二
// 识破尘劳扰扰,何如乐取清闲。
// 流霞细酌咏诗篇。且与白云为伴。
// 三一四一"

这里我们就不一一讲解了,这些函数的操作和功能与字符串操作的相关函数都是类似的,只是参数略有不同。比如它们在对比或者合并、补丁之后都会生成一个文件,所有函数的参数都是以文件为基础的。大家可以自行运行一下测试代码并参考官方文档进行学习。

总结

关于这个 xdiff 扩展其实我们使用得并不多,不过曾经看过有一套开源的使用 PHP 来做的 CMS 系统中管理前端模板页面的功能中就使用到了这一套扩展。任何工具的存在都有它的意义,或许你在为某个功能而苦恼的时候正好就看到了这篇文章,从而轻松地解决了手头上的问题也说不准,了解并有个大概的印象,在工作中才不至于摸瞎,这就是我们刷文档的意义。

测试代码:

https://github.com/zhangyue0503/dev-blog/blob/master/php/202010/source/10.PHP中的文件对比扩展.php

参考文档:

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

https://directory.fsf.org/wiki/LibXDiff

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

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

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

B站ID:482780532

PHP中的文件对比扩展的更多相关文章

  1. 在PHP中操作文件的扩展属性

    在操作系统的文件中,还存在着一种我们可以自己定义的文件属性.这些属性不是保存在文件内容中,也不是直接可以通过 ls -al 所能看到的内容.它们可以将一个键值对信息永久得关联到文件上,一般现在的 Li ...

  2. 从一个标准URL中提取文件的扩展名

    例如:http://www.sina.cn/abc/de.php?id=1  提出php 1. $url = 'http://www.sina.cn/abc/de.php?id=1'; $arr = ...

  3. 获取URL中的文件的扩展名

    问题: 尽可能多地写出获取文件扩展名的方法: //方法一(分割数组) function getExt($url){ $arr = explode('.',$url); $len = count($ar ...

  4. PHP中获取文件扩展名

    function get_extension($file) { return substr(strrchr($file, '.'), 1) ; } function get_extension($fi ...

  5. C#路径中获取文件全路径、目录、扩展名、文件名称

    C#路径中获取文件全路径.目录.扩展名.文件名称常用函数 需要引用System.IO 直接可以调用Path的静态方法 class Program { static void Main(string[] ...

  6. C# 选择文件、选择文件夹、打开文件(或者文件夹) 路径中获取文件全路径、目录、扩展名、文件名称 追加、拷贝、删除、移动文件、创建目录 修改文件名、文件夹名!!

    https://www.cnblogs.com/zhlziliaoku/p/5241097.html 1.选择文件用OpenDialog OpenFileDialog dialog = new Ope ...

  7. PHP中获取文件扩展名的N种方法

    PHP中获取文件扩展名的N种方法 从网上收罗的,基本上就以下这几种方式: 第1种方法:function get_extension($file){substr(strrchr($file, '.'), ...

  8. 三、Linux系统中的文件类型和文件扩展名

    .sock文件也是一类特殊的文件,这类文件通常用在网络之间进行数据连接,如:我们可以启动一个程序来监听客户端的要求,客户端可以通过套接字来进行通信: linux中的文件类型 文件类型介绍 Linux系 ...

  9. 【转】C#路径中获取文件全路径、目录、扩展名、文件名称

    C#路径中获取文件全路径.目录.扩展名.文件名称 原文链接:https://www.cnblogs.com/JiYF/p/6879139.html 常用函数 需要引用System.IO   直接可以调 ...

随机推荐

  1. Servelt&&JSP进阶

    Servlet与JSP进阶 来自mkw的视频课程的总结 1.前言 内容包括 掌握Java Web核心特性,Servlet核心对象以及JSP九大内置对象.主要有以下的内容: 请求结构 && ...

  2. Golang语言系列-14-单元测试

    单元测试 字符串切割函数 package split_string import ( "fmt" "strings" ) // Split:切割字符串 // e ...

  3. 使用POI把查询到的数据表数据导出到Excel中,一个表一个sheet.最详细!!!

    一.需求 我们会遇到开发任务: 经理:小王,你来做一下把数据库里的数据导出到Excel中,一个表是一个sheet,不要一个表一个Excel. 小王:好的,经理.(内心一脸懵逼) 二.前期准备 首先我们 ...

  4. SeacmsV10.7版代码审计笔记

    data: 2020.11.9 10:00AM description: seacms代码审计笔记 0X01前言 seacms(海洋cms)在10.1版本后台存在多处漏洞,事实上当前最新版V10.7这 ...

  5. stm32 connot enter debug mode

    dap 可以发现设备,stlink jlink 均无法发现设备,但是都不能下载.connot enter debug mode ,发现是vdda 未连接

  6. 黑马JVM教程——自学笔记(三)

    四.类加载与字节码技术 4.1.类文件结构 首先获得.class字节码文件 方法: 在文本文档里写入java代码(文件名与类名一致),将文件类型改为.java java终端中,执行javac X:.. ...

  7. WPF 中的style 样式

    WPF相较于以前学的WinForm,WPF在UI设计与动画方面的炫丽是最吸引我来学习的.在WPF中XMAL代码的引入使得代码的编写能够前后端分离,为获得更好的界面,也使得我们不得不分出一半的时间花在前 ...

  8. 【java web】拦截器inteceptor

    一.简介 java里的拦截器提供的是非系统级别的拦截,也就是说,就覆盖面来说,拦截器不如过滤器强大,但是更有针对性. Java中的拦截器是基于Java反射机制实现的,更准确的划分,应该是基于JDK实现 ...

  9. Java File常见用法

    一.构造方法 File(File parent, String child) 从父抽象路径名和子路径名字符串创建新的 File实例. File(String pathname) 通过将给定的路径名字符 ...

  10. ES6扩展——函数扩展之默认参数

    1.函数的默认参数 //函数的默认参数 function add(a, b = 999){ console.log(a,b); //1 999 } add(1); 2. 函数的形参可以设置默认值,默认 ...