2013-02-06 49 views
5
  1. मेरे पास एक बीएलओबी फ़ील्ड वाला एक टेबल है।
  2. तालिका का अक्षर लैटिन 1 है।
  3. मैं डीबी से कनेक्ट हूं और "सेट वर्णक सेट utf8"।
  4. फिर मैं बाइनरी डेटा को फ़ील्ड में सहेजता हूं।
  5. फिर मैं डेटा पुनर्प्राप्त करता हूं, और यह नहीं है कि मैंने सहेजा (भ्रष्ट)।

कोड:क्या एक बीएलओबी MySQL में वर्तमान/डिफ़ॉल्ट वर्णसेट का उपयोग करके परिवर्तित किया गया है?

<?php 
$pdo = new \PDO("mysql:host=127.0.0.1;dbname=***", '***', '***'); 

$pdo->exec('SET CHARACTER SET utf8'); 

$sql = "INSERT INTO pdo_blob (the_blob) VALUES(:the_blob)"; 
$insertStm = $pdo->prepare($sql); 

$blob = (binary) file_get_contents('/home/***/test.pdf'); 
$insertStm->bindParam(":the_blob", $blob, \PDO::PARAM_LOB); 
$insertStm->execute(); 

$selectStm = $pdo->prepare("SELECT the_blob FROM pdo_blob ORDER BY id DESC LIMIT 1"); 
$selectStm->execute(); 

$savedBlob = null; 
$selectStm->bindColumn(1, $savedBlob, \PDO::PARAM_LOB); 
$selectStm->fetch(); 

echo 'equal: ' . ((int) ($blob == $savedBlob)); 
+4

सबसे पहले, कृपया अपना कोड लिखने और पढ़ने के लिए उपयोग किए जाने वाले कोड को दिखाएं - मुझे लगता है कि आप इसे सही नहीं कर रहे हैं। दूसरा, बीएलओबी किसी भी अक्षर चयन से प्रभावित नहीं होना चाहिए। – mvp

+1

मैं इसे या तो काम नहीं कर सका; मैंने एक छोटे से 'favicon.ico' के साथ कोशिश की। तालिका में डाले जाने पर कुछ बाइट गायब थे। आप पुनर्प्राप्ति के बाद 'base64_encode()' डालने से पहले और 'base64_decode()' का उपयोग कर सकते हैं। यह डेटा को '33%' से मिटा देता है और रूपांतरण ओवरहेड होता है। – SparKot

+1

ने 'dll' फ़ाइल के साथ प्रयास किया, बाइट भी यहां गायब थे। 'mysql_real_escape_string()' किसी भी मदद की नहीं है। – SparKot

उत्तर

1

अच्छा उत्तर @ एमवीपी!

लेकिन जब अपने वेब एप्लिकेशन को UTF-8 है और डेटाबेस एन्कोडिंग latin1 है, मैंset the character_set_client and character_set_results करने के लिए है

जब मैं SET CHARACTER SET utf8 का उपयोग करता हूं, तो मुझे बीएलओबी के साथ वर्णित समस्या मिली।

लेकिन जब मैं SET NAMES utf8 का उपयोग करता हूं तो यह काम करता है!

+0

वास्तव में समस्या हल हो गई। – user151851

+0

मेरे लिए नहीं ... मेरे पास इस समस्या को मेरी zf2 वेबसाइट के साथ है ... – Amelie

1

संपादित करें: WAMP-सर्वर

पर यह पीडीओ एपीआई के साथ काम नहीं किया। पुनर्प्राप्ति के बाद आप डालने और base64_decode() का उपयोग कर सकते हैं। यह 33% द्वारा डेटा bloats और रूपांतरण एक ओवरहेड है।

MySQLi एपीआई एक विकल्प तो यहाँ कर रहे हैं कुछ कोड है:

<?php 
$mysqli = new mysqli('localhost', 'spark', 'spark123', 'test'); 

$sql = "INSERT INTO blob_tb (bdata) VALUES(?)"; 
$insertStm = $mysqli->prepare($sql); 

$blob = NULL; //necessary 
$insertStm->bind_param('b', $blob); 

$blob = (binary) (file_get_contents('favicon.ico')); 
$insertStm->send_long_data(0, $blob); 

$insertStm->execute(); 
$insertStm->close(); 

$selectStm = $mysqli->prepare("SELECT bdata FROM blob_tb LIMIT 1"); 
$selectStm->execute(); 

$selectStm->bind_result($savedBlob); 
$selectStm->fetch(); 
$selectStm->close(); 

$mysqli->close(); 

echo 'equal: ' . ((int) ($blob == $savedBlob)); 
// var_dump(($blob), strlen($blob)); 
// var_dump(($savedBlob), strlen($savedBlob)); 
// var_dump(get_defined_vars()); 

?> 
+0

उत्तर के लिए धन्यवाद। यह जाने का एक तरीका है लेकिन मुझे पीडीओ का उपयोग करने की ज़रूरत है। मैं जानना चाहता हूं कि ऐसा क्यों होता है। – user151851

5

लघु उत्तर:

आप हटा सकते हैं या नीचे लाइन बाहर टिप्पणी, और यह हमेशा काम करेंगे, कोई फर्क नहीं पड़ता जो डेटाबेस एन्कोडिंग है वास्तव में उपयोग (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";