Menu
flag Ar iconالعربيةdown icon

الدالة htmlspecialchars() في PHP: تهريب HTML ومنع XSS

تحوّل htmlspecialchars($text) المحارف الخمسة التي لها معنى في HTML (& < > " ') إلى كيانات، فتُعرض مُدخلات المستخدم نصًا بدل أن تعمل وسومًا. تعلّم ENT_QUOTES، وتهريب الخصائص، والترميز المزدوج، وhtmlentities وstrip_tags.

تحتوي هذه الصفحة على محررات قابلة للتشغيل - حرّر، شغّل، وشاهد النتيجة فوراً.

تحوّل htmlspecialchars($text) المحارف & و< و> و" و' إلى &amp; و&lt; و&gt; و&quot; و&#039;. استدعها على كل جزء من مُدخلات المستخدم تطبعه في صفحة، فتُعرض المُدخلات نصًا بدل أن تُقرأ HTML.

تطبع الكتلة التعليق نفسه مرتين، مرة خامًا ومرة مهرّبًا. شغّلها وقارن السطرين في تبويب Page، ثم اكتب HTML خاصًا بك في النموذج، مثل <h1>big</h1> أو <img src=x>، واضغط Show.

في السطر الخام يطيع المتصفح الوسوم: الكلمة العريضة عريضة، والزائر الذي يكتب <script> يجعل سكربته يعمل في متصفح كل قارئ آخر. ويسمى هذا الهجوم البرمجة عبر المواقع (XSS). وفي السطر المهرّب تصل المحارف نفسها على شكل &lt;b&gt; فيرسمها المتصفح نصًا. انتقل إلى تبويب Output لترى الكيانات التي طبعتها PHP فعلًا.

ما الذي تحوّله htmlspecialchars

خمسة محارف، لا شيء غيرها. وتمر الحروف والعلامات والرموز التعبيرية دون تغيير.

& في القائمة لأنها تبدأ كل كيان: لو تُركت كما هي، لعُرض تعليق يذكر &lt; على شكل <.

هرّب الخصائص، لا النص وحده

مُدخلات المستخدم داخل خاصية تحتاج إلى التهريب بالقدر نفسه. ودونه، تغلق علامة تنصيص في القيمة الخاصية ويصبح بقية المُدخل خصائص جديدة. هنا يتسلل «الاسم» بخاصية style؛ شغّله وانظر إلى المربعين.

في المربع غير الآمن يرى المتصفح value="Ada" متبوعة بخاصية style جديدة، فيصبح المربع أحمر ولا يعرض إلا Ada. وسيكتب المهاجم onfocus="..." هناك بدل style، فتعمل شيفرته. وفي المربع الآمن صار كل " على شكل &quot;، فيبقى النص كله داخل value ويُعرض كما كُتب.

منذ PHP 8.1 صارت الأعلام الافتراضية ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401، فتُهرَّب علامات التنصيص المفردة أيضًا وتكون الخصائص المكتوبة بـ '...' آمنة. وكثيرًا ما تمرر الشيفرات الأقدم ENT_QUOTES يدويًا، وكان ذلك لازمًا في PHP 7 وما قبلها:

دالة مساعدة قصيرة للقوالب

كتابة htmlspecialchars($x, ENT_QUOTES, 'UTF-8') عشرات المرات في قالب مزعجة، لذا تغلّفها معظم المشاريع في دالة من حرف واحد. وتفعل محركات القوالب مثل Twig وBlade الشيء نفسه تلقائيًا لكل {{ $var }}.

للنوع ?string ولـ ?? '' أهمية: تمرير null إلى htmlspecialchars() مهمل منذ PHP 8.1، وستطبع PHP لديك إشعار إهمال لكل مستخدم ليست لديه نبذة.

الترميز المزدوج وhtmlspecialchars_decode

إذا هُرّبت قيمة مرتين، يرى القارئ الكيانات: تصبح & في المرة الأولى &amp; وفي الثانية &amp;amp;، فيعرضها المتصفح على شكل &amp;. وغالبًا ما يعني ذلك أن القيمة هُرّبت عند حفظها ومرة أخرى عند طباعتها. مرّر double_encode: false لترك الكيانات الموجودة كما هي، واستخدم htmlspecialchars_decode() للعودة.

الحل الحقيقي أن تخزّن النص الخام ولا تهرّب إلا عند الإخراج. وdouble_encode: false للنص الذي يحتوي أصلًا كيانات لم تنشئها أنت، مثل خلاصة مستوردة.

htmlspecialchars مقابل htmlentities مقابل strip_tags

كثيرًا ما يُخلط بين هذه الثلاث. تشغّلها الكتلة كلها على المُدخل نفسه وتعرض، لكل منها، ما تطبعه PHP وما يفعله المتصفح به:

  • تهرّب htmlspecialchars() محارف HTML الخمسة. استخدمها لأي نص تطبعه في HTML.
  • تحوّل htmlentities() أيضًا é إلى &eacute;. كانت مفيدة حين لم تكن الصفحات UTF-8؛ واليوم لا تفعل إلا جعل المصدر أصعب قراءة.
  • تحذف strip_tags() الوسوم وتُبقي نصها. وهي لتحويل HTML إلى نص عادي (معاينة بريد، أو وصف meta)، لا للأمان: يبيّن الصف الأخير أن <b> المسموح يُبقي onclick الخاص به، والنص الموضوع داخل خاصية لا يُمس أصلًا.

حيث لا تكفي htmlspecialchars

htmlspecialchars() هي التهريب الصحيح لنص HTML وللخصائص بين علامات تنصيص. ولأماكن أخرى في الصفحة قواعد أخرى:

  • في الرابط، ترمّز http_build_query() أو urlencode() القيمة؛ ثم تجعل htmlspecialchars() علامة & بين المعاملات HTML صالحًا.
  • في JavaScript، تنتج json_encode() قيمة JS صالحة، ويحوّل JSON_HEX_TAG المحرفين < و> إلى \u003C و\u003E، فلا يستطيع </script> في البيانات إغلاق وسم السكربت.
  • لا تطبع أبدًا مُدخلات المستخدم في href دون فحص البروتوكول: تبقى htmlspecialchars('javascript:alert(1)') دون تغيير وتعمل عند النقر. لا تقبل إلا روابط http وhttps، كما تبيّن صفحة filter_var.

لمعالجة النماذج التي تجمع كل هذا معًا، راجع النماذج في PHP.

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

ماذا تفعل htmlspecialchars في PHP؟

تستبدل & و< و> و" و' بـ &amp; و&lt; و&gt; و&quot; و&#039;. عندها يعرض المتصفح تلك المحارف بدل قراءتها HTML، فيُعرض <script> المكتوب في نموذج نصًا ولا يعمل أبدًا.

ما الفرق بين htmlspecialchars وhtmlentities؟

لا تحوّل htmlspecialchars() إلا المحارف الخمسة الخاصة في HTML. وتحوّل htmlentities() أيضًا كل محرف له كيان مسمى، فتصبح café النص caf&eacute;. ومع صفحات UTF-8 تتساوى الاثنتان في الأمان، وتُبقي htmlspecialchars() المخرجات مقروءة، لذا فهي الخيار المعتاد.

هل ما زلت أحتاج إلى ENT_QUOTES في PHP 8؟

ليس من أجل الأمان: منذ PHP 8.1 صارت الأعلام الافتراضية ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401، فتُهرَّب علامات التنصيص المفردة أيضًا. وما زالت شيفرات كثيرة تمرر ENT_QUOTES, 'UTF-8' صراحة ليتصرف الاستدعاء بالطريقة نفسها في الإصدارات الأقدم وليكون واضحًا للقراء.

هل أستخدم htmlspecialchars عند الإدخال أم عند الإخراج؟

عند الإخراج. خزّن القيمة الخام وتحقق منها، وهرّبها لحظة طباعتها في HTML. أما التهريب عند الإدخال فيخزّن &lt; في قاعدة بياناتك، ويفسد الأطوال والبحث، ويؤدي إلى تهريب مزدوج مثل &amp;lt;.

هل تكفي strip_tags لمنع XSS؟

لا. تحذف strip_tags() الوسوم لكن معامل الوسوم المسموحة فيها يُبقي خصائصها، فيبقى <b onclick="...">، ولا تفعل شيئًا للنص الموضوع داخل خاصية. استخدم htmlspecialchars() عند طباعة مُدخلات المستخدم.

رسم توضيحي للغات البرمجة في Coddy

تعلّم البرمجة مع Coddy

ابدأ الآن