ما هو URL Encoding؟
URL Encoding — ويُسمّى أيضاً Percent Encoding — هو الطريقة المعيارية لتمثيل الأحرف الخاصّة والمحارف غير الـ ASCII داخل عناوين URL. كل بايت لا ينتمي إلى المجموعة الآمنة يتحوّل إلى رمز % متبوع برقمين ستّ عشريّين يمثّلان قيمة البايت.
المعيار الأساسي هو RFC 3986 الصادر عام 2005، وهو يحدّد بدقّة أيّ المحارف يمكن أن تظهر مباشرةً في URL، وأيّها يجب ترميزه. كل متصفّح وكل لغة برمجة تطبّق هذا المعيار بطريقة متشابهة — لكنها ليست متطابقة تماماً، وهذا ما يربك المطوّرين أحياناً.
لماذا نحتاج هذا الترميز أصلاً؟
URL هو سلسلة نصّية يجب أن تُنقَل عبر بروتوكولات مثل HTTP، وأن تُكتب في شريط العنوان، وأن تظهر في روابط HTML. هذه القنوات جميعها تتعامل مع مجموعة ضيّقة من المحارف الآمنة. تخيّل أنّك تريد إرسال هذا الرابط:
https://example.com/search?q=قهوة سعودية&type=light
هناك ثلاث مشاكل: المسافة بين «قهوة» و «سعودية» ستكسر تحليل الرابط، الأحرف العربية ليست ASCII وقد ترفضها بعض الأنظمة، والرمز & داخل القيمة سيُفسَّر كفاصل بين معاملَين. الحلّ هو الترميز: المسافة تصبح %20، «قهوة» تصبح %D9%82%D9%87%D9%88%D8%A9، و & داخل القيمة يصبح %26.
كيف يعمل Percent Encoding — التفاصيل البسيطة
الخطوات الثلاث:
- 1. حوِّل الحرف إلى تمثيله بـ UTF-8 (سلسلة بايتات).
- 2. اكتب كل بايت كقيمة ستّ عشرية مكوّنة من رقمَين.
- 3. ضع
%قبل كل بايت.
مثال: المسافة U+0020 = بايت واحد 0x20 = %20. الرمز ! = 0x21 = %21. الحرف العربي «ا» U+0627 = بايتان في UTF-8 (0xD8 0xA7) = %D8%A7. وهكذا.
الأحرف المحجوزة وغير المحجوزة في RFC 3986
الأحرف غير المحجوزة (Unreserved): لا تحتاج ترميزاً أبداً وهي الأحرف الأبجدية الإنجليزية A-Z a-z، الأرقام 0-9، والمحارف الأربعة - _ . ~. آمنة دائماً.
الأحرف المحجوزة (Reserved): لها معنى بنيوي في URL، لذا يجب ترميزها لو ظهرت داخل قيمة. هي: : / ? # [ ] @ ! $ & ' ( ) * + , ; =. الفاصلة / مثلاً تفصل أجزاء المسار، و ? يبدأ Query String، و # يبدأ Fragment.
أيّ حرف آخر — بما فيها المسافة والأحرف العربية وكل رموز Unicode — يجب أن يُرمَّز.
لماذا الحرف العربي الواحد ينتج 6 محارف %D8%A7؟
الأحرف العربية تقع خارج نطاق ASCII، لذا تُمثَّل في UTF-8 ببايتَين (وأحياناً ثلاثة لبعض الرموز). كل بايت يحتاج % + رقمَين ستّ عشريَّين = 3 محارف. بايتان = 6 محارف.
مثال كلمة «مرحبا» (5 أحرف): كل حرف بايتان في UTF-8، فالكلمة كاملة تساوي %D9%85%D8%B1%D8%AD%D8%A8%D8%A7 — أي 30 محرفاً مرمَّزاً. هذا التضخّم طبيعي وعالمي، وكل المتصفّحات تفعل الشيء نفسه.
تنبيه: بعض الأنظمة القديمة تستخدم Windows-1256 بدل UTF-8 للترميز، فينتج %E3%D1... بدلاً من %D9%85.... هذا غير قياسي ويسبّب مشاكل تشغيليّة — اعتمد UTF-8 دائماً.
encodeURI مقابل encodeURIComponent — أيّهما تختار؟
JavaScript تقدّم دالّتين متشابهتين الاسم لكن مختلفتين تماماً في السلوك. الفهم الصحيح يوفّر ساعات من تتبّع الأخطاء.
encodeURIComponent — للقيم الفردية
ترمّز كل شيء ما عدا الأحرف غير المحجوزة. تترك A-Z a-z 0-9 - _ . ~ وترمّز الباقي. استخدمها لقيمة معامل واحد داخل Query String، أو لجزء مسار، أو لأيّ قطعة ستُدمَج في رابط أكبر.
مثال: encodeURIComponent("صباح الخير&you=hi") = %D8%B5%D8%A8%D8%A7%D8%AD%20%D8%A7%D9%84%D8%AE%D9%8A%D8%B1%26you%3Dhi — لاحظ أنّ & و = رُمِّزا أيضاً.
encodeURI — للرابط الكامل
تترك أحرف بنية URL سليمة: : / ? # [ ] @ ! $ & ' ( ) * + , ; =. تُستخدم عندما يكون لديك رابط مكتمل تريد ترميزه دون كسر بنيته.
مثال: encodeURI("https://x.com/search?q=قهوة") = https://x.com/search?q=%D9%82%D9%87%D9%88%D8%A9.
القاعدة العمليّة
- قيمة معامل في Query String → encodeURIComponent.
- رابط مكتمل من مصدر موثوق → encodeURI.
- رابط من إدخال مستخدم تريد عرضه فقط → encodeURI لتجنّب كسر البنية.
خطأ شائع: استخدام encodeURI لقيمة Query String — هذا يترك & و = دون ترميز، فتُكسَر القيمة إذا احتوت على هذه الرموز.
تحليل Query Strings — متى ينكسر التحليل؟
Query String هو الجزء بعد ? في URL. صيغته: key=value&key2=value2. التحليل الصحيح يتطلّب:
- القطع عند
&أولاً للحصول على الأزواج. - القطع عند أوّل
=في كل زوج (وليس كل=) — لأنّ القيمة قد تحتوي=مرمَّز. - فكّ ترميز المفتاح والقيمة كلاًّ على حدة.
- التعامل مع
+كمسافة في بعض السياقات (سنشرحها بعد قليل).
أداتنا أعلاه تعرض هذا التحليل تلقائياً عندما تلصق Query String أو رابطاً كاملاً.
+ مقابل %20 — متى يُفكّ كل منهما كمسافة؟
في صياغة application/x-www-form-urlencoded (التي تستخدمها نماذج HTML)، المسافة تُرمَّز بـ + بدلاً من %20. لكن في باقي أجزاء URL تُرمَّز بـ %20.
النتيجة: عند فكّ Query String، يجب استبدال + بمسافة قبل تطبيق decodeURIComponent. أما في المسار /path/with+plus فالرمز + يعني فعلاً +.
هذه الازدواجية هي مصدر أخطاء شائعة. أداتنا تتعامل مع كلا الحالتَين تلقائياً.
الترميز المزدوج Double Encoding — أكبر فخّ
الخطأ: رمَّزتَ القيمة مرّتَين عن غير قصد. الناتج: %2520 بدل %20 — لأنّ % نفسه ترمَّز إلى %25.
متى يحدث ذلك؟ عندما تحصل على قيمة مرمَّزة من مكتبة، ثم تمرّرها لمكتبة أخرى ترمّزها مرّةً ثانية. الحلّ: تتبَّع «حالة» القيمة (مرمَّزة أم لا) في كل خطوة، ولا ترمّز إلّا عند نقطة الإدخال إلى URL.
المؤشّر السريع: لو رأيت %25 كثيراً في رابط، فعلى الأرجح هناك ترميز مزدوج.
ثغرات أمنية مرتبطة بـ URL Encoding
الترميز ليس تشفيراً ولا حماية، لكن سوء استخدامه يفتح ثغرات حقيقية:
Open Redirect
تطبيقك يقبل معامل ?next=/dashboard ثم يعيد التوجيه إليه. المهاجم يستخدم ?next=https%3A%2F%2Fevil.com. لو تحقّقت من قيمة next قبل فكّ الترميز ثم وجّهت بعد فكّه — تسرّبت الحماية. القاعدة: افكّ الترميز ثم تحقّق على قائمة بيضاء (allowlist).
SSRF عبر الترميز
خدمات تقبل URL كقيمة وتجلبه من جهتها. مهاجم يلفّ http://127.0.0.1 بترميز مزدوج فيتجاوز فلاتر سطحيّة. الحلّ: فكّ الترميز بشكل تكراري حتى الاستقرار، ثم تحقّق.
تجاوز WAF عبر التطبيع المختلف
WAF قد يفكّ ترميزاً مرّة، والتطبيق يفكّه مرّتَين، فيُمرَّر هجوم SQL Injection مرمَّز بشكل مضاعف. الحلّ: توحيد عمليّة فكّ الترميز (Canonicalization) في كل مكوّنات السلسلة.
أمثلة عملية سريعة
- المسافة →
%20 !→%21#→%23&→%26=→%3D?→%3F- «أ» →
%D8%A3 - «ة» →
%D8%A9 - «ي» →
%D9%8A - Emoji 🚀 →
%F0%9F%9A%80(4 بايتات)
أسئلة شائعة
هل URL Encoding آمن لإخفاء البيانات؟
لا — هو ترميز قابل للقراءة عكسياً بضغطة زر. لو أردتَ إخفاء البيانات استخدم تشفيراً حقيقياً.
لماذا أحياناً يظهر الحرف العربي سليماً في الشريط؟
المتصفّحات الحديثة تعرض الشكل المفكوك للمستخدم، لكنها تنقل النسخة المرمَّزة فعليّاً على الشبكة. انسخ الرابط من شريط العنوان ستجد %.
هل أرمّز اسم النطاق نفسه؟
لا — اسم النطاق يستخدم Punycode (xn--) وليس Percent Encoding. الترميز يبدأ من المسار وما بعده فقط.
ماذا عن ~ و _؟
كلاهما غير محجوز ولا يحتاج ترميزاً. بعض المكتبات القديمة كانت ترمّز ~ بـ %7E — مقبول لكنه غير ضروري.
هل المعاملات حساسة لحالة الحرف؟
الترميز نفسه (%d8 أم %D8) متساوٍ ومفكوكه واحد، لكن المعيار يفضّل الحروف الكبيرة. أمّا اسم المفتاح q مقابل Q فيعتمد على التطبيق.
لماذا لا أحتاج encodeURIComponent داخل fetch؟
إذا استخدمت URLSearchParams أو URL فهي ترمّز تلقائياً. تجنّب الترميز اليدوي مع هذه الـ APIs لتفادي الترميز المزدوج.
افتح الأداة وجرّب الآن
الأداة في أعلى الصفحة تدعم وضعَي «قيمة» و «رابط كامل»، تحلّل Query Strings تلقائياً، تتعامل مع الأحرف العربية والإيموجي بشكل سليم، وكل المعالجة محلّية في متصفّحك — لا يُرسَل شيء إلى أيّ خادم.
أدوات ذات صلة
أدوات أخرى مجانية على ArabToolBox، كلها تعمل في متصفّحك بدون تسجيل.
- Base64 ترميز وفكترميز وفك Base64 — نصوص، صور، ملفات — محلياً 100%
- مولّد Cron Expressionsابنِ تعبيرات Cron بصرياً + شرح بالعربية
- مولّد التجزئة (Hash)MD5, SHA-1, SHA-256, SHA-384, SHA-512 — للنصوص والملفات
- فك JWTافك JWT واعرض Header و Payload — بدون إرسال للخادم
- اختبار Regexاختبر Regex على نصوص عربية وإنجليزية — مع شرح
- مولّد QR Codeأنشئ QR Code فوراً — 8 أنواع بما فيها فاتورة زاتكا TLV