PHP中的文件對比擴展文件對比這個擴展現(xiàn)在用得比較少,因為大部分情況下我們都在使用一些代碼管理工具,比如 Git 或者 Svn 之類的,其實它的作用就非常類似這類工具,另外還有一個非常常用的 Beyond Compare 工具也能方便地讓我們能夠進行文件的對比。 安裝及準備工作在 PHP 中的這個文件擴展叫做 xdiff 擴展,我們可以直接在 pecl 中下載并安裝。 需要注意的是,安裝這個擴展需要操作系統(tǒng)安裝 libxdiff 工具,在文章最下方的參考鏈接中有這個工具的官網(wǎng)地址。libxdiff 無法使用默認的 yum 安裝,所以需要下載之后自行安裝。和其它的 Linux 工具一樣,安裝過程非常簡單,這里就不多贅述了。 xdiff 擴展支持字符串和文件兩種形式的差異對比以及一些相關的操作,這里我們以字符串的操作為主進行講解,文件相關的操作將在最后給出全部的操作函數(shù)用法。首先,我們需要定義一些字符串以及相關的文件便于后續(xù)的操作。 $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() 函數(shù)就可以獲得兩段字符串中的差異信息。可以看到它的內(nèi)容結構和 Git 的文件差異對比返回的內(nèi)容非常相似。像用 + 、 - 號表示的那一行的差異,我們只要使用過 Git 或 Svn 就一定不會陌生。 合并字符串var_dump(xdiff_string_merge3($old_article, $new_article, $new_article1, $error)); // string(180) "我本無為野客,飄飄浪跡人間。 // 一時被命住名山。未免隨機應變。 // 識破塵勞擾擾,何如樂取清閑。一 // 流霞細酌詠詩篇。且與白云為伴。" var_dump($error); // NULL
xdiff_string_merge3() 函數(shù)用于將三個字符串合并到一起,也是類似于 Git 中的 merge 功能。不過這個函數(shù)需要三個字符串,但是通過測試我們發(fā)現(xiàn)只有第一個 $new_article 和原始的 $old_article 合并成功了。第三個 $new_article1 并沒有合并到最后返回的字符串中。關于這個函數(shù)的功能和實際的效果并不一致的問題并沒有找到任何相關的參考資料,官方文檔的介紹也非常地簡單,所以如果大家如果有知道這個函數(shù)的真實具體情況的,可以留言一起討論哦! $error 參數(shù)是一個可選的引用參數(shù),如果合并過程中出現(xiàn)任何問題它將返回錯誤信息。 修補數(shù)據(jù)(補?。?/span>var_dump(xdiff_string_patch($old_article, $diff, XDIFF_PATCH_NORMAL, $errors)); // string(180) "我本無為野客,飄飄浪跡人間。 // 一時被命住名山。未免隨機應變。 // 識破塵勞擾擾,何如樂取清閑。一 // 流霞細酌詠詩篇。且與白云為伴。" var_dump($errors); // NULL
從函數(shù)的名稱中的 patch 就能看出,這個 xdiff_string_patch() 是為差異字符串打補丁用的。在曾經(jīng)的桌面時代,不管是操作系統(tǒng)還是各種游戲,都經(jīng)常會更新各種補丁。這里的補丁其實和合并差異比較類似。它的第一個參數(shù)是原始的字符串,第二個參數(shù)是 xdiff_string_diff() 生成的差異數(shù)據(jù),打補丁的結果就是返回正式的全并差異之后的字符串。 第三個參數(shù)是可選的,它還可以定義成 XDIFF_PATCH_REVERSE ,也就是反轉補丁,只返回原始的數(shù)據(jù),不返回差異合并后的結果。反過來說,使用這個參數(shù)我們可以將第一個參數(shù)設置為修改后的 $new_article ,然后反轉回原始的數(shù)據(jù),大家可以自行嘗試一下。最后的參數(shù)同樣是可選的引用類型的錯誤變量。 二進制修補數(shù)據(jù)$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() 可以對這個二進制的字符串操作結果打補丁,也就是合并差異。另外在二進制操作中還有一個函數(shù) xdiff_string_bdiff_size() 用于返回二進制差異函數(shù)所返回的結果中的字符長度。 $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() ,也是返回二進制的數(shù)據(jù)差異信息的。它和 xdiff_string_bdiff() 的區(qū)別主要是使用的算法不同。 文件操作上面我們詳細地介紹了 xdiff 擴展對于字符串的操作。它同時還提供了一系列的針對文件的操作,使用這些直接操作文件的函數(shù)就真的和我們的 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) "我本無為野客,飄飄浪跡人間。 // 一時被命住名山。未免隨機應變。二 // 識破塵勞擾擾,何如樂取清閑。 // 流霞細酌詠詩篇。且與白云為伴。 // 三一四一"
這里我們就不一一講解了,這些函數(shù)的操作和功能與字符串操作的相關函數(shù)都是類似的,只是參數(shù)略有不同。比如它們在對比或者合并、補丁之后都會生成一個文件,所有函數(shù)的參數(shù)都是以文件為基礎的。大家可以自行運行一下測試代碼并參考官方文檔進行學習。 總結關于這個 xdiff 擴展其實我們使用得并不多,不過曾經(jīng)看過有一套開源的使用 PHP 來做的 CMS 系統(tǒng)中管理前端模板頁面的功能中就使用到了這一套擴展。任何工具的存在都有它的意義,或許你在為某個功能而苦惱的時候正好就看到了這篇文章,從而輕松地解決了手頭上的問題也說不準,了解并有個大概的印象,在工作中才不至于摸瞎,這就是我們刷文檔的意義。 測試代碼: https://github.com/zhangyue0503/dev-blog/blob/master/php/202010/source/10.PHP中的文件對比擴展.php 參考文檔: https://www./manual/zh/book.xdiff.php https://directory./wiki/LibXDiff
|