为何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
相关产品推荐
相关产品推荐

