البحث في الموقع
المحتوى عن 'جلسة'.
-
لا يُملي الأطباء النفسيون عليك ما يجب عمله، بل يستنبطون الأسئلة التي من شأنها أن تدفع بك نحو اكتشاف ذلك بنفسك لتستطيع التمييز بين الصحيح والأصح، المهم والأهم، لتعرف أنت الجواب، الجواب النابع من بنات أفكارك. يستطيع الإنسان العاقل الراشد فهم نفسه في نهاية الأمر، ويستطيع اتخاذ القرارات الحاسمة بشكلٍ ملائم، ولكن هذا لا يمنع من بعض العراقيل والمطبات بين الحين والآخر خاصّة مع تلك التفاصيل الدقيقة والتي قد تكون غير هامّة ولكنّها قد تأثّر على الصيغة النهائيّة. سيتناول هذا المقال هذه النقطة بالتحديد، ليكون أشبه بالبوصلة التي توجّه رائد الأعمال نحو النجاح، والتفّوق في مسيرته نحو الريادة، والدفع به نحو مواجهة الواقع واتخاذ ما يلزم من قرارات في سبيل حماية تجارته وشركته. سيكون التالي أشبه بجلسة نفسية للرّيادي أو لصاحب الشّركة النّاشئة، سيدفعك التفكير والإجابة على هذه الأسئلة على تحديد ما الذي يجب عليك فعله اليوم لتجني ثماره غدًا وذلك من خلال العوائد المادية ونمو الشركة. في جملة واحدة، ما الذي يقدمه منتجك ومن يشتريه؟في جملة واحدة، لماذا نشتري منتجك؟قد تبدو الإجابة على السؤالين السابقين سهلة من الوهلة الأولى، وقبل الإجابة عليك أن تضع في الحسبان أنه كلما كانت الإجابة قصيرة ودقيقة، كلما دلّ الأمر على أنك مُدرك حقيقة مكانك في السوق، وإن كانت الإجابة على شكل: "بصراحة لا أعلم لماذا الناس تشتري منتجنا" إذًا فهذه مشكلة يتوجّب معالجتها على الفور. إن كان لديك إجابة بالفعل، هل لأنك تعتقد يقينًا وبالدليل القاطع أن زبائنك يعون تمامًا سبب وجودك في السوق ولماذا يجب أن يشتروا منتج، أم أنك فقط تفترض ذلك؟ وما أقصده بالدليل القاطع هو وجود شهادات تجيب على هذا السؤال بأتم الوضوح (ربما عن طريق البريد الإلكتروني أو صفحات التواصل الاجتماعي) فيما عدا ذلك فأنت على الأغلب تفسّر ردود فعل زبائن على هواك، وإن كنت لا تملك هذا الدليل الآن، فلا بأس، ولكن عليك بالبحث عنه. إن كنت بالفعل تعرف الإجابة، فإن الإجابة على هذين السؤالين يجب أن تكون بوصلة عملية التسويق التي توجهك نحو الخيار الصحيح، لا بل إن الإجابات يجب أن تتصدّر صفحة البداية الخاصّة بالموقع، لا أظن أنه لديك شيء أفضل لتقنع به زبائنك، على أقل تقدير يجب أن تكون هذه الإجابات جوهر حملات التسويق. ما هو السبب الأبرز الذي يقف حاجزا أمام الطلب على منتجك؟على سبيل المثال: هل السبب هو عدم معرفة الناس بمنتجك من الأساس؟هل السبب هو السعر؟هل المنتج غير كامل المزايا والمواصفات؟هل السبب هو استراتيجية مبيعات غير منظّمة؟هل هو تصميم الموقع؟لا تكون معظم الشركات الصغيرة صريحةً حول هذه النقطة، مع ذلك من الممكن من أن يكون هذا السؤال هو السؤال الأهم، على سبيل المثال، ستكون إجابتي في بادئ الأمر على السؤال: "لماذا لا تملك المزيد من الزبائن؟" على النحو التالي: "لأننا نحتاج هذه الميزة/الخاصيّة"، فكثير من الأحيان ما تسمع أن شريحة معينة من الزبائن تقول: "سنشتري هذا المنتج إن قمت بإضافة كذا وكذا" وعليه أنت تستنتج أنه في حال تم إضافة الـ "كذا وكذا"، فإن الناس ستأتي وتصطف بطوابير لشراء منتجك. ولكن هل بالفعل هذا هو الحال؟ إن تمّ إضافة هذه الميزة (إن لم يكون المطلوب أكثر من ميزة، ومن تجاربي السابقة هذا ما يكون عليه الحال) ونلت رضى هذه الشريحة من الزبائن، هل هذا الأمر سيجلب لك 100 طلب إضافي؟ هل تظن أن الزبائن الذين نزّلوا التّطبيق ولم يشتروا أبدًا، كان عدم امتلاك التّطبيق لخاصيّةٍ ما هي السّبب الذي منعهم من الشّراء؟ وهل عدم امتلاك تلك الخاصية هي السّبب الذي منعت مئات من الآلاف من الزّبائن المُحتملين من زيارة موقعك من أساسه أو الخروج منه بعد ثوانٍ قليلة من زار الصّفحة الرئيسية؟ هل فعلًا الحلّ هو "المزيد من الخصائص"؟ عندما تسأل نفسك هذا السؤال وتكون صريحّا مع نفسك وتفكّر به مليًّا، سيقودك هذا الأمر لا شعوريًّا إلى الأمور التي يمكنك فعلها الآن لتحصل على المزيد من الزوّار، المزيد من تحميل النّسخة التّجريبية، وبالتالي المزيد من المبيعات، ولهذا لا تركن إلى أوّل إجابة سهلة تخطر على بالك. اذكر شيئا واحدا يمكنك فعله لتحصل على المزيد من التغذية الراجعة feedback من الزبائن/ المستخدم المحتملين/ الزبائن الذين خسرتهم؟يُعرف أن تغذية الزبائن الرّاجعة feedback هي الطريقة العملية في التقرير والفصل في كيفيّة بناء منتج يَرغب المستخدم بشرائه، وعلى الرغم من أنه ليس من الممكن طلب هذه الاستجابة مع كل شاردة وواردة، إلا أنه من المجدي جدًا تخصيص يوم من أيام الشهر في سبيل طلب وجمع أكبر قدر ممكن من المعلومات وردود الفعل من الزبائن والمستخدمين ومن أرض الواقع. إن توقفت المداخيل الآن كم من الوقت أمامك قبل أن تصل إلى مرحلة الإفلاس؟يقودك إدراك حقيقة هذا السؤال إلى أمرين: أولهما معرفة النفقات الشهرية والمدفوعات الشّهرية، وثانيهما ستعرف كم من الوقت ستصمد في السوق عند حدوث أزمة (في حال وجود عوائد) أو عندما لم تحصل على زبونك الأوّل لحدّ الساعة (كما هو الأمر بُعيد الانطلاقة). لا تنس أيضًا أن الإجابة على هذا السؤال ستساعد على الإجابة على سؤال آخر من نوع: "هل أستطيع تجربة هذا الأمر مع مشروعي"، مثلًا توظيف موظّفك الأوّل، أو كم تستطيع الإنفاق على الدعاية الإعلان، وكلما وجدت نفسك تُمعن في التفكير في فكرة مكلفة وجديدة والتي قد تكون مجدية، ولكنّها في نفس الوقت مُكلفة، فإن معرفة الإجابة على هذا السؤال ستساعدك على تقدير المدة الزمنية وإدراك ما هو على المحك، أو ما هي المدة التي ستبقى فيها واقفًا على قدمين في حال أن هذه المغامرة لم تُؤت بثمارها. ماذا لو أعطاك أحدهم 100 ألف دولار؟ كيف ستستخدمها لمضاعفة أرباحكم المستقبليةيقودك هذا السؤال إلى إدراك أهمية النشاطات التي لا تساهم في عوائد الشركة بشكل مباشر، ولقد تحدثنا سابقًا عن مسألة نشاطات التطوير والتسويق المجانية ولكن المستهلكة للوقت وفي معظم الأحيان هذه طريقة جيّدة في التفكير، ولكن في الأحيان الأخرى عليك أن تدفع القليل الحاضر للحصول على الكثير اللاحق. قد يكون من بين هذه النشاطات التي ترغب في القيام بها أمور مُلحّة وضرورية، والتي يمكن التّفكير في الحصول على استثمار صغير أو الاستدانة من أجلها، على كلٍ وبشكل عام من الأفضل دائمًا الاكتفاء بالحد الأدنى والضروري عند الاستدانة أو الاستثمار، ولكن إن كان المطلوب مجديا بالفعل وبإمكانه تحسين الوضع بشكل كبير فقد يجدر بك القيام بذلك. إن كنت مضطرا إلى توظيف أحدهم، كيف لك أن تحدد ما يجب عليه القيام به بحيث يساهم هذا الموظف بشكل كاف لتغطية راتبه؟أعلم أنك كرائد أعمال ناشئ وفي المراحل الأولى، قد لا تكون في وضعٍ يسمح لك بتحمّل نفقات إضافيّة، وربما تظن أنه لا يوجد أحد قد يلبي طلبك في جودة العمل المطلوبة، على كلٍ هذا ليس الغرض من السؤال، الغرض من السؤال هو معرفة واستكشاف ما هي المهام التي لا يتمّ الاهتمام بها بالقدر الكافي أو يتمّ تأجيلها إلى حين، وذلك لوجود أشياء أهم يتمّ العمل عليها، أو لوجود الكثير من الأعباء في الوقت الحالي، أو ربما لأنك لم تحدّد الأولويات بالشكل الأمثل. إن كنت لا تعتقد إنه من الممكن توظيف شخص بدوام كامل وقادر على تقديم عوائد مادية لتغطية راتبه فلا بأس بذلك. ولكن على الأقل سيدفع الأمر إلى معرفة المهام غير المنجزة التي كُنت ترغب في توظيف شخص للقيام بها، طبعًا لا حاجة إلى موظف جديد لتغطية هذه المهام، ولكن ربما عليك إعادة ترتيب الأوليات وجعل هذه المهام على رأس القائمة في الشهر المقبل. قد يكون هناك إجابة أفضل لهذا السؤال، ربما يجب التفكير والأخذ بعين الاعتبار طلب المساعدة، ولا يُقصد بالضرورة أن تكون هذه "المساعدة" توظيف موظف بدوام كامل، بل يمكن أن يكون مُستقلّا بدوام جزئي، أو يمكن أن يكون متدرّبًا intern، أو ربما شريك مستعد للعمل مقابل الحصول على أصول في الشركة. ما هي المهام التي تكره تنفيذها؟هل تحبّ تطوير خصائص جديدة ولكنك تكره الدعم الفني؟ هل تحب استعراض التّطبيق (عمل demo) ولكن تكره القيام بالمبيعات ؟ تحتاج إلى الإلمام بالأمور المالية للشّركة لكن تكره تفاصيل العمليات المالية؟ تحب مجال عملك لكن تكره الكتابة أو حتّى التغريد عنه؟ ما أريد قوله هو أن معظم العمليات التجارية مُملّة وهي أبعد ما تكون عن مهام مرحة، طبعًا هذا ليس بعذر لتجنّب هذه المهام بأي حالٍ من الأحوال، بل الأفضل تحديد هذه المهام والتي يمكن القول عنها أنها غير محبّذة ولكن ضروريّة في نفس الوقت، واتخاذ التدابير اللازمة حولها: إن قمت بإغلاق البريد الإلكتروني، وجميع برامج المحادثة، وهاتفك، وقمت بالتجهيز والتحضير إلى العمل فربما تصبح قادرًا على التحايل على بعض هذه المهام واستكمالها في أقل فترة ممكنة.يُمكن للمهام المملة أو لنقل الروتينية أن تُعهّد، مثلًا الاستعانة بالخدمات المصغّرة أسلوب مجدي بالفعل، وستجد أنه يمكن إنجاز هذه المهام بأقل التكاليف.راجع الأطراف الذين تتعامهم معهم الآن واسألهم فيما إذا كانوا يرغبون بتقديم خدماتهم لك، والتي عادةً ما تكون غير مكلفة.لا تنس أيضًا أنه يمكن الاستعانة بمتدرّب intern أو مُستقل وقبل أن تتحجّج في أن التكلفة قد تصبح عالية، فكّر بالخسارة التي قد تتكبّدها في حال أنك قمت بالعمل على هذه المهام بنفسك.مشاركة هذه المهام مع زملاء العمل؟ فمن المحتمل جدًا أنهم لا يكرهون هذا النوع من المهام بالقدر الذي تكره أنت، بمعنى يمكن المبادلة والمقايضة بين هذه المهام.إن كنت ما تزال لا ترغب في إنفاق المال لتوفير الوقت، إليك ما قاله "Dharmesh": ما هي الأمور التي يمكن إنجازها بشكل غير مثالي من دون أن تؤثر على المبيعات؟أنا من النوع الذي يملك تلك التركيبة المزعجة وهي البحث عن الكماليّة والهوس بالتحكّم بالشاردة والواردة، بحيث أحصل على نتائج استثنائية ومبهرة ولكن مع وقت أطول في التنفيذ، طبعًا يوجد تفاصيل جوهرية في نجاح أي الشركة ولا يمكن التهاون فيها: أي المزايا يجب تنفيذها الآن.كيف تمثّل نفسك وتتفاعل مع الزبائن.معرفة الكيفية والسبب الذي يدفع بالمستخدم إلى الشراء.ولكن، في حقيقة الأمر إن قائمة المهام الخاصّة بك ستكون طويلةً جدًا ويجب عليك الاختيار بعناية واستغلال الوقت أفضل استغلال وتصفية المهام بين ما يجب أن يكون مثاليًّا وبين ما يجب أن يكون عمليًّا، مثلًا، لا بد من وجود صفحة ‹‹تواصل معي›› ولكن ليس من الضرورة أن تكون ذات تصميم خلّاب المهم أن تكون متوفرة، أيضًا لا يجب على كل تدوينة أن تكون قطعة فنيّة خالصة المهم المحتوى المفيد، أيضًا على الإعلانات أن تكون مشكّلة ومختلفة بين بعضها البعض لأغراض الاختبار بدلًا من هدر الوقت على اختيار الكلمات wordsmithing، وأن تملك كتابًا إلكترونيًا حول أي شيء أفضل من ألا تملك كتابًا على الإطلاق. إن كان يمكن إنجاز المهمة بشكل غير مثالي من دون التأثير على العائد المادي، فربما من الأفضل أن تكون على هذا النحو، فستصبح عندها قادرًا على تفويض هذا النوع من المهام، وستصبح قادرًا على تحقيق وإتمام المهام بشكل أسرع. إن تسنى لك الحصول على ساعة كاملة مع مثلك الأعلى في مجالك، ماذا سيكون موضوع النقاش وما سيكون الهدف من الاجتماع؟أقصد بالسؤال السابق: "ما هي الخيارات الأبرز في مشروعك التجاري، والتي تشك في جدواها، وتشعر بأنه يجب الاستعانة بذوي الخبرة، ويمكن أن يقود صياغة السؤال بالشكل السابق إلى الحلول أيضًا، مثلًا، ربما يجب عليك الجلوس أكثر من ساعة للحصول على ما يقدمه المرشد، ربما عليك قراءة كتاب للمرشد، أو الإبحار في مدونته، أو مشاهدة محاضرات له، وذلك في سبيل الدخول إلى عقلية هذا المرشد بدلًا من الاكتفاء فقط في بالنصيحة، كما يمكنك في جميع الأحوال الاستعانة بقسم الأسئلة والأجوبة هنا في الأكاديمية لتحصل على إجابات شافية ووافية فيما بتعلق بريادة الأعمال وما يدور في فلكها. ترجمة -وبتصرف- للمقال: Startup Therapy: Ten questions to ask yourself every month لصاحبه: Jason Cohen. حقوق الصورة البارة: Designed by Freepik.
- 1 تعليق
-
- جلسة
- شركة ناشئة
-
(و 4 أكثر)
موسوم في:
-
مقدمة إذا كنت تعمل(على الشبكة) مُستخدمًا بروتوكول النقل الآمن Secure Shell) SSH)، فإنّك تعلم مُسبقًا أنّ الجلسة session ستُغلق تلقائيًا بعد دقائقٍ قليلةٍ من عدم النشاط "الخمول"، وذلك لأسبابٍ أمنية.من الممكن في الحقيقة أن تكون قد نسيت إغلاقها، وبالتالي فقد يتمكن شخص آخر من السيطرة على نظامك. ولكن إذا كنت لا ترى في ذلك مشكلة، فبإمكانك تغيير هذا السلوك في ضبط GNU/Linux. يجب تنفيذ الأوامر التالية من عميل SSH. كيفيّة منع SSH من قطع الاتصال يجب تنفيذ الخطوات التالية في عميل SSH، وليس في الخادم البعيد. افتح محرّر النص خاصتك في البداية وعدّل ملف الـ config الحالي للمستخدم الخاص بك، والذي تجده في المسار التالي: ~/.ssh/config أضف الأسطر التالية: تأكّد من أن السطر الثاني سيبدأ بمسافة فارغة. يُخبر السطر الأول الـ SSH بتطبيق هذا الضبط على جميع المضيفات البعيدة remote hosts. كما يمكنك بالطبع تحديد واحد منها فقط، وذلك باستبدال رمز الـ "*" بالمضيف المطلوب. ستحتاج بعد الانتهاء من ذلك إلى تطبيق الإعدادات المذكورة أعلاه: sudo source ~/.ssh/config أضف أو عدّل السطر التالي في ملف etc / ssh / ssh_config/ لتطبيق هذه الإعدادات على المستوى العام globally: ServerAliveInterval 60 احفظ الملف واغلقه. وبهذه الطريقة، لن تُغلق جلسة SSH بعد الآن بسبب الخمول. الخلاصة تذكّر أن أمان نظامك، وخصوصًا في حالة الخادم server، ليس أمرًا ثانويًا، وذلك كلّه بيديك. إنّ تغيير سلوك برامج مثل SSH يجب أن يتم فقط في حال كنت تعرف بالضبط ما تريده، وبعد التأكّد من أنّ ذلك لن يضعك في مشكلةٍ ما. ترجمة وبتصرّف للمقال How to prevent SSH from disconnecting sessions لصاحبه Giuseppe Molica
-
تعرّفنا إلى الآن على كيفيّة إنشاء تطبيق بسيط بلغة بايثون وإطار العمل Flask، يُمكن للتّطبيق الاتّصال بقاعدة بيانات، إضافة عناصر، عرضها وحذفها، لكنّ هذا التّطبيق لا يعتبر محميّا، إذ يُمكن لأي كان أن يُضيف مقالات أو يحذفها، لذا من المفضّل أن نقوم بإضافة نظام لتسجيل دخول بحيث تتمكّن وحدك (كمُدير للتّطبيق) من إجراء العمليّات الحسّاسة، بنهاية هذا الدّرس سنمتلك تطبيقا محميا باسم للمُستخدم وكلمة مرور، ولن يتمكّن أحد من حذف المقالات أو إضافتها إلّا إذا حصل على معلومات تسجيل الدّخول. مفهوم الجلسة في إطار العمل Flask الجلسة عبارة عن كائن يتصرّف تماما كقاموس يحتوي على مفاتيح وقيم، الجلسة تكون مرتبطة بنافذة المُتصفّح افتراضيّا، ما يعني بأنّ المفتاح والقيمة ستُسجّلان طيلة مدّة فتح المُتصفّح، وبمجرّد إغلاق نافذة المُتصفّح فإنّ الجلسة تُحذف (أو تدمّر). فكرة تسجيل الدّخول والخروج في درسنا ستكون كالتّالي: سنضع نموذج HTML في أعلى الصّفحة الرّئيسيّة، سيحتوي النّموذج على حقلين، حقل لكتابة اسم المُستخدم، وآخر لكلمة المرور مع زرّ لإرسال طلب الدّخول (أو طلب الاستيثاق Authentication)، عندما يُدخل المُستخدم كلمة "admin" في حقل اسم المُستخدم، وكلمة "password" في حقل كلمة المرور (يُمكن تغيير هذه المعلومات ببساطة)، سيتأكّد التّطبيق من أنّ البيانات صحيحة، وإذا كانت صحيحة فسنستخدم القاموس session المتواجد في حزمة flask لإنشاء مفتاح باسم logged_in وسنضع القيمة المنطقيّة True للمفتاح، بعدها يُمكننا أن نوجّه المُستخدم إلى الصّفحة الرّئيسيّة مع إخفاء نموذج تسجيل الدخول وعرض رابط لتسجيل الخروج عوضا عن النّموذج، أمّا إذا أدخل المُستخدم بيانات استيثاق خاطئة فسنوجّهه إلى الصّفحة الرّئيسيّة مع عرض نموذج تسجيل الدّخول مُجدّدا. تسجيل الدخول سنقوم أولا بإضافة نموذج HTML لتمكين الزّائر من إدخال بيانات الاستيثاق، سنضيف الشيفرة التّالية في ملفّ index.html مُباشرة بعد وسم body: <form action="{{ url_for('login') }}" method='POST'> <input type="text" placeholder="اسم المُستخدم" name="username"> <input type="password" placeholder="كلمة المرور" name="password"> <input type="submit" value="اُدخُل"> </form> الشيفرة أعلاه عبارة عن نموذج لحقلي اسم المُستخدم وكلمة المرور، سنتمكّن من الحصول على القيمتين في ملفّ app.py كالآتي: username = request.form['username'] password = request.form['password'] لاحظ بأنّنا حدّدنا مُوجّها باسم login في النّموذج، لذا فسيتوجّب علينا إنشاؤه في ملفّ app.py والأمر شبيه بما فعلناه في الدّرس السّابق، بحيث يقبل المُوجه طريقة POST لاستقبال البيانات التي يُرسلها المُتصفّح. سيكون موجّه login كالتّالي: # Login Route @app.route("/login", methods=['GET', 'POST']) def login(): if request.method == 'POST': username = request.form['username'] password = request.form['password'] if username == "admin" and password == "password": session['logged_in'] = True else: return redirect(url_for('home')) return redirect(url_for('home')) يستقبل الموجّه اسم المُستخدم وكلمة المرور ويُنفّذ جملة شرطيّة للتحقق من أنّ البيانات صحيحة، لنفرض بأنّ اسم المُستخدم هو admin وكلمة مروره هي password. إذا تحقّق الشّرط وتأكّدنا من أن البيانات التّي أدخلها المُستخدم صحيحة نقوم بإنشاء جلسة باسم logged_in ونعطيها القيمة المنطقيّة True ونقوم بعد ذلك بتوجيه المُستخدم إلى الصّفحة الرّئيسيّة، أمّا إن لم تكن البيانات صحيحة فنقوم بتوجيه المُستخدم إلى الصّفحة الرّئيسيّة دون إنشاء جلسة. لاستخدام الجلسات سيتوجّب علينا استيرادها من Flask في بداية الملفّ، ليُصبح السّطر كالتّالي: from flask import Flask, render_template, redirect, url_for, request, session سيتطلّب استخدام الجلسات تخصيص مفتاح سريّ كذلك، ويُمكن أن نقوم بذلك بإضافة السّطر التّالي مُباشرة بعد تعريف المُتغيّر app. app = Flask(__name__) app.config['SECRET_KEY'] = "Secret" تنبيه: من المهم أن تُغيّر Secret إلى مفتاح لا يُمكن التّنبؤ به ويجب أن يكون سريّا للغاية، يُمكنك استخدام دالة urandom من الوحدة os لتوليد سلسلة عشوائيّا كالتّالي: >>> import os >>> os.urandom(24) '\xee\x9dA\x81\x19\x17\xdd\x04\xae9\xc1\x1a-\xf2\xf8\xda\x9a\x99u\x90\x96]\xbaT' يُمكنك بعد ذلك استعمال السّلسلة المولّدة كقيمة للمفتاح السرّي. وهكذا سنكون قد انتهينا من نظام تسجيل دخول المُدير، الخطوة التّالية هي تسجيل خروجه، وذلك بتدمير الجلسة عند الوصول إلى المُوجّه logout. تسجيل الخروج لتسجيل الخروج يكفي إضافة مُوجّه باسم logout إلى الملفّ app.py، وسيكون دور الموجّه حذف المفتاح logged_in من الجلسة: # Logout Route @app.route("/logout") def logout(): session.pop('logged_in', None) return redirect(url_for('home')) لاحظ بأنّ الموجّه بسيط للغاية، كلّ ما يقوم به هو حذف المفتاح logged_in باستخدام التّابع pop وبعدها يعيد توجيه المُستخدم إلى الصّفحة الرّئيسيّة. الآن إذا قمت بتسجيل دخولك فسيُنشئ التّطبيق جلسة جديدة، أما إذا قمت بزيارة الموجّه logout عبر العنوان http://127.0.0.1:5000/logout فستُدمّر الجلسة. إضافة زر لتسجيل الخروج عوضا عن نموذج HTML رغم أنّنا قُمنا بإضافة نظام لتسجيل الدّخول والخروج إلا أنّ ذلك لا يظهر في الصّفحة، ولا يُمكن لنا أن نعرف تسجيل الدّخول من عدمه. سنقوم في هذا الجزء بتحويل الصّفحة الرّئيسيّة إلى صفحة مُتجاوبة، أي أنّنا سنتأكّد ممّا إذا كان المُستخدم قد سجّل دخوله، فإن كان ذلك صحيحا فسنعرض له زرّا لتسجيل الخروج، أمّا إن لم يكن قد سجّل دخوله فسنعرض نموذج HTML لتسجيل الدّخول. يُمكن القيام بالأمر بإضافة شرط للتأكّد من أنّ المفتاح logged_in موجود في الكائن session، والتّالي تطبيق للأمر في ملفّ index.html: {% if 'logged_in' not in session %} <form action="{{ url_for('login') }}" method='POST'> <input type="text" placeholder="اسم المُستخدم" name="username"> <input type="password" placeholder="كلمة المرور" name="password"> <input type="submit" value="اُدخُل"> </form> {% else %} <a class="logout" href="{{ url_for('logout') }}">خروج</a> {% endif %} يُمكن الآن التمييز بين تسجيل الدخول وتسجيل الخروج؛ الخطوة التّالية هي حماية الموجّهين create و delete لنمنع من لم يسجّل دخوله من حذف وإنشاء المقالات والسّماح بذلك للمُدير فقط. حماية الموجهين create و delete لحماية موجّه ما يجب أن نحمي الدوال التي التّي تقوم بالعمليّة، ما يعني بأنّنا يجب أن نحمي الدّالتين create و delete. وللقيام بالأمر يُمكن الاستعانة بميّزة المُزخرفات في لغة بايثون، يُمكنك الحصول على المزيد من المعلومات بالرّجوع إلى درس المُزخرفات. . سننشئ مُزخرفا باسم login_required، سنحتاج إلى المُزخرف wraps من الوحدة functools وهو مُزخرف مُساعد ويعتبر استعماله من أفضل المُمارسات. سيكون المُزخرف login_required كالتّالي: from functools import wraps def login_required(function): @wraps(function) def wrapper(*args, **kwargs): if 'logged_in' in session: return function(*args, **kwargs) else: return redirect(url_for('home')) return wrapper نقوم أولا باستدعاء wraps من الوحدة functools ونزخرف الدّالة بشرط أن يكون المفتاح logged_in في الجلسة، ما يعني بأنّ الدّالة ستُنفّذ إذا كان المُستخدم قد سجّل دخوله فقط، أمّا إن لم يكن قد سجّل دخوله فسنقوم بتوجيهه إلى الصّفحة الرّئيسيّة دون تنفيذ الدّالة. يُمكن الآن تطبيق المُزخرف على الدّالتين create و delete لمنع الزوار من إنشاء المقالات أو حذفها. لتطبيق المُزخرف يكفي كتابة اسمه مسبوقا بالرّمز @ مُباشرة فوق الدّالة. ما يعني بأنّ الموجّه create سيصبح كالتالي: # Create Post Page @app.route("/create", methods=['GET', 'POST']) @login_required def create(): if request.method == 'POST': title = request.form['title'] content = request.form['content'] manage_db.create(title, content) return redirect(url_for('home')) أما موجّه delete فسيصبح كالتّالي: # Delete Post @app.route("/delete/<post_id>") @login_required def delete(post_id): manage_db.delete(post_id) return redirect(url_for('home')) يمكنك تصفّح ملفّات الأمثلة على Github. ختاما إلى هنا نكون قد تعرّفنا على طرق بسيطة لحماية تطبيقنا ويُمكنك الآن نشر التّطبيق على الأنترنت، لكن تذكر بأنّ هذه الطّرق ليست آمنة بما فيه الكفاية، لذا إن كان تطبيقك حسّاسا فمن المُفضّل استعمال إضافة لإدارة أنظمة الاستيثاق مثل إضافة Flask-login أو Flask-Security.
-
إنّ Redis هو عبارة عن نظام تخزين وذاكرة مؤقتة cache بنمط مفتاح-قيمة key-value مفتوح المصدر، ويتم الإشارة له أيضًا كخادوم بُنية معطيات data structure بسبب دعمه المتقدّم للعديد من أنواع البيانات كالتلبيدات Hashes، اللوائح lists، المجموعات sets والخرائط الثنائيّة Bitmaps من بين الخواديم الأخرى، يدعم أيضًا الحشد clustering والذي يجعل منه مُستخدَمًا عادةً في البيئات ذات التوافر العالي والقابلة للتطوير. سنشاهد في هذا الدّرس كيفيّة تثبيت وإعداد خادوم Redis خارجي لكي يتم استخدامه كمُداوِل للجلسة Session Handler من أجل تطبيق PHP يعمل على Ubuntu. إنّ مُداوِل الجلسة مسؤول عن تخزين واسترجاع البيانات المحفوظة ضمن الجلسات، حيث تستخدم PHP افتراضيًّا الملفّات من أجل هذا، يُمكن استخدام مُداوِل الجلسة الخارجي من أجل إنشاء بيئات PHP قابلة للتطوير خلف مُوازِن الحِمل load balancer، حيث ستتصل جميع عُقَد nodes التّطبيقات إلى خادوم مركزي لتتشارك معلومات الجلسة. المتطلبات الأساسيةسنعمل في هذا الدّرس على خادومين مُنفصلين، ومن الهام من أجل الأداء والأمان أن تتوضّع كلا Droplets الخاصّة بهما في نفس مركز البيانات مع تمكين ربط الشبكات الخاصّة Private networking، وهذا ما سنحتاجه: خادوم ويب PHP يقوم بتشغيل LAMP أو LEMP على Ubuntu – سنقوم بالإشارة لهذا الخادوم بـ web.خادوم Ubuntu آخر حيث سيتم تثبيت Redis – سنقوم بالإشارة لهذا الخادوم بـ redis.سنحتاج نفاذ مناسب عبر SSH إلى كلا الخادومين كمستخدم اعتيادي مع صلاحيّات sudo. نستطيع أيضًا من أجل خادوم Redis استخدام تطبيق Redis بنقرة واحدة والانتقال للخطوة الثانية. الخطوة الأولى – تثبيت خادوم Redisإنّ أول شيء نحتاجه هو الحصول على خادوم Redis يعمل على redis Droplet الخاصّة بنا. سنستخدم مُدير حِزَم Ubuntu الاعتيادي مع مستودع PPA موثوق يتم تزويدنا به بواسطة Chris Lea، وهو ضروري لكي نتأكّد أنّنا نحصل على آخر إصدار مُستَقر من Redis. كنصيحة أمان عامّة ينبغي أن نستخدم PPAs من مصادر موثوقة فقط. نُضيف في البداية مستودع PPA بتنفيذ الأمر التالي: sudo add-apt-repository ppa:chris-lea/redis-serverنضغط Enter للتأكيد. نحتاج الآن لتحديث الذاكرة المؤقتة cache لمدير الحِزَم: sudo apt-get updateفلنقم أخيرًا بتثبيت Redis بتنفيذ الأمر التالي: sudo apt-get updateينبغي الآن أن يكون تم تثبيت Redis على خادومنا، ولاختبار التثبيت نُجرِّب هذا الأمر: redis-cli pingسيقوم هذا الأمر بالاتصال إلى نموذج instance من Redis يعمل على localhost على المنفذ 6379، ويجب أن نتلقّى PONG كاستجابة. الخطوة الثانية – ضبط Redis لكي يقبل اتصالات خارجيةيسمح Redis بالاتصال فقط إلى localhost والذي يعني بشكل أساسي أنّنا نملك النفاذ إليه فقط من داخل الخادوم حيث تمّ تثبيت Redis، نحتاج إلى تغيير هذه الإعدادات للسماح بالاتصالات التي تأتي من خواديم أخرى على نفس الشبكة الخاصّة مثل الخادوم redis. إنّ أول شيء يجب علينا فعله هو معرفة عنوان IP الجهاز Redis على الشبكة الخاصّة، ينبغي تنفيذ الخطوات التالية على الخادوم redis. نقوم بتنفيذ الأمر ifconfig للحصول على معلومات حول واجهات شبكتنا: sudo ifconfigينبغي أن نتلقّى خَرْجًا Output مُشابِهًا لما يلي: eth0 Link encap:Ethernet HWaddr 04:01:63:7e:a4:01 inet addr:188.166.77.33 Bcast:188.166.127.255 Mask:255.255.192.0 inet6 addr: fe80::601:63ff:fe7e:a401/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:3497 errors:0 dropped:0 overruns:0 frame:0 TX packets:3554 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:4895060 (4.8 MB) TX bytes:619070 (619.0 KB) eth1 Link encap:Ethernet HWaddr 04:01:63:7e:a4:02 inet addr:10.133.14.9 Bcast:10.133.255.255 Mask:255.255.0.0 inet6 addr: fe80::601:63ff:fe7e:a402/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:8 errors:0 dropped:0 overruns:0 frame:0 TX packets:7 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:648 (648.0 B) TX bytes:578 (578.0 B)فلنبحث عن inet_addr المُخصَّص للواجهة eth1، في هذه الحالة نجده 10.133.14.9، وهذا هو عنوان IP الذي سنستخدمه لاحقًا للاتصال إلى الخادوم redis من الخادوم web. نفتح الملف etc/redis/redis.conf/ باستخدام مُحرِّر سطر الأوامر command line editor المُفضَّل لدينا ونبحث عن السّطر الذي يحتوي على التّعريف bind، يجب أن نُضيف عنوان IP للشبكة الخاصّة لدينا إلى هذا السّطر كما يلي: sudo vim /etc/redis/redis.confetc/redis/redis.conf/ bind localhost 10.133.14.9إن وجدنا 127.0.0.1 بدلًا من localhost فليس هناك مشكلة، فقط نضيف عنوان IP الخاص لدينا بعد ما هو موجود. نحتاج الآن لإعادة تشغيل الخدمة Redis لتطبيق التغييرات: sudo service redis-server restartإن قمنا بتثبيت Redis باستخدام تطبيق النقرة الواحدة فسيكون اسم الخدمة redis بدلًا من redis-server. ولإعادة تشغيلها نكتب الأمر: sudo service redis restartبعد هذه التغييرات سيكون أي خادوم داخل نفس الشّبكة الخاصّة قادرًا على الاتصال إلى نموذج Redis. الخطوة الثالثة – تعيين كلمة سر لخادوم Redisلإضافة طبقة أمان إضافيّة إلى تثبيت Redis لدينا فنحن نُشجِّع على تعيين كلمة سر للنفاذ إلى بيانات الخادوم، سنقوم بتحرير نفس ملف الإعدادات الذي قمنا بتحريره في الخطوة السّابقة etc/redis/redis.conf/: sudo vim /etc/redis/redis.confنقوم الآن بإلغاء التّعليق uncomment عن السّطر الذي يحتوي على requirepass ونضع كلمة سر قويّة: etc/redis/redis.conf/ requirepass yourverycomplexpasswordhereنعيد تشغيل خدمة Redis لكي يتم تطبيق التغييرات: sudo service redis-server restart الخطوة الرابعة – اختبار الاتصال إلى Redis والاستيثاق Authenticationلكي نتأكّد من أنّ كافّة التغييرات تعمل كما هو متوقّع نقوم بالاتصال إلى خدمة Redis من داخل الجهاز redis: redis-cli -h 10.133.14.9المخرجة: 10.133.14.9:6379>بالرغم من أنّه ليس من الإجباري هنا تحديد المُعامِل host (بما أنّنا نتصل من localhost)، فقد قمنا بذلك للتأكّد من أنّ خدمة Redis تقبل الاتصالات الموجّهة إلى واجهة الشّبكة الخاصّة. إن كُنّا قد عرّفنا كلمة سر وحاولنا الآن النفاذ إلى البيانات ينبغي أن نتلقّى خطأ AUTH: 10.133.14.9:6379> keys *المخرجة: (error) NOAUTH Authentication required.نحتاج من أجل الاستيثاق أن نقوم فقط بتنفيذ الأمر AUTH مع تزويده بنفس كلمة السّر التي عرّفناها في الملف etc/redis/redis.conf/: 10.133.14.9:6379> AUTH yourverycomplexpasswordhereينبغي أن نتلقّى استجابة OK، والآن إن قمنا بتنفيذ الأمر: 10.133.14.9:6379> keys *يجب أن يكون الخَرْج مُشابِهًا لما يلي: المخرجة: (empty list or set)يعني هذا الخَرْج فقط أنّ خادوم Redis لدينا فارغ، وهو ما كُنّا نتوقّعه تمامًا، حيث أنّ الخادوم web ليس مُعدًّا بعد لاستخدام خادوم Redis هذا كمداوِل للجلسة. فلنحافظ على جلسة SSH هذه مفتوحة ومتّصلة إلى redis-cli بينما نقوم بتنفيذ الخطوات التالية، سنعود إلى المُحِث prompt redis-cli لكي نتحقّق من أنّه يتم تخزين بيانات الجلسة بشكل مناسب، وذلك بعد أن نقوم بالتغييرات الضروريّة للخادوم web. الخطوة الخامسة – تثبيت امتداد Redis Extension على الخادوم webيجب تنفيذ الخطوات التالية على الخادوم web، نحتاج إلى تثبيت الامتداد PHP Redis وإلّا لن تكون PHP قادرة على الاتصال إلى الخادوم Redis. في البداية نقوم بتحديث الذاكرة المؤقتة لمدير الحِزَم بتنفيذ الأمر التالي: sudo apt-get updateنقوم بعدها بتثبيت الحِزمَة php5-redis: sudo apt-get install php5-redisينبغي الآن أن يكون الخادوم web قادرًا على الاتصال إلى Redis. الخطوة السادسة – تعيين Redis كمداول الجلسة الافتراضي على الخادوم webنحتاج الآن لتحرير الملف php.ini على الخادوم web لتغيير مُداوِل الجلسة الافتراضي لـ PHP، يعتمد مسار الملف على استخدامنا LAMP أو LEMP، ففي LAMP على Ubuntu يكون المسار عادةً في etc/php5/apache2/php.ini/، وفي LEMP على Ubuntu يكون المسار عادةً في etc/php5/fpm/php.ini/. إن لم نكن متأكّدين من مسار الملف php.ini نستطيع إيجاده بطريقة سهلة باستخدام الدالّة ()phpinfo، فقط نقوم بوضع الشيفرة code التالية في ملف نسمّيه info.php داخل دليل الويب الجذري root: <?php phpinfo();عند الوصول للـ script من متصفحنا ننظر إلى السطر الذي يحتوي على ملف الإعدادات الذي تمّ تحميله، ينبغي أن نجد المسار الصحيح للملف php.ini قد تمّ تحميله. يجب ألّا ننسى إزالة الملف info.php بعد الانتهاء من هذا، لأنّه يحتوي على معلومات حسّاسة حول البيئة لدينا. نفتح الملف php.ini ونبحث عن السّطر الذي يحتوي على session.save_handler، إنّ القيمة الافتراضيّة له هي files، ينبغي أن نقوم بتغييرها إلى redis. على بيئة LAMP: sudo vim /etc/php5/apache2/php.iniعلى بيئة LEMP: sudo vim /etc/php5/fpm/php.inietc/php5/fpm/php.ini/ session.save_handler = redisينبغي أن نجد الآن السّطر الذي يحتوي على session.save_path، نقوم بإلغاء التعليق عنه وتغيير قيمته بحيث تحتوي مقطع string اتصال Redis، يجب أن يتّبع المحتوى النَّسَق التالي كله في سطر واحد: tcp://IPADDRESS:PORT?auth=REDISPASSWORDetc/php5/fpm/php.ini/ session.save_path = "tcp://10.133.14.9:6379?auth=yourverycomplexpasswordhere"نحتاج فقط إلى تزويد المُعامِل auth إن كُنّنا قد أعددنا كلمة سر عند ضبط Redis. نحفظ الملف ونعيد تشغيل خدمة php. على بيئة LAMP: sudo service apache2 restartعلى بيئة LEMP: sudo service php5-fpm restart الخطوة السابعة – اختبار مداولة Redis للجلسةلكي نتأكّد من أنّ الجلسات لدينا يتم الآن مُداوَلتها من قبل Redis نحتاج PHP script أو تطبيق يقوم بتخزين المعلومات في الجلسات، سنستخدم Script بسيط يقوم بتنفيذ عدّاد Counter، حيث تتم زيادة الرقم كلّما أعدنا تحميل الصّفحة. ننشئ ملف يُدعى test.php على الخادوم web ونضعه داخل المجلّد الجذر للمستند document root folder: sudo vim /usr/share/nginx/html/test.phpلا يجب أن ننسى تغيير usr/share/nginx/html/ بحيث يكون مسار جذر المستند لدينا. usr/share/nginx/html/test.php/ <?php //simple counter to test sessions. should increment on each page reload. session_start(); $count = isset($_SESSION['count']) ? $_SESSION['count'] : 1; echo $count; $_SESSION['count'] = ++$count;نتوجّه في متصفحنا إلى http://web/test.php لكي نصل إلى الـ script، ينبغي أن يقوم بزيادة الرقم كلما قمنا بإعادة تحميل الصّفحة. يجب أن نمتلك الآن معلومات الجلسة مُخزّنة على خادوم Redis، وللتحقّق من ذلك نعود إلى جلسة SSH على الجهاز redis، حيث قُمنا مُسبَقًا بالاتصال إلى خدمة Redis باستخدام redis-cli. نقوم بجلب المحتوى مرّة أخرى باستخدام * keys: 10.133.14.9:6379> keys *ينبغي أن نحصل على خَرْج مُشابِه لهذا: 1) "PHPREDIS_SESSION:j9rsgtde6st2rqb6lu5u6f4h83"وهذا يُظهِر أنّه يتم تخزين معلومات الجلسة على خادوم Redis، ونستطيع الاتصال من خواديم ويب إضافيّة إلى خادوم Redis بطريقة مماثلة. الخاتمةإنّ Redis خدمة تخزين من نمط مفتاح-قيمة سريعة وقويّة نستطيع أيضًا استخدامها كمُداوِل للجلسة في PHP، مما يُمكّننا من الحصول على بيئات PHP قابلة للتطوير عن طريق تزويدها لنا بنظام مُوزَّع لتخزين الجلسة، وللمزيد من المعلومات حول تقييس scaling تطبيقات PHP تستطيع التحقّق من هذا الدّرس: تقييس تطبيقات PHP أفقيًّا. ترجمة -وبتصرّف- للمقال How to Set Up a Redis Server as a Session Handler for PHP on Ubuntu 14.04 لصاحبته Erika Heidi.