पहले सुधार, जो काफी सरल है:यदि आप IPv4 और IPv6 दोनों पतों को संग्रहीत करना चाहते हैं, तो आपको VARBINARY(16)
का उपयोग करना चाहिए BINARY(16)
. के बजाय ।
अब समस्या पर आते हैं:यह BINARY(16)
के साथ अपेक्षानुसार काम क्यों नहीं करता है? ?
विचार करें कि हमारे पास एक टेबल है ips
केवल एक कॉलम के साथ ip BINARY(16) PRIMARY KEY
.हम डिफ़ॉल्ट स्थानीय IPv4 पते को
$stmt = $db->prepare("INSERT INTO ips(ip) VALUES(?)");
$stmt->execute([inet_pton('127.0.0.1')]);
और डेटाबेस में निम्न मान खोजें:
0x7F000001000000000000000000000000
जैसा कि आप देखते हैं - यह एक 4 बाइट बाइनरी मान है (0x7F000001
)16 बाइट फिक्स्ड-लेंथ कॉलम में फ़िट होने के लिए ज़ीरो के साथ राइट-पैडेड।
जब आप अब इसे
. के साथ खोजने का प्रयास करते हैं$stmt = $db->prepare("SELECT * FROM ips WHERE ip = ?");
$stmt->execute([inet_pton('127.0.0.1')]);
निम्नलिखित होता है:PHP 0x7F000001
मान भेजता है पैरामीटर के रूप में जिसकी तुलना तब संग्रहीत मूल्य के साथ की जाती है 0x7F000001000000000000000000000000
.लेकिन चूंकि अलग-अलग लंबाई के दो बाइनरी मान कभी बराबर नहीं होते हैं, WHERE की स्थिति हमेशा FALSE लौटाएगी। आप इसके साथ कोशिश कर सकते हैं
SELECT 0x00 = 0x0000
जो 0
return लौटाएगा (गलत)।
नोट:निश्चित लंबाई गैर बाइनरी स्ट्रिंग्स के लिए व्यवहार अलग है (CHAR(N)
)।
हम वर्कअराउंड के रूप में स्पष्ट कास्टिंग का उपयोग कर सकते हैं:
$stmt = $db->prepare("SELECT * FROM ips WHERE ip = CAST(? as BINARY(16))");
$stmt->execute([inet_pton('127.0.0.1')]);
और यह पंक्ति ढूंढेगा। लेकिन अगर हम देखें कि हमें क्या मिलता है
var_dump(inet_ntop($stmt->fetch(PDO::FETCH_OBJ)->ip));
हम देखेंगे
string(8) "7f00:1::"
लेकिन वह नहीं है (वास्तव में) जिसे हमने स्टोर करने की कोशिश की है। और जब हम अब 7f00:1::
स्टोर करने का प्रयास करते हैं , हमें एक डुप्लिकेट कुंजी त्रुटि प्राप्त होगी , हालांकि हमने अभी तक कोई IPv6 पता संग्रहीत नहीं किया है।
तो एक बार फिर:VARBINARY(16)
. का प्रयोग करें , और आप अपने कोड को अछूता रख सकते हैं। यदि आप कई IPv4 पते संग्रहीत करते हैं, तो आप कुछ संग्रहण भी सहेज लेंगे।