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

调用VirusTotal API 2.0始终返回资源未在扫描队列的问题

解决VirusTotal API扫描文件时返回资源不存在的问题

看起来你遇到的核心问题是调用VirusTotal API上传文件后,始终无法获取扫描状态,返回"The requested resource is not among the finished, queued or pending scans",而且手动上传正常,说明API密钥和文件本身没问题,问题大概率出在PHP代码的文件上传逻辑上。结合你的代码和VirusTotal公开API的特性,我整理了几个关键修复点:

1. 修复PHP文件上传的CURL语法(最可能的根本原因)

在PHP 5.5及以上版本中,curl的@语法用于文件上传已经被废弃,默认会被当作普通字符串处理,而不是文件上传。你的AdrianTNT脚本中用了$post['file'] = '@'.$fileToScan;,这会导致VirusTotal无法正确接收文件,自然返回资源不存在的错误。

修改方式:使用CURLFile代替旧的@语法

替换AdrianTNT脚本中的上传代码部分:

// 原代码(错误)
$post['file'] = '@'.$fileToScan;

// 修改为:
$post['file'] = new CURLFile(realpath($fileToScan));

如果你的PHP版本低于5.5(不推荐),可以手动开启CURLOPT_SAFE_UPLOAD为false,但优先推荐使用CURLFile:

curl_setopt($ch, CURLOPT_SAFE_UPLOAD, false);

2. 确保文件路径正确且PHP有读取权限

不管是临时上传文件还是移动后的文件,都要确保:

  • 文件路径是绝对路径(用realpath()验证)
  • PHP进程对该文件有读取权限(比如WAMP环境下,apache用户需要能访问C:/WAMP/www/server/files/目录)

可以在调用扫描函数前添加调试代码:

$filePath = realpath($tmpdir.$fileName);
if (!file_exists($filePath) || !is_readable($filePath)) {
    error_log("文件不存在或无法读取:".$filePath);
    exit;
}

3. 处理API速率限制(公开API的硬限制)

VirusTotal公开API有严格的速率限制:

  • 每分钟最多4个请求
  • 每天最多500个请求

如果你的测试过程中频繁调用API,可能会被临时限制,导致请求被静默拒绝。可以在上传后添加延迟,或者在查询结果时加入重试逻辑(带指数退避):

// 上传文件后,等待一段时间再查询结果(比如10秒)
sleep(10);
// 然后调用查询接口

4. 调试完整的API响应

你目前只输出了部分响应内容,建议把整个API返回的JSON都打印出来,看看有没有隐藏的错误信息:

error_log("完整API响应:".$api_reply);
$api_reply_array = json_decode($api_reply, true);
error_log("响应数组:".print_r($api_reply_array, true));

比如可能返回文件大小超过限制(公开API最大支持32MB,超过需要先获取上传URL),或者请求头不正确。

5. 修复IzzyOnDroid类的调用逻辑

如果你用的是IzzySoft的virustotal.class.php,确保checkFile()方法内部正确处理了文件上传。可以查看该类的源码,确认它是否使用了正确的CURL文件上传方式,如果没有,手动修改类中的上传逻辑,替换为CURLFile。

6. 正确处理扫描状态的等待逻辑

即使文件成功上传到VirusTotal,公开API的扫描也需要排队,不会立刻返回结果。你需要循环查询扫描状态,直到返回response_code=1(有结果)或response_code=-2(排队中):

// 示例:循环查询扫描结果,最多重试5次
$maxRetries = 5;
$retryCount = 0;
$scanId = $api_reply_array['scan_id']; // 上传成功后获取的scan_id
while ($retryCount < $maxRetries) {
    $reportUrl = "https://www.virustotal.com/vtapi/v2/file/report?apikey={$virustotal_api_key}&resource={$scanId}";
    $reportReply = file_get_contents($reportUrl);
    $reportArray = json_decode($reportReply, true);
    
    if ($reportArray['response_code'] == 1) {
        // 有结果,处理 positives
        break;
    } elseif ($reportArray['response_code'] == -2) {
        // 排队中,等待后重试
        sleep(15);
        $retryCount++;
    } else {
        // 其他错误,退出循环
        break;
    }
}

验证测试

修改后,先用一个小的、未知的无毒文件测试,比如新建一个空白文本文件,上传后观察API响应:

  • 上传成功应该返回response_code=1,并带有scan_id
  • 查询时,第一次可能返回-2(排队),几次重试后返回1(结果)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:29:02