【问题标题】:Image data gets corrupted on its way to the browser图像数据在到达浏览器的途中被损坏
【发布时间】:2012-09-18 00:32:36
【问题描述】:

我有一个在 Drupal 下在 LAMP 环境中运行的应用程序。它从数据库中提供图像。在我的个人机器(OS X Lion)上,它工作正常。在开发服务器 (Amazon EC2) 上,完全相同的代码不起作用。两台服务器都运行 PHP 5.3。我已经确认数据在echo $fileData 和浏览器接收之间已损坏。此外,我已经确认,如果数据是 base64 编码的,则数据不会损坏(我使用脚本来请求数据、对其进行解码并将其保存到文件中)。

在 Drupal 方面,代码位于创建菜单回调的模块中;回调函数直接回显文件数据以避免将整个图像存储在内存中(我使用 PDO::FETCH_BOUND 和 PDO::PARAM_LOB 来创建一个流,但是当我试图找到问题时它现在正在进入一个字符串; 不是这样)。菜单条目有一个自定义的传递回调,它基本上什么都不做。我尝试刷新任何输出缓冲,认为 Drupal 可能过于努力地支持 Unicode 或其他东西,但这也无济于事。

我希望有人知道可能导致我的问题的原因。如果我还不够清楚,我会发布一些代码;现在它充满了注释掉的功能,所以需要一些清理。

更新 1:

我整理了一些示例代码,但没有出现错误;我可以将代码转换为 Drupal 模块来测试该代码堆栈。但是,我已将错误范围缩小到echo $fileData。代码如下所示:

function example_menu() {
  $pages['mpicture/%'] = array(
    'title' => 'Picture handler',
    'page callback' => 'example_picture',
    'page arguments' => array(1),
    'delivery callback' => 'example_deliver_png',
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
  );
}

function example_picture($fileID) {
  // Point 1
  example_output_file($fileID);
}

function example_deliver_png($content) {
}

function example_output_file($fileID) {
  $statement = db_select('mfiles', 'f')
    ->fields('f', array('fileType', 'fileSize', 'fileData', 'fileData64', 'lastModified'))
    ->condition('fileID', $fileID, '=')
    ->execute();

  if ($file = $statement->fetchAssoc()) {
    header('Content-Type: ' . $file['fileType']);
    // Point 2
    header('Content-Length: ' . $file['fileSize']);
    echo $file['fileData'];
  }
}

这不起作用。如果我将Point 2 更改为:

    // Point 2
    header('Content-Length: ' . $file['fileSize']*4/3);
    echo $file['fileData64'];

只要我的客户端在输出上运行base64_decode,它就可以正常工作。但是,如果我这样做:

  // Point 1
  ob_start()
  example_output_file($fileID);
  $output = base64_encode(ob_get_clean());
  header('Content-Length: ' . strlen($output));
  echo $output;

...它不适用于相同的 base64_decodeing 客户端。怎么可能?

是的,我将数据存储了两次;在我运行的每一个测试中,使用$file['fileData']base64_decode($file['fileData64']) 都没有关系,所以我认为这不是数据库问题。

更新 2:

但奇怪的是,这是可行的:

  // Point 1
  ob_start()
  example_output_file($fileID);
  $output = base64_encode(trim(ob_get_clean()));
  header('Content-Length: ' . strlen($output));
  echo $output;

所以,我想我现在尝试找到空白打印的位置?

【问题讨论】:

  • 您可以在 [drupal.stackexchange.com](drupal.stackexchange.com) 上重新发布您的问题。
  • 在这一点上,我很确定这不是 Drupal 的事情,因为我正在更改所有标头并刷新输出缓冲区,所以 Drupal 不应该有任何办法弄乱输出.此外,每次我在drupal.stackexchange.com 上发布内容时,它都没有得到任何答案或 cmets;我感觉大多数 Drupal 人都会在官方支持论坛上给予支持。无论如何,我只提到了 Drupal 的东西,试图涵盖所有的可能性。
  • 如果你查看原始图像二进制文件,你能确认是否出现了任何 html PHP 错误吗?
  • 不确定您使用的是什么浏览器,但在 Google Chrome 中,您能否检查并验证图片中的标头是否正确发送?打开开发控制台,网络选项卡,点击镜像源,查看头信息。代码示例肯定也会有所帮助。
  • 如果你对你的内容进行base64编码,你不应该设置一个内容传输编码头吗?我将使用 curl 检查标头和二进制响应。将文件大小乘以 4/3 似乎是个麻烦事。

标签: php apache drupal drupal-7


【解决方案1】:

我要勒死实习生。我发誓。不是真的,这是一种表达方式……但我很生气。

整个问题是因为他添加的新文件末尾有空格。一个简单的“?>\n”。这在服务器上的每个页面之前打印的空白,包括图像处理程序。空白使图像损坏。

我想这里的道德是永远不要在文件末尾关闭 PHP 标记,并确保与你一起工作的每个人都这样做。

【讨论】:

  • 这篇文章拯救了我的一天。我遇到了同样的问题,只是我匆忙编写了一些代码。 15 分钟的编码在 php 结束标记后留下 2 个空格,导致 3 小时的调试。 Grr.
  • 庆幸它只有 3 个小时,而不是一整周。请记住,您不需要在文件末尾关闭 PHP 标记。这是完全有效的,实际上在 Zend 项目的风格中(或者我听说过):<?php echo 'hello world';(没有?>
猜你喜欢
  • 2020-09-07
  • 2015-06-11
  • 2021-08-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多