This is kind of a follow up of this question.
This code retries a row from the database where one column is a resource and creates a file system file with it.
$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),
);
}
Now I have to do this with all the records in the database, not only one. What is the best way to achieve that?
I looked at sqlsrv_fetch_array which has an argument "$fetchType" but this is to define in which format the rows are grouped together (numbered or assoc array).
How can I define the fetchType for each column under that array of rows? Like I can with sqlsrv_get_field($stmt, 2, SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_BINARY)) when only one row is fetched.
Note: I have received the feedback that my questions tend to be unclear, if you see things that can be improved to make this question better and easier to answer, please let me know.
Edit
Thank you @Zhorov the while loop does work! But I face a new silly issue.
I lied, the code I posted was not exactly the code that worked for me. Apparently I didn't test it properly with fetching the file name and extension as well. What worked was only when I fetched the binary data as a stream with nothing else.
I don't understand it at all. The following code works like expected:
$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),
);
}
But if I also want to fetch the file name or anything else
$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),
);
}
I get the following exception:
Error: stream_get_contents(): supplied resource is not a valid stream resource File
I debugged it down to this with xdebug. Here are screenshots of the two scenarios. This is the run with a valid stream and no exception (you can see the "type=stream"):

And here, the only thing I did is remove the comment on the line and a breakpoint right before the exception happens (you can see the "type=Unknown"):
Why does fetching something else break the stream? (This behaviour is the same when I using while loop or not)
Edit 2
Behaviour does change when changing the order in which sqlsrv_get_field is called. If I put the binary data after the file name, the $document variable is false. Not even an "Unknown" stream.
Edit: Reason for this is, as @Zhorov pointed out:
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


