क्या आपको Base64 फ़ॉर्मेट के साथ काम करना होता है? तो यह साइट आपके लिए एकदम सही है! अपने डेटा को एन्कोड या डिकोड करने के लिए, हमारे बेहद आसान ऑनलाइन टूल का इस्तेमाल करें।

Ruby में Base64 एन्कोडिंग: एक सम्पूर्ण गाइड

आपके डेटा का एक ऐसा गंतव्य है जो उसकी दिखाई देने वाली आकृति को स्वीकार नहीं करता। एक इमेज जो JSON दस्तावेज़ के अंदर रहना चाहती है। एक टोकन जो URL को पार करना चाहता है। एक एटैचमेंट जो सात-बिट टेक्स्ट के लिए बने हुए प्रोटोकॉल में जीवित बचना चाहता है। एक सीक्रेट जो एनवायरनमेंट वेरिएबल में, कोटिंग बिना टूटे, बैठना चाहता है। इनमें से हर जगह, यहाँ से वहाँ तक के बीच, आपका बाइनरी नष्ट करने वाला कोई न कोई तैयार है - और उसका हल एक नाम रखता है: Base64।

Ruby में पूरा काम उस एक मॉड्यूल में बसता है जो भाषा के साथ शिप होता है। तीन एन्कोडर, कुछ इंस्टॉल करने को नहीं, और आउटपुट इतना अनुमान योग्य कि आपने कोड चलाया भी नहीं, पहले से हर चर तक सटीक। यही वह अनुमान है जो कहानी का आधा हिस्सा है और जो ज़्यादातर गाइड्स छुपा जाती हैं, क्योंकि एन्कोडिंग वही जगह है जहाँ आश्चर्य अपना भुगतान वसूल करते हैं: एक ट्रेलिंग न्यूलाइन आपके JSON में घुस आता है, एक ऐसी लाइन ब्रेक जो आपने नहीं मांगी, एक टोकन को दो टुकड़ों में बाँट देती है, और एक ग़लत वर्णमाला का चुनाव URL बर्बाद कर देता है। यह गाइड तीनों एन्कोडर, आउटपुट का गणित, और हर वह पेलोड जो कोई Ruby डेवलपर वाकई एन्कोड करता है, सबका सफ़र कराती है, ताकि आश्चर्य आश्चर्य बने रहना बंद कर दें।

शुरुआत से पहले एक त्वरित याद ताज़ा कर लें: Base64 डेटा को तीन-तीन बाइट्स के हिसाब से फिर से लिखता है, 64-चिह्न वर्णमाला के चार चर निकालता है, और जब इनपुट तीन से बराबर नहीं बटता, तो एक या दो = चरों की पैडिंग जोड़ता है - यही वजह है कि आउटपुट इनपुट से लगभग एक-तिहाई बड़ा निकलता है। इस साइट का होम पेज फ़ॉर्मेट को गहराई से कवर करता है, इसलिए यह आर्टिकल फ़ॉर्मेट की बात एक साँस में ख़त्म करता है और सीधे काम पर लग जाता है।

आपको कौन-सा एन्कोडर चाहिए?

Ruby आपको तीन एन्कोडर देता है, और उनमें से चुनाव एक तीन-सवाल का क्विज़ है: आउटपुट में लाइन ब्रेक हो सकते हैं? + या / हो सकते हैं? पैडिंग हो सकती है? यहाँ पूरी टीम खड़ी है:

एन्कोडर आउटपुट का स्वरूप लाइन ब्रेक पैडिंग किस वक़्त हाथ लगाएँ
Base64.strict_encode64(bin) एक लाइन, स्टैंडर्ड वर्णमाला कभी नहीं हमेशा मौजूद JSON, टोकन, API, फ़ाइलें - सुरक्षित डिफ़ॉल्ट
Base64.encode64(bin) कुछ लाइनें, स्टैंडर्ड वर्णमाला हर 60 चर के बाद, साथ में एक ट्रेलिंग हमेशा मौजूद ईमेल बॉडी और लाइन-आधारित टेक्स्ट प्रोटोकॉल
Base64.urlsafe_encode64(bin, padding: true) एक लाइन, हाइफ़न-अंडरस्कोर वर्णमाला कभी नहीं आपका चुनाव, डिफ़ॉल्ट में चालू जो कुछ भी URL, कूकी या पहचान-चिह्न में उतरता है

अगर आप समय के दबाव में फैसला कर रहे हैं, तो छोटा जवाब यह है: डिफ़ॉल्ट रूप से strict_encode64, urlsafe_encode64 तब जब नतीजा URL के अंदर सफ़र करेगा, और encode64 तब केवल जब सामने वाला ऐसा टेक्स्ट प्रोटोकॉल हो जो छोटी लाइनें चाहता है। नीचे सब कुछ इसलिए समझाया गया है, और हर चुनाव की वह ख़ामोश कीमत भी जो वह आपको वसूल करता है।

strict_encode64: मेहनती कामगार

Base64.strict_encode64 वह एन्कोडर है जो आप अपने कोड के ज़्यादातर हिस्से में वाकई इस्तेमाल करेंगे। वह बिल्कुल एक ही लाइन का आउटपुट निकालता है, हमेशा सही पैडिंग के साथ, स्टैंडर्ड वर्णमाला से:

require "base64"
Base64.strict_encode64("hello world")
# => "aGVsbG8gd29ybGQ="
Base64.strict_encode64("s")
# => "cw=="

और क्योंकि एल्गोरिदम डिटर्मिनिस्टिक है, आप इनपुट से आउटपुट की सटीक लंबाई पहले से जान सकते हैं - कोई अंदाज़ा नहीं, डेटाबेस कॉलम में कोई ऑफ-बाय-वन बग नहीं। नीचे की टेबल पूरा गणित है:

इनपुट लंबाई आउटपुट लंबाई अंत में पैडिंग
3n बाइट्स (बराबर बटता है) 4n चर कोई नहीं
3n + 1 बाइट्स 4n + 4 चर दो =
3n + 2 बाइट्स 4n + 4 चर एक =

तो 11 बाइट्स बनकर 16 चर हो जाते हैं, 100 बाइट्स बनकर 136, और 1 मेगाबाइट की फ़ाइल बनकर करीब 1.33 मेगाबाइट टेक्स्ट। वह एक-तिहाई का बढ़ावा हर Base64 पेलोड का प्रवेश-टिकट है जिसे आप शिप करते हैं, और यही वह संख्या है जिसे आप हमेशा अपनी पिछली जेब में रखें, जब भी कोई कॉलम, कैश, या API रेट लिमिट कसने लगे।

Base64.strict_encode64("123")
# => "MTIz"        3 बाइट्स अंदर, 4 चर बाहर
Base64.strict_encode64("1234")
# => "MTIzNA=="   4 बाइट्स अंदर, 8 चर बाहर, दो पैड चर
Base64.strict_encode64("12345")
# => "MTIzNDU="   5 बाइट्स अंदर, 8 चर बाहर, एक पैड चर

encode64: जो न्यूलाइन्स जोड़ देता है

Base64.encode64 क्लासिक है, और उसके पास एक ऐसा व्यवहार है जिसने एक से ज़्यादा दोपहरों को ख़त्म किया है: वह अपने आउटपुट को लपेटता है। हर 60 चर पर वह नई लाइन शुरू करता है, और हमेशा एक ट्रेलिंग लाइन ब्रेक के साथ ख़त्म करता है:

Base64.encode64("hello world")
# => "aGVsbG8gd29ybGQ=\n"
Base64.encode64("*" * 46)
# => "KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioq\nKg==\n"

यह लपेटन कोई बग नहीं है - यह एक ख़ूबी है जो इस मेथड के मूल घर, MIME की दुनिया, से मिली है, जहाँ लंबी लाइनें प्रोटोकॉल के उल्लंघन की गिनती होती थीं। Ruby का mail gem इसका जान-बूझकर सहारा लेता है - उसके Base64 एन्कोडर में इतना तो टिप्पणी भी है कि Ruby की लाइन लपेटन आउटपुट को SMTP लाइन लंबाई की सीमा के अंदर रखती है। अगर आप ईमेल बॉडी एन्कोड कर रहे हैं, तो encode64 आपकी मदद कर रहा है।

लेकिन हर दूसरे संदर्भ में, यह लपेटन एक टैक्स है। सबसे आम दुर्घटना वह JSON दस्तावेज़ है जिसमें Base64 वैल्यू अचानक दो लाइनों पर फैल जाती है:

payload = { "logo" => Base64.encode64(File.binread("logo.png")) }
puts payload.to_json
# logo की वैल्यू के साथ वे लाइन ब्रेक चल रहे हैं जो किसी ने नहीं मांगे

और उसी बग की छोटी जुड़वाँ छवि छोटी स्ट्रिंग्स पर ट्रेलिंग न्यूलाइन है: Base64.encode64("s") "cw==\n" लौटाता है, इसलिए वह टोकन जो आप URL में चिपकाते हैं या किसी अपेक्षित वैल्यू से तुलना करते हैं, असफल हो जाता है - ऐसी वजहों के पीछे जो आप बीस मिनट तक दौड़ते रहेंगे। इलाज strip है - लेकिन बेहतर इलाज strict_encode64 है, जो एक भी ऐसा चर नहीं जोड़ता जो आपने नहीं कमाया हो। एक आकर्षक असममितता भी जानने लायक है: ख़ाली इनपुट ख़ाली स्ट्रिंग देता है, बिना किसी ट्रेलिंग न्यूलाइन के, इसलिए Base64.encode64("") बस "" है।

urlsafe_encode64: लिंक-सेफ़ वर्णमाला

स्टैंडर्ड वर्णमाला में दो ऐसे चर हैं जो कहीं भी URL पार्सर की नज़र हो, वहाँ परेशानी मचाने लगते हैं: + (क्वेरी स्ट्रिंग में यह स्पेस है) और / (यह पाथ सैपरेटर है)। RFC 4648 ने इसे एक बदले-बदलाव से हल किया - - + की जगह लेता है, _ / की जगह - और Ruby इसे Base64.urlsafe_encode64 में पूरा करता है:

Base64.urlsafe_encode64("\xfb\xef\xbe".b)
# => "----"
Base64.urlsafe_encode64("\xff\xff\xff".b)
# => "____"

ये दो उदाहरण वर्णमाला का प्रदर्शन हैं: वही बाइट्स जो स्टैंडर्ड एन्कोडर ++++ या //// के रूप में दिखाता है, यहाँ ---- और ____ के रूप में निकलते हैं - ऐसे चर जो URL, पाथ, फ़ाइल नाम और फ़ॉर्म फ़ील्ड में बिना किसी पर्सैंट एन्कोडिंग के सुरक्षित जीवित रहते हैं। आउटपुट एक लाइन का है, ठीक जैसा strict_encode64 के साथ।

इस मेथड का एकमात्र ऑप्शन padding: कीवर्ड है, जो Ruby 2.3 में जुड़ा, और यही वह जानना ज़रूरी है। JSON Web Token स्पेसिफ़िकेशन base64url बिना पैडिंग की माँग करता है, और कई अन्य टोकन स्कीम भी:

Base64.urlsafe_encode64("*")
# => "Kg=="
Base64.urlsafe_encode64("*", padding: false)
# => "Kg"

पैडिंग बंद कर देने पर लंबाई का गणित बदल जाता है: 3n + 1 बाइट्स अब 4n + 2 चर देते हैं और 3n + 2 बाइट्स से 4n + 3 बनते हैं। डिकोडर पक्ष कामचलाक है - Ruby का urlsafe_decode64 ग़ायब पैडिंग खुद जोड़ लेता है - इसलिए बिना-पैडिंग आउटपुट निकालना सुरक्षित है, लेकिन जब सामने वाला सख़्त RFC 2045 पाठक हो, तो पैडेड आउटपुट ही ज़्यादा दिल-बंद डिफ़ॉल्ट है। एक सावधानी: पैडिंग बस तब ही बंद करें जब कोई स्पेसिफ़िकेशन उसे माँगता हो। इससे एक-दो चर बचते हैं, और बदले में आपको डिकोडरों की शिकायतों का पूरा वर्ग मिल जाता है।

Ruby वाकई क्या एन्कोड करता है: स्ट्रिंग्स बाइट्स हैं

यूज़ केस से पहले, एक Ruby-विशिष्ट तथ्य जो सब कुछ तय करता है: एक Ruby स्ट्रिंग बाइट्स की एक क्रमांकित कतार है जिसने एक एन्कोडिंग टैग पहना है, और एन्कोडर सिर्फ़ बाइट्स देखते हैं। टैग Ruby को बताता है कि स्ट्रिंग को कैसे दिखाया और तुलना की जाए; यह बदलता नहीं है कि क्या एन्कोड होता है:

require "base64"
s = "h\u{e9}llo"
puts s.encoding
# => UTF-8
puts s.bytes.length
# => 6   एक्सेंट वाला e दो बाइट्स है
Base64.strict_encode64(s)
# => "aMOpbGxv"

यही वह फ़सा है जो "मेरा आउटपुट उम्मीद से ज़्यादा लंबा क्यों है?" के पीछे बसी है: आपकी टाइप की स्ट्रिंग अक्सर चरों में बाइट्स से छोटी होती है, और Base64 बाइट प्रति बिल करता है। उल्टी दिशा भी उतनी ही ख़ामोश है - एक ग़ैर-वैध UTF-8 स्ट्रिंग बिना किसी शिकायत के एन्कोड हो जाती है, क्योंकि एन्कोडर के पास वैलिडेट करने के लिए कुछ भी नहीं है:

broken = "h\u{e9}llo".b.force_encoding("UTF-8")
broken.setbyte(1, 0xFF)
puts broken.valid_encoding?
# => false
Base64.strict_encode64(broken)
# => कुछ base64, न एरर, बाइट्स ही बाइट्स हैं

असली बाइनरी के लिए टेक्स्ट की पूरी मशीनरी छोड़ दें और बाइट्स pack से बनाएँ या File.binread से पढ़ें। एक संतुष्टि देने वाला उदाहरण PNG signature है - वे आठ बाइट्स जो पृथ्वी पर हर PNG फ़ाइल का आरम्भ करती हैं:

png_magic = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A].pack("C*")
Base64.strict_encode64(png_magic)
# => "iVBORw0KGgo="

JWT: उस डेटा पर साइन करना जो पढ़ा भी जा सके

JSON Web Tokens Ruby के URL-safe एन्कोडर के सबसे बड़े नामदार उपभोक्ता हैं। टोकन तीन base64url खंडों से बना है जो डॉट्स से जुड़े हैं - हेडर, पेलोड, सिग्नेचर - और स्पेसिफ़िकेशन साफ़ है: वर्णमाला URL-safe वाली ही होनी चाहिए, और पैडिंग बंद होनी चाहिए। jwt gem इसका पूरा काम संभालता है:

# Gemfile में: gem "jwt"
require "jwt"
token = JWT.encode(
  { sub: "1234567890", name: "Alice", exp: Time.now.to_i + 3600 },
  "my-secret-key",
  "HS256"
)
puts token
# => eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFsaWNlIi...
payload, header = JWT.decode(token, "my-secret-key", true, algorithm: "HS256")
puts header
# => {"alg"=>"HS256"}

आप टोकन के अंदर Base64 लेयर को काम करते हुए भी देख सकते हैं, क्योंकि खंड बस JSON का base64url हैं:

require "base64"
require "json"
payload_json = JSON.generate({ "sub" => "1234567890", "name" => "Alice" })
segment = Base64.urlsafe_encode64(payload_json, padding: false)
puts segment
# => eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFsaWNlIn0

इस यूज़ केस के साथ दो नियम चलते हैं। प्रोडक्शन में हाथ से JWT कभी मत बनाइए - सिग्नेचर ही वह चीज़ है जो टोकन को बस एक क़ुबूलियत से कुछ और बनाती है - और gem से डिकोड करते समय ऑप्शन हैश में अल्गोरिदम को ऊपर दिखाए अनुसार तय करें, ताकि टोकन का अपना हेडर आपके लिए वेरिफ़िकेशन तरीका चुन न सके।

HTTP Basic Auth: हेडर बनाना

HTTP में "मैं कौन हूँ" बोलने का सबसे पुराना तरीका अब भी सबसे सरल है: क्रेडेंशियल्स को Base64 करें, उन्हें Basic शब्द के बाद रखें, और हेडर भेजें। Ruby में इसे बनाने में एक ही लाइन लगती है:

require "base64"
credentials = Base64.strict_encode64("alice:s3cr3t!")
puts "Basic #{credentials}"
# => Basic YWxpY2U6czNjcjN0IQ==

Ruby की स्टैंडर्ड लाइब्रेरी Net::HTTP में आपके लिए बिल्कुल यही करती है, कोर pack टेम्पलेट को सीधे कॉल करके - ["user:pass"].pack("m0") वही चीज़ है जिसमें अंदरों-अंदर basic_auth गिर जाता है:

require "net/http"
request = Net::HTTP::Get.new("https://example.org/api")
request.basic_auth("alice", "s3cr3t!")
puts request["Authorization"]
# => Basic YWxpY2U6czNjcjN0IQ==

और सिक्योरिटी की वह चेतावनी, जो एक बार कह दी जाए ताकि रिकॉर्ड पर हो: Base64 अनुवादक है, ताला नहीं। Basic auth हेडर के क्रेडेंशियल्स किसी भी व्यक्ति के लिए पढ़े जा सकते हैं जो पैकेट पढ़ सके। यह हेडर सिर्फ़ HTTPS के ऊपर ही स्वीकार्य है, जहाँ ट्रांसपोर्ट ही असली सुरक्षा करता है।

Data URIs: इनलाइन इमेजेस और फ़ॉन्ट्स

data URI वेब का जवाब है उस सवाल का, "मुझे यह इमेज चाहिए, बिना अलग फ़ाइल के": एक मीडिया टाइप, base64 शब्द, एक कॉमा, और बाइट्स। बस इसी से सिंगल-फ़ाइल HTML डेमो अपना लोगो शिप करते हैं, बस इसी से फ़ेविकॉन्स CSS के अंदर छिपते हैं, और बस इसी से एक जनरेट की गई इमेज पूरा-पूरा एक टेम्पलेट स्ट्रिंग के अंदर रह सकती है:

require "base64"
png = File.binread("logo.png")
data_uri = "data:image/png;base64,#{Base64.strict_encode64(png)}"
css = "background-image: url(#{data_uri});"
puts css.length
# => आपका stylesheet, बस एक HTTP रिक्वेस्ट कम

यहाँ strict_encode64 इस्तेमाल करें - पेलोड एक साफ़, एकल लाइन है, न लपेटन, न न्यूलाइन। और साइज़ पर नज़र रखें: जो इमेज आप इनलाइन करते हैं वह करीब एक-तिहाई बढ़ जाती है, इसलिए data URI छोटे एसेट्स (फ़ेविकॉन, लोगो, आइकन फ़ॉन्ट) में चमकते हैं और बड़े एसेट्स में फूल जाते हैं। 2 मेगाबाइट की हीरो फ़ोटो आपके HTML दस्तावेज़ की 2.7 मेगाबाइट बन जाती है, और आपके user अपनी पहली 4G स्क्रॉल पर इसे महसूस करेंगे।

ईमेल: वहाँ से Base64 आया था

इस आर्टिकल के बाकी हर यूज़ केस इसी के वंशज हैं। SMTP का डिज़ाइन 1980 के दशक में सात-बिट टेक्स्ट की छोटी-छोटी लाइनों के लिए था, यानी इसका मतलब यह था कि वह JPEG नहीं उठा सकता था। हल - Privacy-Enhanced Mail, फिर 1993 में MIME - था कि बाइनरी को 64-चिह्न वर्णमाला से टेक्स्ट के रूप में फिर से लिखा जाए, और वही फ़ॉर्मेट है जो आप आज इस्तेमाल कर रहे हैं। निशान आज भी Ruby के आउटपुट में दिखते हैं: encode64 60 चर पर लपेटता है - एक चौड़ाई जो किसी खास प्रोटोकॉल की सेवा नहीं करती, जैसा आप बाद में देखेंगे, पर ईमेल को सभ्य रखने के लिए काफ़ी छोटी।

अमल में आप mail gem को MIME काम करने देंगे। बाइनरी फ़ाइल एटैच करें और gem Base64 एन्कोडर चुन लेता है, लाइनें लपेट देता है, और हेडर लिख देता है:

# Gemfile में: gem "mail"
require "mail"
message = Mail.new do |m|
  m.from = "dev@example.org"
  m.to = "ops@example.org"
  m.subject = "Binary report"
  m.add_file("report.bin")
end
puts message.encoded
# एटैचमेंट वाला भाग Content-Transfer-Encoding: base64 के साथ चलता है

हेडर में ग़ैर-ASCII टेक्स्ट को थोड़े अलग कपड़ों में वही इलाज मिलता है: RFC 2047 एन्कोडेड वर्ड्स, जो प्रश्न चिह्न के बीच चरसेट टैग में Base64 को लपेटते हैं, जैसे =?UTF-8?B?w7wgc2VjcmV0cw==?=। अगर आप कभी इन्हें हाथ से बनाते या parse करते हैं, तो अंदर की Base64 साधारण ज़ात की है, decode64 से डिकोड होती है, और फिर उस चरसेट से नया टैग लेती है जो वह वर्ड घोषित करता है।

कीज़ और सर्टिफिकेट्स के लिए PEM कवच

कीज़ और सर्टिफिकेट्स PEM कवच पहनते हैं, और वह कवच Base64 है जिसने फ़्रेम पहना है: एक BEGIN लाइन, 64-चर की लाइनों में एन्कोड किए बाइट्स, और एक END लाइन। अगर कभी आपको कच्चे DER बाइट्स से PEM फ़ाइल बनानी पड़े, तो निर्माण दो-कदमी लपेटन है:

require "base64"
der_bytes = File.binread("server.der")
body_lines = Base64.strict_encode64(der_bytes).scan(/.{1,64}/)
pem = (["-----BEGIN PRIVATE KEY-----"] + body_lines +
  ["-----END PRIVATE KEY-----"]).join("\n") + "\n"
File.write("server.key", pem)

दो नोट्स। पहला, आपको यह काम लगभग कभी नहीं चाहिए होगा, क्योंकि openssl gem आपके लिए PEM लिख देता है (key.to_pem), और BEGIN और END लाइनों के बीच का लेबल अंदर की चीज़ से मेल खाना चाहिए - ग़लत लिख देने से ऐसी फ़ाइल बनती है जिसे इंटरनेट का हर टूल ठुकरा देता है। दूसरा, यहाँ लाइन लंबाई 64 है, PEM की क्लासिक चौड़ाई; Ruby का encode64 जगह उसकी 60 पर लपेटता है, और हर ठीक-ठाक PEM पार्सर लाइन लंबाई को बिल्कुल नज़रअंदाज़ कर देता है, इसलिए दोनों चौड़ाई बराबर अच्छे से डिकोड होती हैं।

फ़ाइलें: .b64 का रीवाज़

Base64 की दुनिया में सबसे आम फ़ाइल फ़ॉर्मेट एक प्लेन टेक्स्ट फ़ाइल है जिसका एक्सटेंशन .b64 (या कभी-कभी .base64) होता है और जिसमें एक एन्कोड किया हुआ पेलोड रहता है - इसे ऐसे समझिए: "फ़ाइल, पर कहीं भी paste करने में सुरक्षित"। Ruby से इसे बनाना एक वन-लाइनर है:

require "base64"
File.write("payload.b64", Base64.strict_encode64(File.binread("payload.bin")))
puts File.size("payload.b64")
# => मूल साइज़ का लगभग 1.33 गुना

strict_encode64 इस्तेमाल करें ताकि फ़ाइल एक साफ़, एकल लाइन रखे - वही रीवाज़ जो ज़्यादातर डिकोडिंग टूल्स (और Ruby का सख़्त डिकोडर) उम्मीद करते हैं। वापस पढ़ना उसका दर्पण-चित्र है: पढ़िए, डिकोड कीजिए, और बाइट्स बाइनरी मोड में लिखिए, ताकि बाहर निकलते वक़्त कुछ भी उन्हें बदल न सके:

encoded = File.read("payload.b64")
bytes = Base64.strict_decode64(encoded)
File.binwrite("restored.bin", bytes)

अगर आपकी .b64 फ़ाइलें ऐसे टूल्स से आती हैं जो लाइनें लपेटते हैं - कुछ base64 CLI रूप ऐसा करते हैं - तो strict decode से पहले लाइन ब्रेक हटा लें, या दयालु डिकोडर इस्तेमाल करें, जो उन्हें निःशुल्क छोड़ देता है।

कॉन्फ़िग फ़ाइलें, एनवायरनमेंट वेरिएबल्स और डेटाबेस

जब भी बाइनरी डेटा को टेक्स्ट दस्तावेज़ के अंदर रहना पड़ता है, Base64 वह पुल है। यह पैटर्न तीन जगह छोटे-बड़े बदलावों के साथ दोहराता है।

एनवायरनमेंट वेरिएबल्स और .env फ़ाइलें कच्चे बाइट्स नहीं रख सकतीं, इसलिए बाइट्स एन्कोड हो जाते हैं, वे अपनी मशीन से निकलने से पहले:

require "base64"
# जहाँ आप ऐप का प्रोविज़निंग करते हैं
ENV["APP_LOGO"] = Base64.strict_encode64(File.binread("logo.png"))
# जहाँ ऐप स्टार्टअप करता है
b64 = ENV.fetch("APP_LOGO")
File.binwrite("logo.png", Base64.decode64(b64))

YAML में बाइनरी का अपना टाइप है, और Psych Base64 आपके लिए संभाल लेता है - BINARY स्ट्रिंग को YAML में डंप करें तो वह !binary स्केलर बनकर निकलता है, और वापस load करने पर बाइट-दर-बाइट वैसा ही मिलता है:

require "yaml"
yaml_text = YAML.dump({ "logo" => File.binread("logo.png") })
puts yaml_text.lines.first(2)
# => "---"
# => "logo: !binary |-"
data = YAML.load(yaml_text)
puts data["logo"].encoding
# => ASCII-8BIT

डेटाबेस में सवाल स्टोरेज टाइप का है, एन्कोडिंग का नहीं। अगर आपके डेटाबेस में असली बाइनरी कॉलम है - BLOB, BYTEA, VARBINARY - तो उसे इस्तेमाल करें, और बाइट्स को ड्राइवर उठाते रहने दें। Base64-in-a-TEXT-column तब का पैटर्न है जब स्टोरेज लेयर सिर्फ़ स्ट्रिंग्स की भाषा समझती है: कुछ डॉक्यूमेंट स्टोर, JSON-आकार के API, या वह लीगेसी स्कीमा जिसे आप बदल नहीं सकते। कीमत कॉलम पर एक-तिहाई का साइज़-टैक्स है, और हर बाउंडरी पर अंदर आते समय एन्कोड करने और बाहर जाते समय डिकोड करने का अनुशासन, बिना किसी अपवाद के।

जो चेकसम टेक्स्ट के रूप में सफ़र करते हैं

हैश बाइनरी होते हैं, पर चेकसम ज़्यादातर टेक्स्ट के रूप में सफ़र करते हैं: फ़ाइल-अखंडता की सूचियाँ, कैश कीज़, फ़िंगरप्रिंट्स, लॉग लाइनें। Ruby की हर डिजस्ट क्लास में base64digest मेथड है जो एन्कोडिंग एक ही कॉल में कर देता है:

require "digest"
Digest::SHA256.base64digest("hello")
# => "LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ="

आउटपुट पैडेड स्टैंडर्ड Base64 है - वही जो Base64.strict_encode64(Digest::SHA256.digest("hello")) से मिलता - इसलिए इसे स्टोर करना, तुलना करना और paste करना सुरक्षित है। एकमात्र फैसला समानता है: Base64 से जनरेट की गई चेकसम सूची की जाँच Base64 आउटपुट से ही करनी पड़ती है, और वही हैश का hex और Base64 रूप दो अलग-अलग स्ट्रिंग्स हैं, इसलिए एक चुन लें और उसी पर टिक जाएँ।

छोटे चंक्स में बड़ी चीज़ें एन्कोड करना

डिकोडरों की तरह, एन्कोडर भी बफ़र-आधारित हैं: वे पूरा इनपुट पढ़ते हैं और पूरा आउटपुट निकालते हैं। स्टैंडर्ड लाइब्रेरी में कोई स्ट्रीमिंग एन्कोडर नहीं है, इसलिए बड़े पेलोड्स के लिए प्लान मेमोरी का है, और गणित में एक सुकून भरी सममितता है। एन्कोडिंग आपके डेटा को एक-तिहाई बढ़ाती है, इसलिए आपकी सबसे बड़ी अलोकेशन आउटपुट है - इनपुट नहीं - और 1 गिगाबाइट की फ़ाइल के लिए आपको सामने करीब 1.33 गिगाबाइट टेक्स्ट की उम्मीद रखनी चाहिए।

अगर इतना एक साथ रखना ज़्यादा है, तो आप चंक-चंक एन्कोड कर सकते हैं, क्योंकि Base64 वर्णमाला तीन-बाइट की सीमाओं पर आत्म-सिंक्रोनाइज़िंग है: हर 3-बाइट की स्लाइस को अलग-अलग एन्कोड करें और उनका मिलान पूरे को एन्कोड करने से बिल्कुल एक जैसा होता है:

require "base64"
require "securerandom"
bin = SecureRandom.random_bytes(10_001)
whole = Base64.strict_encode64(bin)
chunked = bin.scan(/.{1,3}/m).map { |slice| Base64.strict_encode64(slice) }.join
puts chunked == whole
# => true

वही ट्रिक आपको encode64 से बिल्कुल मेल खाता हुआ हाथ-से-बनाया लाइन-व्रैपर देती है: 45 बाइट्स हमेशा बिल्कुल 60 चर में एन्कोड होते हैं, इसलिए इनपुट को 45 बाइट्स पर काटकर टुकड़ों को लाइन ब्रेक से जोड़ने पर क्लासिक MIME आउटपुट एक-एक लाइन के साथ दोहराया जा सकता है, एक बार में मेमोरी में सिर्फ़ एक स्लाइस के साथ:

def wrap_like_encode64(bin)
  lines = bin.scan(/.{1,45}/m).map { |slice| Base64.strict_encode64(slice) }
  lines.join("\n") + "\n"
end
bin = SecureRandom.random_bytes(10_001)
puts wrap_like_encode64(bin) == Base64.encode64(bin)
# => true

कमांड लाइन से

एन्कोडिंग के लिए भी स्क्रिप्ट फ़ाइल की ज़रूरत नहीं है। वन-लाइनर फ़ॉर्म एक फ़ाइल पढ़ता है और उसका Base64 stdout में लिख देता है:

ruby -rbase64 -e 'print Base64.strict_encode64(File.binread(ARGV[0]))' payload.bin > payload.b64

और पाइप फ़ॉर्म stdin पढ़ता है, यानी किसी भी दूसरी कमांड से आ रही बाइट्स की धार को लपेटने का यह ही तरीका है:

some_command | ruby -rbase64 -e 'print Base64.strict_encode64(STDIN.read)'

दोनों में print ही रखें - एक फालतू puts आपके Base64 के अंत में न्यूलाइन जोड़ देगा, और strict_encode64 के आउटपुट के लिए वह साफ़ टोकन टूट जाता है। डिकोडिंग पक्ष के वही सरल नियम: अगर आपके आउटपुट के अगले उपभोक्ता सख़्त हैं, तो Base64 के अलावा कुछ भी उसके साथ सफ़र न करे।

वे फँसाव जिनकी Ruby डेवलपर्स को अतिरिक्त बाइट्स की कीमत चुकानी पड़ती है

  • JSON में ट्रेलिंग न्यूलाइन। Base64.encode64 हर ख़ाली-न-होने वाले नतीजे को लाइन ब्रेक के साथ ख़त्म करता है, इसलिए वह वैल्यू जो साफ़ टोकन बननी चाहिए, आपके JSON में आकर अंत में एक अनकही \n के साथ पेश होती है। जो कुछ भी स्टोर, तुलना या एक लाइन में भेजा जाना है, उसके लिए strict_encode64 इस्तेमाल करें।
  • टोकन और URL में 60-चर की लपेट। वही मेथड लंबे आउटपुट को कई लाइनों में लपेट देता है। URL में लपेटी स्ट्रिंग दो URL बन जाती है, और लपेटा टोकन टूटा टोकन। फिर से कहते हैं: strict_encode64, या encode64 के आउटपुट में फँसे रहें तो strip/delete से लाइन ब्रेक हटा लें।
  • URL में प्लस और स्लैश। क्वेरी स्ट्रिंग में स्टैंडर्ड Base64 का मतलब बाहर निकलते वक़्त %2B, %2F और %3D का पर्सैंट एन्कोडिंग है, साथ में आशा कि दूसरी तरफ डिकोड कर ले। urlsafe_encode64 समस्या को जड़ से हटा देता है।
  • पैडिंग ग़लत जगह। JWTs और अन्य टोकन स्कीम चाहती हैं कि पैडिंग बंद हो; कुछ MIME पाठक पैडिंग रहित आउटपुट से निपट न सकें। padding: false सिर्फ़ वहाँ निकालें जहाँ कोई स्पेसिफ़िकेशन माँगता हो, और जान लें कि आपके हर उपभोक्ता उस बाड़ के किस तरफ बैठे हैं।
  • चर बाइट्स नहीं होते। पाँच-चर की स्ट्रिंग जिसमें एक एक्सेंट वाला अक्षर है, UTF-8 में छह बाइट्स है, और आउटपुट लंबाई का गणित बाइट्स पर चलता है। जब एन्कोड नतीजा "ज़्यादा लंबा" लगे, तो चर नहीं, बाइट्स गिनिए।
  • स्कीमा डिज़ाइन में एक-तिहाई का टैक्स। 16 KB का BLOB TEXT कॉलम में करीब 22 KB की Base64 स्ट्रिंग बन जाता है। अपने कॉलम, कैश और API पेलोड्स को एन्कोड रूप के लिए साइज़ कीजिए, बाइनरी रूप के लिए नहीं।
  • दो वर्णमालाएँ, दो अलग-अलग स्ट्रिंग्स। वही बाइट्स स्टैंडर्ड और URL-safe वर्णमालाओं में अलग-अलग एन्कोड होते हैं, इसलिए एन्कोड वैल्यू केवल उसी वर्णमाला की दूसरी वैल्यू से तुलना योग्य है। कभी तुलना न करें, कभी मिलाकर न रखें।
  • Base64 ताला नहीं है। सीक्रेट को एन्कोड करने से वह सीक्रेट नहीं बनता। जिसके पास स्ट्रिंग है, उसके पास आपका डेटा है; Base64 सिर्फ़ बाइट्स के दिखने के तरीके को नियंत्रित करता है, यह नहीं कि वे कौन पढ़ सकता है।

आदतें जो बाइट्स और बग दोनों बचाती हैं

  • strict_encode64 को अपना डिफ़ॉल्ट बनाइए। जिस पल आउटपुट को URL, कूकी या पहचान-चिह्न में रहना हो, urlsafe_encode64 पर बदल जाएँ, और encode64 पर बस तब जब गंतव्य ईमेल जैसा लाइन-आधारित टेक्स्ट प्रोटोकॉल हो।
  • वायर के दोनों सिरों पर एन्कोडर और डिकोडर की वर्णमालाएँ एकसमान रखिए। सबसे आम "Base64 टूट गई" बग वही है: स्टैंडर्ड वर्णमाला वाला उत्पादक URL-safe उपभोक्ता से मिल जाता है, या बस उल्टा।
  • एन्कोडर को वे बाइट्स पिलाइए जो आप वाकई एन्कोड करना चाहते हैं: फ़ाइलों के लिए File.binread, बने-बनाए बाइनरी के लिए pack, और तब जब स्ट्रिंग ही डेटा है, तो UTF-8 स्ट्रिंग। एन्कोडर आपके चुनाव पर सवाल नहीं उठाएगा - वह बस बाइट्स गिनता है।
  • बढ़त का बजट बनाइए। जब भी कोई Base64 स्ट्रिंग बाउंडरी पार करके किसी साइज़ वाले कंटेनर में उतरे, 4/3 से गुणा कर लें और पैडिंग के लिए थोड़ा सा अतिरिक्त छूट भी जोड़ दें।
  • Base64 पोर्टेबिलिटी के लिए इस्तेमाल करें, कभी गोपनीयता के लिए नहीं। अगर लक्ष्य डेटा को निजता में रखना है, तो टूल एन्क्रिप्शन है, और Base64 बस वह काम है जो आप बाद में साइफरटेक्स्ट के साथ करते हैं।

Base64 gem कैसे बना

अपनी ज़िंदगी के ज़्यादातर हिस्से तक Base64 मॉड्यूल बस स्टैंडर्ड लाइब्रेरी की एक फ़ाइल था, जैसे Ruby के कई सबसे पुराने सहायक हैं। strict और URL-safe मेथड 1.9 डेवलपमेंट लाइन के दौरान मूल जोड़ी से जुड़े - पूरी base64 library, चारों मेथडों सहित, सितंबर 2008 में ट्रंक में जुड़ी, पहली बार 1.9.1 (2009) में शिप हुई, और padding: कीवर्ड 2015 में Ruby 2.3 के साथ आया। API का जो सब कुछ आप आज देखते हैं, उसका हर कण तब तक बस चुका था - कहानी का बाकी हिस्सा मॉड्यूल के शिप होने के तरीके के बारे में है।

2020 में, Ruby 3.0 के साथ, कोर टीम ने स्टैंडर्ड लाइब्रेरियों को उनके अपने gems में अलग करने शुरू किया, और base64 उनमें से एक बन गया: वर्ज़न 0.1.0, कोर कंट्रिब्यूटरों की देखरेख में ruby/base64 रिपॉज़िटरी में। यह डिफ़ॉल्ट gem के तौर पर शिप हुई - Ruby के साथ वितरित और हमेशा उपलब्ध, इसलिए require "base64" बिना किसी औपचारिकता के काम करता रहा। वर्ज़न 0.2.0 2023 में Ruby 3.3 के साथ आई, जिसमें Base64::VERSION कॉन्स्टेंट और एक बहुत ज़्यादा भरपूर दस्तावेज़ीकरण समूह जुड़ा।

फिर दिसंबर 2024 में Ruby 3.4 ने रेखा फिर खींची: base64 डिफ़ॉल्ट gem सूची से बंडल्ड gem सूची में चली गई, csv और drb की उसी शेल्व पर। बंडल्ड gems अभी भी भाषा के साथ शिप होते हैं, पर Bundler-आधारित प्रोजेक्ट को उन्हें घोषित करने की उम्मीद है, इसलिए अगर आप Ruby 3.4 या बाद पर हैं और आपका ऐप Bundler-आधारित है, तो Gemfile में gem "base64" जोड़ दीजिए (या gem install base64 चलाइए) और आप सुरक्षित हैं। 2025 में Ruby 4.0 ने वर्ज़न 0.3.0 लाई, जिसमें RBS टाइप सिग्नेचर हैं ताकि स्टैटिक चेकर मॉड्यूल को सही ढंग से देख सकें।

पूरे सफ़र के दौरान implementation बस वही रही जो हमेशा रही है: कोर pack और unpack टेम्पलेट के चारों ओर लिपटी कुछ दर्जन लाइनें शुद्ध Ruby की। कोई C एक्सटेंशन नहीं, कोई डिपेंडेंसी नहीं, और - rubygems.org पर सैकड़ों मिलियन की डाउनलोड संख्या सहित - प्लेटफ़ॉर्म के सबसे ज़्यादा इंस्टॉल किए गए gems में से एक।

Ruby के मज़ेदार तथ्य

  • पूरा मॉड्यूल, एन्कोडरों सहित, इतना छोटा है कि एक कॉफ़ी ब्रेक में पढ़ा जा सकता है। encode64 बिल्कुल सीधे [bin].pack("m") है, strict_encode64 [bin].pack("m0"), और urlsafe_encode64 सख़्त एन्कोडर है जिस पर दो-अक्षर का बदलाव किया गया हो, और आप माँगें तो पैडिंग घटा दी गई हो।
  • encode64 की 60-चर की लपेट न MIME की 76-चर की सीमा से मिलती है, न PEM की क्लासिक 64 से। यह बस वह है जो m pack टेम्पलेट हमेशा से करता रहा है, और mail gem के Base64 एन्कोडर इसे तारीफ़ के साथ टिप्पणी भी करता है: Ruby की अपने-आप लाइन लपेटन आउटपुट को SMTP सीमाओं के अंदर रखती है।
  • Ruby की Net::HTTP Basic auth के लिए Base64 मॉड्यूल पर हाथ तक नहीं मारती - वह सीधे pack टेम्पलेट को कॉल करती है, जो अच्छी याद दिलाती है कि मॉड्यूल कोर पर सुविधा की परत है, उल्टा नहीं।
  • हर डिजस्ट क्लास में base64digest मेथड है, इसलिए Digest::SHA256.base64digest hexdigest के बराबर की पहली श्रेणी का नागरिक है - टेक्स्ट में चेकसम, बिना दूसरी कॉल के।
  • YAML का !binary टैग गुमनाम रूप में Base64 है। Psych को BINARY स्ट्रिंग डंप करते ही एन्कोडिंग कर देता है, और इसीलिए बाइनरी से भरी कॉन्फ़िग फ़ाइलें ऐसी दिखती हैं जैसे दिखती हैं।
  • जो मॉड्यूल आप इस्तेमाल कर रहे हैं, वह हमेशा वह मॉड्यूल नहीं जो आप याद करते हैं। पुरानी Ruby में b64encode (चुनी गई चौड़ाई पर लपेटता था) और decode_b (RFC 2047 हेडर डिकोडिंग) थे; दोनों 1.9 लाइन में गायब हो गए, इसलिए आपसे जो 2010 से पुराना कोड इनका इस्तेमाल करे, वह NoMethodError के साथ मर जाएगा।
  • YouTube की वीडियो ID बिना-पैडिंग वाले base64url हैं - ग्यारह चर, न प्लस, न स्लैश, न इक्वल्स - बस वही छोटे, लिंक-सेफ़ पहचान-चिह्न जिनके लिए URL-safe वर्णमाला बनाई गई थी।

उल्टा पक्ष

अब आपके पास एन्कोडिंग की पूरी तस्वीर है: एक डिफ़ॉल्ट कामगार जो कभी आश्चर्य नहीं करवाता, एक क्लासिक जो उन प्रोटोकॉल्स के लिए लाइनें लपेटता है जो माँगते हैं, एक लिंक-सेफ़ वर्णमाला जिस पर पैडिंग का स्विच है, और बाइट-स्तर के नियम जो ठीक तय करते हैं कि आपका आउटपुट कैसा दिखेगा। उल्टा दिशा - किसी Base64 स्ट्रिंग को टुकड़ों में तोड़ना, Ruby के तीन डिकोडरों में से चुनाव करना, और नतीजे के बाइट्स को इस्तेमाल योग्य चीज़ में बदलना - अपने ख़ामोश गड्ढों के साथ आती है, शुरुआत उस डिकोडर से जो कभी नहीं कहता कि नहीं। उस पक्ष की गली को Base64 डिकोडिंग आर्टिकल में विस्तार से कवर किया गया है, नीचे लिंक है।

अंतिम अपडेट: 2026-09-08

संबंधित लेख: Ruby में Base64 डिकोडिंग: एक सम्पूर्ण गाइड