文件对比这个扩展现在用得比较少,因为大部分情况下我们都在使用一些代码管理工具,比如 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. spring security整体流程

    spring-security原理 图片中各个类的作用: 1JwtUser类:实现Springsecurity的UserDetails类,此类必须有三个属性 private String userna ...

  2. 安鸾CTF Writeup PHP代码审计01

    PHP代码审计 01 题目URL:http://www.whalwl.xyz:8017 提示:源代码有泄露 既然提示有源代码泄露,我们就先扫描一遍. 精选CTF专用字典: https://github ...

  3. DVWA(九):File Upload 全等级文件上传

    File Upload 文件上传,通常是由于对上传文件的类型没有进行严格的过滤.限制造成的,一般思路是 通过上传木马获取服务器的webshell(通过网络端口对网站服务器某种程度上的操作权限 也叫网站 ...

  4. SpringCloud升级之路2020.0.x版-21.Spring Cloud LoadBalancer简介

    本系列代码地址:https://github.com/HashZhang/spring-cloud-scaffold/tree/master/spring-cloud-iiford 我们使用 Spri ...

  5. Java序列化bean保存到本地文件中

    File file = new File("D:\\softTemp\\student.out"); ObjectOutputStream objectOutputStream = ...

  6. docker 安装部署 jenkins

    cd /data/docker-data/jenkins mkdir jenkins_home chmod 777 jenkins_home docker run -d -p 10240:8080 - ...

  7. LeetCoded第242题题解--java--数组

    数组 数组的优点在于: 构建非常简单 能在 O(1) 的时间里根据数组的下标(index)查询某个元素(连续内存+对象指向数组下标0位置+index能够直接找到元素) 而数组的缺点在于: 构建时必须分 ...

  8. JSP编码问题

    JSP的开头内容: 1 <%@ page language="java" contentType="text/html; charset=UTF-8" 2 ...

  9. 多线程编程<四>

    1 /** 2 * 守护线程daemon['diːmən] 3 * @author Administrator 4 * 5 */ 6 public class DaemonDemo { 7 publi ...

  10. redis连接池 go-redis

    为什么使用连接池? 首先Redis也是一种数据库,它基于C/S模式,因此如果需要使用必须建立连接,稍微熟悉网络的人应该都清楚地知道为什么需要建立连接,C/S模式本身就是一种远程通信的交互模式,因此Re ...