PHP中的文件對比擴展 https://directory.fsf.org/wiki/LibXDiff

文件對比這個擴展現在用得比較少,因爲大部分情況下我們都在使用一些代碼管理工具,比如 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

各自媒體平臺均可搜索【硬核項目經理】

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章