PHP stream_get_contents() 从数据库读取 LOB 的行为很奇怪
Posted
技术标签:
【中文标题】PHP stream_get_contents() 从数据库读取 LOB 的行为很奇怪【英文标题】:PHP stream_get_contents() behaves strangely reading an LOB from a database 【发布时间】:2017-05-14 05:49:09 【问题描述】:我的表中有 2 条记录具有相似的 CLOB 数据。其中的每一个都是从查询中解析出来的,然后通过 php 在循环中针对返回的 PDO::FETCH_ASSOC 读入字符串
查询返回结果后是这样的:
ID | NAME | DESCRIPTION | LOB_DEFINITION
4409 foo blah blah long text that is stored in a lob ~ 5k characters
4410 foobar blah blah some other long text stored in a lob ~ 5k characters
我的问题是,一旦我开始循环并从 LOB 中读取内容,它们就不会“重置”因此,所有读取的对象都将具有与它读取的第一个 LOB 相同的值:
类似这样的:
foreach($result as $r)
$lob = stream_get_contents($r['LOB_DEFINITION']);
echo $r['ID'].'-<i>'.$lob.'</i><HR>';
unset($lob);
结果如下所示:
4409-存储在 lob 中的长文本 ~ 5k 个字符
4410-存储在 lob 中的长文本 ~ 5k 个字符
而不是我期望得到的结果是:
4409-存储在 lob 中的长文本 ~ 5k 个字符
4410-存储在 lob 中的一些其他长文本 ~ 5k 个字符
我也检查了资源 ID,它们是不同的资源...
我在这里不知所措......有人对这个主题有见解吗?
【问题讨论】:
为什么...您为此使用stream_get_contents()
?我是在想。你不是已经把结果拉进去了吗?为什么需要stream_get_contents()
。这与使用 Oracle 有关吗?因为据我从手册中可以看出,stream_get_contents()
或多或少等同于file_get_contents()
,除了它在流上运行......我看不到从数据库中检索到的资源如何以任何方式成为流?
检索到的 LOB 是一个流:如果您简单地回显 $r['LOB_DEFINITION'],它将在屏幕上打印一个资源 ID。这个资源是一个句柄(类似于文件句柄),可以而且应该通过 stream_get_contents 或类似的东西来读取。它已经并且一直在为我的项目中的其他几个对象工作,这是我第一次循环它们,但似乎有一些有趣的事情发生。
啊哈。不熟悉Oracle/LOB。因此问题。可能是关于输出内容后流没有拾取/释放的问题?也许有一个重置/停止/设置它?我看到这里有多个示例和建议:php.net/manual/en/pdo.lobs.php - 也许你可以找到一些有用的东西。
【参考方案1】:
这是由于 PDO(OCI)::fetchAll 中的一个长期存在的错误 https://bugs.php.net/bug.php?id=46728
您不必像 Jeffs 的回答那样对每一行进行单独的查询。你只需要避免fetchAll。根据错误描述中建议的解决方法,我正在使用以下函数来获取所有 LOB:
function fetchAllLOB(PDOStatement $stmt): array
$result = [];
while ($row = $stmt->fetch())
foreach ($row as $name => $value)
if (is_resource($value))
$row[$name] = stream_get_contents($value);
$result[] = $row;
return $result;
【讨论】:
【参考方案2】:几个小时的研究得出以下结论:
从其中一列是 clob 数据类型的 oracle 表返回多记录集将导致检索到的最后一条记录 clob 是检索到的所有 clob 的值。这就是导致上述行为的原因。
我最终解决问题的方法是:
选择我计划使用 clob 的所有记录(不是 clob 本身,只是记录 ID)
然后,我遍历这些记录 ID,并通过单独的数据库调用,使用主键逐个处理 CLOB 数据以拉入记录,以确保不超过 1 条记录与 clob 数据一起返回。所以本质上,这就是现在正在发生的事情:
在从表中检索到我想要使用的所有 clob 的 ID 后,我就对它们进行了解析:
foreach($result as $r)
$query = 'select lob_definition from mytable where id = '.$r;
$lobresult = oracleConnection->query($query)->fetchAll(FETCH_COLUM);
$lob = stream_get_contents($lobresult);
echo $r['ID'].'-<i>'.$lob.'</i><HR>';
unset($lob);
某种意义上的东西已经解决了我的问题(所有这些都以各种方法抽象出来,但本质上就是这样。
【讨论】:
谢谢!我按照您的建议解决了这个问题。 我很高兴它有帮助以上是关于PHP stream_get_contents() 从数据库读取 LOB 的行为很奇怪的主要内容,如果未能解决你的问题,请参考以下文章
18.有一个网页地址, 比如PHP开发资源网主页: http://www.phpres.com/index.html,如何得到它的内容?
[问答题]有一个网页地址, 比如PHP开发资源网主页: http://www.phpres.com/index.html,如何得到它的内容?
PhpSpreadsheet 从内存而不是文件加载 Excel 文件?
linux 安装多个PHP版本(php5.6 php7.1 php7.2 php7.3 php7.4 php8.0)nginx配置php多版本