You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Varbinary图片数据经PHP返回后被识别为文本而非图片?

问题:PHP返回二进制图片数据无法在浏览器正常显示

我想通过PHP把二进制图片数据返回给浏览器显示,但尝试了包括设置header('Content-Type: image/jpeg');在内的多种方法都不行。当前流程是:HTML上传JPEG图片,JavaScript读取后用XMLHttpRequest发送到PHP;PHP接收base64编码数据,解码成二进制后输出,预期在指定img标签中显示图片,但功能失效。

以下是可复现代码:

PHP代码(upload.php)

<?PHP
ini_set('memory_limit', '1024M');
/* 
  Must have more than 512MB memory_limit
*/
ini_set('error_reporting', E_ALL);
ini_set('display_errors', 'On');
function uploadImage($conn) 
{
  $encodedData = $_POST['URLData'];
  $data = json_decode($encodedData);
  
  $name = $data->name;
  $qr = $data->qrDataUrl;
  $file = $data->fileDataUrl;

  $baseDataURL = explode(',', $file)[1];
  $decodedData = base64_decode($baseDataURL);

  echo $decodedData;
}
if (isset($_POST['URLData'])) 
{
  try 
  {
    $connection = array("Database" => "", "UID"=>"",
                        "PWD"=>"");
    $conn = sqlsrv_connect('', $connection);

    uploadImage($conn);
  }
  catch(Exception $e)
  {
    echo $e->getMessage();
    die();
  }
}
?>

HTML/JavaScript代码

<!DOCTYPE html>
<html>
  <head>
    <meta charset='UTF-8'>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="Stylesheet2.css">
    <link rel="stylesheet" href="Stylesheet.css">
    <script src="javascript/qr.js"></script>
  </head>
  <body>
    <div class="container">
      <h2>Image Upload</h2>
      <div class="form-group">
        <label style="text-align: center;" for="image">Select JPEG Image:</label>
        <div class="file-input-container">
          <label class="file-input-button" for="image">Upload</label>
          <div class="file-input-text">
            <p id="file-text">No File Chosen</p>
          </div>
        </div>
        <input type="file" id="image" accept="image/jpeg" onchange="handleFileSelect(event)">
      </div>
      <p id="message"></p>
      <div style = "margin: 20px 0px 40px 0px;" id="qrcode"></div>
      <p style="text-align: center; margin: 0px;">
        Example of acceptable image name. <b><u>22OC48-1i</u>.jpg</b></p>
      <div id="yes"></div>
    </div>
  </body>
  <script>
    function handleFileSelect(event) 
    {
      const fileInput = event.target;
      const fileNameContainer = document.getElementById('file-text');
      const message = document.getElementById('message');
      const qrDiv = document.getElementById("qrcode");

      if (fileInput.files.length > 0) 
      {
        const file = fileInput.files[0];
        const reader = new FileReader();


        fileNameContainer.innerText = file.name;


        const qrcode = new QRCode("qrcode");
        qrcode.makeCode(file.name.substring(0,7));
        

        reader.onload = function(e) 
        {
          message.innerText = "Uploading Image. Don't Leave";


          const data = {
            name : file.name,
            qrDataUrl : encodeURIComponent(qrDiv.getElementsByTagName("img")[0].src),
            fileDataUrl : e.target.result
          };

          console.log(data.uploadDataURL);

          const xhttp = new XMLHttpRequest();
          xhttp.onreadystatechange = function() 
          {
            if (this.readyState == 4 && this.status == 200) 
            {
              if (this.responseText == 'exists')
              {
                message.innerText = "Cannot Upload Duplicates.";
              }
              else if (this.responseText == 'uploaded')
              {
                document.getElementById('message').innerText = 'Image Was Uploaded';
              }
              else
              {
                document.getElementById('yes').innerHTML = '<img src="'+this.response+'" alt="Image">';
              }
            }
          };
          xhttp.open("POST", "upload.php", true);
          xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
          xhttp.send("URLData=" + JSON.stringify(data));
        }
        setTimeout(function() {
          reader.readAsDataURL(file);
        }, 100);
      } 
      else 
      {
        fileNameContainer.innerText = 'No file chosen';
      }
    }
  </script>
</html>

问题根源与修复方案

1. PHP端:缺少正确响应头+多余输出干扰

  • 必须在输出二进制数据前设置Content-Type头,明确告诉浏览器返回的是JPEG图片
  • 禁止任何多余输出(错误提示、PHP标签前后空格等),否则会破坏二进制数据结构

修改后的PHP代码:

<?PHP
ini_set('memory_limit', '1024M');
// 关闭前台错误输出,避免干扰二进制数据
ini_set('error_reporting', 0);
ini_set('display_errors', 'Off');

function uploadImage($conn) 
{
  $encodedData = $_POST['URLData'];
  $data = json_decode($encodedData);
  
  $file = $data->fileDataUrl;
  $baseDataURL = explode(',', $file)[1];
  $decodedData = base64_decode($baseDataURL);

  // 设置正确的图片响应头
  header('Content-Type: image/jpeg');
  // 清空输出缓冲区,确保无多余内容
  ob_clean();
  flush();
  echo $decodedData;
  exit; // 输出后立即终止程序,避免后续代码产生输出
}

if (isset($_POST['URLData'])) 
{
  try 
  {
    $connection = array("Database" => "", "UID"=>"", "PWD"=>"");
    $conn = sqlsrv_connect('', $connection);
    uploadImage($conn);
  }
  catch(Exception $e)
  {
    // 错误信息写入日志,不要直接输出
    error_log($e->getMessage());
    header('HTTP/1.1 500 Internal Server Error');
    echo 'error';
    die();
  }
}
?>

2. JavaScript端:二进制响应处理方式错误

直接将XMLHttpRequest的response赋值给img的src无效,因为response是原始二进制数据,需要转换成浏览器可识别的URL格式,可通过Blob和URL.createObjectURL()实现:

修改后的JavaScript请求部分:

const xhttp = new XMLHttpRequest();
// 设置响应类型为blob,正确接收二进制数据
xhttp.responseType = 'blob';
xhttp.onreadystatechange = function() 
{
  if (this.readyState == 4 && this.status == 200) 
  {
    const responseText = this.responseText;
    if (responseText == 'exists')
    {
      message.innerText = "Cannot Upload Duplicates.";
    }
    else if (responseText == 'uploaded')
    {
      document.getElementById('message').innerText = 'Image Was Uploaded';
    }
    else
    {
      // 将blob对象转换为临时URL
      const blobUrl = URL.createObjectURL(this.response);
      document.getElementById('yes').innerHTML = `<img src="${blobUrl}" alt="Image">`;
      // 页面卸载时释放临时URL资源
      window.addEventListener('unload', () => URL.revokeObjectURL(blobUrl));
    }
  }
};
xhttp.open("POST", "upload.php", true);
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhttp.send("URLData=" + JSON.stringify(data));

额外注意事项

  • 若需支持多种图片格式,可根据上传文件的MIME类型动态设置Content-Type
  • 数据库连接逻辑如果暂时不需要,可注释掉,避免连接失败的错误输出干扰图片数据

内容的提问来源于stack exchange,提问作者Azur_Was_here

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 02:54:53