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 的行为很奇怪的主要内容,如果未能解决你的问题,请参考以下文章

php oracle数据库clob和nclob字段

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多版本

php [guzzle php] guzzle php #php