PHP में Base64 डिकोडिंग: एक सम्पूर्ण गाइड
यह किसी सपोर्ट टिकट में, किसी API लॉग में, किसी कॉन्फ़िग फ़ाइल में, या किसी URL के ठीक बीच में सामने आता है: अक्षरों और अंकों की लंबी स्ट्रिंग, कभी-कभार + या /, और शायद अंत में एक-दो =। इसे पहचानने में पल भर लगता है। Base64 एक बाइनरी-से-टेक्स्ट फ़ॉर्मैट है: यह कच्चे डेटा के हर तीन बाइट को चार चरों में पुनर्लिखता है, जो 64-अक्षरों की वर्णमाला से लिए जाते हैं, और जब बाइट की संख्या तीन की गुणज नहीं होती, तो दो = निशान आख़िरी छोर को पूरा करते हैं। डिकोडिंग उसी सौदे की वह दिशा है जिसमें डेटा सिकुड़ता है: चार चर अंदर जाते हैं, तीन बाइट बाहर आते हैं। इस साइट का होम पेज इस फ़ॉर्मैट को चरण-दर-चरण समझाता है, इसलिए यह लेख अपनी मेहनत उसी जगह लगाता है जहाँ वह आनी चाहिए: इस काम के PHP पक्ष पर।
पहले मुख्य समाचार। PHP 4 से लेकर आज तक PHP के कॉर में एक Base64 डिकोडर शामिल है। base64_decode() को न एक्सटेंशन चाहिए, न कोई Composer पैकेज, न कोई कॉन्फ़िगरेशन, और वह हर जगह चलता है जहाँ PHP चलता है। थोड़ा कम अच्छा समाचार: इसका डिफ़ॉल्ट रुख चुपचाप ख़राब इनपुट निगलता है और बिना एक शब्द कहे आपको कचरा सौंप देती है। अच्छा समाचार और अच्छा होता है: एक फ़्लैग ($strict) इस फ़ंक्शन को सच्चा दरवाज़ेदार बना देता है, और जैसे ही आपको समझ आता है कि रुख कैसे चुना जाए, इनपुट के असली होने का प्रमाण कैसे लाया जाए, और बाइटों को फिर से अर्थ में कैसे बदला जाए, Base64 रहस्यमयी बगों का स्रोत बनना बंद करके वह रूटीन बन जाता है जिसे आप ऑटोमेट कर सकते हैं।
साइज़ पर एक छोटी सी नोट: डिकोडिंग डेटा को करीब एक चौथाई सिकोड़ देती है (हर चार चरों के प्रवेश पर तीन बाइट बाहर आते हैं), इसलिए आउटपुट हमेशा इनपुट से कम मेमोरी लेता है। आपको कभी डिकोड के कारण मेमोरी फ़ूटने की चिंता नहीं करनी पड़ेगी। अब चलिए, इस औज़ार से मिलते हैं।
वह फ़ंक्शन जो काम करता है
यह पूरी साइग्नेचर है, ठीक वैसी ही जैसी आधुनिक PHP रिपोर्ट करती है:
base64_decode(string $string, bool $strict = false): string|false
उस पंक्ति में तीन शब्द ही पूरा काम करते हैं। $string पर कोई साइज़ सीमा नहीं है: एक मेगाबाइट एक मिलीसेकंड से भी कम समय में डिकोड हो जाती है, इसलिए पूरी फ़ाइल को एक ही कॉल में डिकोड करने से कोई नहीं रोक सकता। रिटर्न टाइप पूरा करार कह देता है: या तो डिकोड किए गए बाइट्स की स्ट्रिंग, या false। न एक्सेप्शन हैं, न एरर कोड, न कोई दूसरा चैनल। false ही एकमात्र संकेत है जो आपको मिलता है, इसलिए इसे जाँचना भी इसी काम का हिस्सा है। और मैनुअल का एक वाक्य याद रखने लायक है: वापस आया डेटा बाइनरी भी हो सकता है। जिस पल भी रिज़ल्ट में PNG, ZIP या हैश बसे, वह किसी भी ढीले अर्थ में "टेक्स्ट स्ट्रिंग" नहीं रहती, फिर भी PHP खुशी-खुशी आपको उसे ऐसे ही मानने दे देगा। वह लचीलापन सुपरपावर भी है और फ़ज़ाद भी, और नीचे दिए सेक्शन इसे नियंत्रण में रखते हैं।
वर्ज़न टैग्स पर एक तेज़ नज़र डाल लेते हैं, क्योंकि वारिसा में मिलने वाला कोड अक्सर चीज़ें मान लेने की आदत रखता है। यह फ़ंक्शन PHP 4 से ही कॉर में है। इसका $strict पैरामीटर नवंबर 2006 में, PHP 5.2.0 के साथ आया। PHP 8.0 से साइग्नेचर के साथ असली नेटिव टाइप चलते हैं (ऊपर जो string और bool दिख रहे हैं, साथ में string|false रिटर्न), इसलिए IDEs और स्टैटिक एनालाइज़र आख़िरकार जानते हैं कि यह फ़ंक्शन फेल भी हो सकता है। PHP 8.1 से null पास करने पर एक डीप्रेकेशन नोटिस निकलती है; अगर आपका मतलब "कुछ नहीं" है, तो '' स्पष्ट रूप से लिखें:
$decoded = base64_decode('');
var_dump($decoded); // string(0) ""
सख़्त मोड या चुपचाप सफ़ाई
$strict फ़्लैग दो बिल्कुल अलग व्यक्तित्वों के बीच का स्विच है। बंद (डिफ़ॉल्ट) रहने पर डिकोडर एक दोस्ताना भूलने वाला है: Base64 वर्णमाला से बाहर का हर चर चुपचाप फेंका जाता है, बाक़ी डिकोड हो जाता है, और किसी को कुछ बताया ही नहीं जाता। मैनुअल इसे बिना उलझाए कहता है: अन्यथा, अवैध चर चुपचाप हटा दिए जाएँगे। चालू रहने पर डिकोडर एक दरवाज़ेदार बन जाता है: पहला ही चर जो वह पहचान नहीं पाता, पूरे पेलोड को false कमा देता है।
यह नुक़सान की रिपोर्ट है। नीचे दी गई हर पंक्ति base64_decode() का PHP 8.x पर असली व्यवहार है:
| इनपुट | ढीला (डिफ़ॉल्ट) | सख़्त |
|---|---|---|
Zm9vYmFy, साफ़-सुथरा |
"foobar" |
"foobar" |
Zm9v\r\nYmFy, स्ट्रिंग के बीच CRLF |
"foobar" |
"foobar" |
" Zm9vYmFy ", दोनों सिरों पर स्पेस |
"foobar" |
"foobar" |
Zm9v\x0bYmFy, वर्टिकल टैब |
"foobar" |
false |
Zm9v\x00YmFy, एम्बेडेड NUL बाइट |
"foobar" |
false |
V@hpcy, बेजगह @ |
3 बाइट का कचरा | false |
Zm9vY, पाँच चर |
"foo", आख़िरी चर गिरा हुआ |
false |
Z, एक अक्षर |
"", एक ख़ाली स्ट्रिंग |
false |
=Zm9, आगे में पैडिंग |
"fo" |
false |
Zm9vYmFy==, पूरे ग्रुप के बाद पैड |
"foobar" |
false |
Zm9vYmFy==A, पैड के बाद डेटा |
"foobar" |
false |
Zm9vYmF, सात चर, कोई पैड नहीं |
"fooba" |
"fooba" |
तीन पंक्तियों को दूसरी नज़र से देखना ज़रूरी है। V@hpcy पंक्ति यह दिखाती है कि जहाँ भी इनपुट पर भरोसा न हो, वहाँ ढीला मोड ख़तरनाक क्यों है: बेजगह @ डिकोड को रोकता नहीं है; वह सिर्फ़ गायब हो जाता है, और बाहर आने वाले तीन बाइट का कोई मतलब नहीं होता। एक अकेले Z वाली पंक्ति दिखाती है कि ख़ाली रिज़ल्ट लगभग कुछ भी साबित नहीं करता; एक-चर का पेलोड फेल होने के बिना "डिकोड" होकर ख़ाली स्ट्रिंग बन जाता है। Zm9vYmFy==A पंक्ति दिखाती है कि पैडिंग के बाद दिखने वाले डेटा को डिकोडर खुशी-खुशी नज़रअंदाज़ कर देता है, और यही वजह है कि कटता हुआ या छेड़ता हुआ पेलोड बिल्कुल सही दिख सकता है।
सख़्त मोड फिर भी क्या-क्या पार जाने देता है? बिल्कुल चार व्हिटस्पेस चर: स्पेस, टैब, कैरिएज रीटर्न और लाइन फ़ीड, किसी भी जगह, = निशानों के ठीक बगल में भी। यह इरादे से है। MIME-रैप किए ईमेल पेलोड एन्कोडेड स्ट्रीम के अंदर CRLF लाइन ब्रेक ले आते हैं, और सख़्त मोड बिना किसी प्री-प्रोसेसिंग के उन्हें चबा डालता है (नीचे ईमेल वाला सेक्शन वजह बताता है)। वर्णमाला के अक्षरों से छोड़कर बाक़ी सब, NUL बाइट से लेकर वर्टिकल टैब तक, false कमाते हैं।
एक सच्ची ढीलेपन वाली बात जानने लायक है, हालाँकि यह PHP-ख़ास ख़ासियत नहीं है: PHP आपके लिए ग़ायब पैडिंग चुपचाप भर देता है। सात-चर का पेलोड Zm9vYmF (पैड बिल्कुल नहीं) दोनों रुखों में "fooba" में डिकोड होता है, बिल्कुल वैसा ही जैसे उसका पैड वाला रिश्तेदार Zm9vYmF=। RFC 4648 आम मामलों में पैडिंग माँगता है, इसलिए बिना पैड पूँछ को स्वीकार करना एक इरादे से ढीलापन है, और यह PHP-ख़ास नहीं है: Go का RawStdEncoding और Java का डिकोडर भी वैसा ही बिना पैड इनपुट लेते हैं। अगर आपका PHP पक्ष और कोई साथी सिस्टम किसी किनारे के पेलोड पर मतभेद में हों, तो जहाँ सबसे पहले नज़र डालनी चाहिए, वह ग़ायब पैड है।
मानक भी सख़्त रुख से सहमत है। RFC 4648, सेक्शन 3.3, कहता है कि इम्प्लीमेंटेशन को ज़रूर उस एन्कोडेड डेटा को रद्द करना चाहिए जिसमें वर्णमाला से बाहर के चर हों, जब तक कि चारों ओर का स्पेसिफ़िकेशन कुछ और न कह रहा हो (MIME वही क्लासिक "कुछ और कहने वाला" मामला है)। उसी सेक्शन में वजह भी बताई गई है: वर्णमाला-बाहरी चरों को एक गुप्त चैनल के तौर पर इस्तेमाल किया जा सकता है, जानकारी उन चरों में छुपाकर जिन्हें आपका डिकोडर फेंक देता है, और इन्हीं का इस्तेमाल डिकोडर बग चटकाने के लिए हो चुका है। अगर आपका इनपुट बाहरी दुनिया से आता है, तो सख़्त मोड कोई स्टाइल-चॉइस नहीं है। यह वही चीज़ है जो मानक माँगता है।
यह साबित करना कि पेलोड Base64 है
जो डिकोडर चुपचाप फेल हो सकता है, उसके आगे एक वैलिडेशन पाइपलाइन का हक़ है। तीन परतें, और हर परत पकड़ती है वह जो बाक़ी पार कर जाती हैं।
पहली परत रेगैक्स से एक आकार-जाँच है: सिर्फ़ वर्णमाला के चर, और बिल्कुल आख़िर में ज़्यादा से ज़्यादा दो पैड।
$shapeLooksPlausible = preg_match('/^[A-Za-z0-9+\/]*={0,2}$/', $payload) === 1;
यह रेगैक्स बाक़ी कुछ भी चलने से पहले ही साफ़-साफ़ कचरा पकड़ लेता है (बेजगह स्पेस, @ निशान, स्ट्रिंग के बीच का पैड)। हालाँकि यह कोई वैलिडेटर नहीं है: यह देख नहीं पाता कि Zm9vYmFy= एक पैड के साथ नौ चर है, जिसे सख़्त मोड भी मना कर देता है। यही वजह है कि दूसरी परत मौजूद है। सख़्त डिकोडिंग ही एकमात्र जाँच है जो Base64 के अर्थ को समझती है, इसलिए आख़िरी फैसला उसके पास है।
तीसरी परत वह है जिसे हर कोई भूल जाता है: false का इलाज स्पष्ट रूप से करें, क्योंकि यह ही एकमात्र संकेत है जो आपको मिलता है।
function decode_payload(string $payload): string
{
$clean = str_replace(["\r", "\n"], '', $payload);
$decoded = base64_decode($clean, true);
if ($decoded === false) {
throw new InvalidArgumentException('Not a valid Base64 payload.');
}
return $decoded;
}
आगे रखा गया str_replace() वैकल्पिक आराम है: सख़्त मोड CRLF को पहले से सहन करता है, लेकिन इसे हटाने से आपकी बाद की लंबाई की गणना साफ़ रहती है, क्योंकि साफ़ पेलोड के चरों की संख्या हमेशा चार की गुणज होती है। (चार की गुणज से एक ज़्यादा, जैसे पाँच या नौ, Base64 में असंभव है, और सख़्त मोड उसे मना कर देगा।) ध्यान रखें कि यह फ़ंक्शन अपने आप कभी थ्रो नहीं करता; जाँच लिखना आपकी ज़िम्मेदारी है।
URL-सुरक्षित Base64
बाहर की दुनिया में आपको दूसरी वर्णमाला मिलेगी, और वही वह है जो काटती है। स्टैंडर्ड Base64 + और / इस्तेमाल करता है, दो ऐसे चर जो URL में मुसीबत पैदा करते हैं: क्वेरी स्ट्रिंग में + PHP को दिखने से पहले ही स्पेस की तरह मँना जाता है, और / पाथ सेपरेटर है। RFC 4648, सेक्शन 5, इलाज परिभाषित करता है: URL और फ़ाइल-नाम सुरक्षित वर्णमाला, जहाँ + बन जाता है -, / बन जाता है _, और आख़िरी = पैडिंग आमतौर पर चर बचाने के लिए छोड़ दी जाती है। RFC इस बात पर अडिग है कि इसे "base64 एन्कोडिंग से समान नहीं माना जाना चाहिए", और सबसे ज़्यादा सुना जाने वाला नाम है base64url। JSON Web Tokens, OAuth के स्टेट पैरामीटर, API सेशन ID और वीडियो साइटों के URL सब इसी डायलैक्ट में रहते हैं।
डिकोडर पक्ष दो कदमों का है: वर्णमाला वापस बदलें, फिर ग़ायब पैडिंग बहाल करें। यह वही हेल्पर है जिसे आप आख़िरकार हर जगह फिर से इस्तेमाल करेंगे:
function base64url_decode(string $data): string|false
{
$standard = strtr($data, '-_', '+/');
$missing = strlen($standard) % 4;
if ($missing !== 0) {
$standard .= str_repeat('=', 4 - $missing);
}
return base64_decode($standard, true);
}
var_dump(base64url_decode('aGk_PnRoZXJl')); // string(9) "hi?>there"
आधुनिक PHP यहाँ आपकी तरफ़ है: यह आपके लिए ग़ायब पैडिंग भर देता है, इसलिए स्पष्ट रूप से बहाल करना बेल्ट-एंड-ब्रेसेस (दोहरी सुरक्षा) है (और यह आपके कोड को पुरानी PHP वर्ज़न के लिए पोर्टेबल भी रखता है)। ख़तरे की दिशा एक तरफ़ की है। अगर आप URL-सुरक्षित टेक्स्ट को ढीले मोड के स्टैंडर्ड डिकोडर में डालें, तो - और _ चर बस स्टैंडर्ड वर्णमाला में नहीं होते, इसलिए उन्हें फेंक दिया जाता है। आपका आउटपुट उतना छोटा आता है जितना होना चाहिए था, न कोई एरर, न कोई नोटिस, कुछ नहीं। हमेशा पहले strtr() वाला बदलाव चलाएँ, या और बेहतर, हमेशा हेल्पर के रास्ते से जाएँ।
एक ख़ुलकर कही गई चेतावनी: अगर किसी URL-सुरक्षित पेलोड में न - हो न _, तो उस ख़ास डेटा के लिए दोनों वर्णमालाएँ बाइट-दर-बाइट एक जैसी होती हैं, और फ़र्क़ नहीं पड़ता कि आपने कौन सा डिकोडर इस्तेमाल किया। ख़तरा तब ही दिखता है जब वे चर मौजूद हों, क्योंकि बस वही जगह है जहाँ दोनों वर्णमालाएँ अलग होती हैं।
टेक्स्ट, बाइट्स और कैरेक्टर सेट्स
Base64 को पता ही नहीं कि आपके बाइट्स का मतलब क्या है, और PHP का डिकोडर उसी अंधेरे को उत्तराधिकार में लेता है। यह कोडेक कैरेक्टर-सेट के लिए अंधा है: चाहे अंदर क्या आया हो, UTF-8 टेक्स्ट, Windows-1252 टेक्स्ट, JPEG या हैश, वह वापस वही 8-बिट मान सौंपता है जो गए थे। PHP खुद उसी पन्ने पर है: स्ट्रिंग सिर्फ़ बाइट्स की एक कतार है, बस। जिस पल आप रिज़ल्ट दिखाना चाहें या उसे किसी दूसरे टेक्स्ट से तुलना करना चाहें, किसी को दो सवालों के जवाब देने पड़ते हैं: यह बस टेक्स्ट है या नहीं, और हाँ है तो किस कैरेक्टर सेट में?
अमली जाँच के दो बाल्टे हैं। बाइनरी लगभग हमेशा NUL और निचले कंट्रोल बाइट्स से ख़ुद को पहचानाता है, और जो टेक्स्ट वैध UTF-8 नहीं है, वह दूसरा बाल्टा है। mbstring एक्सटेंशन (जो डिफ़ॉल्ट में चालू नहीं होता) आपको सख़्त UTF-8 जाँच देता है:
function looks_binary(string $bytes): bool
{
if ($bytes === '') {
return false;
}
if (strpbrk($bytes, "\x00\x01\x02\x03\x04") !== false) {
return true;
}
return !mb_check_encoding($bytes, 'UTF-8');
}
var_dump(looks_binary("\x89PNG\r\n\x1a\n...png body")); // bool(true)
var_dump(looks_binary("héllo wörld, 日本語")); // bool(false)
जब पेलोड किसी पुराने (लीगेसी) कैरेक्टर सेट का टेक्स्ट हो, तो उसे अपने HTML को छुए पश्चात नहीं, उसके छूने से पहले ही बदल लें। Windows-1252 वेब और डेस्कटॉप डेटा का सबसे आम लीगेसी एन्कोडिंग है, और साफ़ ISO-8859-1 से इसका अंतर यह तय करता है कि बाइट 0x93 एक मुड़ा-हुआ कोट है या एक अदृश्य कंट्रोल चर:
// Windows-1252 में "café": é एक अकेला बाइट है, 0xE9
$legacy = base64_decode('Y2Fm6Q==', true);
$utf8 = mb_convert_encoding($legacy, 'UTF-8', 'Windows-1252');
var_dump($utf8); // string(5) "café": é अब दो UTF-8 बाइट्स है
मशहूर mb_detect_encoding() के बारे में एक चेतावनी: PHP का अपना मैनुअल कहता है कि ऑटोमैटिक डिटेक्शन "कभी पूरी तरह भरोसेमंद नहीं हो सकती", और इसे बिना की के किसी संदेश को डिकिप्ट कराने से तुलना करता है। इसे Windows-1252 का "café" दें तो वह Windows-1252 ही कह सकती है; इसे PNG हेडर दें तो वह फिर भी खुशी-खुशी Windows-1252 कह सकती है, क्योंकि ISO-8859 परिवार के कैरेक्टर सेट्स हर संभावित बाइट मान के लिए परिभाषित हैं और इसलिए सब कुछ मेल खा सकते हैं। डिटेक्शन को आख़िरी इलाज मानें, जब तक कोई घोषित कैरेक्टर सेट मौजूद हो (किसी हेडर, किसी कॉन्फ़िग पंक्ति, किसी डेटाबेस कोलेशन) उसी पर भरोसा करें, और बाक़ी सबको डिफ़ॉल्ट रूप से UTF-8 या बाइनरी मान लें।
जब पेलोड एक फ़ाइल हो
सबसे आम फ़ाइल-काम किसी एक्सपोर्ट रूटीन के काम का उल्टा है: एक .b64 टेक्स्ट फ़ाइल आती है, और आपको मूल फ़ाइल वापस चाहिए। सख़्त डिकोडिंग और false जाँच के साथ, यह कोड पहले से ही प्रोडक्शन-स्तर का है:
$encoded = file_get_contents('/var/www/uploads/blob.b64');
$decoded = base64_decode($encoded, true);
if ($decoded === false) {
http_response_code(400);
exit('That upload is not valid Base64.');
}
PHP स्ट्रिंग्स बस बाइट्स होती हैं, इसलिए इस रास्ते में किसी को फ़र्क़ नहीं पड़ता कि पेलोड टेक्स्ट फ़ाइल है, ZIP आर्काइव है, या वीडियो। साइज़ की गणना आपके पक्ष में काम करती है: डिकोड किया हुआ आउटपुट एन्कोडेड इनपुट की लंबाई का तीन-चौथाई होता है, इसलिए डिकोडिंग कभी मेमोरी को ख़राब नहीं करती।
एक अच्छी आदत यह है कि किसी भी लेबल पर भरोसे से पहले बाइट्स को ख़ुद को पहचानने दें। finfo क्लास (fileinfo एक्सटेंशन, जो स्टैंडर्ड PHP बिल्ड्स के साथ बंडल होती है) आपको बताती है कि डेटा वाक़ई में क्या है:
$mime = (new finfo(FILEINFO_MIME_TYPE))->buffer($decoded);
var_dump($mime); // string(9) "image/png"
$extensions = ['image/png' => 'png', 'application/pdf' => 'pdf', 'application/zip' => 'zip'];
$ext = $extensions[$mime] ?? 'bin';
$target = '/var/www/uploads/file-' . bin2hex(random_bytes(4)) . '.' . $ext;
file_put_contents($target, $decoded);
वह आख़िरी कदम जितना दिखता है उससे ज़्यादा मायने रखता है। वह पेलोड जो छवि होने का दावा करता है मगर कुछ और में डिकोड होता है, बस ऐसी ही चीज़ है जिसे दूसरी राय पकड़ लेती है। और अगर आप बाद में बहाल की गई फ़ाइल को ब्राउज़र को वापस सर्व करें, तो जो Content-Type आप भेजें वह उसी finfo जाँच से आना चाहिए, फ़ाइल-नाम से नहीं।
डेटा URI: क्लिपबोर्ड का फ़ॉर्मैट
एक पसंदीदा आगमन: कोई छवि फ़ॉर्म में पेस्ट करता है, और फ्रंट एंड आपको पूरा डेटा URI सौंपता है: data:image/png;base64,iVBORw0KGgo...। RFC 2397 आकार की परिभाषा देता है: data:, एक वैकल्पिक मीडिया टाइप, एक वैकल्पिक ;base64 फ़्लैग, एक कॉमा, और फिर डेटा। जब फ़्लैग मौजूद हो तो पेलोड Base64 होता है; जब न हो, तो पेलोड परसेंट-एन्कोडेड सादा टेक्स्ट होता है, जो कम आम मगर वैध है। अगर मीडिया टाइप छोड़ा गया हो, तो डिफ़ॉल्ट text/plain;charset=US-ASCII होता है। यहाँ Base64 का काम ही क्या है? क्योंकि URI में राव बाइट्स या कॉमा सुरक्षित रूप से नहीं रखे जा सकते, और Base64 आपको एक ऐसी वर्णमाला देता है जिसका एस्केपिंग ज़रूरी नहीं होता।
function split_data_uri(string $uri): ?array
{
if (!str_starts_with($uri, 'data:') || !str_contains($uri, ',')) {
return null;
}
$meta = substr($uri, 5, strpos($uri, ',') - 5);
$payload = substr($uri, strpos($uri, ',') + 1);
$isBase64 = str_ends_with($meta, ';base64');
$mime = $isBase64 ? substr($meta, 0, -7) : $meta;
if ($mime === '') {
$mime = 'text/plain;charset=US-ASCII';
}
return [$mime, $isBase64, $payload];
}
$uri = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJ';
[$mime, $isBase64, $payload] = split_data_uri($uri);
var_dump($mime); // string(9) "image/png"
इस फ़ॉर्मैट में दो गड्ढे बसे हैं। पहला है ;base64 फ़्लैग की कमी: फ़्लैग के बिना का वैध डेटा URI परसेंट-एन्कोडेड पेलोड ले जाता है, और उसे base64_decode() से गुज़ारा जाए तो कचरा निकलता है। दूसरा है दावा किया गया मीडिया टाइप: यह भेजने वाले की तरफ़ से एक इशारा है, कोई सच नहीं। finfo की जाँच जो फ़ाइल वाले सेक्शन में थी, वही आपका सच है। और RFC की अपनी सलाह को याद रखें कि डेटा URI सिर्फ़ छोटे मानों के काम आते हैं; URL के अंदर कई मेगाबाइट की छवि गंध है, कोई पैटर्न नहीं।
JWT: ऐसा टोकन जिसमें झाँका जा सकता है
वेब पर सबसे मशहूर Base64 पेलोड JSON Web Token है, और आकार जानते हुए वह सबसे कम डरावना भी। RFC 7519 के अनुसार, कम्पैक्ट JWT तीन डॉट से अलग किए गए URL-सुरक्षित Base64 हिस्सों से बनता है: हेडर, पेलोड, और सिग्नेचर, हर एक बिना पैडिंग और बिना लाइन ब्रेक एन्कोड होता है (RFC 7515 स्पष्ट कहता है कि कोई अतिरिक्त चर अंदर घुस नहीं सकते)। हेडर और पेलोड सादा JSON है, इसलिए हर कोई उन्हें पढ़ सकता है, और इसलिए अगला पैराग्राफ़ टोकन छूने से पहले हर किसी को समझ लेना चाहिए।
पहले दो हिस्सों को पढ़ना उपर दिए हेल्पर के साथ पाँच पंक्तियों का काम है, और टोकन के रहस्य को भंग करने का बढ़िया तरीका भी है:
$token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.8GljXWCrvkTYln_WtTVhyWSzflOC1iGL8jBDUHQmaEE';
[$headerPart, $payloadPart] = explode('.', $token);
$header = json_decode(base64url_decode($headerPart), true);
$payload = json_decode(base64url_decode($payloadPart), true);
var_dump($header);
// array(2) { ["alg"] => string(5) "HS256" ["typ"] => string(3) "JWT" }
var_dump($payload);
// array(3) { ["sub"] => string(10) "1234567890" ["name"] => string(8) "John Doe" ["iat"] => int(1516239022) }
अब वह हिस्सा जो मायने रखता है: तीसरा हिस्सा सिग्नेचर है, और जो दो हिस्से आपने अभी डिकोड किए वे न गुप्त हैं, न सत्यापित हैं। किसी के पास पैकेट कैप्चर हो तो वह उन्हें पढ़ सकता है, और किसी के पास टेक्स्ट एडिटर हो तो वह उन्हें फिर से लिख सकता है। सिग्नेचर के सत्यापन से पहले पेलोड पर भरोसा करना ही क्लासिक JWT बग है। प्रोडक्शन के लिए, वह जाँच हाथ से मत लिखें। कॉम्युनिटी का जवाब firebase/php-jwt पैकेज है, जो अभी v7 पर है, RFC 7519 के मुताबिक है, और PHP 8.0 या नया माँगता है। इसे Composer से इंस्टॉल करें:
composer require firebase/php-jwt
फिर API पहले सत्यापित करती है और पेलोड तभी सौंपती है जब सिग्नेचर ठीक निकले:
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
$secret = 'correct-horse-battery-staple-long-enough-secret';
try {
$claims = JWT::decode($token, new Key($secret, 'HS256'));
var_dump($claims->sub); // एक गुण, और सिर्फ़ तब जब सिग्नेचर ठीक निकल चुकी हो
} catch (UnexpectedValueException $e) {
// गलत बने टोकन, ख़राब सिग्नेचर, या एक्सपायर्ड claims
}
एक वर्ज़न-नोट: लाइब्रेरी के v7 में HMAC एल्गोरिदम के लिए न्यूनतम कुंजी लंबाई ज़रूरी है, इसलिए 32 बाइट से छोटा HS256 सीक्रेट सिग्नेचर की जाँच से पहले ही DomainException के साथ मना हो जाता है। अपने सीक्रेट्स लंबे रखें; लाइब्रेरी आपको भूलने नहीं देती।
उस API में क्रम पर नज़र रखें: JWT::decode() ख़राब सिग्नेचर, एक्सपायर्ड टोकन, या ग़ायब एल्गोरिदम पर गार्बेज लौटाने के बजाय थ्रो कर देता है, इसलिए जो पेलोड आपको वापस मिलता है वह भरोसे का होता है। उपर दिया हाथ-से-लिखा वाला वर्ज़न समझने के लिए है, और उन टोकनों में झाँकने के लिए जो आपके लिए ही नहीं थे; लाइब्रेरी भरोसे के लिए है।
HTTP Basic Auth: सबसे पुराना हेडर
वेब का सबसे पुराना ऑथेंटिकेशन हेडर आज भी Base64 पर सवार है। RFC 7617 के अनुसार, HTTP Basic रिक्वेस्ट Authorization: Basic भेजती है, और उसके बाद username:password का Base64 एन्कोडिंग होता है। RFC स्पष्ट कहता है कि यह एन्कोडिंग है, प्रोटेक्शन नहीं: जिसके पास पैकेट कैप्चर है, वह दोनों हिस्से एक ही कीस्ट्रोक में डिकोड कर सकता है। डिकोड पक्ष पर आपका काम है: हेडर को पार्स करें, सख़्त डिकोड करें, और टाइमिंग-सुरक्षित फ़ंक्शन से तुलना करें।
function basic_credentials(string $header): ?array
{
if (!str_starts_with($header, 'Basic ')) {
return null;
}
$decoded = base64_decode(substr($header, 6), true);
if ($decoded === false || !str_contains($decoded, ':')) {
return null;
}
[$user, $password] = explode(':', $decoded, 2);
return [$user, $password];
}
$header = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
$creds = basic_credentials($header);
if ($creds !== null
&& hash_equals('alice', $creds[0])
&& hash_equals('secret123', $creds[1])
) {
// सत्यापित
}
दो विवरण इसे सुरक्षित रखते हैं। explode() में 2 की सीमा मायने रखती है, क्योंकि पासवर्ड में वैध रूप से कॉलन भी हो सकते हैं, और तुलना hash_equals() होनी चाहिए, कभी == नहीं, ताकि अटैकर समय नापकर आपकी यूज़र लिस्ट में प्रवेश का रास्ता नहीं निकाल सके। और इसे सिर्फ़ HTTPS पर सर्व करें; साधारण कनेक्शन पर Base64 की परत बस सजावट है।
ईमेल: जहाँ सब कुछ शुरू हुआ
Base64 का जन्म एक ख़ास समस्या के लिए हुआ था: मेल ट्रांसपोर्ट सिर्फ़ 7-बिट ASCII ले जाता था, मगर लोग बाइनरी भेजना चाहते थे। MIME मानक (RFC 2045, सेक्शन 6.8) ने Base64 को बाइनरी ट्रांसफ़र एन्कोडिंग्स में से एक बनाया और दो घर के नियम जोड़े। पहला: एन्कोडेड लाइनें 76 चरों से ज़्यादा लंबी नहीं हो सकतीं। दूसरा: डिकोडिंग सॉफ्टवेयर को वर्णमाला से बाहर के हर चर को नज़रअंदाज़ करना होगा, लाइन ब्रेक समेत। वही दूसरा नियम यही वजह है कि PHP का डिकोडर, दोनों रुखों में, CRLF-रैप किए पेलोड को आपकी किसी भी प्री-प्रोसेसिंग के बिना चबा डालता है। (यह वही जगह है जहाँ आपको उपर सख़्त मोड की टेबल में \r\n सहनशीलता दिखी थी।)
$png = "\x89PNG\r\n\x1a\n" . random_bytes(256);
$wrapped = chunk_split(base64_encode($png), 76, "\r\n");
// बाद में, पाने वाले पक्ष पर, कोई सफ़ाई ज़रूरी नहीं:
$decoded = base64_decode($wrapped, true);
var_dump($decoded === $png); // bool(true): हर बाइट रउंड ट्रिप पूरा करके लौटा
दो अमली नोट्स। पहला: रैपिंग वज़न बढ़ाती है: हर 76 चरों पर CRLF के साथ, 100 KB का अटैचमेंट करीब 137 KB टेक्स्ट बनकर पहुँचता है (आम चार-तिहाई गुणक, साथ में लाइन-ब्रेक का ख़र्च)। दूसरा: असली दुनिया के ईमेल में, हेडर, कई हिस्से और quoted-printable रिश्तेदारों के साथ, वैकल्पिक mailparse एक्सटेंशन पूरे RFC 822 संदेशों को हिस्सा-दर-हिस्सा तोड़ता है; एक ख़ास ज़्ञात अटैचमेंट के लिए सख़्त डिकोडिंग ही पूरी ज़रूरत है।
PEM कवच: कुंजियाँ और प्रमाणपत्र
प्रमाणपत्र और कुंजियाँ PEM कवच में यात्रा करती हैं: एक BEGIN लेबल, 64-चर लाइनों का Base64 ब्लॉक, और एक END लेबल। 64-चर की लाइन लंबाई मूल Privacy Enhanced Mail स्पेसिफ़िकेशन (RFC 1421) से आई एक रस्म है, और OpenSSL टूल इसे ही अपेक्षा करते हैं, इसलिए जब आप कवच फिर से बनाएँ तो यह मायने रखती है। जब आप डिकोड करते हैं, तो इसका बिलकुल कोई महत्व नहीं है: डिकोडर लाइन ब्रेक को सिर्फ़ नज़रअंदाज़ कर देता है।
$pem = file_get_contents('/etc/ssl/my-key.pem');
preg_match('/-----BEGIN ([A-Z ]+)-----\s*(.*?)\s*-----END \1-----/s', $pem, $m);
$label = $m[1];
$der = base64_decode(preg_replace('/\s+/', '', $m[2]), true);
if ($der === false) {
// आख़िर में Base64 ही नहीं निकला
}
var_dump($label); // string(11) "PRIVATE KEY"
डिकोड किए गए बाइट्स DER होते हैं, एक कम्पैक्ट बाइनरी सिरियलाइज़ेशन, और यही वे बाइट्स हैं जिनसे openssl_* फ़ंक्शन आख़िर में काम करते हैं। रेगैक्स में बैक-रेफ़रेंस \1 ही चुपचाप नायक है: यह पक्का करता है कि END लेबल BEGIN लेबल से मेल खाए, और यही वह तरीका है जिससे आप बचते हैं जब एक फ़ाइल में कई ब्लॉक हों - प्रमाणपत्र का END किसी कुंजी के BEGIN से जोड़ लेने से।
स्ट्रीम्स और बड़े पेलोड
डिकोडिंग वह दिशा है जो आपकी मदद करती है: आउटपुट इनपुट का तीन-चौथाई साइज़ होता है, इसलिए Base64 से मेमोरी दबाव दुर्लभ है। फिर भी, जब कई सौ मेगाबाइट की .b64 फ़ाइल डिस्क पर उतरती है, तो फ़ुटप्रिंट को सपाट रखने के आपके पास दो औज़ार हैं।
पहला है चंकड डिकोडिंग। सफ़ाई की गई इनपुट को ऐसे टुकड़ों में बाँटें जिनकी लंबाई चार चरों की गुणज हो, हर टुकड़ा सख़्त डिकोड करें, और जोड़ दें। हर चंक एक स्वतंत्र, वैध पेलोड है, इसलिए सीमाओं पर कुछ खोया नहीं जाता, और ख़राब फ़ाइल एक ऐसे ऑफ़सेट के साथ तेज़ी से फेल होती है जो आप रिपोर्ट कर सकते हैं।
$clean = str_replace(["\r", "\n"], '', file_get_contents('/var/www/uploads/huge.b64'));
$decoded = '';
$chunkSize = 4 * 50000; // चार चरों की गुणज लंबाई, हर कॉल से करीब 150 KB बाहर
for ($offset = 0; $offset < strlen($clean); $offset += $chunkSize) {
$part = base64_decode(substr($clean, $offset, $chunkSize), true);
if ($part === false) {
exit('Corrupted payload near offset ' . $offset);
}
$decoded .= $part;
}
आधुनिक हार्डवेयर पर एक मेगाबाइट Base64 एक मिलीसेकंड से भी कम में डिकोड हो जाता है, इसलिए यह लूप लगभग निःशुल्क है; इसे गति के लिए नहीं, बल्कि अपनी वैलिडेशन और रिपोर्टिंग की ख़ासियतों के लिए चुनें।
दूसरा औज़ार स्ट्रीमिंग दुनिया का नागरिक है: convert.base64-decode स्ट्रीम फ़िल्टर। यह किसी भी PHP स्ट्रीम पर काम करता है, इसलिए आप फ़ाइल पॉइंटर, php://input, या मेमोरी स्ट्रीम से सीधे डिकोड कर सकते हैं, बिना पूरी एन्कोडेड स्ट्रिंग को कभी एक वेरिएबल में रखा। ढीले फ़ंक्शन की तरह, यह Base64 वर्णमाला से बाहर के हर चर को सिर्फ़ छोड़ देता है:
$in = fopen('/var/www/uploads/huge.b64', 'rb');
$out = fopen('/var/www/uploads/huge.bin', 'wb');
stream_filter_append($in, 'convert.base64-decode', STREAM_FILTER_READ);
stream_copy_to_stream($in, $out);
fclose($in);
fclose($out);
आप कौन सा औज़ार चुनेंगे? फ़िल्टर तब, जब डेटा स्ट्रीम के अंदर बह रहा हो और आप चाहते हों कि PHP पूरा प्लंबिंग संभाले; चंक लूप तब, जब आपको चंक-दर-चंक वैलिडेशन, प्रोग्रेस रिपोर्टिंग, या ख़राबी के ऑफ़सेट की ज़रूरत हो।
डेटाबेस, कॉन्फ़िग फ़ाइलें और एनवायरनमेंट वेरिएबल्स
Base64 एक टेक्स्ट कंटेनर है, और यही वजह है कि यह अजाइन जगहों पर दिखाई देता है जहाँ आपकी उम्मीद नहीं होगी। डेटाबेस में, बाइनरी ब्लॉब (फ़ाइल, आइकन, सिरियलाइज़्ड स्ट्रक्चर) TEXT कॉलम में Base64 के रूप में रह सकता है, और हर उस टूल से बच जाता है जो टेक्स्ट की धारणा करता है। स्टोर किए गए मान को मूल से करीब 33 प्रतिशत बड़ा रहने की उम्मीद करें, और कॉलम्स की साइज़ भी उसी के हिसाब से तय करें। कॉन्फ़िग फ़ाइलों और एनवायरनमेंट वेरिएबल्स में, Base64 वह ट्रिक है जिससे आप उन मानों को घुसा लेते हैं जो वरना फ़ॉर्मैट को तोड़ देते: सेमीकोलॉन्स वाले डेटाबेस DSN, कोट्स वाला पासवर्ड, न्यूलाइन वाला मान।
// .env या कॉन्फ़िग, जो ऑप्स व्यक्ति ने लिखा:
// DB_DSN_B64 = cGc6aG9zdD1kYjtwYXNzd29yZD1xdSJvdGU=
$dsn = base64_decode(getenv('DB_DSN_B64') ?: '', true);
if ($dsn === false) {
exit('DB_DSN_B64 is not valid Base64.');
}
// $dsn अब यह है: pg:host=db;password=qu"ote
यहाँ वही सावधानी दो बार लागू होती है। पहली: यह फ़ॉर्मेट सेफ़्टी है, सीक्रेसी नहीं: जिस पल कोई डेवलपर कॉन्फ़िग फ़ाइल पढ़ता है, वह एक ही कॉल में मान डिकोड कर सकता है। कभी भी सीक्रेट को Base64 स्टोर करके उसे एन्क्रिप्टेड न समझें। दूसरी: बूट पर वैलिडेट करें: ख़राब या आधा-पेस्ट एनवायरनमेंट मान सख़्त कॉल से false है, और एक-पंक्तियाँ की जाँच क्रिप्टिक रन्टाइम एरर को काम में लाए जाने योग्य स्टार्टअप संदेश में बदल देती है।
कमांड लाइन से
हर डिकोडिंग वेब रिक्वेस्ट के अंदर नहीं होती। CLI स्क्रिप्ट्स, क्रॉन जॉब्स, और वन-लाइनर्स Base64 की डिकोडिंग हमेशा करते हैं, और कमांड लाइन ही वह जगह है जहाँ फ़ंक्शन php://stdin से मिलता है:
php -r 'fwrite(STDOUT, base64_decode(file_get_contents("php://stdin"), true));' < payload.b64 > restored.bin
शेल के पास अपना Base64 यूटिलिटी पहले से ही है (coreutils base64 -d), और तेज़ काम के लिए वह ठीक है; PHP वन-लाइनर इसलिए है जब अगला कदम PHP लॉजिक हो: डेटाबेस में लिखना, किसी API को कॉल करना, वैलिडेशन चलाना। दो शेल-ख़ास गड्ढे। डिकोड का आउटपुट राव बाइट्स होते हैं, इसलिए उसे फ़ाइल में या ऐसे कमांड में भेजें जो बाइट्स को समझता है, ऐसे टर्मिनल में नहीं जो उन्हें बदल देगा। और वन-लाइनर में सख़्त फ़्लैग चालू ही रखें, क्योंकि टर्मिनल में आधा पेस्ट किया पेलोड false का हक़दार है, तीन कचरा-बाइट्स का नहीं।
PHP-लहजा वाली गड़वाहटें
उन फ़ंदों की एक झलक जो PHP-ख़ास हैं, एक जगह इकट्ठे:
- ढीला डिफ़ॉल्ट ही सबसे बड़ा है।
base64_decode('V@hpcy')बिना किसी चेतावनी के तीन बाइट कचरा लौटाता है, इसलिए अविश्वसनीय इनपुट का हर डिकोडर सख़्त फ़्लैग औरfalseजाँच से रहता है। - एक अकेला चर ढीले मोड में ख़ाली स्ट्रिंग में डिकोड होता है, और सिर्फ़ स्पेसों की स्ट्रिंग भी। ख़ाली रिज़ल्ट लगभग कुछ भी साबित नहीं करता; फेल होने का अर्थ सिर्फ़
falseहै, और वह आपको सिर्फ़ सख़्त मोड में मिलता है। - क्वेरी स्ट्रिंग का
+PHP उसे देखने से पहले ही स्पेस बन चुका होता है। अगर कोई क्लाइंट बिना परसेंट-एन्कोडिंग के?token=abc+defभेजे, तो PHP आपकोabc defसौंपता है (यह फ़ॉर्म-एन्कोडिंग का व्यवहार है, जोparse_str()औरurldecode()भी साझा करते हैं), और कितनी भी डिकोडिंग मैजिक हो, प्लस वापस नहीं आता। URL-सुरक्षित Base64 (बिल्कुल प्लस के बिना) ही URL में टोकन्स का ठिकाना है। - ग़ायब पैडिंग आपके लिए चुपचाप भर दी जाती है। सात चर आठ की तरह डिकोड होते हैं; यह सुविधा है, लेकिन इसका मतलब यह भी है कि एक-दो पैड से कटता हुआ पेलोड बिना शिकायत के डिकोड हो सकता है, इसलिए साफ़ डिकोड कभी पक्का साबित नहीं कर पाता कि पेलोड पूरा पहुँचा है (Go के राव एन्कोडर्स और Java भी बराबर ही ढीले हैं)।
mbstring.func_overloadका भूत। वह लंबे समय से डीप्रेकेटेड सेटिंग जोstrlen()और उनके साथियों को चर गिनने के लिए पुनर्लिखती थी (PHP 8.0 में हटाई गई) पुराने समय में UTF-8 स्ट्रिंग्स पर Base64 बाइट-गणना तोड़ती थी। वह लीगेसी कोड जो आप वारिसा में लें, उसमें इसके लिए कमेंट्स और वर्कआराउंड्स आज भी हो सकते हैं। उन्हें हटा दें।- डिकोड किए बाइट्स UTF-8 स्ट्रिंग नहीं हैं। डिकोड बाइनरी पर
preg_match()को/uफ़्लैग के साथ याmb_substr()चलाना "मालफ़ॉरम्ड इनपुट" एररों का तुरंत स्रोत है। पहले सूंघें, फिर फैसला करें। nullपास करना PHP 8.1 से डीप्रेकेटेड है। अगर कोई वेरिएबल null हो सकता है, तो कॉल से पहले उसे''पर कोयलेस कर दें।$_GETऔर उसके साथी फ़ॉर्म रूल्स से डिकोड होते हैं, URL रूल्स से नहीं। अगर कोई मान परसेंट-एन्कोडेड आया है, तोrawurldecode()ही सुरक्षित उल्टा है, क्योंकि वह+को हाथ नहीं लगाता।
base64_decode का छोटा-सा इतिहास
Base64 खुद आधुनिक वेब के ज़्यादा हिस्से से पुराना है (इसे शासन करने वाला मानक, RFC 4648, 2006 का है, और उसने 1996 की MIME एन्कोडिंग को कोड किया, जो स्वयं 1990 के दशक की शुरुआत के PEM कवच की विरासत है)। PHP की कहानी उसका अपना छोटा-सा चेंजलॉग है।
PHP 4 में base64_decode() कॉर फ़ंक्शन के रूप में शिप्प्ड हुआ, बिना किसी ऑप्शन, बिना सख़्त मोड के; ढीला रुख ही एकमात्र रुख था, और डिकोडर से शिकायत माँगने का कोई रास्ता नहीं था। नवंबर 2006 में PHP 5.2.0 ने $strict फ़्लैग जोड़ा, और चेंजलॉग प्रविष्टि पढ़ने लायक है: यह RFC 3548 की पाबंदी ज़रूर कराने के लिए जोड़ी गई थी, जो आज के RFC 4648 की पिछली पीढ़ी है। वह एकमात्र फ़्लैग निकलकर फ़ंक्शन की पूरी ज़िन्दगी का सबसे काम-आने वाला जुड़ाव साबित हुआ।
फिर डीबगिंग के साल आए। PHP 5.3 ने दो पॉइंट-रीलीज़ में सख़्त मोड के बगों की एक कतार ठीक की: बग #52327 (सख़्त मोड में लीडिंग पैडिंग का असही इलाज, 5.3.4 में ठीक) और बग #55273 (सख़्त मोड में पैडिंग के बाद व्हिटस्पेस अस्वीकृत, 5.3.9 में ठीक)। (2016 का एक इंटीजर-ओवरफ़्लो फ़िक्स भी इसी फ़ंक्शन के नाम पर दर्ज है: बग #72836, आधिकारिक शीर्षक "integer overflow in base64_decode caused heap corruption", 5.6.25 में ठीक, लेकिन बग रिपोर्ट का अपना रिप्रोडक्शन कोड और पैच्ड फ़ंक्शन दिखाते हैं कि असली ओवरफ़्लो base64_encode() की लंबाई गणना में था, डिकोडर में नहीं; शीर्षक मूल रिपोर्ट से आया एक गलत नाम है)। हर फ़िक्स ने टेबल में दिखने वाले उसी व्यवहार को और कसा। PHP 8.0 ने दोनों Base64 फ़ंक्शनों को नेटिव पैरामीटर और रिटर्न टाइप्स दिए, वही साइग्नेचर जो इस लेख की शुरुआत में देखी, और उसी रीलीज़ लाइन ने mbstring.func_overload हटाया, वह सेटिंग जो सालों तक चुपचाप बाइट-गणना तोड़ रही थी। PHP 8.1 ने उन्हें null पास करना डीप्रेकेटेड कर दिया। उससे अब तक, सतह जम चुकी है: एक पैरामीटर, एक फ़्लैग, एक रिटर्न टाइप, बिना बदलाव।
कुछ नर्द-मज़े
क्योंकि यह एक लंबा रीफ़रेंस लेख है, यहाँ कुछ PHP-ख़ास तथ्य हैं जो बस मज़ेदार हैं:
- ख़ालीपन की पहचान।
base64_encode('')औरbase64_decode('')दोनों''हैं। दोनों दिशाओं में फ़ंक्शन ख़ालीपन को एक पहली-श्रेणी का मान मानते हैं,falseका कोई सवाल नहीं। - एक अजीब पता। PHP मैनुअल में दोनों Base64 फ़ंक्शन "अन्य बेसिक एक्सटेंशन" किताब के "URLs" अध्याय में बसे हैं। "एन्कोडिंग" का कोई ख़ास अध्याय नहीं है; वही "URLs" वह जगह है जहाँ आप उन्हें पाएँगे, उस अध्याय की लिस्ट के शीर्ष पर,
parse_url()और उनके साथियों से आगे। - डिकोडर एक होमोमॉर्फिज़्म है। php.net का एक क्लासिक यूज़र नोट ध्यान देता है कि यह फ़ंक्शन मॉड्युलो-4 और मॉड्युलो-3 से बँटी हुई स्ट्रिंग्स के बीच एक होमोमॉर्फिज़्म है, जो उस बात का आधिकारिक तरीका है कि चार की हर गुणज की कटाई एक वैध कटाई है। यही वजह है कि चंकड डिकोडिंग वाला सेक्शन बस काम करता है, और यही वजह है कि 1 MB की फ़ाइल 50 KB के टुकड़ों में बिल्कुल ख़ोए बगैर डिकोड हो सकती है।
- एक पैरामीटर, एक फ़्लैग। बीस से ज़्यादा सालों में,
base64_decode()को बिल्कुल एक पैरामीटर मिला ($strict), औरbase64_encode()को कोई नहीं मिला। - इसके बड़े भाइयों-बहनों की भी ख़ाक़ है। वही कॉर एक्सटेंशन
convert_uuencode()औरconvert_uudecode()भी ले जाता है (मैनुअल में स्ट्रिंग फ़ंक्शन्स के तहत सूचीबद्ध), डायल-अप युग के अवशेष, जब uuencode बाइनरी ट्रांसपोर्ट की पसंदीदा फ़ॉर्मैट थी। आपको इनकी लगभग कभी ज़रूरत नहीं पड़ेगी, लेकिन अगर कभी कोई पुरानी.uuफ़ाइल आपके इनबॉक्स में उतरे, तो PHP उसे खोल सकता है। - सख़्त मोड ईमेल के लिए एक खुली दरवाज़ा रखता है। चार व्हिटस्पेस चर (स्पेस, टैब, कैरिएज रीटर्न और लाइन फ़ीड) इरादे से सख़्त मोड में आराम से पार होते हैं, ताकि MIME-रैप अटैचमेंट को कोई प्री-प्रोसेसिंग न चाहिए। बाक़ी सब, NUL बाइट समेत,
falseहै।
दूसरी दिशा
यह थी डिकोडर की तरफ़, और यहीं सबसे ज़्यादा दर्द छिपा है, क्योंकि डिकोडिंग वही जगह है जहाँ आप दूसरों के डेटा से मिलते हैं: उनकी पैडिंग की पसंद, उनके लाइन ब्रेक, उनके कैरेक्टर सेट्स, उनके टोकन्स। दूसरी दिशा, बाइट्स को base64_encode() से Base64 स्ट्रिंग में बदलना, शांत जानवर है: वह कभी फेल नहीं होता, उसका कोई सख़्त मोड नहीं है, और उसके अपने फ़ंदों (डबल-एन्कोडिंग, रैपिंग का मेल न होना, साइज़ का बिल) का अपना गाइड मिलेगा। PHP में Base64 एन्कोडिंग, जो इस पेज से जुड़ा है, एन्कोडर को उसी गहराई में कवर करता है।
अंतिम अपडेट: 2026-09-08
संबंधित लेख: PHP में Base64 एन्कोडिंग: एक सम्पूर्ण गाइड