المعلمات الرئيسية تمرير الوسائط إلى البرنامج

15.04.2019

أثناء الإنشاء استمارة القنصليةفي لغة البرمجة C++، يتم إنشاء سطر مشابه جدًا لهذا تلقائيًا:

Int main(int argc, char* argv) // معلمات الدالة main()

هذا الخط هو الرأس الوظيفة الأساسية main() ، يتم الإعلان عن المعلمات argс و argv بين قوسين. لذلك، إذا قمت بتشغيل برنامج عبر سطر الأوامر، فمن الممكن نقل بعض المعلومات إلى هذا البرنامج، ولهذا هناك معلمات argc و argv. المعلمة argc من النوع كثافة البياناتويحتوي على عدد المعلمات التي تم تمريرها إلى الوظيفة الرئيسية. علاوة على ذلك، يكون argc دائمًا على الأقل 1، حتى عندما لا نمرر أي معلومات، نظرًا لأن المعلمة الأولى هي اسم الوظيفة. المعلمة argv عبارة عن مجموعة من المؤشرات إلى السلاسل. يمكن نقل البيانات فقط عبر سطر الأوامر نوع السلسلة. المؤشرات والسلاسل نوعان مواضيع كبيرة، والتي تم إنشاء أقسام منفصلة لها. لذلك يتم إرسال أي معلومات من خلال المعلمة argv. دعونا نطور برنامجًا سنطلقه عبر سطر الأوامر سلسلة ويندوز، وإعطائها بعض المعلومات.

// argc_argv.cpp: يحدد نقطة الدخول لتطبيق وحدة التحكم. #تتضمن "stdafx.h" #تتضمن استخدام اسم للمحطة؛ int main(int argc, char* argv) (إذا (argc ><< argv<

// الكود Code::Blocks

// كود Dev-C++

// argc_argv.cpp: يحدد نقطة الدخول لتطبيق وحدة التحكم. #يشمل استخدام اسم للمحطة؛ int main(int argc, char* argv) ( if (argc > 1) // إذا مررنا الوسائط، فسيكون argc أكبر من 1 (حسب عدد الوسائط) ( cout<< argv<

بعد أن قمنا بتصحيح أخطاء البرنامج، افتح سطر أوامر Windows واسحبه إلى النافذة سطر الأوامرسيتم عرض الملف القابل للتنفيذ لبرنامجنا في سطر الأوامر مسار كاملإلى البرنامج (ولكن يمكنك تسجيل المسار إلى البرنامج يدويًا)، بعد ذلك يمكنك الضغط على يدخلوسيبدأ البرنامج (انظر الشكل 1).

الشكل 1 - معلمات الوظيفة الرئيسية

وبما أننا قمنا ببساطة بتشغيل البرنامج ولم نمرر أي وسيطات إليه، فقد ظهرت رسالة "ليست وسيطات". ويبين الشكل 2 إطلاق نفس البرنامج عبر سطر الأوامر، مع تمرير الوسيطة Open إليه.

الشكل 2 - معلمات الوظيفة الرئيسية

الحجة هي كلمة فتح، كما يتبين من الشكل، ظهرت هذه الكلمة على الشاشة. يمكنك تمرير عدة معلمات مرة واحدة، مع فصلها بفاصلة. إذا كنت بحاجة إلى تمرير معلمة تتكون من عدة كلمات، فيجب وضعها بين علامتي اقتباس، ثم سيتم اعتبار هذه الكلمات كمعلمة واحدة. على سبيل المثال، يوضح الشكل إطلاق برنامج، وتمرير وسيطة إليه تتكون من كلمتين - إنه يعمل.

الشكل 3 - معلمات الوظيفة الرئيسية

وإذا قمت بإزالة علامات الاقتباس. عندها سنرى فقط الكلمة It. إذا كنت لا تخطط لتمرير أي معلومات عند تشغيل البرنامج، فيمكنك إزالة الوسائط في الدالة main()، ويمكنك أيضًا تغيير أسماء هذه الوسائط. في بعض الأحيان، تتم مواجهة تعديلات على معلمات argc وargv، ولكن كل هذا يعتمد على نوع التطبيق الذي يتم إنشاؤه أو على بيئة التطوير.

بغض النظر عن مقدار استخدامنا لـ PHP، لا تزال بعض الوظائف تظهر والتي لم نسمع عنها من قبل. وبعض منهم سيكون مفيدا جدا بالنسبة لنا. لقد قمت بإنشاء قائمة صغيرة من الوظائف المفيدة التي يجب أن تكون في ترسانة كل مبرمج PHP.

1. إنشاء وظائف بعدد متغير من الوسائط

على الأرجح، أنت تعلم بالفعل أن PHP تسمح لنا بإنشاء وظائف ذات وسائط اختيارية. سأعرض الآن وظيفة يمكن أن يختلف فيها عدد الوسائط من حالة إلى أخرى.

لكن أولاً، دعونا نتذكر كيف نقوم بإنشاء الوظائف بالطريقة المعتادة:

// دالة بمعلمتين اختياريتين function foo($arg1 = "", $arg2 = "") ( echo "arg1: $arg1\n"; echo "arg2: $arg2\n"; ) foo("hello", "عالم")؛ /* سيُخرج: arg1: hello arg2:world */ foo(); /* سيتم إخراج: arg1: arg2: */

الآن دعونا نلقي نظرة على كيفية كتابة دالة بعدد غير محدود من الوسائط. للقيام بذلك، سيتم استخدام طريقة func_get_args():

// لا تحدد الوسائط function foo() ( // تُرجع مصفوفة من الوسائط التي تم تمريرها $args = func_get_args(); foreach ($args as $k => $v) ( echo "arg".($k+1) ." : $v\n" ) ) foo(); /* لن يُخرج أي شيء */ foo("hello"); /* ستتم طباعة arg1: hello */ foo("hello", "world", "again"); /* ستتم طباعة arg1: مرحبًا arg2: العالم arg3: مرة أخرى */

2. استخدم Glob() للبحث عن الملفات

في كثير من الأحيان أسماء الوظائف تتحدث عن نفسها. لا يمكن قول الشيء نفسه عن الدالة glob().

دون الخوض في الكثير من التفاصيل، وظائفها تشبه طريقة scandir(). يسمح لك بالعثور على الملف المطلوب باستخدام القالب:

// البحث عن كافة ملفات PHP $files = glob("*.php"); print_r($files); /* سيتم إخراج: Array ( => phptest.php => pi.php => post_output.php => test.php) */

للعثور على ملفات من عدة أنواع، عليك أن تكتب مثل هذا:

// العثور على كافة ملفات php وtxt $files = glob("*.(php,txt)", GLOB_BRACE); print_r($files); /* الإخراج: صفيف ( => phptest.php => pi.php => post_output.php => test.php => log.txt => test.txt) */

يمكنك أيضًا تحديد المسار في القالب:

$files = glob("../images/a*.jpg"); print_r($files); /* الإخراج: مصفوفة ( => ../images/apple.jpg => ../images/art.jpg) */

للحصول على المسار الكامل للمستند، استخدم طريقة realpath() :

$files = glob("../images/a*.jpg"); // قم بتطبيق وظيفة "realpath" على كل عنصر من عناصر المصفوفة $files = array_map("realpath",$files); print_r($files); /* سيتم إخراج: Array ( => C:\wamp\www\images\apple.jpg => C:\wamp\www\images\art.jpg) */

3. معلومات عن الذاكرة المستخدمة

إذا قمت بتتبع مقدار الذاكرة التي تستهلكها البرامج النصية الخاصة بك، فمن المحتمل أن تقوم بتحسينها في كثير من الأحيان.

في PHP هناك أداة قويةتتبع استخدام الذاكرة. قد تكون الأحمال مختلفة في أجزاء مختلفة من البرنامج النصي. للحصول على قيمة الذاكرة المستخدمة هذه اللحظةيجب أن نستخدم طريقة Memory_get_usage(). للتثبيت الحد الأقصى للكميةالذاكرة المستخدمة استخدم Memory_get_peak_usage()

صدى "الأولي: ".memory_get_usage()." بايت \n"; /* الأولي: 361400 بايت */ // إعطاء حمل صغير لـ ($i = 0; $i< 100000; $i++) { $array = md5($i); } // и ещё for ($i = 0; $i < 100000; $i++) { unset($array[$i]); } echo "Final: ".memory_get_usage()." bytes \n"; /* Final: 885912 bytes */ echo "Peak: ".memory_get_peak_usage()." bytes \n"; /* Peak: 13687072 bytes */

4. معلومات المعالج

للقيام بذلك تحتاج إلى استخدام طريقة getrusage (). لكن ضع في اعتبارك أن هذه الميزة لن تعمل على نظام التشغيل Windows.

Print_r(getrusage()); /* طباعة المصفوفة ( => 0 => 0 => 2 => 3 => 12692 => 764 => 3864 => 94 => 0 => 1 => 67 => 4 => 0 => 0 => 0 => 6269 => 0) */

الصورة الموضحة أعلاه ستكون واضحة لمن لديه خبرة في إدارة النظام. ولجميع الآخرين، نقدم نسخة:

  • ru_oublock: عدد عمليات كتابة الكتلة
  • ru_inblock: عدد عمليات قراءة الكتلة
  • ru_msgsnd: عدد الرسائل المرسلة
  • ru_msgrcv: عدد الرسائل المستلمة
  • ru_maxrss: أكبر مقاسمجموعة غير مقسمة إلى صفحات
  • ru_ixrss: إجمالي حجم الذاكرة المشتركة
  • ru_idrss: الحجم الإجمالي للبيانات غير المشتركة
  • ru_minflt: عدد صفحات الذاكرة المستخدمة
  • ru_majflt: عدد الأخطاء المفقودة في الصفحة
  • ru_nsignals: عدد الإشارات المستقبلة
  • ru_nvcsw: عدد مفاتيح السياق حسب العملية
  • ru_nivcsw: عدد مفاتيح السياق القسرية
  • ru_nswap: عدد مرات الوصول إلى القرص عند الترحيل
  • ru_utime.tv_usec: وقت التشغيل في وضع المستخدم (ميكروثانية)
  • ru_utime.tv_sec: وقت التشغيل في وضع المستخدم (بالثواني)
  • ru_stime.tv_usec: وقت التشغيل في الوضع المميز (ميكروثانية)
  • ru_stime.tv_sec: وقت التشغيل في الوضع المميز (بالثواني)

لمعرفة موارد المعالج التي يستخدمها البرنامج النصي، تحتاج إلى قيمة "وقت المستخدم" (وقت المستخدم) و"وقت النظام" (وقت الوضع المميز). يمكنك الحصول على النتيجة في كل من الثواني والميكروثانية. من أجل أن تتحول المجموعثواني في عدد عشري، تحتاج إلى قسمة قيمة الميكروثانية على مليون وإضافتها إلى قيمة الثواني.

إنه نوع من الارتباك. هنا مثال:

// راحة لمدة 3 ثواني من النوم(3); $data = getrusage(); صدى "وقت المستخدم:". ($data["ru_utime.tv_sec"] + $data["ru_utime.tv_usec"] / 1000000)؛ صدى "وقت النظام:". ($data["ru_stime.tv_sec"] + $data["ru_stime.tv_usec"] / 1000000)؛ /* يطبع وقت المستخدم: 0.011552 وقت النظام: 0 */

على الرغم من أن تنفيذ البرنامج النصي استغرق حوالي 3 ثوانٍ، إلا أنه لم يتم تحميل المعالج بشكل كبير. الحقيقة هي أنه عند استدعاء (النوم)، لا يستهلك البرنامج النصي أي موارد للمعالج تقريبًا. بشكل عام، هناك العديد من المهام التي تستغرق وقتا كبيرا، ولكن لا تستخدم المعالج. على سبيل المثال، انتظار العمليات المتعلقة بالقرص. لذلك لا تستخدم دائمًا وقت وحدة المعالجة المركزية في البرامج النصية الخاصة بك.

وهنا مثال آخر:

// المشي 10 ملايين مرة for($i=0;$i<10000000;$i++) { } $data = getrusage(); echo "User time: ". ($data["ru_utime.tv_sec"] + $data["ru_utime.tv_usec"] / 1000000); echo "System time: ". ($data["ru_stime.tv_sec"] + $data["ru_stime.tv_usec"] / 1000000); /* выводит User time: 1.424592 System time: 0.004204 */

استغرق البرنامج النصي 1.4 ثانية من وقت وحدة المعالجة المركزية. في هذه الحالة، تكون أوقات استدعاء النظام منخفضة بشكل عام.

وقت الوضع المميز (وقت النظام) هو الوقت الذي يقضيه المعالج في تنفيذ طلبات النظام إلى النواة نيابة عن البرنامج. مثال:

$start = ميكروتايم(صحيح); // استدعاء microtime كل 3 ثواني while(microtime(true) - $start< 3) { } $data = getrusage(); echo "User time: ". ($data["ru_utime.tv_sec"] + $data["ru_utime.tv_usec"] / 1000000); echo "System time: ". ($data["ru_stime.tv_sec"] + $data["ru_stime.tv_usec"] / 1000000); /* выводит User time: 1.088171 System time: 1.675315 */

الآن تم إنفاق وقت النظام أكثر بكثير مما كان عليه في المثال السابق. كل ذلك بفضل طريقة microtime()، التي تستخدم موارد النظام.

ومع ذلك، تجدر الإشارة إلى أن الوقت المعروض قد لا يكون دقيقًا. في وقت معين، يتم أيضًا استخدام موارد المعالج بواسطة برامج أخرى، مما قد يؤدي إلى حدوث خطأ بسيط.

5. الثوابت السحرية

هناك العديد من الثوابت السحرية في PHP، مثل رقم السطر الحالي (__LINE__)، مسار الملف (__FILE__)، مسار الدليل (__DIR__)، اسم الوظيفة (__FUNCTION__)، اسم الفئة (__CLASS__)، اسم الطريقة (__METHOD__) ومساحات الأسماء ( __مساحة الاسم__).

لن نعتبرهم جميعا. دعونا نلقي نظرة على زوجين فقط:

// يعتمد هذا البرنامج النصي على موقع الملف الحالي و// قد يسبب مشاكل إذا تم استخدامه من أدلة مختلفة require_once("config/database.php"); // هذا البرنامج النصي لن يسبب مشاكل require_once(dirname(__FILE__) . "/config/database.php");

استخدم __LINE__ عند تصحيح البرامج النصية:

// الكود // ... my_debug("بعض رسائل التصحيح"، __LINE__)؛ /* سيعرض السطر 4: بعض رسائل تصحيح الأخطاء */ // المزيد من التعليمات البرمجية // ... my_debug("another debug message"، __LINE__); /* سيطبع السطر 11: رسالة تصحيح أخرى */ function my_debug($msg, $line) ( echo "Line $line: $msg\n"; )

6. إنشاء معرفات فريدة

هناك أوقات تحتاج فيها إلى إنشاء سلسلة فريدة. لقد رأيت عدة مرات أن الدالة md5() تُستخدم لحل هذه المشكلة:

// إنشاء سلسلة عشوائية echo md5(time() . mt_rand(1.1000000));

ولكن في الواقع، لدى PHP وظيفة خاصة ()uniqid لهذه الأغراض

// إنشاء سلسلة عشوائية echo uniqid(); /* ستتم طباعة 4bd67c947233e */ // مرة أخرى echo uniqid(); /* سيتم طباعة 4bd67c9472340 */

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

من أجل تقليل فرص الحصول على نسخة مكررة، يمكننا إضافة بادئة أو استخدام معلمة ثانية (يزيد عدد الأحرف):

// مسبوقة بـ echo uniqid("foo_"); /* ستطبع foo_4bd67d6cd8b8f */ // مع المعلمة الثانية echo uniqid("",true); /* ستتم طباعة 4bd67d6cd8b926.12135106 */ // كلاهما echo uniqid("bar_",true); /* سيتم إخراج bar_4bd67da367b650.43684647 */

تولد هذه الطريقة سلاسل أصغر من md5، وبالتالي توفر المساحة.

7. التسلسل

هل اضطررت يومًا إلى تخزين بيانات معقدة في قاعدة بيانات أو ملف؟ من أجل تحويل كائن إلى سلسلة، توفر PHP وظيفة خاصة.

بشكل عام، هناك طريقتان من هذه الطرق: serialize() وunserialize()

// مصفوفة معقدة $myvar = array("hello", 42, array(1,two"), "apple"); // تحويل إلى سلسلة $string = serialize($myvar); صدى سلسلة $؛ /* سيطبع a:4:(i:0;s:5:"hello";i:1;i:42;i:2;a:2:(i:0;i:1;i:1; s :3:"two";)i:3;s:5:"apple";) */ // احصل على القيمة الأصلية $newvar = unserialize($string); print_r($newvar); /* سيتم إخراج المصفوفة ( => hello => 42 => Array ( => 1 => two) => apple) */

هذه هي الطريقة التي تعمل بها هذه الوظائف. ومع ذلك، نظرًا للنمو السريع في شعبية JSON، تمت إضافة طريقتين json_encode() وjson_decode() إلى PHP 5.2. عملهم مشابه لـ serialize ():

// مصفوفة معقدة $myvar = array("hello", 42, array(1,two"), "apple"); // تحويل إلى سلسلة $string = json_encode($myvar); صدى سلسلة $؛ /* ستطبع ["hello",42,,"apple"] */ // استعادة القيمة الأصلية $newvar = json_decode($string); print_r($newvar); /* طباعة المصفوفة ( => hello => 42 => Array ( => 1 => two) => apple) */

يعد هذا الخيار أكثر إحكاما ومتوافقًا مع اللغات الأخرى مثل JavaScript. ومع ذلك، عند العمل مع كائنات معقدة للغاية، قد يحدث فقدان البيانات.

8. ضغط السلسلة

عندما نتحدث عن الضغط، تتبادر إلى ذهننا على الفور ملفات الأرشيف بتنسيق ZIP. يوفر PHP وظيفة الضغط طوابير طويلةبدون أي ملفات.

يوضح المثال التالي كيفية عمل الدالتين gzcompress() وgzuncompress():

$string = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ut elit id mi ultricies adipiscing. Nulla facilisi. Praesent pulvinar, sapien vel feugiat ve الدهليز, nulla two pretium orci, non ultricies elit lacus quis ante. أبجد ipsum ألم الجلوس amet , consectetur adipiscing elit. $compressed = gzcompress($string); صدى "الحجم الأصلي:". strlen($string)."\n"; /* سيخرج الحجم الأصلي: 800 */ echo "الحجم المضغوط: ". strlen($compressed)."\n"; /* سيخرج الحجم المضغوط: 418 */ // return $original = gzuncompress($compressed);

يمكننا تقليل حجم النص بنسبة 50%. لنفس الأغراض، يمكنك استخدام طريقتي gzencode() وgzdecode()، اللتين تستخدمان خوارزمية ضغط مختلفة.

9. قم بالتنفيذ قبل الخروج

لدى PHP وظيفة Register_shutdown_function() التي ستسمح لك بتنفيذ بعض التعليمات البرمجية قبل إيقاف تشغيل البرنامج النصي.

لنفترض أنك تريد معرفة بعض المعلومات... وقت تشغيل البرنامج النصي:

// احصل على وقت البدء $start_time = microtime(true); // بعض العمليات // ... // عرض وقت التشغيل echo "استغرق التنفيذ: ". (ميكروتايم (صحيح) - $start_time). "ثواني.";

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

عند استخدام طريقة Register_shutdown_function()، سيتم تنفيذ التعليمات البرمجية في أي حال:

$start_time = ميكروتايم(صحيح); Register_shutdown_function("my_shutdown"); الدالة my_shutdown() ( global $start_time; echo "استغرق التنفيذ: ". (microtime(true) - $start_time). " ثواني."; )

خاتمة

PHP كوكب كامل لا يتوقف أبدًا عن إبهارنا بمحتواه. ما رأيك في هذه الوظائف؟

هتكس اختياري ملف الضبط Apache، والذي يسمح لك بتكوين خادم الويب لكل دليل على حدة دون التأثير على الخوادم العالمية إعدادات أباتشي. تشبيه محلي httpd.conf. عادةً ما يكون مسؤولاً عن عمليات إعادة التوجيه والتحكم في الوصول إلى الدليل.

الاسم يبدأ بنقطة. يمكننا القول أن هذا ملف بدون عنوان بامتداد htaccess.

تؤثر إعدادات .htaccess على الدليل الذي يوجد به وجميع الدلائل الفرعية. قم بإنشاء ملف ووضعه في الدليل الذي تحتاجه. على سبيل المثال، إلى جذر المشروع.

الآن أنت بحاجة لملء ذلك. دعونا نرى ما يمكن أن يفعله .htaccess، ولكن أولاً، دعونا ندرس مثالاً لعملية إعادة توجيه بسيطة.

mod_rewrite وعمليات إعادة التوجيه

تأكد من ذلك في التكوين ملف أباتشيhttpd.confمفعل mod_rewrite. أي أن السطر المقابل غير معلق:

LoadModule rewrite_module Modules/mod_rewrite.so

أو إذا كنت لا تريد فتحه محرر النصالملف، يمكنك استخدام الأمر في المحطة:

إعادة كتابة سودو a2enmod

mod_rewrite هي وحدة Apache مصممة لإعادة كتابة عناوين URL. دعونا نلقي نظرة على مثال لكيفية عمله. لنفترض أن المستخدم أدخل العنوان التالي:

باستخدام mod_rewrite يمكنك إرسال المحتوى من عنوان URL مختلف، مثل هذا:

http://www.example.com/public/src/view/page.html

لماذا نحتاج هذا؟ من السهل تخمين أن كتابة المسار الكامل للصفحة أمر طويل وغير مريح. لا يحتاج زوار الموقع إلى التفكير في البنية الداخلية للموقع - فالمهم بالنسبة لهم هو الوصول إلى الصفحة التي يبحثون عنها في أسرع وقت ممكن.

في شريط العنوانسيظل المستخدم يرى ما أدخله:

http://www.example.com/page.html

هذا مثال على أبسط عملية إعادة توجيه.

مباشرة إلى الممارسة

دعونا نحلل ملف التكوين المستخدم في أحد مشاريعنا. بهذه الطريقة سوف نفهم السطر الذي يجب تعديله في حالة ظهور مشكلات.

Php_value short_open_tag 1 php_value upload_max_filesize 10M php_value post_max_size 10M RewriteEngine On RewriteBase / RewriteRule ^(application|modules|system) - RewriteCond %(REQUEST_FILENAME) !-f RewriteCond %(REQUEST_FILENAME) !-d RewriteRule .* Index.php/$0

بناء جملة التوجيه العام

Php_value/php_flag directive_name علم/قيمة php

التوجيه short_open_tagيسمح باستخدام بناء جملة قصير لتنسيق كود PHP:

Php_value short_open_tag 1

upload_max_filesizeيحدد الحد الأقصى لحجم الملف الذي تم تحميله.

Php_value upload_max_filesize 10M

أ post_max_sizeيحدد الحد الأقصى الحجم المسموح بهالبيانات المرسلة طريقة ما بعد.

Php_value post_max_size 10M

RewriteEngine

يقوم بتشغيل/إيقاف الآلية mod_rewrite.

إعادة كتابة المحرك قيد التشغيل

RewriteRule

يقوم RewriteRule ببساطة بتحويل السلسلة وفقًا للتعبيرات العادية.

بناء الجملة:إعادة كتابة القاعدة Regular_expression

# قاعدة إعادة كتابة الإدخال "index.php" قاعدة إعادة كتابة ^index.php main.php [R] # الإخراج: "index.php" -> "main.php"

قمنا بتحويل ملف Index.php إلى main.php وقمنا بإعادة التوجيه.

مهم: RewriteRule عادة ما يأخذ وسيطتين: ماذايحتاج إلى استبدال و لماذا؟بحاجة إلى استبدال. إذا لم نكن بحاجة إلى إجراء الاستبدال، يمكننا كتابته في النموذج:

الرمز "-" يعني "لا تقم بالتحويل"

RewriteBase

بعد كل RewriteRules، يدخل RewriteBase حيز التنفيذ. إذا كان الاستعلام الناتج بعد التحويلات نسبيًا ومختلفًا عن الاستعلام الأصلي، فسيقوم RewriteBase باستعادته، مما يجعله مطلقًا. سوف يقوم RewriteBase ببساطة بإلحاق نفسه بالطلب الموجود على اليسار. لأن قيمة RewriteBase هي المسار من جذر الموقع إلى .htaccess. في حالتنا، يقع .htaccess مباشرة في الجذر، لذلك:

بناء الجملة: RewriteBase URL-path-from-.htaccess-file-to-site-root

على سبيل المثال:

# .htaccess موجود في /dir/ # المسار من جذر الموقع إلى .htaccess /dir/ RewriteBase /dir/ # طلب http://example.com/dir/logo.gif # إدخال RewriteRule هو "logo.gif" RewriteRule ^ logo.gif$ logo-orange.gif # بعد RewriteRule: "logo.gif" -> "logo-orange.gif" # بعد RewriteBase: "logo-orange.gif" -> "/dir/logo-orange. GIF"

التعبيرات العادية

التعبيرات العادية التي قد تواجهها في .htaccess.

رمز معنى مثال
. أي واحدرمز c.t هو قطة، سرير أطفال، قطع، إلخ.
+ واحد أو أكثر تطابقالشخصيات a+ هو a، aa، aaa، إلخ.
* صفرأو عدة تطابقالشخصيات تعمل a* بنفس الطريقة التي تعمل بها a+ ولكن في حالة a* فإن السلسلة الفارغة ستفي بالشرط
? المباراة اختيارية اللون سوف يناسب كلا من اللون واللون.
^ الرمز الذي منه يبدأخط ^a يطابق سلسلة تبدأ بـ a
$ الرمز الذي ينتهيخط يتطابق $a مع سلسلة تنتهي بـ .
() يجد ويتذكر المباريات مجموعاتالشخصيات.

ويمكن أيضا أن تستخدم ل المرجع الخلفي(انظر المثال)

(أب)+ سوف يرضي الأبباب

مثال المرجع الخلفي:

إعادة كتابة القاعدة ^/ (+) /(.*) $ /الصفحة الرئيسية?صفحة= $1 &معرف= $2

/album/123 → /الصفحة الرئيسية?page= الألبوم&معرف= 123

واحد منالشخصيات الممكنة ct قطع مناسب، سرير أطفال أوقطة.

المزيد من التعبيرات العادية

أعلام

بناء الجملة: إعادة كتابة القاعدة العادية_التعبير [flag1,flag2,flag3]

علَم وصف
[F] مُحرَّم- إرجاع الخطأ 403 ممنوع.
[ل] آخر- أوقف عملية التحويل عند هذه النقطة ولا تطبق أي قواعد تحويل أخرى.
إلحاق سلسلة الاستعلام- تشير هذه العلامة إلى آلية التحويل للإضافة وليس الاستبدالسلاسل الاستعلام من URL إلى القائمة، في سلسلة الاستبدال.
يمر من خلال- يوقف عملية التحويل ويرسل المستلمة رابط جديدمزيد من أسفل السلسلة.
[ص] إعادة توجيه- إيقاف عملية التحويل وإرجاع النتيجة إلى متصفح العميل كإعادة توجيه إلى صفحة جديدة.
[س] يتخطى- يخطئ القاعدة التالية، إذا نجحت القاعدة الحالية. يمكنك تحديد عدد القواعد اللاحقة التي سيتم تجاهلها.

يحدث أن يتم نقل البيانات إلى البرنامج من سطر الأوامر عند استدعائه. تسمى هذه البيانات وسيطات سطر الأوامر. يبدو مثل هذا، على سبيل المثال:

./a.out test.txt ls -lt /home/peter/

هنا يتم استدعاء البرامج a.out (من الدليل الحالي) و ls (من نفس الدليل المحدد في متغير بيئة PATH). يتلقى البرنامج الأول من سطر الأوامر كلمة واحدة - test.txt، والثاني - اثنين: -lt و /home/peter/.

إذا كان البرنامج مكتوبًا بلغة C، فعند إطلاقه، يتم نقل التحكم فورًا إلى الوظيفة main()، وبالتالي، فهي الوظيفة التي تستقبل وسيطات سطر الأوامر التي تم تعيينها لمتغيرات المعلمة الخاصة بها.

لقد قمنا سابقًا بتعريف الدالة main() كما لو أنها لا تأخذ أي معلمات ولا تُرجع شيئًا. في الواقع، في لغة C، أي دالة افتراضيًا (إذا لم يتم تعريف أي شيء آخر) تُرجع عددًا صحيحًا. يمكنك التأكد من هذا. إذا كتبت الكود بهذه الطريقة:

main() (printf ("Hi \ن") ; العودة 0 ; )

ثم لن يحدث أي تحذير أو خطأ أثناء التجميع. يحدث نفس الشيء إذا كتبت int main() . وهذا يثبت أن الدالة بشكل افتراضي تُرجع عددًا صحيحًا وليس لا شيء (باطل). على الرغم من أن ما تُرجعه الدالة يمكن دائمًا "تجاوزه"، على سبيل المثال، voidmain() أو float main() .

عند استدعاء برنامج من سطر الأوامر، يتم دائمًا تمرير زوج البيانات التالي إليه:

  1. عدد صحيح، للإشارة إلى عدد الكلمات (العناصر مفصولة بمسافات) في سطر الأوامر عند استدعائها،
  2. مؤشر إلى مجموعة من السلاسلحيث يكون كل سطر كلمة منفصلة عن سطر الأوامر.

ضع في اعتبارك أن اسم البرنامج نفسه مهم أيضًا. على سبيل المثال، إذا كانت المكالمة تبدو كما يلي:

./a.out12 الموضوع 2

ثم الوسيطة الأولى للبرنامج لها القيمة 4، ويتم تعريف مصفوفة السلاسل على النحو التالي (./a.out)، "12"، "theme"، "2").

لاحظ المصطلحات، هناك وسيطتان فقط للبرنامج (رقم ومصفوفة)، ولكن يوجد عدد من وسيطات سطر الأوامر كما تريد. يتم "تحويل" وسيطات سطر الأوامر إلى وسيطات البرنامج (إلى وسيطات الدالة main()).
يتم تمرير هذه البيانات (الرقم والمؤشر) إلى البرنامج حتى عندما يتم استدعاؤها بالاسم دون تمرير أي شيء إليها: ./a.out. في هذه الحالة، تحتوي الوسيطة الأولى على القيمة 1، وتشير الوسيطة الثانية إلى صفيف يتكون من سطر واحد فقط ("./a.out").

حقيقة أن البيانات يتم نقلها إلى البرنامج لا تعني ذلك على الإطلاق الوظيفة الأساسية() يجب أن يقبلهم. إذا تم تعريف الدالة main() بدون معلمات، فلن يكون من الممكن الوصول إلى وسائط سطر الأوامر. على الرغم من أنه لا يوجد شيء يمنعك من نقلها. لن يكون هناك أي خطأ.

للوصول إلى البيانات التي تم تمريرها إلى البرنامج، يجب أن يتم تخصيصها للمتغيرات. نظرًا لأنه يتم تمرير الوسائط فورًا إلى main()، فيجب أن يبدو رأسها كما يلي:
الرئيسي (int n، char *arr)

يحتوي المتغير الأول (n) على عدد الكلمات، ويحتوي المتغير الثاني على مؤشر إلى مصفوفة من السلاسل. غالبًا ما تتم كتابة المعلمة الثانية كـ **arr . ومع ذلك، فهو نفس الشيء. تذكر أن مصفوفة السلاسل نفسها تحتوي على مؤشرات للسلاسل كعناصرها. ونقوم بتمرير مؤشر إلى العنصر الأول من المصفوفة إلى الدالة. اتضح أننا نقوم بتمرير مؤشر إلى مؤشر، أي. ** ص.

يمارس
اكتب برنامج مثل هذا:

#يشمل int main(int argc, char ** argv) ( int i; printf ("%d \ن"، أرجك)؛ ل (ط = 0 ؛ ط< argc; i++ ) puts (argv[ i] ) ; }

يعرض عدد الكلمات في سطر الأوامر عند استدعائها وكل كلمة بها خط جديد. نسميها بدون وسيطات سطر الأوامر ومع الوسائط.

استخدمنا في البرنامج متغيرات المعلمات argc و argv. من المعتاد استخدام هذه الأسماء، ولكن في الواقع يمكن أن تكون أي شيء. من الأفضل الالتزام بهذا المعيار حتى تكون برامجك أكثر قابلية للفهم ليس فقط بالنسبة لك، ولكن أيضًا للمبرمجين الآخرين.

الأهمية العملية لنقل البيانات إلى البرنامج

إذا كانت لديك أي خبرة في سطر أوامر GNU/Linux، فأنت تعلم أن معظم الأوامر تحتوي على مفاتيح ووسائط. على سبيل المثال، عند عرض محتويات الدلائل، والنسخ، والنقل، يتم تحديد كائنات نظام الملفات التي يتم تنفيذ الأمر عليها كوسائط. يتم تحديد ميزات تنفيذه باستخدام المفاتيح. على سبيل المثال، في الفريق

Cp -r ../les_1 ../les_101

cp هو اسم الأمر، و-r هو رمز التبديل، و../les_1 و../les_101 هما وسيطتا الأمر.

بشكل عام، في أغلب الأحيان، يتم نقل عناوين الملفات و"المعدلات" (هذه هي المفاتيح) لعملية تنفيذ البرنامج إلى البرامج عند إطلاقها.

لنكتب برنامجًا يفتح الملفات التي يحددها المستخدم في سطر الأوامر للكتابة أو الإضافة ويكتب (يضيف) هناك نفس المعلومات التي يدخلها المستخدم من لوحة المفاتيح أثناء تنفيذ البرنامج:

#يشمل #يشمل الرئيسي (int argc, char ** argv) ( int i, ch; FILE * f[ 5 ] ; if (argc< 3 || argc >7) (يضع ( "عدد المعلمات غير صالح") ; العودة 1 ؛ ) if (strcmp (argv[ 1 ] , "-w" ) != 0 && strcmp (argv[ 1 ] , "-a" ) != 0 ) ( يضع ( "يمكن أن تكون المعلمة الأولى إما -w أو -a") ; العودة 2 ؛ ) لـ (i= 0; i< argc- 2 ; i++ ) { f[ i] = fopen (argv[ i+ 2 ] , argv[ 1 ] + 1 ) ; if (f[ i] == NULL) { printf ("لا يمكن فتح الملف %s\n ", argv[i+ 2 ] ) ; العودة 3 ؛ ) ) while ((ch = getchar () ) != EOF) for (i= 0 ; i< argc- 2 ; i++ ) putc (ch, f[ i] ) ; for (i= 0 ; i < argc- 2 ; i++ ) fclose (f[ i] ) ; return 0 ; }

توضيحات للكود:

  1. يتم إنشاء مجموعة من خمسة مؤشرات الملف. لذلك، لا يمكنك فتح أكثر من خمسة ملفات في نفس الوقت. سيتم تخزين مؤشر الملف للملف الأول في عنصر الصفيف f، والثاني - في f، وما إلى ذلك.
  2. يتم التحقق من عدد وسيطات سطر الأوامر. يجب أن يكون هناك ثلاثة منهم على الأقل، لأن... الأول هو اسم البرنامج، والثاني هو وضع فتح الملف، والثالث هو الملف الأول أو الوحيد الذي سيتم الكتابة إليه. وبما أن البرنامج يسمح لك بفتح خمسة ملفات فقط، فلا يمكن أن يكون إجمالي عدد وسائط سطر الأوامر أكثر من سبعة. لذلك، إذا كان عدد الوسائط أقل من 3 أو أكثر من 7، فسينتهي البرنامج، لأن يؤدي بيان الإرجاع إلى خروج الوظيفة، حتى لو كان هناك المزيد من التعليمات البرمجية بعدها. يمكن تفسير القيمة التي يتم إرجاعها من دالة لا تساوي 0 بواسطة العملية الأصلية كرسالة مفادها أنه تم إنهاء البرنامج بسبب خطأ.
  3. التحقق من صحة وسيطة سطر الأوامر الثانية. إذا لم يكن "-w" أو "-a"، إذن التعبير الشرطيفي الثانية إذا عاد 1 (صحيح). تتيح لك الدالة strcmp()‎ مقارنة السلاسل وإرجاع 0 إذا كانت متساوية.
  4. في لحلقةيتم فتح الملفات بواسطة عناوين محددةوالتي تبدأ من العنصر الثالث في مصفوفة argv. ولهذا السبب تتم إضافة 2 إلى i للحصول على عناصر مصفوفة argv، بدءًا من العنصر الثالث. يشير التعبير argc-2 إلى عدد أسماء الملفات التي تم تمريرها؛ لأن يخزن argc إجمالي عدد وسيطات سطر الأوامر، أول اثنين منها ليسا أسماء ملفات.
  5. يتيح لك التعبير argv+1 "قص" السلسلة الفرعية "w" (أو "a") من السلسلة "-w" (أو "-a")، لأن argv هو في الأساس مؤشر إلى العنصر الأول في السلسلة. بإضافة واحد إلى المؤشر، ننقله إلى العنصر التاليمجموعة مصفوفة.
  6. إذا تعذر فتح الملف، تقوم الدالة fopen() بإرجاع NULL. في هذه الحالة، ينتهي البرنامج.
  7. تتم كتابة كل حرف يدخله المستخدم على لوحة المفاتيح في جميع الملفات المفتوحة.
  8. وفي النهاية يتم إغلاق الملفات.

نشأت هذه المقالة من فكرة التدريب المتقدم لموظفينا دعم فنيالعمل مع mod_rewrite. أظهرت الممارسة أنه بعد دراسة عدد كبير من الكتب المدرسية المتوفرة باللغة الروسية، فإن فرق الدعم جيدة في حل مشكلات القالب، ولكن التجميع المستقل للقواعد يحدث من خلال التجربة والخطأ. كمية كبيرةأخطاء. تكمن المشكلة في أن الفهم الجيد لكيفية عمل mod_rewrite يتطلب دراسة الوثائق الإنجليزية الأصلية، متبوعة إما بتفسيرات إضافية أو ساعات من التجارب باستخدام RewriteLog.

توضح المقالة كيفية عمل mod_rewrite. يتيح لك فهم مبادئ تشغيله أن تفهم بوضوح تأثير كل توجيه وأن تتخيل بوضوح ما يحدث في وقت أو آخر داخل mod_rewrite عند معالجة التوجيهات.

أفترض أن القارئ على دراية بماهية mod_rewrite، ولن أصف أساسياته التي يسهل العثور عليها على الإنترنت. تجدر الإشارة أيضًا إلى أن المقالة تتناول عمل mod_rewrite عند استخدام توجيهاته في ملف htaccess. الاختلافات عند العمل في السياق المنصوص عليها في .

لذا، لقد درست mod_rewrite، وقمت بتجميع العديد من RewriteRules وتمكنت من مواجهة عمليات إعادة توجيه لا نهاية لها، والحالة التي لا تلتقط فيها القاعدة طلبك لسبب ما، بالإضافة إلى التشغيل غير المتوقع لمجموعة من القواعد عندما تغير قاعدة لاحقة بشكل غير متوقع الطلب الذي تم إعداده بعناية وفقًا للقواعد السابقة.

ما الذي يعمل به RewriteRule؟

يتم تمرير RewriteRule الأول إلى المسار من حيث يوجد .htaccess إلى الملف المطلوب. هذا السطر لا يبدأ أبدًا بـ "/". تنقل قواعد إعادة الكتابة اللاحقة نتيجة التحويلات السابقة.

لفهم كيفية عمل RewriteRule بشكل كامل، يجب عليك أولاً تحديد ما تعمل به. دعونا نلقي نظرة على كيفية استقبال Apache للسلسلة التي تم تمريرها في البداية إلى RewriteRule في .htaccess للمعالجة.

عندما تبدأ العمل مع mod_rewrite لأول مرة، فإنك تفترض منطقيًا أنه يعمل مع الروابط. ومع ذلك، ليس هذا هو الحال عند استخدام mod_rewrite في .htaccess. في الواقع، ليس الرابط الذي يتم إرساله إلى RewriteRule، ولكنه المسار إلى الملف المطلوب.

بسبب الهندسة المعمارية الداخلية Apache، في اللحظة التي يدخل فيها .htaccess حيز التنفيذ، يمكن أن يعمل mod_rewrite فقط على المسار إلى الملف الذي يحتاج إلى المعالجة. ويرجع ذلك إلى حقيقة أنه قبل إرساله إلى mod_rewrite، كان من الممكن أن يكون الطلب قد تم تعديله بالفعل بواسطة وحدات أخرى (على سبيل المثال، mod_alias)، وقد لا يتطابق المسار النهائي للملف الموجود على الموقع مع الرابط الأصلي. إذا عمل mod_rewrite على المرجع الأصلي، فسيؤدي ذلك إلى تعطيل عمل الوحدات التي عدلت الطلب قبله.

ولذلك، يتم تمرير mod_rewrite المسار المطلق إلى الملف الذي يجب معالجته. يعرف Mod_rewrite أيضًا المسار إلى .htaccess، حيث توجد قواعد RewriteRule. لجعل المسار إلى الملف مشابهًا للرابط الذي يخطط مطور الموقع للعمل معه، يقوم mod_rewrite بقطع الجزء الخاص بملف .htaccess من المسار المطلق.

لذلك، فإن هذا المسار، الذي تم قطع المسار إلى .htaccess، هو الذي يتم تمريره إلى RewriteRule الأولى. على سبيل المثال:

الطلب: http://example.com/templates/silver/images/logo.gif DocumentRoot: /var/www/example.com مسار الملف: /var/www/example.com/templates/silver/images/logo. gif .htaccess موجود في: /var/www/example.com/templates/.htaccess

ستتلقى قاعدة RewriteRule الأولى: Silver/images/logo.gif يرجى ملاحظة: تم أيضًا قطع "templates/". كيف يعمل RewriteRule يتم قطع المسار إلى .htaccess مع الشرطة المائلة. هناك نتيجة لذلك: السطر الذي تم تمريره في البداية إلى معالجة RewriteRule لا يبدأ أبدًا بـ "/".

من المهم أن تتذكر ما لا تفعله RewriteRule. ولا يعالج اسم الموقع، والوسائط التي يتم تمريرها إلى البرنامج النصي، ولا يعالج الرابط بالكامل إذا لم يكن .htaccess موجودًا في جذر الموقع. كل هذا يتم بواسطة RewriteCond، والذي سنتطرق إليه بإيجاز بعد قليل. لذا:

# لن تعمل - القاعدة تبدأ بـ / RewriteRule ^/index.php$ /my-index.php # لن تعمل - لم يتم تحليل اسم الموقع RewriteRule RewriteRule ^example.com/.* http://www.example .com # لن يعمل - وسيطات الرابط لا تقع في RewriteRule RewriteRule Index.php\?newspage=(+) news.php?page=$1 # سيعمل فقط إذا كان .htaccess موجودًا في نفس مكان القوالب المجلد # على سبيل المثال، في جذر الموقع. أي أنه إذا كان .htaccess موجودًا في templates/.htaccess، فلن تعمل القاعدة #، لأن mod_rewrite سيقطع المسار إلى .htaccess وسينتهي السطر عند إدخال RewriteRule # بدون "templates/" RewriteRule ^templates/ common/yandex-money templates/shared/yad.gif

لقد اكتشفنا ما الذي يعمل به RewriteRule. الآن دعونا نرى كيف يعمل.

كيف تعمل RewriteRule

يقوم RewriteRule ببساطة بتحويل السلسلة وفقًا للتعبيرات العادية وهذا كل شيء. تعمل RewriteRule على سلسلة، وليس على رابط أو مسار إلى ملف.

كما اكتشفنا أعلاه، يتضمن إدخال RewriteRule المسار من .htaccess إلى الملف المطلوب. من الأنسب الآن التجريد من المسارات والروابط والنظر في ما يعمل به RewriteRule سلسلة منتظمة. يتم تمرير هذه السلسلة من RewriteRule إلى RewriteRule، ويتم تعديلها في حالة عمل أي من RewriteRules.

في منظر عامبصرف النظر عن تعقيدات استخدام العلامات (التي سننظر إلى بعضها أدناه) وتعقيدات كتابة التعبيرات العادية (والتي لن نتطرق إليها كثيرًا في هذه المقالة)، تعمل RewriteRule بكل بساطة. أخذنا الخط. قارن مع التعبير العادي في الوسيطة الأولى. إذا كان هناك تطابق، فاستبدل السلسلة بأكملها بقيمة الوسيطة الثانية. قم بتمرير السلسلة إلى RewriteRule التالي. هذا كل شيء في الأساس. لتوضيح أن RewriteRule يعمل بشكل خاص مع السلسلة، فكر في المثال الرائع التالي:

# الطلب: http://mysite.com/info.html # ستحتوي قاعدة إعادة الكتابة الأولى على "info.html" # تحويل الطلب إلى سلسلة عشوائية. RewriteRule ^info.html$ "لقد رأيت سلحفاة في الحفرة. وكانت ترقص موسيقى الروك أند رول. وكانت تبتسم. وبشكل عام، كانت دمية مضحكة للغاية." # "info.html" -> "لقد رأيت سلحفاة..." # استبدل هذا السطر بـ رابط خارجي. RewriteRule Turtle https://example.com/information/index.html # "رأيت سلحفاة..." -> "https://example.com/information/index.html" # استبدل اسم الموقع! RewriteRule ^(.*)example.com(.*)$ $1example.org$2 # "https://example.com/information/index.html" -> "https://example.org/information/index. html" # استبدل البروتوكول! RewriteRule ^https:(.*)$ ftp:$1 # "https://example.org/information/index.html" -> "ftp://example.org/information/index.html" # استبدل الرابط النهائي . قاعدة إعادة الكتابة ^(.*)/index.html$ $1/main.php # "ftp://example.org/information/index.html" -> "ftp://example.org/information/main.php"

كما ترون، RewriteRule لا يهتم بما يعمل معه - فهو ببساطة يحول السلسلة وفقًا للوسيطات المعطاة لها. إذا كنت تريد، يمكنك تخزين أي صفائف بيانات في سطر؛ إذا كنت ترغب في ذلك، والمثابرة ولديك معرفة جيدة بالتعبيرات العادية، يمكنك حتى كتابة tic-tac-toe على RewriteRule.

يجب ملاحظة ملاحظة هنا: على الرغم من أن RewriteRule يعمل مع سلسلة نصية خالصة، إلا أنه لا يزال يركز على العمل مع الروابط. لذلك، سوف يتفاعل بطريقة خاصة مع الأسطر التي تبدأ بـ

https://

أو نظائرها (سوف نتذكر أننا أردنا إجراء إعادة توجيه خارجي) وإلى "؟" (تعتبر الأحرف التالية كوسيطات يجب استبدالها للطلب). ومع ذلك، نحن لسنا مهتمين بذلك في الوقت الحالي - من المهم أن نفهم أنه لا يوجد سحر في RewriteRule - فهو يتطلب سلسلة فقط ويغيرها بالطريقة التي تخبرها بها. سنلقي نظرة على عمليات إعادة التوجيه والحجج الخارجية لاحقًا في المقالة؛ هناك أيضًا ما يمكن الحديث عنه.

بعد اكتمال جميع التحويلات وتنفيذ قاعدة RewriteRule الأخيرة، تصبح RewriteBase نافذة المفعول.

ما هو RewriteBase المستخدمة؟

إذا كان الاستعلام الناتج نسبيًا ومختلفًا عن الاستعلام الأصلي، فسيضيف RewriteBase نفسه إلى يساره. من الضروري تحديد RewriteBase في .htaccess. قيمته هي المسار من جذر الموقع إلى .htaccess. يتم تنفيذ RewriteBase فقط بعد كل قواعد RewriteRules، وليس بينها.

لقد قلنا سابقًا أن mod_rewrite، الذي يعمل في .htaccess، يحتوي على المسار المطلق للملف المطلوب. لتمريرها إلى RewriteRule، يقوم mod_rewrite بقطع المسار إلى .htaccess. ثم تقوم RewriteRules بتغيير الطلب واحدًا تلو الآخر بشكل تسلسلي. والآن، بعد تعديل الطلب، يجب على Apache استعادة المسار المطلق للملف الذي يجب عليه معالجته في النهاية. RewriteBase هو في الواقع اختراق يساعد في استعادة المسار الأصلي للملف.

يتم تنفيذ RewriteBase بعد كل التحويلات. هذا يعني أنه لن يغير الطلب بين RewriteRules، ولكنه لن يصبح ساري المفعول إلا عند اكتمال جميع RewriteRules.

بعد كل التحويلات، يبحث RewriteBase فيما إذا كان المسار الناتج نسبيًا أم مطلقًا. في سياق Apache، هذا يعني مسارًا نسبيًا أو مطلقًا، بدءًا من جذر الموقع: Images/logo.gif - نسبي. /images/logo.gif - مطلق (شرطة مائلة في البداية). http://example.com/images/logo.gif - الأكثر مطلقًا على الإطلاق. إذا كان المسار مطلقًا، فلن يقوم RewriteBase بأي شيء. وإذا كان نسبيًا، فإن RewriteBase يُلحِق نفسه إلى اليسار. يعمل هذا مع عمليات إعادة التوجيه الداخلية والخارجية:

# .htaccess موجود في /images/ # تم تحديد RewriteBase /images/ RewriteBase /images/ # طلب http://example.com/images/logo.gif # إدخال RewriteRule هو "logo.gif" RewriteRule ^logo.gif $ logo -orange.gif # بعد RewriteRule: "logo.gif" -> "logo-orange.gif" # بعد RewriteBase: "logo-orange.gif" -> "/images/logo-orange.gif" # طلب http :/ /example.com/images/header.png # إدخال قاعدة إعادة الكتابة هو "header.png" RewriteRule ^header.png$ /templates/rebranding/header.png # بعد قاعدة إعادة الكتابة: "header.png" -> "/ templates/rebranding /header.png" # بعد RewriteBase: لم يتغير شيء، لذا النتيجة النهائيةتبدأ التحولات بـ "/". # اطلب http://example.com/images/director.tiff # مدخلات RewriteRule هي "director.tiff" # نستخدم إعادة توجيه نسبية خارجية RewriteRule ^director.tiff$ Staff/manager/director.tiff # بعد RewriteRule: "director.tiff" -> "staff/manager/director.tiff" # + تذكر mod_rewrite أنه ستكون هناك إعادة توجيه خارجية # بعد RewriteBase: "staff/manager/director.tiff" -> "/images/staff/manager/ Director.tiff" # mod_rewrite تذكرت إعادة التوجيه الخارجي: # "/images/staff/manager/director.tiff" -> http://example.com/images/staff/manager/director.tiff

عادة، بعد بعض الإلمام بـ mod_rewrite، تتطور العادة التالية:

    أضف "RewriteBase /" إلى كل ملف .htaccess

    تبدأ جميع عمليات إعادة التوجيه بشرطة مائلة: "RewriteRule news.php /index.php?act=news". وهذا يساعد على التخلص من القطع الأثرية من RewriteBase، ولكن من الخطأ القيام بذلك. الآن بعد أن عرفنا ما يفعله RewriteBase، يمكننا صياغة القواعد الصحيحة التالية:

يجب أن يتطابق RewriteBase مع المسار من جذر الموقع إلى .htaccess. ما عليك سوى بدء عمليات إعادة التوجيه باستخدام "/" عندما تحتاج إلى تحديد المسار المطلق من جذر الموقع إلى الملف.

ماذا يحدث إذا لم تحدد RewriteBase؟ افتراضيًا، يجعل Apache الأمر متساويًا المسار المطلقعلى نظام الملفات to.htaccess (على سبيل المثال /var/www/example.com/templates/). يتجلى عدم صحة افتراض Apache هذا في عمليات إعادة التوجيه النسبية الخارجية:

# اطلب http://example.com/index.php # DocumentRoot: /var/www/example.com/ # .htaccess موجود في جذر الموقع ولا يحتوي على قاعدة إعادة كتابة محددة. # لذلك، بشكل افتراضي، RewriteBase يساوي المسار المطلق to.htaccess: /var/www/example.com/ # RewriteRule المدخلات هو "index.php" RewriteRule ^index.php main.php [R] # الإخراج هو "index.php" " -> "main.php" # تذكر mod_rewrite أن هناك حاجة إلى إعادة توجيه خارجية # نفدت RewriteRule # لا يزال mod_rewrite ينفذ RewriteBase، لأنه يحتوي على قيمة افتراضية. # اتضح: "main.php" -> "/var/www/example.com/main.php" # هنا يتذكر mod_rewrite أنه كانت هناك إعادة توجيه خارجية: # "/var/www/example.com/main. php" -> http://example.com/var/www/example.com/main.php # اتضح أنه ليس ما كان يدور في ذهنهم على الإطلاق.

لذلك، مر الطلب بجميع قواعد RewriteRules، وبعد ذلك، إذا لزم الأمر، تمت إضافة RewriteBase إليه. هل يجب على Apache الآن أن يخدم الملف الذي يشير إليه المسار الناتج؟ لا. الآن ستتم معالجة الطلب الناتج مرة أخرى.

كيف يعمل mod_rewrite. علم [ل]

يبدأ mod_rewrite في معالجة الطلب مرارًا وتكرارًا حتى يتوقف عن التغيير. والعلم [ل]لا أستطيع إيقافه.

عند إنشاء تكوينات mod_rewrite أكثر أو أقل تعقيدًا، من المهم فهم ذلك تعديل الاستعلام لا ينتهي عند RewriteRule الأخير. بعد تشغيل RewriteRule الأخير وإضافة RewriteBase، يبحث mod_rewrite لمعرفة ما إذا كان الطلب قد تغير أم لا. إذا تغير الطلب، فستبدأ معالجته مرة أخرى من البداية.htaccess.

يقوم Apache بهذا لأنه أثناء عملية تغيير الطلب، ربما تمت إعادة توجيهه إلى دليل آخر. قد يكون له ملف .htaccess الخاص به والذي لم يشارك في معالجة الطلب السابق. قد يحتوي ملف .htaccess الجديد هذا على قواعد تؤثر على معالجة الطلب - قواعد mod_rewrite وقواعد الوحدات الأخرى. للتعامل مع هذا الموقف بشكل صحيح، يجب على Apache إعادة تشغيل حلقة المعالجة بأكملها.

انتظر، ولكن هناك علم [ل]مما يؤدي إلى توقف معالجة طلب mod_rewrite!

ليس بالتأكيد بهذه الطريقة. علَم [ل]يوقف التكرار الحالي لمعالجة الطلب. ومع ذلك، إذا تم تعديل الطلب بواسطة RewriteRules التي لا تزال قادرة على المعالجة، فسيبدأ Apache دورة معالجة الطلب مرة أخرى من قاعدة RewriteRule الأولى.

# الطلب: http://example.com/a.html RewriteBase / RewriteRule ^a.html$ b.html [L] RewriteRule ^b.html$ a.html [L]

سيؤدي المثال أعلاه إلى حلقة لا نهائية من عمليات إعادة التوجيه و" الخادم الداخليخطأ" في النهاية. في هذا المثال، تكون الحلقة اللانهائية واضحة، ولكن في التكوينات الأكثر تعقيدًا قد تحتاج إلى البحث في القواعد لتحديد الطلبات التي تتكرر بين بعضها البعض.

لتجنب حالات مماثلةيوصى باستخدام العلامة [L] فقط عند الضرورة. يمكن أن تكون الحاجة من نوعين: عند استخدام إعادة توجيه خارجي - أو . في حالة إعادة التوجيه الخارجية، يعد إجراء المزيد من المعالجة للطلب أمرًا غير مرغوب فيه (انظر أدناه حول العلامة [ص])، والأفضل إيقافه. عندما تكون هناك حلقة في .htaccess لا يمكن إزالتها، ويجب إيقاف معالجة الطلب بواسطة mod_rewrite بالقوة، في هذه الحالة، يتم استخدام إنشاء خاص - راجع النصائح حول هذا الموضوع في نهاية المقالة.

لكن المثال أدناه لن يتكرر. حاول تحديد السبب والملف الذي سيتم تسليمه إلى Apache في النهاية.

# الطلب: http://example.com/a.html # Start.htaccess RewriteBase / RewriteRule ^a.html$ b.html RewriteRule ^b.html$ a.html # End.htaccess

الحل: نتيجة لتنفيذ جميع RewriteRules، يتغير الطلب بهذه الطريقة النتيجة النهائيةيساوي الأصل. يرى Apache هذا ولا يقوم بإعادة معالجة الطلب. سيتم إرجاع ملف a.html.

كيف يعمل mod_rewrite. علم [ر]

    علَم [ص]لا يتوقف عن معالجة الطلب، ويعيد توجيهًا خارجيًا على الفور. وبدلاً من ذلك، يتذكر الحاجة إلى إعادة توجيه خارجي، وتستمر معالجة الطلب باستخدام RewriteRule التالية. يوصى باستخدامه دائمًا مع العلم [ل].

    علَم [ص]يخبر Apache أنه لا يحتاج إلى إجراء عملية إعادة توجيه داخلية، بل خارجية. ما الفرق بين إعادة التوجيه الخارجية والداخلية؟ تقوم عملية إعادة التوجيه الداخلية ببساطة بتغيير المسار إلى الملف الذي سيتم منحه للمستخدم، بينما يعتقد المستخدم أنه يتلقى الملف الذي طلبه في الأصل. من خلال إعادة التوجيه الخارجي، يقوم Apache بإرجاع حالة الاستجابة 301 أو 302 إلى المستخدم بدلاً من محتويات الملف وإعلام المستخدم بالارتباط الذي يجب أن يستخدمه المتصفح للحصول على الملف.

يبدو أنه عند معالجة العلم [ص]يجب أن يتوقف Apache على الفور عن معالجة RewriteRule ويعيد إعادة التوجيه الخارجي إلى المستخدم. ومع ذلك، دعونا نتذكر المثال الرائع من قسم كيفية عمل RewriteRule. في ذلك أشرنا أولا إلى العلم [ص]، مما يشير إلى الحاجة إلى إعادة توجيه خارجي، وبعد ذلك استمروا في تغيير الرابط باستخدام قاعدة RewriteRule التالية.

هذه هي بالضبط الطريقة التي يعمل بها Apache عند تحديد إعادة توجيه خارجي. إنه ببساطة "يلاحظ" لنفسه أنه بعد تنفيذ جميع القواعد، من الضروري إرجاع الحالة 302 (الافتراضي)، ولكن في نفس الوقت يستمر في تنفيذ جميع RewriteRules في أسفل القائمة. يمكننا الاستمرار في تغيير الطلب حسب حاجتنا، والشيء الوحيد الذي لن ينجح هو إعادة التوجيه مرة أخرى داخليًا.

ومع ذلك، فمن غير المرجح أن ترغب في تغييره بأي شكل من الأشكال بعد إرسال إعادة توجيه خارجي. ولذلك، فمن المستحسن عند استخدام العلم [ص]تشير إلى ذلك مع [ل]:

# انتقلت لعبة بلاك جاك إلى الاسم الجميل RewriteRule ^bj/(.*) blackjack/$1 # يمكنك فقط استخدام الرابط الخارجي RewriteRule ^bj/(.*) http://blackjack.example.com/$1 [L]

بدلا من استخدام العلم [ص]يمكنك ببساطة توفير رابط خارجي. في هذه الحالة، سيخمن Apache نفسه أنه من الضروري إجراء إعادة توجيه خارجي. هنا، كما في حالة تحديد العلم بشكل صريح [ص]يوصى باستخدام العلم [ل]. إذا كانت عملية إعادة التوجيه الخارجية تؤدي إلى نفس الموقع، فمن الأفضل استخدام العلامة [ص]دون إشارة الرابط الكامل(وبعبارة أخرى، استخدم إعادة توجيه خارجية نسبية). وهذا سيجعل القاعدة مستقلة عن اسم الموقع. إذا أدت عملية إعادة توجيه خارجية إلى موقع آخر، فلا يمكن القيام بذلك إلا عن طريق تحديد رابط خارجي كامل.

كيف يعمل mod_rewrite. تحديد معلمات الطلب والعلامة

لا يؤدي تغيير معلمات الاستعلام في RewriteRule إلى تغيير الصف الذي تعمل عليه RewriteRule التالية. ومع ذلك، يؤدي تغيير المعلمات إلى تغيير المتغير %(QUERY_STRING) الذي يمكن لـ RewriteCond العمل معه.

المصطلحات المستخدمة: "المعلمات" - معلمات الطلب، "الوسائط" - وسيطات RewriteRule.

باستخدام RewriteRule، لا يمكنك تغيير المسار إلى الملف الذي ستتم معالجته فحسب، بل يمكنك أيضًا تغيير معلمات طلب GET التي سيتم تمريرها إليه. يُستخدم هذا غالبًا لنقل معالجة NC إلى برنامج نصي معالج عام، على سبيل المثال: RewriteBase /

# الطلب: http://example.com/news/2010/07/12/grand-opening.html # الإدخال: "news/2010/07/12/grand-opening.html" RewriteRule ^news/(.* ) $index.php?act=news&what=$1 # بعد إعادة الكتابة: "news/2010/07/12/grand-opening.html" -> "index.php" # %(QUERY_STRING): "" -> "act= news&what =2010/07/12/grand-opening.html"

في اللحظة التي تواجه فيها RewriteRule علامة استفهام في وسيطتها الثانية، فإنها تعلم أنه يتم تعديل المعلمات في الطلب. ما يحدث نتيجة لذلك هو أن RewriteRule يستبدل السلسلة التي تعمل بها بجزء من الوسيطة الثانية من قبل علامة استفهام. يرجى ملاحظة أن معلمات الطلب الجديدة لا تنتهي في السلسلة التي ستعمل عليها RewriteRules اللاحقة. ينتهي جزء الوسيطة الثانية بعد علامة الاستفهام في المتغير %(QUERY_STRING). إذا تم تحديد العلم ، ستتم إضافة معلمات الاستعلام إلى بداية %(QUERY_STRING). إذا لم يتم تحديد العلامة، فسيتم استبدال %(QUERY_STRING) بالكامل بمعلمات الاستعلام من RewriteRule. بضعة أمثلة أخرى:

RewriteBase / # الطلب: http://example.com/news/2010/?page=2 # Input RewriteRule: "news/2010/" RewriteRule ^news/(.*)$ Index.php?act=news&what=$1 # بعد التحويل: "news/2010/" -> "index.php" # Value %(QUERY_STRING): "page=2" -> "act=news&what=2010/" على الأرجح، القاعدة أعلاه لا تعمل بشكل صحيح، كما إنها صفحة الوسيطة المفقودة. دعونا نصلح هذا: RewriteBase / # الطلب: http://example.com/news/2010/?page=2 # Input RewriteRule: "news/2010/" RewriteRule ^news/(.*)$ Index.php?act= news&what=$1 # بعد التحويل: "news/2010/" -> "index.php" # Value %(QUERY_STRING): "page=2" -> "act=news&what=2010/&page=2"

من المهم أن نفهم أن تغيير معلمات الاستعلام يغير %(QUERY_STRING) الذي يمكن استخدامه لاحقًا في RewriteCond. يجب أن يؤخذ ذلك في الاعتبار عند كتابة القواعد اللاحقة التي تتحقق من الوسائط.

بالطبع يتغير، لأنه يتم إرسال الطلب لإعادة المعالجة بواسطة Apache!

لا، %(QUERY_STRING) يتغير على الفور. لن أقدم دليلاً - لقد تم بالفعل كتابة المزيد عن المعلمات أكثر مما هو مثير للاهتمام لقراءته :)

ما الذي يمكنك فعله للتحقق في RewriteCond من معلمات الطلب التي تم تمريرها من قبل المستخدم، وليس تلك التي تم تعديلها بواسطة RewriteRules، راجع النصائح في نهاية المقالة.

RewriteCond والأداء

أولاً، يتم التحقق من تطابق الطلب مع RewriteRule، وعندها فقط - شروط إضافية RewriteCond.

ينبغي قول بضع كلمات حول الترتيب الذي تنفذ به mod_rewrite التوجيهات. نظرًا لأن .htaccess يأتي مع RewriteCond أولاً ثم RewriteRule، فيبدو أن mod_rewrite يتحقق من جميع الشروط أولاً ثم يبدأ في تنفيذ RewriteRule.

في الواقع، كل شيء يحدث في الاتجاه المعاكس. أولاً، يتحقق mod_rewrite مما إذا كانت قيمة الطلب الحالية تتطابق مع التعبير العادي RewriteRule، وعندها فقط سيتحقق من جميع الشروط المدرجة في RewriteCond.

لذا، إذا كان لديك تعبير عادي مكون من صفحتين في RewriteRule الخاص بك، وبالتفكير في الأداء، قررت قصر تنفيذ هذه القاعدة على RewriteConds إضافية، فيجب أن تعلم أنه لن ينجح أي شيء. في هذه الحالة، من الأفضل استخدام علامتي RewriteRule [C] أو [S] لتخطي المزيد قاعدة معقدة، إذا كان أكثر الشيكات البسيطةلم ينجح.

متغيرات وأعلام RewriteCond، وأعلام RewriteRule الأخرى، وما إلى ذلك.

اقرأ الوثائق.

تعرفنا على مبادئ تشغيل RewriteRule وRewriteBase والأعلام [ل], [ص]و وقم أيضًا بتحليل آلية معالجة الطلب داخل mod_rewrite. بقي ما يلي دون أن يتأثر: إشارات RewriteRule الأخرى وتوجيهات RewriteCond وRewriteMap.

لحسن الحظ، هذه التوجيهات والإشارات ليست محفوفة بأي غموض وتعمل تمامًا كما هو موضح في معظم البرامج التعليمية. لفهمها، ما عليك سوى قراءة الوثائق الرسمية. أولاً، أوصي بدراسة قائمة المتغيرات التي يمكن التحقق منها في RewriteCond - %(QUERY_STING)، %(THE_REQUEST)، %(REMOTE_ADDR)، %(HTTP_HOST)، %(HTTP:header)، إلخ.)

الفرق في كيفية عمل mod_rewrite في سياق .htaccess وفي سياق VirtualHost

في سياق يعمل mod_rewrite على العكس تمامًا.

كما قلت في بداية المقال، كل ما هو موضح أعلاه يتعلق باستخدام mod_rewrite في سياق .htaccess. إذا تم استخدام mod_rewrite في سيعمل بشكل مختلف: في تتضمن RewriteRule مسار الطلب بالكامل، بدءًا من الشرطة المائلة الأولى وانتهاءً بالبداية الحصول على المعلمات: "http://example.com/some/news/category/post.html?comments_page=3" → "/news/category/post.html". يبدأ هذا السطر دائمًا بـ /. الوسيطة الثانية لـ RewriteRule يجب أن تبدأ أيضًا بـ /، وإلا فستكون "طلب غير صالح". RewriteBase لا معنى له. تمرير القواعد يحدث مرة واحدة فقط. علَم [ل]ينتهي بالفعل من معالجة جميع القواعد الموضحة في ، دون أي تكرارات أخرى.

كتابة التعابير العادية

حاول إنشاء تعبيرات عادية بحيث تحدد بدقة تلك الاستعلامات التي تريد تعديلها - بحيث لا تعمل قواعد RewriteRule عن طريق الخطأ مع استعلام آخر. على سبيل المثال:

# ابدأ جميع التعبيرات النمطية بـ "^" (بداية السطر) # وانتهي بـ "$" (نهاية السطر): RewriteRule ^news.php$ Index.php # حتى لو لم يكن ذلك ضروريًا - من أجل التنوع وفهم أفضل للتكوين: RewriteRule ^news/(.*)$index.php # إذا كان يجب تضمين أرقام فقط في القناع، فحدد ذلك بوضوح. # إذا كانت بعض الأرقام ثابتة، فحددها بشكل صريح. # إذا لم يكن من الممكن وجود الخطوط المائلة في بقية الطلب، فقم بتقييد وجودها. #لا تنسى الهروب"." (النقاط). # تستهدف القاعدة التالية استعلامات مثل http://example.com/news/2009/07/28/b-effect.html RewriteRule ^news/20(2)/(2)/(2)/[^/]+ \.html فهرس.php

ومع ذلك، أوه التعبيرات العاديةيوجد قسم كامل على موقع واحد معروف.

تغيير عمليات إعادة التوجيه الخارجية

على الرغم من حقيقة أن mod_rewrite يسمح لك بتغيير عمليات إعادة التوجيه الخارجية باستخدام RewriteRule، وصولاً إلى البروتوكول، إلا أنني لا أوصي بشدة بالقيام بذلك. في المقالة، يتم استخدام مثال تغيير عمليات إعادة التوجيه الخارجية فقط للتخلص من مفاهيم مثل "الروابط" و"الملفات" ولإظهار أكثر وضوحًا أن RewriteRule يعمل بسلسلة بسيطة.

لا أعتقد أن مطوري mod_rewrite كانوا يقصدون أن يقوم أي شخص بذلك، لذا فإن جميع أنواع المصنوعات اليدوية ممكنة. لا تفعل هذا من فضلك.

كيفية إيقاف حلقة لا نهاية لها

في بعض الأحيان يكون منطق عمليات إعادة التوجيه على الموقع هو أنه بدون إجراءات خاصة، فإن mod_rewrite ينظر إليها على أنها حلقة لا نهاية لها من عمليات إعادة التوجيه. لنأخذ المثال التالي.

كان الموقع يحتوي على صفحة /info.html. قرر متخصص تحسين محركات البحث (SEO) ذلك محركات البحثسيتم فهرسة هذه الصفحة بشكل أفضل إذا كانت تسمى /information.html وطلبت إعادة توجيه خارجي من info.html إلى information.html. ومع ذلك، لسبب ما، لا يستطيع مطور الموقع ببساطة إعادة تسمية info.html إلى information.html وإجراء إعادة التوجيه - فهو يحتاج إلى إرسال البيانات مباشرة من ملف info.html. يكتب القاعدة التالية: # قم بإجراء إعادة توجيه خارجي RewriteRule ^info.html information.html # ولكن عند الطلب /information.html لا يزال يعطي info.html RewriteRule ^information.html info.html

... ويواجه حلقة لا نهاية لها. يتلقى كل طلب /information.html إعادة توجيه خارجية مرة أخرى إلى /information.html.

يمكن حل هذه المشكلة بطريقتين على الأقل. لقد تم وصف إحداها بالفعل على حبري - تحتاج إلى تثبيتها متغيرات البيئةواستنادًا إلى قيمته، قم بإيقاف عمليات إعادة التوجيه. سيبدو الكود كالتالي:

RewriteCond %(ENV:REDIRECT_FINISH) !^$ RewriteRule ^ - [L] RewriteRule ^info.html$ information.html RewriteRule ^information.html$ info.html

لاحظ أن mod_rewrite يُلحق "REDIRECT_" باسم المتغير.

الطريقة الثانية هي التحقق من THE_REQUEST ما طلبه المستخدم بالضبط:

# إعادة التوجيه الخارجيةيحدث فقط إذا طلب المستخدم info.html. # إذا كان info.html نتيجة إعادة توجيه داخلية، فلن يتم تفعيل القاعدة. RewriteCond %(THE_REQUEST) "^(GET|POST|HEAD) /info.html HTTP/+$" RewriteRule ^info.html$ information.html RewriteRule ^information.html$ info.html

تحليل طلب المستخدم الأصلي - مكافحة الكشف عن رابط Apache

أثناء المعالجة طلب أباتشييقوم بتوسيع الأحرف المشفرة بعنوان URL من الطلب الأصلي. في بعض الحالات، قد لا يكون ذلك مرغوبًا - حيث يريد المطور التحقق تمامًا من طلب المستخدم الأصلي غير المعدل. يمكن القيام بذلك عن طريق التحقق من المتغير %(THE_REQUEST) في RewriteCond:

RewriteCond %(THE_REQUEST) ^GET[\ ]+/tag/([^/]+)/[\ ]+HTTP.*$ RewriteRule ^(.*)$ Index.php?tag=%1 [L]