लघु उत्तर:
आप हटा सकते हैं या नीचे लाइन बाहर टिप्पणी, और यह हमेशा काम करेंगे, कोई फर्क नहीं पड़ता जो डेटाबेस एन्कोडिंग है वास्तव में उपयोग (utf8
, latin1
, आदि) में:
$pdo->exec('SET CHARACTER SET utf8');
लांग उत्तर:
यह पीडीओ बग नहीं है, यह MySQL बग है।
जब वास्तविक डेटाबेस एन्कोडिंग latin1
है, लेकिन आप का उपयोग करें:
SET CHARACTER SET utf8
(या इसके विपरीत: वास्तविक utf8
है, लेकिन आप latin1
का उपयोग करें - महत्वपूर्ण हिस्सा है कि यह अलग है), तो, के रूप में जहां तक मैं कह सकता हूं, MySQL क्लाइंट और सर्वर के बीच सभी ट्रैफ़िक के लिए वर्णसेट रूपांतरण करने का प्रयास करेगा (यहां तक कि BLOB
के लिए भी!)।
आप मैं स्क्रिप्ट (PHP/पीडीओ या पर्ल/DBI) कनेक्शन चारसेट डिफ़ॉल्ट रूप से के लिए क्या देख से SET CHARACTER SET
बयान, उपयोग नहीं करते हैं डेटाबेस चारसेट होने के लिए सेट कर दिया जाता है, और उस मामले में कोई अंतर्निहित रूपांतरण जगह लेता है।
जाहिर है, यह स्वचालित रूपांतरण बीएलओबी को मारता है, जो कोई रूपांतरण नहीं होना चाहता है।
मैं दोनों PHP/पीडीओ और पर्ल/DBI पर इस परीक्षण किया है, और इस मुद्दे को आसानी से प्रतिलिपि प्रस्तुत करने योग्य है: दोनों अगर latin1
एन्कोडिंग के साथ डेटाबेस का उपयोग और SET CHARACTER SET utf8
(या इसके विपरीत) का उपयोग असफल हो जायेगी।
आप पूरी तरह से UTF8
संगत होना चाहते हैं, तो आप का उपयोग कर अपने डेटाबेस की एन्कोडिंग बदलना चाहिए:
ALTER DATABASE mydb CHARSET utf8;
इस के साथ
, सब कुछ UTF8
का उपयोग करेंगे, और BLOBs भी ठीक से काम करेगा।
इस भ्रष्टाचार की समस्या का कारण बनने वाली न्यूनतम फ़ाइल blob.bin
एकल बाइट 0xFF
के साथ है। लिनक्स पर, तो आप इस परीक्षण फ़ाइल printf
आदेश का उपयोग कर बना सकते हैं:
printf "0xFF" > blob.bin
अब
, परीक्षण स्क्रिप्ट है कि समस्या को पुन:
पीएचपी परीक्षण कोड:
<?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";
सबसे पहले, कृपया अपना कोड लिखने और पढ़ने के लिए उपयोग किए जाने वाले कोड को दिखाएं - मुझे लगता है कि आप इसे सही नहीं कर रहे हैं। दूसरा, बीएलओबी किसी भी अक्षर चयन से प्रभावित नहीं होना चाहिए। – mvp
मैं इसे या तो काम नहीं कर सका; मैंने एक छोटे से 'favicon.ico' के साथ कोशिश की। तालिका में डाले जाने पर कुछ बाइट गायब थे। आप पुनर्प्राप्ति के बाद 'base64_encode()' डालने से पहले और 'base64_decode()' का उपयोग कर सकते हैं। यह डेटा को '33%' से मिटा देता है और रूपांतरण ओवरहेड होता है। – SparKot
ने 'dll' फ़ाइल के साथ प्रयास किया, बाइट भी यहां गायब थे। 'mysql_real_escape_string()' किसी भी मदद की नहीं है। – SparKot