php - 将非常大的 Blob 从 MySQL 流式传输到 PHP 并创建一个文件
问题描述
我们有一个 MySQL 数据库,其中有一些非常大的文件存储在 blob 字段中,例如一些超过 700MB 的视频。文件大小范围从 0.5 MB PDF 到 JPEGS 等...
我正在尝试使用 PHP 来检索这些列并在服务器上创建一个文件,该文件稍后将作为下载提供。
我目前正在使用以下方法:
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
PDO::MYSQL_ATTR_MAX_BUFFER_SIZE => 1024*1024*500
];
try {
$pdo = new PDO($dsn, $user, $pass, $options);
} catch (\PDOException $e) {
throw new \PDOException($e->getMessage(), (int)$e->getCode());
}
$stmt = $pdo->prepare('SELECT a.TITLE, a.ATTVERSION, a.ATTACHMENTID, a.CONTENTTYPE, a.FILESIZE, d.DATA FROM ATTACHMENTS a
LEFT JOIN ATTACHMENTDATA d ON d.ATTACHMENTID=a.ATTACHMENTID
WHERE a.ATTACHMENTID= ?');
$stmt->execute([$fileid]);
$file = $stmt->fetch();
file_put_contents($storage_dir . "/" . $filename, $file['DATA']);
这适用于较小的文件(注意我将缓冲区大小设置为 500MB),但较大的文件会被截断和损坏。
接下来我尝试了 LOB 和无缓冲查询方法:
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false,
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => false
];
try {
$pdo = new PDO($dsn, $user, $pass, $options);
} catch (\PDOException $e) {
throw new \PDOException($e->getMessage(), (int)$e->getCode());
}
$stmt = $pdo->prepare('SELECT a.TITLE, a.ATTVERSION, a.ATTACHMENTID, a.CONTENTTYPE, a.FILESIZE, d.DATA FROM ATTACHMENTS a
LEFT JOIN ATTACHMENTDATA d ON d.ATTACHMENTID=a.ATTACHMENTID
WHERE a.ATTACHMENTID= ?');
$stmt->execute([$fileid]);
$stmt->bindColumn(1, $title, PDO::PARAM_STR, 256 );
$stmt->bindColumn(2, $attversion, PDO::PARAM_INT);
$stmt->bindColumn(3, $attid, PDO::PARAM_INT);
$stmt->bindColumn(4, $contenttype, PDO::PARAM_STR, 256);
$stmt->bindColumn(5, $filesize, PDO::PARAM_INT);
$stmt->bindColumn(6, $data, PDO::PARAM_LOB);
$stmt->fetch(PDO::FETCH_BOUND);
file_put_contents($storage_dir . "/" . $filename, $data)
使用这个选项,我只得到 1MB 的文件,它似乎忽略了 MYSQL_ATTR_USE_BUFFERED_QUERY => false 并且因为我没有设置缓冲区大小,所以它默认为 1MB。任何人都可以提供任何建议或看到任何明显的东西吗?MySQL 在不同的服务器上,但我也愿意以另一种方式这样做,并通过 PHP 调用 bash 脚本或其他东西。
解决方案
这最初是在 php 5.4.16 上完成的,它似乎不支持无缓冲流。升级到 php 8.0.11 后,我现在可以正常工作了,除了使用 ini_set 增加 PHP 内存。
推荐阅读
- sql - 如何防止ms sql server中现有表中给定外键的重复条目。?
- firebase - [] 未在 Map 中定义
- python - python - 如何根据Python中的条件合并两行熊猫数据框?
- bash - 用新的一组行替换多行的 Bash 脚本
- textures - 如何在three.js中沿曲线实现一系列精灵
- html - 当没有输出可用时,如何在 SHINY 中控制 HTML 背景不显示
- java - 有没有可能 JMenuBar 可以点击的方式?
- c# - 如何减少安装包的 LibCef.dll 大小
- acr - AKS 与 ACR 不同订阅的集成
- python-3.x - python3 在 Apple 硅 M1 上安装 Tensorflow