You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Google Drive/Docs API获取文档版本历史的具体变更内容

问题

已通过Google OAuth 2.0完成Google Docs/Drive API对接,采用PHP+Composer开发,目前能获取文档的Revision ID和修改时间,但无法获取各版本的具体变更信息。需要实现:

  • 通过JS/HTML按钮触发,根据版本ID或时间展示对应版本的具体变更
  • 文本新增用绿色标注、删除用红色标注
  • 支持识别图片新增等变更

当前代码:

<?php
require_once 'vendor/autoload.php';

session_start();

$client = new Google_Client();
$client->setAuthConfig('client_secrets.json');  // Path to your client_secrets.json file
$client->addScope(Google_Service_Drive::DRIVE_METADATA_READONLY);
$client->addScope(Google_Service_Docs::DOCUMENTS_READONLY);
$client->setRedirectUri('http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php');  // Path to your OAuth 2.0 callback file

if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
    $client->setAccessToken($_SESSION['access_token']);
    $driveService = new Google_Service_Drive($client);

    // Query to get Google Documents owned by the user
    $optParams = array(
        'q' => "'me' in owners and mimeType='application/vnd.google-apps.document'",
        'fields' => 'files(id, name)',
    );

    $results = $driveService->files->listFiles($optParams);

    if (count($results->getFiles()) == 0) {
        print "No Google Documents found.\n";
    } else {
        $userInfo = $driveService->about->get(['fields' => 'user']);
        $googleUsername = $userInfo->getUser()->getDisplayName();

        echo "Hello : " . $googleUsername . "<br><br>";

        print "Google Documents:<br>";
        foreach ($results->getFiles() as $file) {
            printf("Document: %s (%s)<br>", $file->getName(), $file->getId());

            $revisions = $driveService->revisions->listRevisions($file->getId());
            foreach ($revisions->getRevisions() as $revision) {
                $modTime = $revision->getModifiedTime();
                echo "Revision ID: " . $revision->getId() . ", Modified Time: " . $modTime . "<br>";
            }

            echo "<hr>"; // Add a horizontal rule
        }
    }
} else {
    $redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php';  // Path to your OAuth 2.0 callback file
    header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}
?>

解决方案

1. 权限调整

Google Drive API的DRIVE_METADATA_READONLY权限仅能获取元数据,无法读取版本内容,需要将其替换为DRIVE_READONLY,保留DOCUMENTS_READONLY用于解析文档结构:

$client->addScope(Google_Service_Drive::DRIVE_READONLY);
$client->addScope(Google_Service_Docs::DOCUMENTS_READONLY);

2. 获取历史版本内容

通过Drive API的revisions->get方法,可导出指定版本的文档为JSON/HTML格式,JSON更适合结构化解析文本和图片:

// 在遍历revision的循环中添加
$revisionId = $revision->getId();
// 导出JSON格式的历史版本内容
$revisionContent = $driveService->revisions->get($file->getId(), $revisionId, [
    'alt' => 'media',
    'mimeType' => 'application/vnd.google-apps.document+json'
])->getBody()->getContents();

3. 版本差异对比

文本差异

使用文本对比库(如sebastian/diff,通过Composer安装)生成差异标记,或前端用diff-match-patchJS库处理。示例后端处理:

// 安装依赖:composer require sebastian/diff
use SebastianBergmann\Diff\Differ;
use SebastianBergmann\Diff\Output\UnifiedDiffOutputBuilder;

// 获取当前版本文本和历史版本文本
$currentText = extractDocText($docsService->documents->get($fileId));
$revisionText = extractRevisionText(json_decode($revisionContent, true));

// 生成差异
$builder = new UnifiedDiffOutputBuilder("--- 当前版本\n+++ 历史版本 $revisionId\n");
$differ = new Differ($builder);
$diff = $differ->diff($currentText, $revisionText);

图片变更

解析JSON中的inlineObjects字段,对比当前版本与历史版本的图片ID,找出新增图片:

$currentImages = extractDocImages($docsService->documents->get($fileId));
$revisionImages = extractRevisionImages(json_decode($revisionContent, true));
$newImages = array_diff_key($revisionImages, $currentImages);

4. 前端交互与样式

给每个版本添加触发按钮,通过AJAX获取差异数据并渲染:

<!-- PHP遍历revision时输出按钮 -->
<button onclick="showDiff('<?php echo $file->getId(); ?>', '<?php echo $revisionId; ?>')">查看变更</button>
<div id="diff-<?php echo $file->getId().'-'.$revisionId; ?>" class="diff-container"></div>

<script>
function showDiff(fileId, revisionId) {
    fetch(`get_diff.php?fileId=${fileId}&revisionId=${revisionId}`)
        .then(res => res.json())
        .then(data => {
            document.getElementById(`diff-${fileId}-${revisionId}`).innerHTML = data.html;
        });
}
</script>

<style>
.diff-added { color: green; }
.diff-deleted { color: red; text-decoration: line-through; }
.diff-header { font-weight: bold; color: #666; }
.diff-container { margin: 10px 0; padding: 10px; border: 1px solid #eee; }
</style>

5. 辅助函数示例

// 提取当前版本文档文本
function extractDocText($doc) {
    $text = '';
    foreach ($doc->getBody()->getContent() as $content) {
        if (property_exists($content, 'paragraph')) {
            foreach ($content->getParagraph()->getElements() as $elem) {
                if (property_exists($elem, 'textRun')) {
                    $text .= $elem->getTextRun()->getContent();
                }
            }
        }
    }
    return $text;
}

// 提取历史版本文档文本
function extractRevisionText($revisionDoc) {
    $text = '';
    foreach ($revisionDoc['body']['content'] as $content) {
        if (isset($content['paragraph'])) {
            foreach ($content['paragraph']['elements'] as $elem) {
                if (isset($elem['textRun'])) {
                    $text .= $elem['textRun']['content'];
                }
            }
        }
    }
    return $text;
}

// 提取当前版本图片
function extractDocImages($doc) {
    $images = [];
    foreach ($doc->getInlineObjects() as $id => $obj) {
        if (property_exists($obj, 'inlineObjectProperties') && 
            property_exists($obj->getInlineObjectProperties(), 'imageProperties')) {
            $images[$id] = $obj->getInlineObjectProperties()->getImageProperties()->getContentUri();
        }
    }
    return $images;
}

内容的提问来源于stack exchange,提问作者Polarr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 17:55:01