PHP 使用 sqlsrv 一次检索包含流内容的多行

PHP retrieve multiple rows with stream content at once with sqlsrv

这是 this question 的跟进。

此代码重试数据库中的一行,其中一列是资源,并使用它创建一个文件系统文件。

$query = "select top(1) DESCRIPTION, FILETYPE, DOCUMENT from dbo.Documents;";
$stmt = sqlsrv_query($this->sqlsrv_conn, $query);
if (sqlsrv_fetch($stmt)) {
    $document = sqlsrv_get_field($stmt, 2, SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_BINARY));
    // $fileName = sqlsrv_get_field($stmt, 0, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR));
    // $ext = sqlsrv_get_field($stmt, 1, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR));
    file_put_contents(
        // $fileName . '.' . $ext,
        'filename'.'.doc',
        stream_get_contents($document),
    );
} 

现在我必须对数据库中的所有记录执行此操作,而不仅仅是一个。实现该目标的最佳方法是什么?

我查看了 sqlsrv_fetch_array,它有一个参数“$fetchType”,但这是为了定义行以何种格式组合在一起(编号或关联数组)。
如何为该行数组下的每一列定义 fetchType?就像我可以使用 sqlsrv_get_field($stmt, 2, SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_BINARY)) 当只获取一行时。

注意:我收到的反馈是我的问题往往不清楚,如果您看到可以改进的地方以使这个问题更好更容易回答,请告诉我。

编辑

谢谢@Zhorov while 循环确实有效!但我面临一个新的愚蠢问题。
我撒谎了,我发布的代码并不完全适合我。显然我也没有通过获取文件名和扩展名来正确测试它。只有当我将二进制数据作为流 没有其他任何东西 .

时才起作用

完全看不懂。以下代码按预期工作:

$query = "select top(1) DESCRIPTION, FILETYPE, DOCUMENT from dbo.Documents;";
$stmt = sqlsrv_query($this->sqlsrv_conn, $query);
if (sqlsrv_fetch($stmt)) {
    $document = sqlsrv_get_field($stmt, 2, SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_BINARY));
    // $fileName = sqlsrv_get_field($stmt, 0, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR));
    file_put_contents(
        // $fileName . '.doc',
        'filename.doc',
        stream_get_contents($document),
    );
} 

但如果我还想获取文件名或其他任何内容

$query = "select top(1) DESCRIPTION, FILETYPE, DOCUMENT from dbo.Documents;";
$stmt = sqlsrv_query($this->sqlsrv_conn, $query);
if (sqlsrv_fetch($stmt)) {
    $document = sqlsrv_get_field($stmt, 2, SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_BINARY));
    $fileName = sqlsrv_get_field($stmt, 0);
    file_put_contents(
        'filename.doc',
        stream_get_contents($document),
    );
} 

我得到以下异常:

Error: stream_get_contents(): supplied resource is not a valid stream resource File

我用xdebug调试到这个程度。这是两个场景的屏幕截图。这是具有有效流且没有异常的 运行(您可以看到“type=stream”):

在这里,我唯一做的就是在异常发生之前删除行上的注释和断点(您可以看到“type=Unknown”): 为什么获取其他东西会中断流? (无论是否使用 while 循环,此行为都是相同的)

编辑 2

当更改调用 sqlsrv_get_field 的顺序时,行为确实会发生变化。如果我把二进制数据放在文件名后面,$document变量就是false。甚至没有“未知”流。

编辑:正如@Zhorov 指出的那样,原因是:

From documentation - sqlsrv_get_field retrieves data from the specified field of the current row. Field data must be accessed in order. For example, data from the first field cannot be accessed after data from the second field has been accessed

@Zhorov 让我找到了正确的解决方案。

看来必须最后访问流内容。如果我在文档之前获取文件名,则流为“未知”并抛出异常。但是,如果我最终获得了流,它就会起作用!

自己看看。以下是流无效的版本:

最后在 DOCUMENT 列中检索二进制数据时,它起作用了: