有没有什么方法可以将PDO查询结果"流"到输出缓冲区中,而不是将其存储到字符串中?

gd1*_*gd1 6 php mysql pdo

如果您看到此问题的标题,则几乎没有添加内容.

我有一个从MySQL表中检索单行的查询,我对特定列感兴趣,这是一个BLOB.我希望PHP将其写入输出缓冲区,而不是将~500 KB存储到字符串中(此外我不确定它是否是二进制安全的).

PDOStatement的功能如下:

string PDOStatement::fetchColumn ([ int $column_number = 0 ] )
Run Code Online (Sandbox Code Playgroud)

不帮我

你能帮我一个方向吗?提前致谢.

PS:我知道在DB表中存储~500 KB的东西并不好,但这不是我的选择,我只需要坚持下去.

meu*_*rus 2

请参阅此页。这会将数据加载到流中,然后可以与 f* 函数一起使用,包括使用 fpassthru 直接输出到浏览器。这是该页面的示例代码:

<?php
$db = new PDO('odbc:SAMPLE', 'db2inst1', 'ibmdb2');
$stmt = $db->prepare("select contenttype, imagedata from images where id=?");
$stmt->execute(array($_GET['id']));
$stmt->bindColumn(1, $type, PDO::PARAM_STR, 256);
$stmt->bindColumn(2, $lob, PDO::PARAM_LOB);
$stmt->fetch(PDO::FETCH_BOUND);

header("Content-Type: $type");
fpassthru($lob);
?>
Run Code Online (Sandbox Code Playgroud)

这里的关键是,在 后$stmt->execute(),您调用$stmt->bindColumn('columnName', $stream, PDO::PARAM_LOB);,然后调用$stmt->fetch(PDO::FETCH_BOUND)来获取该行(其中的值存储到绑定的 PHP 变量中)。这就是我在 Drupal 中使用它、测试和工作的方式;它包含许多额外的缓存处理,可以加快您的客户端速度,并且只需要您跟踪 blob 的上次修改时间:

<?php
$rfc2822_format = 'D, d M Y H:i:s e';

// This is basically the Drupal 7 way to create and execute a prepared
// statement; the `->execute()` statement returns a PDO::Statement object.
// This is the equivalent SQL:
//   SELECT f.fileType,f.fileSize,f.fileData,f.lastModified
//   FROM mfiles AS f WHERE fileID=:fileID
// (with :fileID = $fileID)
$statement = db_select('mfiles', 'f')
  ->fields('f', array('fileType', 'fileSize', 'fileData', 'lastModified'))
  ->condition('fileID', $fileID, '=')
  ->execute();
// All of the fields need to be bound to PHP variables with this style.
$statement->bindColumn('fileType', $fileType, PDO::PARAM_STR, 255);
$statement->bindColumn('fileSize', $fileSize, PDO::PARAM_INT);
$statement->bindColumn('fileData', $fileData, PDO::PARAM_LOB);
$statement->bindColumn('lastModified', $lastModified, PDO::PARAM_STR, 19);

$success = false;

// If the row was fetched successfully...
if ($statement->fetch(PDO::FETCH_BOUND)) {
  // Allow [public] caching, but force all requests to ask the server if
  // it's been modified before serving a cache [no-cache].
  header('Cache-Control: public no-cache');

  // Format the Last-Modified time according to RFC 2822 and send the
  // Last-Modified HTTP header to aid in caching.
  $lastModified_datetime = DateTime::createFromFormat('Y-m-d H:i:s',
    $lastModified, new DateTimeZone('UTC'));
  $lastModified_formatted = $lastModified_datetime->format($rfc2822_format);
  header('Last-Modified: ' . $lastModified_formatted);

  // If the client requested If-Modified-Since, and the specified date/time
  // is *after* $datetime (the Last-Modified date/time of the API call), give
  // a HTTP/1.1 304 Not Modified response and exit (do not output the rest of
  // the page).
  if (array_key_exists('HTTP_IF_MODIFIED_SINCE', $_SERVER)) {
    // Ignore anything after a semicolon (old browsers sometimes added stuff
    // to this request after a semicolon).
    $p = explode(';', $_SERVER['HTTP_IF_MODIFIED_SINCE'], 2);
    // Parse the RFC 2822-formatted date.
    $since = DateTime::createFromFormat($rfc2822_format, $p[0]);

    if ($lastModified_datetime <= $since) {
      header('HTTP/1.1 304 Not Modified');
      exit;
    }
  }

  // Create an ETag from the hash of it and the Last-Modified time, and send 
  // it in an HTTP header to aid in caching.
  $etag = md5($lastModified_formatted . 'mfile:' . $fileID);
  header('ETag: "' . $etag . '"');

  // If the client requested If-None-Match, and the specified ETag is the
  // same as the hashed ETag, give a HTTP/1.1 304 Not Modified response and
  // exit (do not output the rest of the page).
  if (array_key_exists('HTTP_IF_NONE_MATCH', $_SERVER) && $etag ==
      str_replace('"', '', stripslashes($_SERVER['HTTP_IF_NONE_MATCH']))) {
    header('HTTP/1.1 304 Not Modified');
    exit;
  }

  // Set the content type so that Apache or whatever doesn't send it as
  // text/html.
  header('Content-Type: ' . $fileType);

  // Set the content length so that download dialogs can estimate how long it
  // will take to load the file.
  header('Content-Length: ' . $fileSize);

  // According to some comments on the linked page, PDO::PARAM_LOB might
  // create a string instead of a stream.
  if (is_string($fileData)) {
    echo $fileData;
    $success = true;
  } else {
    $success = (fpassthru($fileData) !== false);
  }
}
?>
Run Code Online (Sandbox Code Playgroud)

旁白:如果您需要提供文件名,一个快速但肮脏的解决方案是将文件名添加到引用该文件的实际 URL 中;用来。http://example.com/fileurl.phphttp://example.com/fileurl.php/filename.jpg如果某些东西已经在解释路径信息(如 Drupal),这可能不起作用;“更好”的解决方案是发送 header Content-Disposition: attachment; filename=filename.jpg,但这也会阻止客户端直接在浏览器中查看图像(尽管这可能是一件好事,具体取决于您的情况)。