# توجيه الروابط ذات الأحرف الكبيرة إلى صيغتها الصغيرة
Source: https://docs.webgee.com/ar/performance/redirect-mixed-case-urls-to-lowercase







اجعل كل طلب لموقعك ينتهي إلى رابط واحد بأحرف صغيرة، فيقدّم LiteSpeed نسخة
مخزَّنة واحدة لكل صفحة بدل نسخة لكل صيغة من صيغ الأحرف.

تنطبق على أي موقع في الاستضافة المشتركة أو الموزِّعة أو المميّزة يقع خلف
Cloudflare، وعلى أي خطة من خطط Cloudflare بما فيها المجانية. وتحتاج وصولًا إلى
حساب Cloudflare الذي يستخدمه النطاق — انظر
[وضع موقعك خلف Cloudflare](/ar/domains-dns/how-do-i-enable-cloudflare-for-my-websites).

## لماذا تُجزِّئ الأحرف الكبيرة ذاكرة التخزين [#لماذا-تُجزِّئ-الأحرف-الكبيرة-ذاكرة-التخزين]

يبني LiteSpeed Cache مفتاح كل مدخل على مسار الطلب كنصٍّ حرفي، فهذان مدخلان
منفصلان:

```txt
https://example.com/Blog/My-Great-Article
https://example.com/blog/my-great-article
```

الصفحة نفسها والمحتوى نفسه ووسم canonical نفسه — ومدخلان اثنان، يُسخَّن كلٌّ
منهما على حدة.

وتصل الطلبات ذات الأحرف الكبيرة بلا انقطاع، من:

* **مسارات التصنيفات والوسوم وأنواع المحتوى المخصّصة** التي أُنشئت بحرف كبير ولم
  تُوحَّد بعدها،
* **روابط داخلية قديمة** كُتبت قبل ترتيب هذه المسارات،
* **روابط خارجية ونسخ منقولة** حفظت الصيغة كما وردت في وسم `og:url` أو في رابط
  منسوخ،
* **فهرس Google**، الذي يظلّ يطلب النصّ نفسه الذي زحف إليه. فوسم canonical يوحّد
  الفهرسة، لكنه لا يمنع وصول الطلب إلى الرابط المفهرَس.

والأخير هو الأغلى ثمنًا. فزيارات البحث التي تهبط على صيغة نادرة الطلب تخطئ
الذاكرة، فتعيد PHP وMySQL بناء الصفحة في كل زيارة، بينما تجلس النسخة ذات الأحرف
الصغيرة مخزَّنة وسريعة لا تخدم أحدًا تقريبًا. وبيانات Core Web Vitals الميدانية
(CrUX) تُجمع من زيارات حقيقية، فتصير التجربة المقيسة لتلك الصفحة هي المسار
البطيء غير المخزَّن.

ويسهل إغفال ذلك، لأن:

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

ولا يحوّل Apache ولا LiteSpeed الروابط إلى أحرف صغيرة من تلقاء نفسه، وذلك عن
قصد: فالمسارات في لينكس حسّاسة لحالة الأحرف، والملفات الحقيقية تعتمد على ذلك.

## تحقّق هل تعنيك المشكلة [#تحقّق-هل-تعنيك-المشكلة]

نزّل [سجلّ وصول خامًا](/ar/performance/raw-access-logs) واعرض الطلبات الناجحة
لمسارات تحوي حرفًا كبيرًا وليست ملفات:

```bash
awk '$9 == 200 && $7 ~ /[A-Z]/ && $7 !~ /\./ {print $7}' example.com-ssl_log | sort | uniq -c | sort -rn | head -20
```

وكل مسار له عدد يُعتدّ به هو صفحة قُدِّمت من PHP لا من الذاكرة في كل تلك
الزيارات.

وفي Google Search Console تظهر المشكلة نفسها في **Performance → Pages**: صفحة
واحدة مذكورة مرتين بصيغتي أحرف مختلفتين.

## أضف قاعدة التوجيه في Cloudflare [#أضف-قاعدة-التوجيه-في-cloudflare]

1. في Cloudflare، اختر النطاق ثم افتح **Rules → Overview**.

   <img alt="صفحة Rules Overview في Cloudflare مصفّاة على Redirect Rules، وزر Create rule في أعلى اليمين" src="__img0" />

2. اختر **Create rule** ثم **Redirect Rules**.

3. في **Rule name** اكتب اسمًا تعرفه لاحقًا، مثل `UnifiedURLs`.

4. تحت &#x2A;*If incoming requests match…** اختر **Custom filter expression**.

5. الصق هذا في صندوق التعبير. وإن ظهر لك البنّاء المرئي بدل صندوق النصّ، فاختر
   **Edit expression** في الزاوية للتحويل إلى النصّ.

   ```txt
   (http.request.uri.path contains "A" or http.request.uri.path contains "B" or http.request.uri.path contains "C" or http.request.uri.path contains "D" or http.request.uri.path contains "E" or http.request.uri.path contains "F" or http.request.uri.path contains "G" or http.request.uri.path contains "H" or http.request.uri.path contains "I" or http.request.uri.path contains "J" or http.request.uri.path contains "K" or http.request.uri.path contains "L" or http.request.uri.path contains "M" or http.request.uri.path contains "N" or http.request.uri.path contains "O" or http.request.uri.path contains "P" or http.request.uri.path contains "Q" or http.request.uri.path contains "R" or http.request.uri.path contains "S" or http.request.uri.path contains "T" or http.request.uri.path contains "U" or http.request.uri.path contains "V" or http.request.uri.path contains "W" or http.request.uri.path contains "X" or http.request.uri.path contains "Y" or http.request.uri.path contains "Z") and http.request.uri.path.extension eq ""
   ```

   والصيغة البديهية لهذا هي `http.request.uri.path matches "[A-Z]"`، غير أن
   المعامل `matches` يحتاج خطة Business أو Enterprise. وسلسلة `contains` تؤدّي
   العمل نفسه على كل الخطط.

6. تحت &#x2A;*Then…** اضبط **Type** على `Dynamic`، والصق هذا في **Expression**:

   ```txt
   concat("https://", http.host, lower(http.request.uri.path))
   ```

7. اضبط **Status code** على `301 - Permanent Redirect`، وفعّل **Preserve query
   string**.

8. تحت **Place at** اختر **First**. فالتوجيه ينبغي أن يقع قبل أن تشتغل أي قاعدة
   أخرى على رابط على وشك التغيّر.

9. اختر **Save**.

<img alt="نموذج Edit Single Redirect، وفيه تعبير التصفية المخصّص وتعبير التوجيه الديناميكي ورمز الحالة 301 وترتيب القاعدة" src="__img1" />

<Callout type="warn">
  `http.request.uri.path.extension eq ""` هو شطر التعبير الذي يُبقي الملفات
  الحقيقية خارج التوجيه، وهو مهم. فمجلد الرفع مليء بأسماء مثل `IMG_2024.jpg`
  و`Banner-Photo.png`، ونظام الملفات حسّاس لحالة الأحرف — وتصغير تلك المسارات
  يحوّل صورًا عاملة إلى صفحات 404. فأبقِه. ويُستثنى موقع تنتهي روابطه بـ
  `.html`: فتلك الصفحات تُستبعد مع الملفات.
</Callout>

### لماذا 301 لا 302 [#لماذا-301-لا-302]

التوجيه الدائم يخبر محرّكات البحث أن تجمع إشارات الترتيب على الرابط ذي الأحرف
الصغيرة بدل فهرسة الاثنين. كما تحفظ المتصفحات والطبقات الوسيطة استجابة 301، فتُوجَّه
الزيارة التالية للرابط ذي الأحرف الكبيرة دون رحلة جديدة إلى Cloudflare.

## تأكّد أنه نجح [#تأكّد-أنه-نجح]

ينبغي أن يردّ الرابط ذو الأحرف الكبيرة الآن بتوجيه:

```bash
curl -sI https://example.com/Blog/My-Great-Article | head -n 3
```

ابحث عن `HTTP/2 301` وعن `location: https://example.com/blog/my-great-article`.

ثم اطلب الرابط ذا الأحرف الصغيرة مرتين وتحقّق أنه مخزَّن:

```bash
curl -sI https://example.com/blog/my-great-article | grep -i litespeed
```

وينبغي أن يعيد الطلب الثاني `x-litespeed-cache: hit` — انظر
[التأكد من عمل LiteSpeed Cache](/ar/hosting/wordpress/how-do-i-check-if-litespeed-cache-is-working-on-my-site).

ثم تأكّد أن ملفًا في اسمه أحرف كبيرة ما زال يُفتح. وينبغي أن يعيد هذا `200`:

```bash
curl -so /dev/null -w '%{http_code}\n' https://example.com/wp-content/uploads/2026/01/IMG_2024.jpg
```

## إن لم ينجح [#إن-لم-ينجح]

* **الرابط ذو الأحرف الكبيرة ما زال يعيد 200.** فالمضيف لا يمرّ عبر Cloudflare —
  إذ يحتاج سجلّ DNS إلى السحابة البرتقالية، وإلا لم تر القواعد هذه الزيارات.
  وتأكّد كذلك أن القاعدة تظهر **Active**.
* **صارت الصور 404.** فاختبار الامتداد ناقص، أو سقطت الأقواس حول سلسلة `or` عند
  اللصق. فـ `and` أقوى ارتباطًا من `or`، ومن دون الأقواس ينطبق الاستثناء على
  `contains "Z"` الأخيرة وحدها. صحّح التعبير ثم امسح ذاكرة Cloudflare: فالتوجيه
  الخاطئ قد خُزِّن.
* **الموقع في حلقة توجيه.** فثمّة ما يعيد الرابط ذا الأحرف الصغيرة إلى آخر بحرف
  كبير — إضافة، أو قاعدة في `.htaccess`، أو **Site Address** محفوظ في ووردبريس
  بحرف كبير. عالجه هناك لا بإزالة هذه القاعدة.
* **رابط ما زال يتصرّف بالطريقة القديمة بعد تعديل القاعدة.** فالمتصفحات تحفظ 301
  بشدّة. اختبر بـ `curl` أو في نافذة خاصة، لا في التبويب الذي كنت تستعمله.

## لماذا لا يصلح هذا في .htaccess [#لماذا-لا-يصلح-هذا-في-htaccess]

المقطع المتداوَل لهذه المشكلة يستعمل خريطة إعادة كتابة:

```apache
RewriteMap lc int:tolower
```

و`RewriteMap` لا يصحّ إلا في سياق إعدادات الخادم أو المضيف الافتراضي، في Apache
وLiteSpeed على السواء. وفي ملف `.htaccess` يعيد Apache خطأ 500، وفي الاستضافة
المشتركة لا وصول لك إلى المستوى الذي يُسمح فيه بالتوجيه. ولا بديل يعمل من
`.htaccess` وحده — فـ mod\_rewrite لا يستطيع تغيير حالة أحرف نصٍّ بغير خريطة.

وإن لم يكن الموقع خلف Cloudflare، فافعلها في PHP. أنشئ `wp-content/mu-plugins/`
إن لم يكن موجودًا، واحفظ هذا في
`wp-content/mu-plugins/lowercase-urls.php`. فالإضافات الواجبة تُحمَّل تلقائيًا
ولا تحتاج تفعيلًا:

```php
<?php
/**
 * Plugin Name: Lowercase URL redirect
 */
add_action( 'init', function () {
	if ( is_admin() || wp_doing_ajax() || 'GET' !== ( $_SERVER['REQUEST_METHOD'] ?? '' ) ) {
		return;
	}

	$parts = explode( '?', $_SERVER['REQUEST_URI'] ?? '', 2 );
	$path  = $parts[0];

	if ( $path === strtolower( $path ) || strpos( $path, '/wp-json/' ) === 0 ) {
		return;
	}

	wp_safe_redirect( strtolower( $path ) . ( isset( $parts[1] ) ? '?' . $parts[1] : '' ), 301 );
	exit;
} );
```

وهذا لا يعمل إلا مع الطلبات التي يتولّاها ووردبريس، فلا يمسّ الملفات في
`wp-content/uploads`. وهو بديل احتياطي لا عوض: إذ يظلّ الطلب يصل إلى PHP، وهو
العمل الذي تتجنّبه قاعدة Cloudflare من أصله.

## مواضيع ذات صلة [#مواضيع-ذات-صلة]

* [التأكد من عمل LiteSpeed Cache](/ar/hosting/wordpress/how-do-i-check-if-litespeed-cache-is-working-on-my-site)
* [وضع موقعك خلف Cloudflare](/ar/domains-dns/how-do-i-enable-cloudflare-for-my-websites)
* [تنزيل سجلات الوصول الخام](/ar/performance/raw-access-logs)
* [QUIC.cloud أم Cloudflare](/ar/hosting/wordpress/litespeed-comparing-quic-cloud-and-cloudflare)
