संक्षिप्त उत्तर:
बस नीचे दी गई पंक्ति को हटाएं या टिप्पणी करें, और यह हमेशा काम करेगा, इससे कोई फर्क नहीं पड़ता कि कौन सा डेटाबेस एन्कोडिंग वास्तव में उपयोग में है (utf8
, latin1
, आदि):
$pdo->exec('SET CHARACTER SET utf8');
लंबा उत्तर:
यह PDO बग नहीं है, यह MySQL बग है।
जब वास्तविक डेटाबेस एन्कोडिंग latin1
हो , लेकिन आप उपयोग करते हैं:
SET CHARACTER SET utf8
(या इसके विपरीत:वास्तविक utf8
है , लेकिन आप latin1
. का उपयोग करते हैं - महत्वपूर्ण हिस्सा यह है कि यह भिन्न है ), फिर, जहाँ तक मैं बता सकता हूँ, MySQL क्लाइंट और सर्वर के बीच सभी ट्रैफ़िक के लिए वर्णसेट रूपांतरण करने का प्रयास करेगा (यहां तक कि BLOB
के लिए भी) !).
यदि आप SET CHARACTER SET
. का उपयोग नहीं करते हैं स्क्रिप्ट (PHP/PDO या Perl/DBI) कनेक्शन वर्णसेट के लिए जो मैं देखता हूं उससे कथन डिफ़ॉल्ट रूप से डेटाबेस वर्णसेट के रूप में सेट होता है, और उस स्थिति में कोई अंतर्निहित रूपांतरण नहीं होता है।
जाहिर है, यह स्वचालित रूपांतरण बीएलओबी को मारता है, जो नहीं चाहते कि कोई रूपांतरण हो।
मैंने PHP/PDO और Perl/DBI दोनों पर इसका परीक्षण किया है, और समस्या आसानी से प्रतिलिपि प्रस्तुत करने योग्य है:latin1
के साथ डेटाबेस का उपयोग करने पर दोनों विफल हो जाएंगे एन्कोडिंग और SET CHARACTER SET utf8
. का उपयोग करना (या इसके विपरीत)।
अगर आप पूरी तरह से UTF8
बनना चाहते हैं संगत, आपको निम्न का उपयोग करके अपने डेटाबेस के एन्कोडिंग को बदलना चाहिए:
ALTER DATABASE mydb CHARSET utf8;
इसके साथ, सब कुछ UTF8
का उपयोग कर रहा होगा , और बीएलओबी भी ठीक काम करेंगे।
इस भ्रष्टाचार समस्या का कारण बनने वाली न्यूनतम फ़ाइल है blob.bin
सिंगल बाइट के साथ 0xFF
. Linux पर, आप printf
. का उपयोग करके इस परीक्षण फ़ाइल को बना सकते हैं आदेश:
printf "0xFF" > blob.bin
अब, समस्या को पुन:उत्पन्न करने वाली स्क्रिप्ट का परीक्षण करें:
PHP परीक्षण कोड:
<?php
$dbh = new PDO("mysql:host=127.0.0.1;dbname=test");
# If database encoding is NOT utf8, uncomment to break it:
# $dbh->exec("SET CHARACTER SET utf8");
$blob1 = file_get_contents("blob.bin");
$sth = $dbh->prepare(
"INSERT INTO pdo_blob (the_blob) VALUES(:the_blob)"
);
$sth->bindParam(":the_blob", $blob1, PDO::PARAM_LOB);
$sth->execute();
$sth = $dbh->prepare(
"SELECT the_blob FROM pdo_blob ORDER BY id DESC LIMIT 1"
);
$sth->execute();
$blob2 = null;
$sth->bindColumn(1, $blob2, PDO::PARAM_LOB);
$sth->fetch();
if ($blob1 == $blob2) {
echo "Equal\n";
} else {
echo "Not equal\n";
$arr1 = str_split($blob1);
$arr2 = str_split($blob2);
$i=0;
for ($i=0; $i<count($arr1); $i++) {
if ($arr1[$i] != $arr2[$i]) {
echo "First diff: " . dechex(ord($arr1[$i])) . " != "
. dechex(ord($arr2[$i])) . "\n";
break;
}
}
}
?>
पर्ल टेस्ट कोड:
#!/usr/bin/perl -w
use strict;
use DBI qw(:sql_types);
my $dbh = DBI->connect("dbi:mysql:host=127.0.0.1;dbname=test");
# If database encoding is NOT utf8, uncomment to break it:
# $dbh->do("SET CHARACTER SET utf8");
open FILE, "blob.bin";
binmode FILE;
read(FILE, my $blob1, 100000000);
close FILE;
my $sth = $dbh->prepare(
"INSERT INTO pdo_blob (the_blob) VALUES(?)"
);
$sth->bind_param(1, $blob1, SQL_BLOB);
$sth->execute();
my ($blob2) = $dbh->selectrow_array(
"SELECT the_blob FROM pdo_blob ORDER BY id DESC LIMIT 1"
);
print ($blob1 eq $blob2 ? "Equal" : "Not equal") , "\n";