当存储为 blob 时,微小的 PNG 会膨胀
Tiny PNGs bloating up in size when stored as blob
我有一个 PHP 脚本试图将图像作为 blob 存储到 MySQL table 中。该脚本运行良好,并按预期完成工作。但是,当尝试从 table 查看存储的图像时,我注意到只存储了上半部分;剩下的只是切断!这就是我的意思:
此外,我注意到在存储为 blob 时图像大小无缘无故地被填充了。有问题的图像(左)最初是 46kB,但是当从 table(右)下载时,它显示 36kB(我知道 BLOB 最多可以占用 64kB,所以这应该不是问题)。这也发生在较小的图像上。
更有趣的是 PHPMyAdmin 中的文件大小看起来并不一致。看看:
这是在 table 视图中:
这是在插入视图中:
这是怎么回事?难道我做错了什么?一个 46kB 的文件如何在一个视图中变成 36 而在另一个视图中变成 90?
至于我的 max_allowed_packet 尺寸,它目前默认为 4194304,远高于我要存储的尺寸。
更新 这是将图像插入数据库的 PHP 片段:
foreach($files as $fname) {
if($fname != '.' && $fname != '..') {
rename($oldfolder.$fname, $newfolder.$fname);
$imgname = array_shift(explode(".",$fname)); //Individual image file name, without extension
echo "\n".$imgname;
$thumbph = fopen($newfolder.$fname, 'rb');
$sql = 'UPDATE distilled_contacts SET THUMB = ? WHERE PHONE = ?';
$connect = dbconn(PROJHOST,PROJDB,PROJDBUSER,PROJDBPWD);
$query = $connect->prepare($sql);
$query->bindParam(1, $thumbph, PDO::PARAM_LOB);
$query->bindParam(2, $imgname);
$query->execute();
$query = NULL;
$sql = NULL;
$connect = NULL;
}
}
dbconn() 函数如下所示:
function dbconn($strHost, $strDB, $strUser, $strPass) {
try {
$conn = new PDO("mysql:host=".$strHost.";dbname=".$strDB.";charset=utf8", $strUser, $strPass);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$conn->setAttribute(PDO::ATTR_PERSISTENT, true);
return $conn;
}
catch(PDOException $e) {
die("Could not connect to the database $dbname :" . $e->getMessage());
return false;
}
}
更新: 根据 Ryan 的要求,这里是 table 结构:
ID int(10) unsigned, auto-increment
PHONE varchar(20), utf8_unicode_ci
POPULARNAME varchar(60), utf8_unicode_ci
PREFERREDNAME varchar(60), utf8_unicode_ci
LATITUDE float(8,6)
LONGITUDE float(9,6)
LASTSEEN datetime
THUMB blob
数据库的默认排序规则是 utf8_unicode_ci
,我无法更改,因为我需要支持非欧洲语言。
PHP 版本: 5.5.20,
MySQL版本:5.6.24
您在连接字符串中使用了 utf-8。这可能是问题所在吗?您可能必须删除它并使用 "SET NAMES utf8".
看到这个:Is a BLOB converted using the current/default charset in MySQL?
另请查看此处的评论:http://php.net/manual/en/pdo.lobs.php
具体来说:
I spend a lot of time trying to get this to work, but no matter what I
did PDO corrupted my data.
I finally discovered that I had been using:
$pdo->exec('SET CHARACTER SET utf8');
in the TRY part of my connection script.
This off course doesn't work when you feed binary input to PDO using
the parameter lob.
更新
像这样
function dbconn($strHost, $strDB, $strUser, $strPass) {
try {
$conn = new PDO("mysql:host=".$strHost.";dbname=".$strDB, $strUser, $strPass);
$conn->exec('SET CHARACTER SET utf8');
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$conn->setAttribute(PDO::ATTR_PERSISTENT, true);
return $conn;
}
catch(PDOException $e) {
die("Could not connect to the database $dbname :" . $e->getMessage());
return false;
}
}
作为 'method' 的要求,以确保图像文件的 'upload' 和 'display' 正常工作:
当 'things' 变得混乱时 - 我相信 'back to first principles' 可以确保 'basics' 正常工作。
我有 'work' 此处包含您的数据的脚本。我希望您确保这些脚本按预期工作。
我已将您的图片上传到正确尺寸的 'blob' 中并正确显示。
这些不是 'pretty' - 它们需要工作并且易于检查。
脚本:上传图片:
<?php // Q30212477_uploading-image.php
session_start();
DEFINE ('BIGGEST_FILE', 64 * 1024);
/*
Table: distilled_contacts
Field Type Collation Null Key Default Extra Privileges Comment
----------- ----------- --------------- ------ ------ ------- -------------- -------------------- ---------
id int(11) (NULL) NO PRI (NULL) auto_increment select,insert,update
PHONE varchar(20) utf8_general_ci NO (NULL) select,insert,update
POPULARNAME varchar(60) utf8_general_ci NO (NULL) select,insert,update
LATITUDE float (NULL) NO (NULL) select,insert,update
LONGITUDE float (NULL) NO (NULL) select,insert,update
THUMB mediumblob (NULL) NO (NULL) select,insert,update
*/
?>
<?php if (!empty($_FILES)): // process the form... ?>
<?php // process the input files...
// start file processing...
/* debug */ // var_dump($_FILES); // show what we got as files...
// database connection...
$dsn = 'mysql:host=localhost;dbname=testmysql';
$username = 'test';
$password = 'test';
$options = array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8',
);
$connection = new PDO($dsn, $username, $password, $options);
$connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
if (is_uploaded_file($_FILES['thumb']['tmp_name'])) {
$imgThumb = fopen($_FILES['thumb']['tmp_name'], 'rb');
$stmt = $connection->prepare("INSERT INTO distilled_contacts (`PHONE`, `POPULARNAME`,
`LATITUDE`, `LONGITUDE`,
`THUMB`)
VALUES (?, ?, ?, ?, ?)");
$stmt->bindValue(1, $_POST['phone'], PDO::PARAM_STR);
$stmt->bindValue(2, $_POST['popularname'], PDO::PARAM_STR);
$stmt->bindValue(3, $_POST['latitude'], PDO::PARAM_STR);
$stmt->bindValue(4, $_POST['longitude'], PDO::PARAM_STR);
$stmt->bindParam(5, $imgThumb, PDO::PARAM_LOB);
$connection->beginTransaction();
$stmt->execute();
$connection->commit();
fclose($imgThumb);
}
else
echo "Error uploading image";
unset($connection);
?>
<?php endif; // processed the form? ?>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Upload images</title>
</head>
<body>
<form action="" method="POST" enctype="multipart/form-data">
<input type="hidden" name="MAX_FILE_SIZE" value="<?php echo BIGGEST_FILE ?>">
<label for="phone">Phone Number</label>
<input type="text" name="phone" id="phone" value="1-800-TESTFILE"><br>
<label for="popularname">Popular Name</label>
<input type="text" name="popularname" id="popularname" value="Jane Doe"><br>
<label for="latitude">Latitude</label>
<input type="text" name="latitude" id="latitude" value="29.9792"><br>
<label for="latitude">Longitude</label>
<input type="text" name="longitude" id="longitude" value="31.1344"><br>
<label for="">Thumb image</label>
<input type="file" name="thumb" id="thumb" value="test_image_Q30212477.png"><br>
<input type="submit" value="Upload file" />
</form>
</body>
</html>
<?php if (empty($_FILES)) {
exit; // leave this script...
} ?>
并且:显示图像:
<?php // index.php
//
// !!! Change this id for your record!!!
$ID = '1';
// database connection...
$dsn = 'mysql:host=localhost;dbname=testmysql';
$username = 'test';
$password = 'test';
$options = array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8',
);
$connection = new PDO($dsn, $username, $password, $options);
$connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// query
$stmt = $connection->prepare("SELECT `PHONE`, `POPULARNAME`,
`LATITUDE`, `LONGITUDE`,
`THUMB`
FROM
`distilled_contacts` dc
WHERE
dc.id = ?");
$result = array('PHONE' => "", 'POPULARNAME' => "",
'LATITUDE' => "", 'LONGITUDE' => "",
'THUMB' => null);
$stmt->bindColumn(1, $result['PHONE']);
$stmt->bindColumn(2, $result['POPULARNAME']);
$stmt->bindColumn(3, $result['LATITUDE']);
$stmt->bindColumn(4, $result['LONGITUDE']);
$stmt->bindColumn(5, $result['THUMB']);
// which row to return
$stmt->bindValue(1, $ID);
$allOK = $stmt->execute();
// this returns an arry of results
$allResults = $stmt->fetchAll(PDO::FETCH_ASSOC);
/* debug */ // var_dump($result);
$currentRow = current($allResults);
?>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Upload images</title>
</head>
<body>
<ul>
<li>Phone: <?= $currentRow['PHONE'] ?></li>
<li>Name: <?= $currentRow['POPULARNAME'] ?></li>
<li>Lat: <?= $currentRow['LATITUDE'] ?></li>
<li>Long: <?= $currentRow['LONGITUDE'] ?><li>
<li>
<div style="border: red solid 1px;">
<img src="<?= 'data:image/'. 'png' .';base64,'. base64_encode($currentRow['THUMB']); ?>">
</div>
</li>
</ul>
</body>
</html>
您需要更改图像 ID 的 $ID
变量。
我有一个 PHP 脚本试图将图像作为 blob 存储到 MySQL table 中。该脚本运行良好,并按预期完成工作。但是,当尝试从 table 查看存储的图像时,我注意到只存储了上半部分;剩下的只是切断!这就是我的意思:
此外,我注意到在存储为 blob 时图像大小无缘无故地被填充了。有问题的图像(左)最初是 46kB,但是当从 table(右)下载时,它显示 36kB(我知道 BLOB 最多可以占用 64kB,所以这应该不是问题)。这也发生在较小的图像上。
更有趣的是 PHPMyAdmin 中的文件大小看起来并不一致。看看:
这是在 table 视图中:
这是在插入视图中:
这是怎么回事?难道我做错了什么?一个 46kB 的文件如何在一个视图中变成 36 而在另一个视图中变成 90?
至于我的 max_allowed_packet 尺寸,它目前默认为 4194304,远高于我要存储的尺寸。
更新 这是将图像插入数据库的 PHP 片段:
foreach($files as $fname) {
if($fname != '.' && $fname != '..') {
rename($oldfolder.$fname, $newfolder.$fname);
$imgname = array_shift(explode(".",$fname)); //Individual image file name, without extension
echo "\n".$imgname;
$thumbph = fopen($newfolder.$fname, 'rb');
$sql = 'UPDATE distilled_contacts SET THUMB = ? WHERE PHONE = ?';
$connect = dbconn(PROJHOST,PROJDB,PROJDBUSER,PROJDBPWD);
$query = $connect->prepare($sql);
$query->bindParam(1, $thumbph, PDO::PARAM_LOB);
$query->bindParam(2, $imgname);
$query->execute();
$query = NULL;
$sql = NULL;
$connect = NULL;
}
}
dbconn() 函数如下所示:
function dbconn($strHost, $strDB, $strUser, $strPass) {
try {
$conn = new PDO("mysql:host=".$strHost.";dbname=".$strDB.";charset=utf8", $strUser, $strPass);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$conn->setAttribute(PDO::ATTR_PERSISTENT, true);
return $conn;
}
catch(PDOException $e) {
die("Could not connect to the database $dbname :" . $e->getMessage());
return false;
}
}
更新: 根据 Ryan 的要求,这里是 table 结构:
ID int(10) unsigned, auto-increment
PHONE varchar(20), utf8_unicode_ci
POPULARNAME varchar(60), utf8_unicode_ci
PREFERREDNAME varchar(60), utf8_unicode_ci
LATITUDE float(8,6)
LONGITUDE float(9,6)
LASTSEEN datetime
THUMB blob
数据库的默认排序规则是 utf8_unicode_ci
,我无法更改,因为我需要支持非欧洲语言。
PHP 版本: 5.5.20, MySQL版本:5.6.24
您在连接字符串中使用了 utf-8。这可能是问题所在吗?您可能必须删除它并使用 "SET NAMES utf8".
看到这个:Is a BLOB converted using the current/default charset in MySQL?
另请查看此处的评论:http://php.net/manual/en/pdo.lobs.php
具体来说:
I spend a lot of time trying to get this to work, but no matter what I did PDO corrupted my data.
I finally discovered that I had been using:
$pdo->exec('SET CHARACTER SET utf8');
in the TRY part of my connection script.
This off course doesn't work when you feed binary input to PDO using the parameter lob.
更新
像这样
function dbconn($strHost, $strDB, $strUser, $strPass) {
try {
$conn = new PDO("mysql:host=".$strHost.";dbname=".$strDB, $strUser, $strPass);
$conn->exec('SET CHARACTER SET utf8');
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$conn->setAttribute(PDO::ATTR_PERSISTENT, true);
return $conn;
}
catch(PDOException $e) {
die("Could not connect to the database $dbname :" . $e->getMessage());
return false;
}
}
作为 'method' 的要求,以确保图像文件的 'upload' 和 'display' 正常工作:
当 'things' 变得混乱时 - 我相信 'back to first principles' 可以确保 'basics' 正常工作。
我有 'work' 此处包含您的数据的脚本。我希望您确保这些脚本按预期工作。
我已将您的图片上传到正确尺寸的 'blob' 中并正确显示。
这些不是 'pretty' - 它们需要工作并且易于检查。
脚本:上传图片:
<?php // Q30212477_uploading-image.php
session_start();
DEFINE ('BIGGEST_FILE', 64 * 1024);
/*
Table: distilled_contacts
Field Type Collation Null Key Default Extra Privileges Comment
----------- ----------- --------------- ------ ------ ------- -------------- -------------------- ---------
id int(11) (NULL) NO PRI (NULL) auto_increment select,insert,update
PHONE varchar(20) utf8_general_ci NO (NULL) select,insert,update
POPULARNAME varchar(60) utf8_general_ci NO (NULL) select,insert,update
LATITUDE float (NULL) NO (NULL) select,insert,update
LONGITUDE float (NULL) NO (NULL) select,insert,update
THUMB mediumblob (NULL) NO (NULL) select,insert,update
*/
?>
<?php if (!empty($_FILES)): // process the form... ?>
<?php // process the input files...
// start file processing...
/* debug */ // var_dump($_FILES); // show what we got as files...
// database connection...
$dsn = 'mysql:host=localhost;dbname=testmysql';
$username = 'test';
$password = 'test';
$options = array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8',
);
$connection = new PDO($dsn, $username, $password, $options);
$connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
if (is_uploaded_file($_FILES['thumb']['tmp_name'])) {
$imgThumb = fopen($_FILES['thumb']['tmp_name'], 'rb');
$stmt = $connection->prepare("INSERT INTO distilled_contacts (`PHONE`, `POPULARNAME`,
`LATITUDE`, `LONGITUDE`,
`THUMB`)
VALUES (?, ?, ?, ?, ?)");
$stmt->bindValue(1, $_POST['phone'], PDO::PARAM_STR);
$stmt->bindValue(2, $_POST['popularname'], PDO::PARAM_STR);
$stmt->bindValue(3, $_POST['latitude'], PDO::PARAM_STR);
$stmt->bindValue(4, $_POST['longitude'], PDO::PARAM_STR);
$stmt->bindParam(5, $imgThumb, PDO::PARAM_LOB);
$connection->beginTransaction();
$stmt->execute();
$connection->commit();
fclose($imgThumb);
}
else
echo "Error uploading image";
unset($connection);
?>
<?php endif; // processed the form? ?>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Upload images</title>
</head>
<body>
<form action="" method="POST" enctype="multipart/form-data">
<input type="hidden" name="MAX_FILE_SIZE" value="<?php echo BIGGEST_FILE ?>">
<label for="phone">Phone Number</label>
<input type="text" name="phone" id="phone" value="1-800-TESTFILE"><br>
<label for="popularname">Popular Name</label>
<input type="text" name="popularname" id="popularname" value="Jane Doe"><br>
<label for="latitude">Latitude</label>
<input type="text" name="latitude" id="latitude" value="29.9792"><br>
<label for="latitude">Longitude</label>
<input type="text" name="longitude" id="longitude" value="31.1344"><br>
<label for="">Thumb image</label>
<input type="file" name="thumb" id="thumb" value="test_image_Q30212477.png"><br>
<input type="submit" value="Upload file" />
</form>
</body>
</html>
<?php if (empty($_FILES)) {
exit; // leave this script...
} ?>
并且:显示图像:
<?php // index.php
//
// !!! Change this id for your record!!!
$ID = '1';
// database connection...
$dsn = 'mysql:host=localhost;dbname=testmysql';
$username = 'test';
$password = 'test';
$options = array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8',
);
$connection = new PDO($dsn, $username, $password, $options);
$connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// query
$stmt = $connection->prepare("SELECT `PHONE`, `POPULARNAME`,
`LATITUDE`, `LONGITUDE`,
`THUMB`
FROM
`distilled_contacts` dc
WHERE
dc.id = ?");
$result = array('PHONE' => "", 'POPULARNAME' => "",
'LATITUDE' => "", 'LONGITUDE' => "",
'THUMB' => null);
$stmt->bindColumn(1, $result['PHONE']);
$stmt->bindColumn(2, $result['POPULARNAME']);
$stmt->bindColumn(3, $result['LATITUDE']);
$stmt->bindColumn(4, $result['LONGITUDE']);
$stmt->bindColumn(5, $result['THUMB']);
// which row to return
$stmt->bindValue(1, $ID);
$allOK = $stmt->execute();
// this returns an arry of results
$allResults = $stmt->fetchAll(PDO::FETCH_ASSOC);
/* debug */ // var_dump($result);
$currentRow = current($allResults);
?>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Upload images</title>
</head>
<body>
<ul>
<li>Phone: <?= $currentRow['PHONE'] ?></li>
<li>Name: <?= $currentRow['POPULARNAME'] ?></li>
<li>Lat: <?= $currentRow['LATITUDE'] ?></li>
<li>Long: <?= $currentRow['LONGITUDE'] ?><li>
<li>
<div style="border: red solid 1px;">
<img src="<?= 'data:image/'. 'png' .';base64,'. base64_encode($currentRow['THUMB']); ?>">
</div>
</li>
</ul>
</body>
</html>
您需要更改图像 ID 的 $ID
变量。