ما هو Base64؟ شرح الترميز

Base64 طريقة لتمثيل البيانات الثنائية — الصور والملفات والبايتات المشفّرة وأي شيء آخر — باستخدام 64 حرفاً قابلاً للطباعة فقط (A–Z وa–z و0–9 و+ و/). وُجد لأن كثيراً من القنوات صُممت للنص: البريد الإلكتروني وJSON وXML وعناوين URL وترويسات HTTP وملفات تعريف الارتباط تستطيع جميعها نقل سلسلة Base64 بأمان حيث كانت البايتات الخام ستتلف أو تُرفض.

يشرح هذا الدليل كيف يعمل الترميز، ومتى يكون الخيار الصحيح، والفرق بين Base64 وBase64URL، والأخطاء التي تنتج مخرجات مشوّهة — بما فيها الخطأ الأهم: Base64 ليس تشفيراً.

كيف يعمل ترميز Base64

يأخذ Base64 المدخلات ثلاثة بايتات (24 بت) في كل مرة ويقسمها إلى أربع مجموعات من ستة بتات. تُربط كل قيمة من ستة بتات (⁦0–63⁩) بحرف واحد من الأبجدية. ثلاثة بايتات تدخل وأربعة أحرف تخرج — ولهذا يكون ناتج Base64 دائماً أكبر من المدخل بنحو 33%.

وعندما لا يكون طول المدخل من مضاعفات الثلاثة، تُحشى المجموعة الأخيرة ببتات صفرية ويُلحق حرف «=» أو حرفان حتى يعرف مفكّك الترميز عدد البايتات الحقيقية المتوقعة.

المثال أدناه خطوة خطوة: النص ⁦Hi!⁩ ثلاثة بايتات (Text ثم Bytes)، تُقسم بتاتها الأربعة والعشرون إلى أربع مجموعات من ستة بتات (Groups)، قيمها 18 و6 و36 و33 (Index)، وهي في الأبجدية الأحرف S وG وk وh، فالناتج ⁦SGkh⁩. أما ⁦Hi⁩ فبايتان فقط: تُكمَّل المجموعة الأخيرة ببتّين صفريين ويُلحق حرف «=» واحد، فالناتج ⁦SGk=⁩.

ثلاثة بايتات هي 24 بتاً تُقرأ من جديد أربعَ مجموعات من ستة بتات، فتخرج أربعة أحرف. وتُحشى المجموعة الأخيرة الناقصة ببتات صفرية ويُلحق حرف «=».

Hi! — ثلاثة بايتات، دون حشو

النص (Text)

H i !

البايتات (Bytes)

01001000 01101001 00100001

المجموعات (Groups)

010010 000110 100100 100001

القيم (Index)

18 6 36 33

الناتج (Base64)

S G k h

Hi — بايتان، وحرف «=» واحد للحشو

النص (Text)

H i

البايتات (Bytes)

01001000 01101001 00

المجموعات (Groups)

010010 000110 100100

القيم (Index)

18 6 36

الناتج (Base64)

S G k =

الخطوط المتصلة حدود البايتات، والمتقطعة حدود مجموعات الستة بتات. والخانات الباهتة ليست من المدخل: البتات الصفرية وحرف «=» المضافة حشواً، والمكان الفارغ للبايت الناقص.

النسخة النصية
Text:   Hi!
Bytes:  01001000 01101001 00100001
Groups: 010010 000110 100100 100001
Index:  18     6      36     33
Base64: S      G      k      h        → "SGkh"

Text:   Hi      (2 bytes → one "=" of padding)
Base64: SGk=

جرّبها: مرمّز Base64 جرّبها: مرمّز / مفكّك ترميز ثنائي

Base64 ليس تشفيراً

يستطيع أي شخص فك ترميز Base64 فوراً دون أي مفتاح — فهو ترميز قابل للعكس، مثل كتابة رقم بالنظام السداسي عشري. لا يخفي شيئاً. كلمة المرور أو مفتاح API أو الرمز «المحمي» بـ Base64 مكشوف لكل من يراه. استخدم تشفيراً حقيقياً (AES وTLS) لحماية البيانات، وBase64 لنقلها فقط.

جرّبها: مفكّك ترميز Base64

متى تستخدم Base64

  • تضمين الصور أو الخطوط الصغيرة في HTML أو CSS أو JSON كعناوين data: URI.
  • إرسال محتوى ثنائي داخل حمولة JSON أو XML التي لا تحمل سوى النص.
  • مصادقة HTTP Basic: تحمل الترويسة Base64 لـ «username:password» (للنقل فقط — وعبر HTTPS دائماً).
  • رموز JWT وغيرها من الرموز التي تستخدم النسخة الآمنة لعناوين URL في ترويستها وحمولتها وتوقيعها.
  • مرفقات البريد الإلكتروني (MIME) وأي بروتوكول قديم يتوقع نصاً بسبعة بتات.
  • ليس للملفات الكبيرة عندما توجد قناة ثنائية — فالزيادة 33% وخطوة الترميز الإضافية هدر محض.

الفرق بين Base64 وBase64URL

يستخدم Base64 القياسي «+» و«/» ولكليهما معنى خاص في عناوين URL، وحشو «=» الذي غالباً ما يُرمَّز بالنسبة المئوية. أما Base64URL (RFC 4648 §5) فيستبدلهما بـ «-» و«_» ويحذف الحشو عادةً، فيمكن استخدام الناتج في عنوان URL أو اسم ملف أو رمز JWT دون تهريب إضافي. ومفكّك الترميز الذي يتوقع نسخة سيرفض الأخرى، وهذا أكثر أسباب فشل فك ترميز رمز «صالح» شيوعاً.

جرّبها: مرمّز URL جرّبها: مفكّك ترميز JWT

ترميز النصوص: انتبه إلى مجموعة الأحرف

يرمّز Base64 البايتات لا الأحرف، لذا يجب تحويل النص إلى بايتات أولاً — بـ UTF-8 في الغالبية الساحقة من الحالات. تصبح الأحرف العربية والهندية والرموز التعبيرية تسلسلات متعددة البايتات؛ وإذا استخدم المرمّز UTF-8 وافترض مفكّك الترميز Latin-1 (أو العكس) خرج النص مشوّهاً. عندما يختلف نظامان حول سلسلة Base64، فمجموعة الأحرف هي أول ما يجب فحصه.

جرّبها: مرمّز Base64 جرّبها: مرمّز Hex

لماذا يفشل فك الترميز

  • أبجدية خاطئة — سلسلة Base64URL («-» و«_») تُمرَّر إلى مفكّك قياسي، أو العكس.
  • حشو ناقص أو زائد — تحذف بعض المرمّزات «=»، بينما تشترط المفكّكات الصارمة طولاً من مضاعفات الأربعة.
  • مسافات أو فواصل أسطر داخل السلسلة — يلفّ MIME الأسطر عند 76 حرفاً؛ أزلها قبل فك الترميز.
  • ترميز مزدوج — سلسلة رُمّزت بـ Base64 مرتين تبدو صالحة لكنها تُفكّ إلى Base64 آخر.
  • لم تكن Base64 أصلاً — قد يبدو Hex أو الهاش أو رمز عشوائي مشابهاً. يستخدم Base64 الأحرف الأربعة والستين بالضبط مع «=»، وطوله من مضاعفات الأربعة عند الحشو.

جرّبها: مفكّك ترميز Base64

الأسئلة الشائعة

هل Base64 آمن؟

لا. إنه ترميز قابل للعكس دون مفتاح. لا يوفر أي سرّية على الإطلاق؛ استخدم التشفير لذلك.

لماذا ينتهي Base64 بـ «=» أو «==»؟

الحشو. تُعالج المدخلات في مجموعات من ثلاثة بايتات؛ وعندما يتبقى بايت أو بايتان يُلحق «==» أو «=» حتى يعرف مفكّك الترميز الطول الحقيقي.

كم يكبر ناتج Base64؟

بنحو 33% — كل 3 بايتات تصبح 4 أحرف. صورة بحجم 300 كيلوبايت تصبح نصاً بنحو 400 كيلوبايت.

هل يمكن لـ Base64 ترميز صورة أو ملف PDF؟

نعم — يعمل Base64 على أي بايتات. هكذا تضمّن عناوين data: URI الصور في HTML وهكذا تنتقل الملفات داخل واجهات JSON API.

ما الفرق بين Base64 وHex؟

كلاهما يمثّل البايتات كنص. يستخدم Hex 16 حرفاً ويضاعف الحجم (حرفان لكل بايت)؛ ويستخدم Base64 64 حرفاً ويزيد الحجم بالثلث. Hex أسهل في القراءة؛ وBase64 أكثر إيجازاً.

ما الفرق بين Base64 وترميز URL؟

ترميز URL (النسبة المئوية) يهرّب الأحرف غير الآمنة في عنوان URL فقط ويترك الأحرف العادية كما هي. أما Base64 فيعيد ترميز كل بايت. وكثيراً ما يُجمع بينهما: قد تحتاج سلسلة Base64 إلى ترميز بالنسبة المئوية قبل وضعها في معامل استعلام، ما لم تُستخدم النسخة الآمنة لعناوين URL.

المراجع

تمرين عملي

شخّص مشكلات Base64 في واجهة برمجية لرفع المستندات

المطلوب

أنت تختبر خدمة المستندات (Documents service) في منصة خدمات حكومية إلكترونية (مثال خيالي) قبل الإصدار ⁦3.2⁩. يرفق المتقدّمون المستندات الداعمة في تطبيقات الجوال، التي ترسل كل ملف داخل طلب JSON على شكل سلسلة Base64؛ ويستدعي نظامُ وكالة سفر شريكة الواجهةَ البرمجية نفسها مباشرةً بمصادقة HTTP Basic؛ ويحمل بريد الإيصال رابطاً فيه مرجع بترميز Base64. تعرض المادة أدناه المتطلب، ومقتطفاً من عقد الواجهة البرمجية (API contract)، وملاحظتين عن المنصة، وست ملاحظات جُمعت في بيئة Staging.

قرّر لكل ملاحظة هل تكشف عيباً، واشرحها بقاعدة Base64 التي تقف وراءها، وحدّد أين يجب أن يكون الإصلاح؛ ثم صمّم الاختبارات التي تلتقط هذه المشكلات في المرة القادمة. اعمل بالورقة والقلم، وبأداتَي ترميز Base64 وفك ترميزه (في أداة فك الترميز خيار Latin-1 ضمن «فك ترميز النص كـ»)، وأداة فك ترميز URL، وأداة لتحليل القيم الحدّية. خصّص ⁦40–45⁩ دقيقة؛ فحساب الحجم لا يحتاج إلا إلى الضرب والقسمة.

المادة
منصة خدمات حكومية إلكترونية (مثال خيالي) - خدمة المستندات، الإصدار 3.2
اختبار النظام في بيئة Staging

المتطلب DOC-4
  يستطيع المتقدّم أن يرفق بطلبه ملف PDF أو JPG أو PNG حجمه حتى 5 ميغابايت
  (5,000,000 بايت). ويُرفض الملف الأكبر برمز الحالة HTTP 413 والخطأ
  FILE_TOO_LARGE («حجم الملف أكبر من 5 ميغابايت»).

عقد الواجهة البرمجية (مقتطف)
  POST /api/v3/applications/{id}/documents       Content-Type: application/json
    content  الملف بترميز Base64 (RFC 4648، الأبجدية القياسية، مع الحشو)
    النجاح   201 مع معرّف المستند
    الأخطاء  400 INVALID_BASE64، 413 FILE_TOO_LARGE
  GET /api/v3/receipts?ref={ref}                 ref = 12 بايتاً عشوائياً بترميز Base64
  المستدعون: تطبيقا iOS وAndroid (يفحصان حدّ 5 ميغابايت قبل الرفع)،
             ونظام وكالة سفر شريكة (مصادقة HTTP Basic)

ملاحظتان عن المنصة
  ترفض بوابة الواجهات البرمجية (API gateway) أي جسم طلب يزيد على 6,000,000 بايت
  بصفحة HTML خاصة بها مع HTTP 413، قبل أن يصل الطلب إلى خدمة المستندات.
  إعدادات السجلات في البوابة واحدة في بيئة Staging وفي الإنتاج.

عيّنة رفع (قيمة Base64 مختصرة)
  {"fileName":"family-book.pdf","mimeType":"application/pdf","content":"JVBERi0xLjcK..."}
  حجم هذا الجسم دون قيمة Base64 هو 72 بايتاً.

الملاحظات
O1  الملف family-book.pdf بحجم 4,800,000 بايت يجتاز فحص التطبيق: HTTP 413
    وصفحة HTML من البوابة. الملف birth-certificate.pdf بحجم 4,200,000 بايت: HTTP 201.
O2  تطبيق Android: كل عملية رفع تفشل بالرمز 400 INVALID_BASE64، والملفات نفسها
    تُرفع من iOS بنجاح. في طلب Android الملتقَط يحوي "content" الرمز \n
    (فاصل سطر) بعد كل 76 حرفاً.
O3  رابطا إيصال من رسالتَي بريد إلكتروني:
      GET /api/v3/receipts?ref=Lm0x8Qp/Vt2aKc3Q   200، نُزِّل الإيصال
      GET /api/v3/receipts?ref=k7Qd2+fA9w1Z0LsE   400 "Invalid reference"
    سجل الخدمة للطلب الثاني: ref = "k7Qd2 fA9w1Z0LsE"
O4  سجل الوصول في البوابة، استدعاء من الشريك:
      POST /api/v3/applications 201  Authorization: Basic YWdlbmN5MDc6VmlzYSNUZXN0MjY=
    تعليق المطوّر: «لا بأس بإبقائه، فالترويسة مرمَّزة ولا يستطيع أحد قراءتها».
O5  يرسل التطبيقان اسم صاحب المستند في ترويسة، بترميز Base64 لأن قيم الترويسات
    يجب أن تبقى ASCII:   X-Doc-Owner: 2LPYp9ix2Kk=
    وتعرض شاشة المراجعة في النظام الداخلي (Back office) اسمه هكذا:   سارة
O6  ملاحظة مختبِر على ثلاث عمليات رفع ناجحة: «يبدو content تالفاً، ففي آخره
    علامات = زائدة، والأحجام لا تطابق الملفات».
      الملف                    الحجم (بايت)   طول content (حرف)   ينتهي بـ
      passport-photo.png             48,211              64,284   ==
      salary-certificate.pdf        120,005             160,008   =
      lease-contract.jpg             96,300             128,400   (بلا =)
الخطوات
  1. فكّ ترميز كل قيمة Base64 في المادة، واكتب ما تحتويه كل منها.
  2. في O1 احسب طول Base64 وحجم جسم الطلب لأكبر ملف مسموح، ثم أكبر ملف تسمح البوابة بمروره. اذكر أي الملفات الصالحة تفشل، وما الذي يتوقعه DOC-4 بدلاً من ذلك.
  3. في الملاحظات من O2 إلى O6 قرّر: هل هي عيب أم لا، وما قاعدة Base64 التي تفسّرها، وأين يجب أن يكون الإصلاح (تطبيق Android، أو الشيفرة التي تبني الرابط، أو البوابة، أو النظام الداخلي، أو لا مكان).
  4. استخرج قيم اختبار حجم الملف بتحليل القيم الحدّية الثنائي (2-value BVA) لحدّ المتطلب ولحدّ البوابة معاً، أي اختبر كل قيمة حدّية وأقرب قيمة مجاورة لها في القسم المجاور: هنا أكبر حجم يُقبل والحجم الذي يزيد عليه ببايت واحد، ثم أضف أحجاماً تغطي كل حالة من حالات الحشو.
  5. اكتب الاختبارات السلبية لحقل content ولمرجع الإيصال مع النتيجة المتوقعة لكل منها، والأسئلة التي سترسلها إلى مالك الواجهة البرمجية.
إظهار الإجابة النموذجية
الإجابة النموذجية

القيم بعد فك الترميز. JVBERi0xLjcK تُفكّ إلى %PDF-1.7 يليها فاصل سطر، وهي الترويسة التي يبدأ بها ملف PDF، فـ content يحمل بايتات الملف فعلاً. وYWdlbmN5MDc6VmlzYSNUZXN0MjY= تُفكّ إلى agency07:Visa#Test26، أي اسم مستخدم الشريك وكلمة مروره. و2LPYp9ix2Kk= تُفكّ إلى الاسم العربي سارة عندما تُقرأ بايتاتها D8 B3 D8 A7 D8 B1 D8 A9 بترميز UTF-8، وإلى سارة بالضبط عندما تُقرأ البايتات نفسها بترميز Latin-1. أما مرجعا الإيصال فيُفكّ كل منهما إلى ⁦12⁩ بايتاً عشوائياً، ولا يُتوقع فيهما نص مقروء.

O1: عيب في إعدادات البوابة. يحوّل Base64 كل ثلاثة بايتات إلى أربعة أحرف، ويقرّب المجموعة الأخيرة إلى الأعلى. فأكبر ملف مسموح، ⁦5,000,000⁩ بايت، يساوي ⁦1,666,667⁩ مجموعةً، أي إن طول content ⁦6,666,668⁩ حرفاً (مع حرف حشو «=» واحد)، والجسم ⁦6,666,668 + 72 = 6,666,740⁩ بايتاً، وهذا فوق حدّ البوابة البالغ ⁦6,000,000⁩. وأكبر ملف يمرّ: يبقى لـ content ⁦6,000,000 − 72 = 5,999,928⁩ حرفاً، و⁦5,999,928 ÷ 4 = 1,499,982⁩ مجموعةً كاملة، و⁦1,499,982 × 3 = 4,499,946⁩ بايتاً. لذلك، مع ⁦72⁩ بايتاً من JSON كما في العيّنة، يُرفض كل ملف صالح حجمه من ⁦4,499,947⁩ إلى ⁦5,000,000⁩ بايت (فالملف family-book.pdf بحجم ⁦4,800,000⁩ بايت يحتاج جسماً من ⁦6,400,072⁩ بايتاً، بينما يُرمَّز birth-certificate.pdf بحجم ⁦4,200,000⁩ بايت إلى ⁦5,600,000⁩ حرف فيمرّ)، ويتلقى المتقدّم صفحة HTML من البوابة بدلاً من خطأ مفهوم. والملفات التي تتجاوز الحد تتلقى استجابة خاطئة أيضاً: فملف من ⁦5,000,001⁩ بايت يرسله نظام الشريك، الذي لا يسبقه فحص التطبيق، لا يصل إلى الخدمة أصلاً، فلا يعود الخطأ FILE_TOO_LARGE الذي يشترطه DOC-4 أبداً.

وبمصطلحات ISTQB فإن الإخفاق (Failure) هو الاستجابة 413 لملف صالح، والعيب هو حدّ لجسم الطلب ضُبط على حجم الملف الخام لا على الطلب المرمَّز. أبلغ عنه على إعدادات البوابة، مع DOC-4 أساساً للاختبار (Test basis). أما طريقة الإصلاح فقرار الفريق: رفع الحد فوق أكبر جسم مرمَّز مع هامش لأسماء الملفات الطويلة، أو رفع الملفات بصيغة ثنائية (مثل multipart/form-data) بدلاً من Base64 داخل JSON، وهذا يلغي أيضاً زيادة الثلث. وأضف ملاحظة للمطورين: الملفان بحجم ⁦5,000,000⁩ و⁦5,000,001⁩ بايت يُرمَّزان كلاهما إلى ⁦6,666,668⁩ حرفاً، لذا يجب فحص قاعدة الحجم على البايتات بعد فك الترميز، لا على طول سلسلة Base64 أبداً.

O2: عيب في تطبيق Android. فاصل السطر بعد كل ⁦76⁩ حرفاً هو التفاف الأسطر على طريقة MIME. ينص ⁦RFC 4648 §3.1⁩ على أن المرمِّزات يجب ألا تضيف فواصل أسطر ما لم تطلب ذلك المواصفة التي تستخدم Base64، والعقد لا يطلبه؛ وينص ⁦§3.3⁩ على أن مفكّك الترميز يجب أن يرفض الأحرف الخارجة عن الأبجدية ما لم تنص المواصفة على غير ذلك. فاستجابة الخدمة 400 INVALID_BASE64 صحيحة، ونجاح iOS يثبت أن الملفات نفسها سليمة. ويمكنك أن ترى نوعَي مفكّك الترميز جنباً إلى جنب: رمّز ملفاً صغيراً بأداة ترميز Base64 مع ضبط «التفاف السطر» على «76 حرفاً (MIME)»، ثم الصق الناتج في أداة فك ترميز Base64، وهي متسامحة: تتجاهل فواصل الأسطر وتذكر عدد المسافات البيضاء التي تجاهلتها. أما خدمة المستندات فصارمة، كما يطلب الـ RFC افتراضياً. الإصلاح: أن يُخرج مرمِّز Android القيمة في سطر واحد. واطلب من مالك الواجهة البرمجية أن يكتب في العقد صراحةً: «سطر واحد بلا مسافات بيضاء».

O3: عيب في طريقة بناء رابط الإيصال. المرجع الثاني يحوي «+». فالرابط يضع Base64 القياسي في سلسلة الاستعلام (Query string) دون ترميز بالنسبة المئوية، والخدمة تقرأ سلسلة الاستعلام بقواعد ترميز النماذج (Form encoding) التي يعني فيها «+» مسافة، فتستلم k7Qd2 fA9w1Z0LsE وترفضه. وأداة فك ترميز URL تعيد إنتاج ذلك: مع تفعيل «فك ترميز + كمسافة» يخرج k7Qd2+fA9w1Z0LsE بصورة k7Qd2 fA9w1Z0LsE. والمرجع الأول ينجح فقط لأنه لا يحوي «+»؛ أما «/» فيه فمسموح في سلسلة الاستعلام، لكنه سيكسر المسار لو نُقل المرجع يوماً إلى المسار نفسه. ولأن المراجع بايتات عشوائية، يبدو فشل الروابط عشوائياً أيضاً، ولهذا كثيراً ما يُبلَّغ عن هذا النوع من العيوب على أنه متقطع. الإصلاح: استخدام Base64URL ⁦(RFC 4648 §5)⁩ للمرجع، فلا تحتاج القيمتان k7Qd2-fA9w1Z0LsE وLm0x8Qp_Vt2aKc3Q إلى أي تهريب؛ أو ترميز القيمة بالنسبة المئوية فيصبح «+» هو %2B (تُظهره أداة ترميز URL)، لكن نسيان ذلك أسهل. ويجب أن تبقى الروابط المرسلة سابقاً بالبريد صالحة بعد الإصلاح: اسأل كيف ستُقبل المراجع القديمة.

O4: عيب أمني، وهو أخطر الملاحظات الست لأنه يكشف بيانات اعتماد. تُفكّ الترويسة في ثوانٍ إلى agency07:Visa#Test26، أي إن سجل البوابة يحفظ كلمة مرور الشريك بصيغة مقروءة لكل من يستطيع قراءة السجلات، والإنتاج يسجّل بالطريقة نفسها. وتعليق المطوّر خاطئ: Base64 ترميز بلا مفتاح وليس تشفيراً، وHTTPS يحمي بيانات اعتماد Basic أثناء النقل فقط، لا بعد كتابتها في سجل. أبلغ عنه بخطورة عالية، واذكر في التقرير اسم المستخدم مع إخفاء كلمة المرور. الإصلاح المتوقع: إخفاء ترويسة Authorization أو حذفها من سجل البوابة ومن أي سجل أو أداة مراقبة أخرى تسجّل الترويسات، وتغيير بيانات الاعتماد المكشوفة. اختبار التأكيد: كرّر استدعاء الشريك وتحقق من أن السجل لا يُظهر أي بيانات اعتماد؛ وفي اختبارات الانحدار افحص الترويسات الأخرى التي تحمل أسراراً، مثل مفاتيح API ورموز Bearer.

O5: عيب في النظام الداخلي. التطبيقان على صواب: 2LPYp9ix2Kk= هو ترميز UTF-8 للاسم سارة (أربعة أحرف في ثمانية بايتات). أما النظام الداخلي فيحوّل البايتات بعد فك الترميز إلى نص بترميز Latin-1، حرفاً لكل بايت، فيصبح D8 هو Ø وB3 هو ³، والنتيجة سارة؛ ويعيد إنتاجها بالضبط اختيارُ «Latin-1 / سلسلة ثنائية» في «فك ترميز النص كـ» بأداة فك ترميز Base64. وتتابُع Ø أو Ù، يلي كلاً منهما رمز آخر، علامة نموذجية على نص عربي بترميز UTF-8 قُرئ بترميز Latin-1. الإصلاح: قراءة البايتات بعد فك الترميز بترميز UTF-8. بيانات الاختبار لاختبار التأكيد ولحزمة الانحدار: اسم عربي، واسم هندي بالخط الديوناغري (ثلاثة بايتات لكل حرف في UTF-8)، واسم لاتيني فيه حرف بعلامة تشكيل مثل José (الحرف é بايتان)، واسم فيه رمز تعبيري إن كان الحقل يسمح به (أربعة بايتات)، واسم بأحرف ASCII فقط يجب أن يبقى كما هو.

O6: ليس عيباً. الحشو يتبع حجم الملف لأن Base64 يعمل على مجموعات من ثلاثة بايتات: ⁦48,211⁩ يترك باقياً قدره ⁦1⁩ عند القسمة على ⁦3⁩ فتنتهي القيمة بـ «==»، و⁦120,005⁩ يترك ⁦2⁩ فتنتهي بـ «=»، و⁦96,300⁩ يترك ⁦0⁩ فلا حشو. (طريقة سريعة للتحقق: باقي قسمة العدد على ⁦3⁩ يساوي باقي قسمة مجموع أرقامه على ⁦3⁩.) والأطوال تساوي ⁦4⁩ × (الحجم ÷ ⁦3⁩ مقرَّباً إلى الأعلى): ⁦16,071 × 4 = 64,284⁩ و⁦40,002 × 4 = 160,008⁩ و⁦32,100 × 4 = 128,400⁩، أي أكثر من كل ملف بنحو الثلث كما هو متوقع. أغلق الملاحظة بأنها ليست عيباً مع هذا الحساب، واحتفظ بالملفات الثلاثة: فهي معاً تغطي حالات الحشو كلها.

قيم اختبار حجم الملف (تحليل القيم الحدّية الثنائي). حدّ المتطلب: ⁦5,000,000⁩ بايت تُقبل بالرمز 201، و⁦5,000,001⁩ بايت تُرفض بالرمز 413 والخطأ FILE_TOO_LARGE؛ أرسل الحالتين إلى الواجهة البرمجية مباشرةً كما يفعل نظام الشريك، لا عبر التطبيق فقط. حدّ البوابة لاسم الملف في العيّنة، وهو حدّ تقني لا يذكره المتطلب: ⁦4,499,946⁩ بايتاً (الجسم ⁦6,000,000⁩ بالضبط، يُقبل) و⁦4,499,947⁩ بايتاً (الجسم ⁦6,000,004⁩، ترفضه البوابة اليوم، ويُقبل بعد إصلاح العيب). حالات الحشو: ثلاثة أحجام بواقي قسمتها على ⁦3⁩ هي ⁦0⁩ و⁦1⁩ و⁦2⁩، مثل ملفات O6. وشغّل حدّ البوابة أيضاً بأطول اسم ملف مسموح، لأن كل بايت إضافي في JSON يخفض أكبر ملف يمرّ، واسأل ماذا يتوقع DOC-4 لملف فارغ. وأبقِ الحالتين ⁦4,499,947⁩ و⁦5,000,000⁩ في حزمة الانحدار بعد الإصلاح.

اختبارات سلبية لـ content، يُتوقع في كل منها 400 INVALID_BASE64 وعدم تخزين أي شيء، بحسب نص العقد اليوم: فواصل أسطر أو مسافات داخل القيمة؛ وحرفا Base64URL «-» أو «_»؛ وحرف خارج الأبجدية مثل «*»؛ وطول ليس من مضاعفات الأربعة (بحذف الحشو)؛ وعلامة «=» في وسط القيمة. أما الملف المرمَّز مرتين فهو Base64 صالح تُفكّ بايتاته إلى نص Base64 (يبدأ بـ SlZCRVJp بدلاً من JVBERi0): ينبغي رفضه لأنه ليس PDF إن كانت الخدمة تفحص محتوى الملف مقابل mimeType، فاسأل هل تفعل. ولمرجع الإيصال: مراجع تحوي «+» و«/»، و«=» إن كان طول المراجع قد يتغير؛ ومرجع فيه مسافة؛ ومرجع مرمَّز بالنسبة المئوية (%2B)؛ ومرجع سليم الصيغة لكنه غير موجود، ويجب أن يعيد خطأً من جهة العميل (Client error)، لا 500 أبداً (ولا يحدد المقتطف أيّ خطأ، فاسأل عنه).

أسئلة لمالك الواجهة البرمجية: هل تقبل الخدمة غياب الحشو والمسافات البيضاء أم ترفضهما، وهل يمكن أن ينص العقد على ذلك صراحةً؟ ما أطول اسم ملف مسموح، بما أنه يحرّك حدّ البوابة؟ هل تتحقق الخدمة من أن البايتات بعد فك الترميز تطابق mimeType؟ هل ستنتقل مراجع الإيصالات إلى Base64URL، وكيف ستبقى الروابط المرسلة سابقاً صالحة؟ وهل Base64 داخل JSON هو القناة المناسبة أصلاً لملفات حتى ⁦5⁩ ميغابايت، مع زيادة الثلث التي يضيفها؟

إن اختلفت أرقامك فتحقق من أنك قرّبت عدد المجموعات إلى الأعلى عند حساب الطول المرمَّز وإلى الأدنى عند حساب أكبر ملف يمرّ، ومن أنك أضفت ⁦72⁩ بايتاً من JSON.

تقدّمك في هذا الموضوع

جزء من مسار تعلم ضمان الجودة

الأدوات المذكورة في هذا الدليل

ترميز النصوص أو الملفات إلى Base64 (القياسي أو الآمن لعناوين URL) داخل متصفحك.

الترميز

فكّ ترميز سلاسل Base64 أو Base64url إلى نص، مع إصلاح الحشو تلقائياً.

الترميز

ترميز النص بالنسبة المئوية (percent-encoding) لاستخدامه بأمان في عناوين URL وسلاسل الاستعلام وبيانات النماذج.

الترميز

تحويل النص إلى بايتات سداسية عشرية (UTF-8) مع فواصل مخصصة وحالة أحرف قابلة للتحديد.

الترميز

فكّ ترميز ترويسة JWT وحمولته، وفحص المطالبات (claims) والتحقق من انتهاء الصلاحية — بالكامل داخل متصفحك.

الأمان

أدلة أخرى

أدلة أخرى
الأمان

ما هو JWT؟ شرح رموز JSON Web Token

شرح مبسّط لـ JWT: الأجزاء الثلاثة للرمز، والمطالبات مثل exp وsub، وكيفية فك ترميزه والتحقق منه، ولماذا فك الترميز ليس تحققاً، وقواعد الأمان.

وقت القراءة 4 دقائق
JSON والبيانات

ما هو JSON؟

شرح JSON بلغة مبسّطة: ما هو، وأنواع القيم الست، وقواعد الصياغة التي يخطئ فيها الكثيرون، وكيفية تنسيقه والتحقق منه، ومقارنته بـ XML وYAML.

وقت القراءة 4 دقائق
أدوات مساعدة

ما هو UUID؟ الفرق بين v4 وv7 وبين UUID وGUID وULID

شرح UUID: صيغة الـ 128 بت، والفرق بين v4 وv7، ولماذا v7 أفضل لمفاتيح قواعد البيانات، ومقارنة UUID بـ GUID وULID، واحتمال التصادم، والتوليد والتحقق.

وقت القراءة 4 دقائق
الويب

شرح رموز حالة HTTP

شرح كل فئة من رموز حالة HTTP مع الرموز التي تقابلها فعلاً — 200 و301 و400 و401 و403 و404 و422 و429 و500 و502 و503 و504 — وسبب كل منها وأيها تعيده.

وقت القراءة 5 دقائق
أدوات مساعدة

شرح تعابير cron

شرح تعابير cron حقلاً حقلاً: الدقيقة والساعة واليوم والشهر ويوم الأسبوع، والمعاملات * و/ و- و,، والجدولات الشائعة، والمناطق الزمنية، والأخطاء الشائعة.

وقت القراءة 5 دقائق
أدوات مساعدة

التعابير النمطية (Regex) للمبتدئين

تعلّم Regex من الصفر: فئات الأحرف والمحددات الكمية والمراسي والمجموعات والأعلام، وأنماط جاهزة للبريد والهواتف والتواريخ، وكيفية الاختبار بأمان.

وقت القراءة 4 دقائق