اذهب إلى المحتوى

Adnane Kadri

الأعضاء
  • المساهمات

    4965
  • تاريخ الانضمام

  • تاريخ آخر زيارة

  • عدد الأيام التي تصدر بها

    51

إجابات الأسئلة

  1. إجابة Adnane Kadri سؤال في كيفية إضافة أكثر من قاعدة بيانات بأنواع مختلفة في لارافيل Laravel؟ كانت الإجابة المقبولة   
    واحدة من المميزات التي يقدمها لارافيل هي في إمكانية استعماله لاتصالات قواعد بيانات مختلفة، ولن يكون ذلك الا بإعداد كل منها في ملفات الاعداد. 
    لاحظ أن ملف config/database.php يتوفر على مصفوفة بالمفتاح connections تحمل هاته المصفوفة تعريفات مختلفة من بينها تلك الخاصة بـ mysql و pgsql: 
    'mysql' => [ 'driver' => 'mysql', 'url' => env('DATABASE_URL'), 'host' => env('DB_HOST', '127.0.0.1'), 'port' => env('DB_PORT', '3306'), 'database' => env('DB_DATABASE', 'forge'), 'username' => env('DB_USERNAME', 'forge'), 'password' => env('DB_PASSWORD', ''), 'unix_socket' => env('DB_SOCKET', ''), 'charset' => 'utf8mb4', 'collation' => 'utf8mb4_unicode_ci', 'prefix' => '', 'prefix_indexes' => true, 'strict' => true, 'engine' => null, 'options' => extension_loaded('pdo_mysql') ? array_filter([ PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'), ]) : [], ], 'pgsql' => [ 'driver' => 'pgsql', 'url' => env('DATABASE_URL'), 'host' => env('DB_HOST', '127.0.0.1'), 'port' => env('DB_PORT', '5432'), 'database' => env('DB_DATABASE', 'forge'), 'username' => env('DB_USERNAME', 'forge'), 'password' => env('DB_PASSWORD', ''), 'charset' => 'utf8', 'prefix' => '', 'prefix_indexes' => true, 'schema' => 'public', 'sslmode' => 'prefer', ], كل نموذج Model من نماذج لارافيل يحتوي على الخاصية connection التي تكون مضبوطة على اتصال قواعد البيانات الافتراضي المعرف في ملف اعداد قواعد البيانات. 
    يمكنك تخصيص تلك التي تعمل على اتصال قاعدة بيانات pgsql وتلك التي تعمل على اتصال mysql باسنادها كقيمة ل connection في ملف النموذج المستهدف: 
    class Post extends Model{ protected $connection = 'pqsql'; .. } في ملف التهجير المرافق لهذا النموذج قم بضبط نفس الامر عن طريق استعمال التابع connection للواجهة Schema: 
    Schema::connection('pqsql')->create('posts', function (Blueprint $table) { $table->id(); $table->string('title'); $table->timestamps(); }); بفرض أنك اتصالي قواعد البيانات اللذان لديك يعملان بشكل عادي، نفذ أمر التهجير php artisan migrate وستلاحظ أن كل قاعدة بيانات تهجر بها بيانات مختلفة. 
  2. إجابة Adnane Kadri سؤال في كيفية تجميع عدد من النطاقات Domains عند إنشاء مسارات Routes في لارافيل Laravel؟ كانت الإجابة المقبولة   
    السبب وراء هاته الفكرة ليس واضحا، ولكن كون المعامل الثاني الذي يستقبله التابع group عبارة عن شيفرة تنفذ executable فسيمكنك بنفس المنطق تحقيق ذلك عن طريق تعريف كامل مساراتك بشكل منفصل وحقنها كمعامل ثان في كل تعريف للنطاقين الفرعين، يكون ذلك كـ: 
    $my_routes = function() { Route::get('/home', HomeController::class); Route::get('/admin', AdminController::class); }; Route::group(array('domain' => 'app.example.com'), $my_routes); Route::group(array('domain' => 'dashboard.example.com'), $my_routes);  
  3. إجابة Adnane Kadri سؤال في ما الفرق بين إستخدام mysqli أو PDO للإتصال بقاعدة البيانات في PHP؟ كانت الإجابة المقبولة   
    بالتأكيد فإنه توجد هنالك فروقات جوهرية بين الاثنين، نذكر من بينها: 
    PDO تدعم أكثر من 12 نظام قواعد بيانات مختلف في حين ان MySQLi يمكنها العمل مع Mysql فقط.  PDO تستعمل البرمجة الكائنية التوجه في عملها في حين Mysqli توفر بجانب خيار الـ OOP واجهة اتصال بسيطة (يعرفان ب Mysqli الاجرائية و Mysqli كائنية التوجه). في هاته الناحية تعطى الافضلية ل PDO فعند تبديل نظام قواعد البيانات لن يكفي في mysqli تغيير نوع الاتصال وانما سيشمل ذلك تغيير كامل الشيفرة ومن بينها استعلامات قواعد البيانات. تعتبر PDO أفضل من ناحية تشخصي الاخطاء وتقريرها. في PDO يمكن تسمية المعاملات وعنونتها بشكل عام global بشكل يجعل من السهل التعديل عليها لاحقا اما في mysqli فلا يمكن. لـ PDO أفضلية استخدامها من قبل اغلب المجتمع البرمجي بلغة PHP، يعني هذا ان اخطاءها ومشاكلها اسهل تشخيصا وحلا مقارنة بـ MySQLi. مبدئيا، استعمال PDO سيكون أفضل بكثير، من ناحية التنفيذ والتعديل وخدمة انظمة قواعد البيانات. اما Mysqli فتعتبر افضل من ناحية التخصص، فإن كنت لا تستعمل الا اتصال MySQL دون وجود اي احتمال لتوسيع قواعد البيانات او تغيير نمطها او نظامها فسيكون استعمال MySQLi عمليا.
  4. إجابة Adnane Kadri سؤال في كيف يمكنني الحصول على صف عشوائي باستخدام Eloquent في لارافيل Laravel؟ كانت الإجابة المقبولة   
    يمكنك أيضا استعمال التابع inRandomOrder للحصول على نتيجة عشوائية من بين تجميعة نتائج كالتالي: 
    $users = User::inRandomOrder()->first(); أو كطريقة أقرب لـ SQL أكثر يمكنك ترتيب الصفوف التي تجلبها من قواعد البيانات بواسطة الدالة RAND()  منتجة استعلاما مشابها لـ: 
    select * from users order by RAND() ASC وذلك كالتالي: 
    $user = User::select("*")->orderBy(DB::raw('RAND()'))->first(); وبالطبع فإن هذا سيتطلب منك تضمين الواجهة DB قبل استعمال اي توابع لها. 
    use DB;  
  5. إجابة Adnane Kadri سؤال في كيفية التحقق من قيمة حقل checkbox في لارافيل Laravel؟ كانت الإجابة المقبولة   
    يتم استعمال القاعدة accepted بدل required لمربعات التحقق في لارافيل، يجب أن يكون الحقل قيد التحقق "true" أو "on" أو "1. يكون هذا مفيدا في حالات التحقق من الموافقة على شروط الاستخدام مثلا.
    مثال عملي: 
    $validated = $request->validate([ 'email' => 'required|unique:users', 'terms' => 'accepted', // ... ]); تعرف أكثر عن التحقق (validation) في Laravel
  6. إجابة Adnane Kadri سؤال في كيفية تعين متغير عام في الجلسة session في لارافيل Laravel؟ كانت الإجابة المقبولة   
    يمكنك توظيف فكرة الطبقات الوسيطة Middlewares لهذا الغرض. فقبل استهداف اي متحكم يتم التحقق من ما ان كانت الجلسة تحتوي على متغير باسم lang او لا، في حالة عدم وجوده يتم تعيينه بشكل افتراضي.
    نقوم أولا بإنشاء الطبقة الوسيطة الخاصة بنا عن طريق تشغيل الأمر: 
    php artisan make:middleware LanguageMiddleware يقوم هذا بإنشاء ملف جديد داخل مجلد http\middlewares ، قم بفتح الملف وقم بتعديل الشيفرة بحسب حاجتك.
    use Session; .. public function handle($request, Closure $next) { if (! Session::has('lang')) { // ان لم تحتوي الجلسة على متغير للغة Session::put('lang' ,'ar'); // نقوم بتعيين المتغير باسناد قيمة افتراضية له } return $next($request); } لا يزال علينا تعريف هاته الطبقة الوسيطة في ملف app/Http/Kernel.php في مصفوفة middleware ليتم تطبيقه على أية مسارات. ويكون ذلك كـ: 
    protected $middleware = [ \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class, \App\Http\Middleware\EncryptCookies::class, \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, \Illuminate\Session\Middleware\StartSession::class, \Illuminate\View\Middleware\ShareErrorsFromSession::class, \App\Http\Middleware\VerifyCsrfToken::class, // \App\Http\Middleware\LanguageMiddleware::class ]; الآن سيتم استهداف شيفرة التحقق السابقة كل مرة يتم فيها طلب مسار ويب.
    ان كنت تنوي تغيير لغة التطبيق عن طريق تغيير القيمة المخزنة ك lang في الجلسة فيمكنك ضبط الشيفرة بما يلائم هذا: 
    use Session; use App; .. public function handle($request, Closure $next) { if (! Session::has('lang')) { // ان لم تحتوي الجلسة على متغير للغة Session::put('lang' ,'ar'); // نقوم بتعيين المتغير باسناد قيمة افتراضية له App::setLocale('ar'); // قم بضبط لغة التطبيق وفق اللغة الافتراضية التي تريدها } else{ App::setLocale(Session::get('lang')); // في حالة توفر الجلسة على متغير يخص اللغة قم بضبط لغة التطبيق وفقه } return $next($request); } تعرف أكثر عن البرمجيّات الوسيطة (Middleware) في Laravel.
  7. إجابة Adnane Kadri سؤال في مشكلة في قائمة collapsed اطار react js كانت الإجابة المقبولة   
    يمكنك استخدام الخطاف useEffect لاستدعاء الوظيفة widthResizer المسؤولة عن اظهار واخفاء القائمة الجانبية لديك عند تركيب المكون. 
    يتم ذلك عن طريق التعديل على ملف المكون Navbar/index.js: 
    const widthResizer = () => { if(window.innerWidth > 768){ setVisible(true); }else{ setVisible(false); } } useEffect(() => { widthResizer(); }, []); window.addEventListener('resize', widthResizer); let pages = props.items; return ( .. من المهم اضافة المصفوفة التبعية الفارغة كمعامل ثان لتحميل الوظيفة عند تركيب (عمل mounting) للمكون. 
  8. إجابة Adnane Kadri سؤال في كيف يمكنني إزالة جزء من نص في PHP؟ كانت الإجابة المقبولة   
    يمكنك استعمال الدالة str_replace لاستبدال الجزء الغير مرغوب فيه في سلسلة نصية بفراغ ثم ازالة هذا الفراغ عن طريق الدالة trim. سيتبع ذلك منطقا مشابها: 
    $title = 'https://www.example.com'; $title = trim(str_replace('https://www.','',$title)); echo $title; // example.com يمكنك التعرف أكثر عن كل من: 
    الوظيفة trim الوظيفة str_replace
  9. إجابة Adnane Kadri سؤال في بديل tinymc editor بدون عمل تسجيل لكل دومين ؟ كانت الإجابة المقبولة   
    يوجد العديد من البدائل التي يمكن استعمالها لتحرير النصوص والمقالات بأحجام أقل وباستعمال مفتوح، نذكر من بينها: 
    محرر LineContro
    محرر RichText
    محرر MultiformTextEditor
    ويتم تثبيتها بشكل بسيط عن طريق استدعاءها بجانب ملفات تنسيقها وفقط، أفضل استعمال RichText لبساطته وتوفيره لأكثر المكونات المستعملة عادة. 
    هذا ويمكنك تحرير النصوص والمقالات وفق تنسيق Markdownوإعادة اخراجها لاحقال كمخرجات HTML سهلة التنسيق والتخصيص والهيكلة. يمكنك استعمال مثلا simplemde لكتابة المقالات والنصوص وفق تنسيق Markdown وحزمة markdown-it/markdown-it لتفسير ماركداون وفق HTML.
  10. إجابة Adnane Kadri سؤال في كيفية انشاء حدث باستخدام livewire كانت الإجابة المقبولة   
    بشكل عام، الطرق الممكنة التي يمكن بها استدعاء أحداث في ليفواير هي ما كالتالي:
    من داخل ملف العرض: <button wire:click="$emit('yourEventName')">  
    من ملف المكون:
    $this->emit('yourEventName');  
    من داخل سكربت جافاسكربت:
    <script> Livewire.emit('yourEventName') </script>  
    بمعنى أن استدعاءك للحدث يجب أن يكون كـ :
    <button wire:click="$emit('deleteproduct', {{$product->id}})"> كأشياء جانبية أخرى، تأكد من:
    أن الحدث deleteproduct موجود بالفعل أن الحدث deleteproduct موجود كتابع للمكون المستهدف
  11. إجابة Adnane Kadri سؤال في ملفات الخطوط والصور المستخدمة في ملفات التنسيقات لا تظهر علي الصفحة webpack كانت الإجابة المقبولة   
    يحتمل ان يكون ذلك بسبب تعارض حزمة file-loader مع احد الحزم الأخرى، وبما أنك ذكرت ملفات الخطوط والصور فيحتمل أن يكون هذا متعلقا بشكل أو بآخر بحزمة css-loader. 
    تحدث مشكلة التعارض بينهما أحيانا بسبب أن كلا من الحزمتين يقوم بمحاولة تحميل وبناء هاته الملفات واحدا تلو الآخر مما يسبب في كسر مساراتهما وبالتالي عدم عرضها رغم أن بناءها قد تم وبشكل عادي. 
    في هاته الحالة نقوم بإستعمال نسخ متوافقة مع بعضها من الحزمتين، يقترح النسخ التالية:
    "file-loader": "^6.2.0", "css-loader": "^5.0.0", يحتمل أن يكون أيضا هذا بسبب نسخة html-loader أيضا، ولذلك تأكد من تعديل هذا السطر بجانب السطرين السابقين أيضا بملف package.json لديك. 
     
    "html-loader": "^1.3.2",  
  12. إجابة Adnane Kadri سؤال في لماذا يجب استخدام Refresh token ؟ كانت الإجابة المقبولة   
    يتعلق هذا بشكل وثيق بطبيعة نوع آخر من رموز token هو رمز الوصول access token. 
    عندما يقوم المستخدم بتسجيل الدخول، يصدر خادمنا رمز وصول، وهو بشكله البسيط رمز أو سلسلة نصية تستعمل للوصول إلى خادم الواجهة البرمجية API. فعندما يحتاج العميل إلى الوصول إلى الموارد المحمية على الخادم، فإن هذا الرمز يسمح له بذلك. من هذا المنطق، يجب أن تخضع هاته الرموز إلى قواعد حماية عالية.
    من بين استراتيجيات الأمان توجد تلك التي تنص على إنشاء رموز وصول ذات عمر قصير، بمعنى أنها صالحة فقط لفترة قصيرة محددة من حيث الساعات أو الأيام. وبالتالي فإن العميل يحتاج دوما امتلاك رموز وصول غير منتهية الصلاحية.
    من بين طرق إنتاج رمز وصول جديد، يوجد طريقة التحديث عن طريق إنشاء رمز تحديث للعميل يتيح له استبدال رمز وصول منتهي الصلاحية بآخر جديد. هذا الرمز هو ما يعرف بـ refresh token. يعني هذا أن العملاء لن يجبروا على إعادة تسجيل الدخول وكل عملية التحديث ستحدث خلف الكواليس. 
    وفيما يلي طريقة عمله وكيفية حمايته للموارد:
    يطلب العميل رمز وصول عن طريق المصادقة مع خادم نسميه خادم الترخيص Authorization Server وهو جهة أو خدمة أو واجهة في واجهتنا الخلفية تقوم بتولي عمليات الترخيص والتوثيق وتوليد رموز الوصول.  يقوم خادم الترخيص بمصادقة العميل والتحقق من صحة منح الترخيص، فإذا كان صالحًا ،يقوم هذا الخادم بإصدار رمز وصول ورمز مميز للتحديث. يقوم العميل بتقديم طلب مورد محمي إلى خادم يخزن المورد نسميه خادم المورد Resource Server من خلال تقديم رمز وصول access token. هذا الخادم هو جهة أو خدمة أو واجهة في واجهتنا الخلفية تقوم بتولي عمليات تقديم الموارد وعرضها وإدارتها. يتحقق خادم المورد Resource Server من رمز الوصول Access token، وإذا كان صالحًا، فإنه يخدم الطلب. يتم تكرير الخطوتين 3 و 4 حتى تنتهي صلاحية رمز الوصول. في حالة انتهاء صلاحية رمز الوصول، يقوم خادم المورد Resource Server بإرجاع خطأ رمز غير صالح. في هاته الحالة يطلب العميل رمز وصول جديد من خلال المصادقة مع خادم الترخيص  Authorization Server وتقديم رمز التحديث إليه. يقوم خادم الترخيص Authorization Server بمصادقة طلب العميل والتحقق من صحة رمز التحديث، وإذا كان صالحًا، فإنه يصدر رمز وصول جديد. وهكذا..  تنبيه بشأن خطأ في الصورة: رمز وصول وليس رمز توصيل.
     
  13. إجابة Adnane Kadri سؤال في ما سبب تجاوز العناصر للمحور الأفقي في حاوية مرنة عند استعراض الموقع في شاشات أقل عرضا؟ كانت الإجابة المقبولة   
    من غير المنطقي أن يتم إخفاء العناصر على المحور X في حاوية مرنة (display:flex) مرفقة بالقيمة wrap في الخاصية flex-wrap، فأي عنصر يحمل عرضا لا يكفي سيتم إنزاله للسطر الثاني وهكذا. 
    أظن أن المشكلة بالضبط هي في تهيئة المتصفح لتفسير الصفحة على عرض معين. إذ تحدث المشكلة أحيانا عند الانتقال من عرض 1 الى عرض 2 مباشرة في المتصفح دون انتقالة بين العرضين. فعندما نقوم مثلا باستعراض عنصر ما عن طريق Inspect ثم نقوم بتغيير العرض الى عرض معين (وليكن 307px) ثم نغلق شاشة الاستعراض. ونقوم مباشرة باستعراض العنصر مرة ثانية فسيحافظ المتصفح على العرض الذي استعرضت به العنصر سابقا ويظهر لك مباشرة 307 في شاشة الاستعراض. وبسبب الانتقالة من عرض الشاشة كاملة الى العرض 307 دون تدرج يحدث أن لا يستجيب المتصفح لهاته الانتقالة وتظهر وكأنها غير متجاوبة. وقد تأخذ من البعض ساعات وساعات وهو يحاول ضبط التجاوبية ولكن دون فعالية. وهذا ما حدث معك ببساطة. 
    وكدليل عن ذلك، لاحظ أن حتى شريط التنقل الخاص بموقع CodePen لا يظهر بشكل متجاوب أثناء عمل هاته الانتقالة مباشرة. 

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

    النتيجة: 

     
  14. إجابة Adnane Kadri سؤال في افضل طريقة لتخزين Token كانت الإجابة المقبولة   
    بشكل عام، تتباين طرق تخزين رموز المصادقة بين: التخزين المحلي LocalStorage، تخزين الجلسة SessionStorage أو التخزين عن طريق ملف تعريف الارتباط Cookies.
    يتم عادة وضع رموز التوثيق في تخزين الويب Web Storage للمتصفحات، والذي يعمل بشكل ممتاز في أغلب حالات الاستعمال. وبشكله المجمل. ويحوي هو ذاته طريقتين تشتركان في حيث أنهما يستعملان مساحة تخزين المتصفح: 
    التخزين المحلي  localStorage: حيث أن البيانات تبقى مخزنة حتى يتم حذفها اما يدويا أو عن طريق جافاسكربت التطبيق. تخزين الجلسة sessionStorage: أين يتم حفظ التغييرات التي تم إجراؤها وإتاحتها للصفحة الحالية فقط، وبمجرد إغلاق النافذة، يتم حذف التخزين. من بين عيوب هاته الطريقة:
    على عكس ملفات تعريف الارتباط، يتم تضييق نطاق الوصول للبيانات المخزنة محليا في نطاق معين ولا يمكن الوصول إلى هاته البيانات من قبل أي نطاق آخر بما في ذلك النطاقات الفرعية، ولذلك فإن تخزين الويب ليس خيارا جيدا ان كنت تستعمل نطاقات فرعية. يمكن الوصول إلى مساحة تخزين الويب من خلال JavaScript في نفس المجال، لذا فإن أي سكربت JavaScript يعمل على موقعك سيكون له حق الوصول إلى مساحة تخزين الويب، قد يسبب هذا هجمات البرمجة النصية عبر المواقع (XSS أو Cross Site Scripting). الطريقة الأخرى للتخزين هي في استخدام ملفات تعريف الارتباط. وتتميز بأن لها عمر يمكن التحكم فيه عن طريق التالي:
    يمكن تدمير ملفات تعريف الارتباط بعد إغلاق المتصفح (ملفات تعريف ارتباط الجلسة session cookies). كما يمكن أن تكون ملفات تعريف الارتباط دائمة (لا يتم إتلافها بعد إغلاق المتصفح) مع انتهاء الصلاحية. يمكن قراءة ملفات تعريف الارتباط بواسطة كل من JavaScript وجانب الخادم (في حالة Node مثلا). من بين عيوب هاته الطريقة: 
    لملفات تعريف الارتباط حجم أقصى لا يمكن تجاوز (4 كب)، ولذلك فإن هاته الطريقة قد تسبب بعض المشاكل أحيانا. يمكن أن تكون ملفات تعريف الارتباط عرضة لهجمات طلب التزوير عبر المواقع (CSRF أو XSRF). إذا كنت تستخدم ملفات تعريف الارتباط، سيقوم المتصفح تلقائيًا بإرسال معلومات المصادقة مع كل طلب إلى الخادم. أما إذا كنت تستخدم تخزين ويب فيجب عليك كتابة الأمر الذي يدير بالضبط معلومات المصادقة التي يتم إرسالها إليه. كأن ترسلها في الـHeaders أو كمعامل في طلبات GET أو POST.
    في الأخير، يجب معرفة أن ما يجب الاهتمام به بأكبر قدر هو كيفية تخزين رمز التوثيق على الخادم وكيفية التعامل مع الطلبات التي يستقبلها الخادم من العميل لأن الخادم هو ما يتحكم في كيفية تسيير هذا الأمر، وان قام الخادم بتغطية كامل هاته الاعتبارات فلن تختلف الطريقة والأخرى كثيرا. على أن الشائع والمفضل لدى أغلب المطورين التخزين المحلي في تخزين الويب localStorage لما له من أفضلية من ناحية سهولة التعامل معه. 
    اقرأ أيضا:
    التخزين المحلي (Local Storage) في HTML5 ملفات تعريف الارتباط وضبطها في جافاسكربت
  15. إجابة Adnane Kadri سؤال في العمل على شيفرة PHP لاخفاء و إظهار حقول بناء على الخيار المحدد من قائمة منسدلة كانت الإجابة المقبولة   
    إن كنت تحاول إظهار مجموعة حقول بناء على الخيار الذي يحدده المستخدم من قائمة خيارات المنسدلة فهذا تلاعب في شجرة الوثيقة ومن مستحيل عمل ذلك بدون الجافاسكربت ﻷن جافاسكربت وجدت لدعم هاته التفاعليات والتلاعبات.
    مثال: 
    اذا قام المستخدم بتحديد خيار جواز سفر يتم إظهار حقلي رقم جواز السفر ورقم التأشيرة.  ولذلك فإن العملية نظريا وعمليا مستحيلة بالإستغناء عن جافاسكربت، وما يقوم به صاحب الشيفرة في الرابط المرفق هو ليس تلاعبا في شجرة الوثيقة بعد تحميل موارد الصفحة، بل هو ضبط شرطي للإعدادات الإفتراضية التي تكون عليها قائمة الخيارات. 
    مثال: 
    لنقل أن مستخدما ما يريد تعديل حالته من "صاحب شركة ناشئة" إلى "عامل حر". بعد أن يتوجه هذا المستخدم إلى صفحة التعديل نحتاج افتراضيا ضبط الخيار الافتراضي الذي قام بتحديده سابقا.  وبالتالي فإننا قبل أن نضع خاصية selected على أي من الخيارات، نحتاج إضافة شرط تطابق قيمة الخيار مع حالة المستخدم:
    <select name="userStatus"> <option value="startup" @if($user->status == 'startup') selected @endif>شركة ناشئة</option> <option value="freelancer" @if($user->status == 'freelancer') selected @endif>عامل حر</option> </select> وهذا ببساطة إستعمال من بين العديد من الإستعمالات التي تجهمعها الشيفرة الموضحة. 
    في حالة ما أردت القيام بذلك بـ PHP فقط فيمكنك كاقتراح عمل ثلاث صفحات تحتوي ثلاث نماذج حيث: 
    الصفحة الأولى تحوي نموذجا يتم من عليه اختيار نوع العميل.  تستقبل الصفحة الثانية خرج الصفحة الأولى وتقوم بعرض القائمة المنسدلة التالية: @foreach ($formhandler['guest_form_types[citizen]'] as $guest_type => $value) echo '<option value=' {{$guest_type}} '>' {{$value}} '</option>' @endforeach تستقبل الصفحة الثالثة خرج الصفحة الثانية وتقوم بعرض حقلي جواز السفر ورقم التأشيرة بناء على النتيجة المستقبلة. 
  16. إجابة Adnane Kadri سؤال في ما معنى POLICY و FORM REQUESTES في أوامر انشاء النماذج والمتحكمات وجداول التهجير في لارافيل كانت الإجابة المقبولة   
    يعتبر كل من اللواحق المضافة للأوامر خيارات يتم تطبيقها أثناء تنفيذ الأمر. ومن بين الخيارات التي يقبلها الأمران:
    php artisan make:model ModelName الخياران policy-- و request--
    حيث أن الخيار policy يقوم بإنشاء صنف سياسة policy جديد. السياسات هي تصنيفات تنظم منطق الترخيص حول نموذج أو مورد معين. على سبيل المثال، إذا كان تطبيقك عبارة عن مدونة، فقد يكون لديك نموذج منشور Post وسياسة PostPolicy مقابلة لترخيص عمليات المستخدم مثل إنشاء أو تحديث المنشورات، حيث يحوي هذا الصنف كامل عمليات الترخيص بشأن كل تابع أو كل وظيفة.
    مبدئيا ، يمكن إنشاء سياسة ما عن طريق الأمر:
    php artisan make:policy PostPolicy أو يمكن ربطها بملف النموذج عن طريق الأمر:
    php artisan make:policy PostPolicy --model=Post أو عن طريق إضافتها كلاحقة خيار في أمر إنشاء النموذج:
    php artisan make:model ModelName --policy ليقوم هذا بإنشاء صنف نموذج وصنف سياسة مقابل له.
    الخيار الآخر الذي يقبله أمر إنشاء النموذج هو خيار requests-- . يتم عن طريق تخصيص هذا الخيار إنشاء صنفي طلبيات Request يخصان عملية التحديث والإنشاء بداخل مجلد app\requests.  أصناف الطلبيات في لارافيل هي نسخ عن الصنف Request قابلة للتخصيص تحتوي على منطق يمكن عن طريقه التحقق من سلامة الطلبيات وتوثيقها.
    يمكنك التعرف أكثر عن الطلبيات في:
    قد تحتاج مراجعة التحقق في لارافيل > التحقّق من صحّة طلب استمارة > إنشاء طلبات الاستمارة.
    و الترخيص في لارافيل > إنشاء السياسات.
  17. إجابة Adnane Kadri سؤال في لماذا يتم إنشاء صنف طلب مخصص هنا ولا يتم إستعمال الصنف العام Request مباشرة؟ لارافيل كانت الإجابة المقبولة   
    لعلك لم تنتبه إلى أحد الأوامر المهمة في لارافيل أثناء استعراض الأوامر التي يوفرها artisan عن طريق طباعة.
    php artrisan هذا الأمر هو:
    php artisan make:request CustomRequest إذ يتيح هذا الأمر إمكانية إنشاء صنف يرث Request ويحمل صفاته الأساسية ويوفر إماكانية تغيير أشياء من مثل قواعد التحقق Validation أو غيرها. وهو أحد الأمور التي أحب العمل بها في لارافيل. 
    يقوم الأمر 
    php artisan make:request CustomRequest بإنشاء ملف CustomRequest.php داخل app\http\requests، يحمل افتراضا:
    تابعا rules يقوم بإعادة مصفوفة بكامل قواعد التحقق validation بشأن طلبية Http  /** * Get the validation rules that apply to the request. * * @return array */ public function rules() { return [ ]; } تابعا authorize يقوم بتحديد ما ان كان من المسموح قبول هاته الطلبية:
    /** * Determine if the user is authorized to make this request. * * @return bool */ public function authorize() { return false; } نقوم بتضمين هذا الصنف في أحد ملفات المتحكمات كالتالي:
    use App\Http\Requests\CustomRequest; ثم نقوم بإستقبال نموذج عنه في التابع المستهدف بطلبية ما، مثال: إذا كان الرابط: 
    POST http://path.to/api/users يستهدف التابع store من المتحكم UserController بطلبية Http، فإن هذا التابع يستقبل معاملا request من الصنف CustomRequest كالتالي:
    public function store(CustomRequest $request){ } ثم سيمكن إستعمال أي من الخواص أو التوابع التي يقدمها الصنف مباشرة. ولنقل أننا نريد استخراج البيانات المتحقق منها من الطلب فقط:
    public function store(CustomRequest $request){ $data = $request->validated(); } في حين أن CustomRequest هو من سيضم قواعد التحقق كالتالي:
    public function rules(){ return [ 'username' => 'required|max:8', 'password' => 'required|min:10', 'extra_data' => 'nullable', ]; } أليست الفكرة أفضل من هذا الشكل:
    public function store(Request $request){ $data = $request->validate([ 'username' => 'required|max:8', 'password' => 'required|min:10', 'extra_data' => 'nullable', ]); } ثما ماذا لو أردنا إضافة التحقق من صلاحية المستخدم في إنشاء مورد جديد: 
    public function store(Request $request){ if(auth()->user()->is_able_to_store_user) { $data = $request->validate([ 'username' => 'required|max:8', 'password' => 'required|min:10', 'extra_data' => 'nullable', ]); } } تخيل أن الأمر سيمتد لتصبح حتى قراءته مزعجة.
    فيما يلي مجموعة من الميزات التي تجعلك تنشئ أصناف طلببيات خاصة:
    كون الطلبيات تختلف فيما بينها يجعل الحاجة إلى معالجتها بشكل منفصل شيء مهم.  يقتضي فصل الطلبيات عن المتحكمات اثنين من أهم مبادئ REST لتصميم واجهات تطبيق برمجية فعالة ومميزة. مبدأ فصل المهام الذي يقتضي فصل مكونات التطبيق عن بعضها البعض، فكل صنف أو تابع يجب أن يحوي وظيفة واحدة. وفكرة أن تابعا ما يقوم هو بعملية التحقق والتوثيق والإستعلام من قواعد البيانات والرد فكرة غير محببة كثيرة ويتطلب فصل مكوناتها.. هذا وبجانب أنه يحترم أيضا مبدأ نظام الوسطاء بتوسطه بين طلبية العميل وواجهة المتحكم وعدم تركهما يتفاعلان بصفة مباشرة.  يحقق إستعمال أصناف طلبيات مخصصة الكثير من مبادئ الشيفرة النظيفة التي تجعل الشيفرة الخاصة بك قابلة للقراءة والتعديل والتخصيص على شكل واسع.  يقوم إنشاء طلبيات مخصصة بإتاحة إمكانية جعل جميع الوظائف المماثلة تستند إلى نفس قواعد التحقق والتوثيق الخاصة بطلب واحد، وذلك بدلا عن إنشاء واحد لكل منها. بمعنى، أنه لو كنا نقوم بإنشاء مستخدم جديد في التابع store الخاص بالمتحكم UserController وأيضا في التابع store للمتحكم AdminController وتابع آخر في متحكم آخر، سيصبح لدينا الكثير من الشيفرة المتشابهة والمكررة في كل منها، فسنحتاج أن نكتب قواعد التحقق لكل تابع في كل متحكم، وأن نتحقق من صلاحية الطلبية في كل تابع من كل متحكم وهكذا.. هذا بجانب أن الأمر يصبح صعب التعديل لاحقا، ماذا لو قمت بإضافة عمود جديد في قواعد البيانات وأردت تعميم قاعدة التحقق الخاصة به على كامل الطلبات؟  بدلا عن كل هذا يتيح إنشاء صنف مخصص توحيد كل تفاصيل هاته الطلبيات. وبدل أن تبدوا متحكماتك كالتالي:  public function update(Request $request, User $user){ if(auth()->user()->is_able_to_update_user){ $validator = Validator::make($request->all(), [ 'username' => 'required|max:8', 'password' => 'required|min:10', 'extra_data' => 'nullable', ]); if($validator->fails()) { return back()->withErrors($validator); }else{ $data = $validator->validated(); $user->update($data); return back()->with('success' ,'تم !'); } }else{ return back()->with('unauthorized' ,'غير مسموح لك !'); } } ستبدوا كـ:
    public function update(UpdateUserRequest $request, User $user){ $user->update( $request->validated() ); return back()->with('success' ,'تم !'); } مقسمة إلى:
    // UpdateUserRequest.php <?php /** * Determine if the user is authorized to make this request. * * @return bool */ public function authorize() { return auth()->user()->is_able_to_update_user; } /** * Get the validation rules that apply to the request. * * @return array */ public function rules() { return [ 'username' => 'required|max:8', 'password' => 'required|min:10', 'extra_data' => 'nullable', ]; }  
    وهذا ما تم العمل به في المقال الذي قمت بإرفاقه، وبالتالي فإن عليك بدل تضمين كامل الواجهات التي يقوم صاحب المقال بتضمينها أن تقوم بإنشاء صنف Request المخصص الخاص بك وإستدعاءه متى طلبت الحاجة. 
    تتحدث هاته المقالة عن أفضل التطبيقات وأساسيات التحقق من المدخلات في لارافيل، يوجد من بينها طريقة إنشاء أصناف طلبيات مخصصة: 
     كما يمكنك الإطلاع على التوثيق الرسمي لكامل ما يخص التحقق في لارافيل هنا.
     
  18. إجابة Adnane Kadri سؤال في تبسيط إطار عمل لارافيل نظريًا أو شرحه موجزًا كانت الإجابة المقبولة   
    العناصر التي ذكرتها لم يأت بها لارافيل أو اخترعها، بل قد كانت مجموعة مفاهيم تقنية شائعة جمعها ولخصها و جاء بها كمميزات، فلارافيل ليس إلا مجموعة شيفرات جاهزة تجعل التطوير عليه أسهل وأكثر وضوحا مما هو عليه في PHP بتوفير مجموعات من الأصناف والتوابع والمساعدات والملفات التي تخدم غرضا أو مفهوما معينا، وفيما يأتي مجموعة المفاهيم الأساسية:
    التهجير
    بشكلها العام تعرف عمليات تهجير قواعد البيانات على أنها عملية ترحيل البيانات من قاعدة بيانات مصدر واحدة أو أكثر إلى قاعدة بيانات هدف واحدة أو أكثر. فعند الانتهاء من هذا الترحيل ، تتواجد مجموعة البيانات في قواعد البيانات المصدر بالكامل على الرغم من نشاطها في القاعدة الهدف. وعلى الرغم من احتمال إعادة هيكلتها في قواعد البيانات الهدف. 
    لارافيل هو نفسه أيضا يستعمل هذا المفهوم ويقوم بتوفير طريقة لإنشاء هياكل قاعدة بيانات مصدر وبأمر بسيط ترحيلها إلى قاعدة بيانات هدف والحفاظ على هيكلة قواعد البيانات الأساسية.
    تشبه عمليات التهجير في لاراففيل نظم التحكم في الإصدار لقاعدة البيانات الخاصة بك، بشكل يجعل فريق قادرا على تعديل مخطط قاعدة بيانات التطبيق ومشاركته بكل سهولة. فلو أردت مثلا بعد عام من نشاط موقعك من إضافة عمود إلى جدول المستخدمين سيمكنك إنشاء ملف تهجير جديد.
    النموذج Model ، العرض View و المتحكم Controller
    يعرف نمط الـ MVC كنمط تصميم Design Pattern، أي أنه أقرب الى أن يكون اسلوب برمجة وليس برمجة في حد ذاتها، ينطلق من مبدأ فصل المهام concerns separation ليقوم بفصل كل من:
    مكونات النموذج Model: تضم كل المنطق المتعلق بالبيانات الذي يعمل به المستخدم وتفاعلها معها. على سبيل المثال ، استرداد البيانات من قاعدة البيانات ، ومعالجتها وتحديثها.  مكونات العرض View: وهي مجموع المكونات التي يتم فيها تمثيل البيانات وعرضها للمستخدم والتفاعل معها. مكونات المتحكم Controller: وحدات التحكم كواجهة بين مكونات النموذج والعرض لمعالجة جميع الطلبات الواردة ، توثيقها وفحصها. ومعالجة البيانات باستخدام مكون النموذج والتفاعل مع طرق العرض لتقديم الخرج النهائي، أي أنها المكون الأساسي في العملية فهي المنسق بين مكونات العرض و النماذج.  لارافيل يستعمل هذا النمط في تفصيل اهتماماته أيضا، ويوفر لنا ثلاث أنواع من المكونات تتكامل فيما بينها. 
    التوجيه Routing
    بشكل عام، التوجيه هو عملية تحديد المسار في شبكة أو بين شبكات متعددة أو عبرها.
    والتوجيه في لارافيل هو ليس إلا طريقة تسمح لك بتوجيه جميع طلبات التطبيق إلى وحدة التحكم المناسبة لكل طلب.
  19. إجابة Adnane Kadri سؤال في الفرق بين env المحلية و config vars في heroku كانت الإجابة المقبولة   
    في هيروكو، أي متغيرات تخص البيئة يجب إضافتها إلى قسم إعداد المتغيرات ليتم العمل بها لأن ملف البيئة env. متجاهل افتراضا من عليها.
    للإجابة على سؤالك الثاني بشأن تجاهل ملف التهجير يجب أولا فهم طريقة لارافيل والمنطق وراء تعقب ملفات التهجير وتطبيقات الشيفرات داخلها حتى يمكن تحديد المشكل بالضبط.
    تحمل ملفات التهجير في لارافيل الأسماء على النحو التالي: 2021_12_03_100000_create_users_table  
    يتم تقطيع سلسلة الاسم النصية إلى 7 أجزاء كالتالي:
    2021 12 03 100000 create users table  
    يتم اقتطاع الأربع أجزاء الأولى الممثلة بتاريخ إنشاء ملف التهجير ليتبقى:
    create users table  
    يتم إعادة تشكيل السلسة النصية و كتابة الأحرف الأولى كأحرف كبيرة كالتالي:
    CreateUsersTable  
    يكون هذا هو اسم الصنف الموجود داخل ملف التهجير، ولارافيل تقوم بكل هذا عند إنشاء ملف تهجير عن طريق الأمر: 
    php artisan make:migration create_users_table أو عند إنشاء ملف نموذج:
    php artisan make:model -m تحدث أحيانا مشكلة تجاهل ملف التهجير هاته عند إنشاء الملفات يدويا أو تعديل أسماءها لاحقا، ويكون ذلك عن الإخلال بترتيب أو خطأ بخصوص توافق اسم ملف التهجير مع الصنف المحتو فيه مثل: وضع تاريخ الإنشاء آخرا، وهذا في الأرجح ما حصل معك. 
    وبالتالي يجب دوما عند إنشاء ملفات التهجير يدويا مراعاة القواعد التي يستعملها لارافيل في استخراج الأصناف المستهدفة من الملفات.
    [year]_[month]_[day]_[HHMMSS]_[action]_[tableName]  حل آخر يقدمه لارافيل، هو في إنشاء ملفات التهجير المجهولة التي لا يتطلب اسم ملفها مراعاة لقواعد التسمية في لارافيل. إذ يمكنك تسمية هذا الملف وفق ما تشاء بشرط أن يحتوي التعريف التالي داخله:
    <?php use Illuminate\Database\Migrations\Migration; return new class extends Migration { // }; تعرف أكثر عن تهجير قواعد البيانات (migrations) على Laravel.
  20. إجابة Adnane Kadri سؤال في تحويل ip الزائر الى اسم الدولة كانت الإجابة المقبولة   
    أظن أنك الأدرى بما ستحتاج الإستغناء عليه أو لا، ولكن بشكل عام لا أظن أنه هنالك حاجة من أسطر التحقق:
    if (filter_var($ip, FILTER_VALIDATE_IP) && in_array($purpose, $support)) { فالواجهة تقوم بعمل ذلك بدلا عنك، وفي حالة عدم صلاحية هذا العنوان فلن يتم إعادة أي رد. خصوصا وأنك لا تقوم بخزن هذا العنوان إلا بعد إستلام الرد. 
    ولا من هذا الشرط أيضا: 
    if (@strlen(trim($ipdat->geoplugin_countryCode)) == 2) {  فكامل الcountry codes مميزة بمحرفين ولا حاجة للتحقق من ذلك. 
    أما باقي الشيفرة فجيدة.
  21. إجابة Adnane Kadri سؤال في ما الخطأ في إستعلام CHECK لدي ؟ كانت الإجابة المقبولة   
    يحددث هذا بسبب أن لديك خطأ في السياق العام لإضافة إستعلام قيد CHECK ، فالشكل العام لإستعماله يكون كالتالي : 
    ALTER TABLE [table_name] ADD CONSTRAINT [check_name] CHECK ([column_name] IN ('check1', 'check2', 'check3' ... )); حيث أن : 
    table_name : يعبر عن اسم الجدول الحاوي للعمود المستهدف .  check_name : يعبر عن اسم القيد الذي تحاول إضافته .  column_name : يعبر عن اسم العمود المستهدف .  ما داخل القوسين يعبر عن القيد و شرطه . ففي المثال الذي لديك يجب أن يوجد كالتالي : 
    ALTER TABLE orders ADD CONSTRAINT size_check CHECK (size IN ("s", "e", "l", "xl")); ليصبح كامل الإستعلام كالتالي : 
    ALTER TABLE ADD COLUMN size varchar(255); ALTER TABLE posts ADD CONSTRAINT size_check CHECK (size IN ("s", "e", "l", "xl"));  
  22. إجابة Adnane Kadri سؤال في ما هي عيوب استخدام بوتستراب؟ كانت الإجابة المقبولة   
    بشكل عام ، إستعمال بوتستراب ليس به أي عيوب إن كنت تحبذ نمطا معينا للتصميم فيه و لكنك ستواجه أحد هاته العيوب في حالات أخرى : 
    ستكون هناك حاجة إلى الكثير من تجاوز الشيفرات و إعادة كتابة الملفات أو إعادة تعيين بعض التنسيقات التي يمكن أن تؤدي إلى قضاء الكثير من الوقت في تصميم موقع الويب وترميزه إذا كان التصميم يميل إلى الانحراف عن التصميم المعتاد المستخدم في Bootstrap ، أي أنه سيتعين عليك بذل جهد إضافي أثناء إنشاء تصميم وإلا ستبدو جميع مواقع الويب التي تقوم بهاا متشابهة إذا لم تقم بإجراء عمليات تخصيص كبيرة.
    الأصناف التي يوفرها بوتستراب كثير ويمكن أن تؤدي إلى الكثير من العبث في HTML وهو أمر غير مطلوب دوما و قد يتعارض مع مفاهيم الشيفرة النظيفة في بعض الأحيان . 
    نسخ متأخرة من بوتستراب معتمدة كليا على jQuery و Pooper ، مما يترك معظم الشيفرات الإضافية غير مستخدمة ، وهو أمر اخر يتعارض مع مفاهيم الشيفرة النظيفة بجانب أنه قد يؤخر تحميل الصفحات إن كانت سرعات التحميل لدى عملائك أو أغلبهم بطيئة . 
    لكن هذا لا يمنع بالطبع من إمتلاك الكثير من الإيجابيات التي يمكن أن تجعلك تغفل أو تتقبل هاته السلبيات ، نذكر من بينها : 
    كونه يساعدك على تجنب العديد من الأخطاء التي يمكن أن تظهر أثناء تعميم الخواص على المتصفحات . فعلى سبيل المثال : لا نقوم بتخصيص صنف لـ google chrome و اخر لـ IE ، بل نجد أن بوتستراب يوفر صنفا واحدا جامعا يتعامل به بوتستراب مع كامل التغيرات بين المتصفحات .  بجانب أنه يعتمد على jQuery فهو أيضا يجنبك إستعمال الكثير من إضافات الجيكويري أو تضمين المكتبات المعتمدة عليها لخدمة أغراض معينة .  يساعدك في الحصول على عمل و يضمن لك مكانا في سوق العمل ، إذ أن بوتستراب واحد من أكثر الأدوات المطلوبة في سوق العمل .  يقدم Bootstrap نظام تخطيط شبكي Grid system رائع ، يختصر عليك هذا الكثير من الجهد و الشيفرات الإضافية .  التجاوبية ، فأغلب حاويات بوتستراب تجاوبية و مرنة مع كل الشاشات ، هذا بجانب أنه يوفر أصنافا خاصة بكل نوع من الشاشات .  يوفر الوقت ، فبوتستراب يحرص على توفير أغلب -إن لم نقل كل- ما تحتاجه لتصميم موقع الويب الخاص بك . 
      أما عن تفضيلك لنظام التخطيط الشبكي grid system عن نمط الصندوق المرن flexbox فهو شيء طبيعي جدا ، ولا مشكلة بذلك إن كان إستخدامه أفضل و أكثر مرونة بالنسبة لك . 
    قد تحتاج الإطلاع على العلاقة بين الخطاطة الشبكية Grid Layout وبين طرق التخطيط الأخرى .
  23. إجابة Adnane Kadri سؤال في cURL error 60: SSL certificate problem كانت الإجابة المقبولة   
    طبقا للتوثيق الرسمي لمرجع أخطاء مكتبة libcurl  المشار إليه في نص الخطأ فإن الخطأ cURL error 60 يعني أنه قد تم اعتبار شهادة SSL للخادم الذي تحاول إرسال الطلب من عليه غير مقبولة . 
    قد تتعدد أسباب رفضها ، و لكن إشارتك للتالي :
     توضح أنه لا يمكنك إرسال طلب موثق بشهادة SSL لأنك في الغالب تستعمل localhost ، و ليكن في العلم أنه لا يحتوي على هاته الشهادة افتراضا . 
    لا أظن أن بالأمر مشكلة كونك تقوم بتجربة الواجهة التي تستهدفها عن طريق خادمك المضيف . و لكن يقترح كحل لهاته المشكلة إضافة SSL صالح للمضيف المحلي لـ XAMPP كونك تقوم بإرسال هاته الطلبات بإستخدام أو بوساطة cURL . 
  24. إجابة Adnane Kadri سؤال في هل يجب تعلم CSS و HTML لإنشاء تطبيقات أندرويد؟ كانت الإجابة المقبولة   
    أظن أن سؤالك متشعب كثيرا , إذ أن " تعلم HTML و CSS كمطور تطبيقات أندرويد "  يعتمد بالدرجة الأولى على نهجك في تطوير هاته التطبيقات . فإذا كنت تقوم بتطوير تطبيقات الـ Android بإستعمال تقنيات هجينة من مثل ReactNative أو Cordova ، فستحتاج بالطبع إلى معرفة HTML و CSS لأنها تستخدم ذلك في مضمونها . 
    و لكن إذا كنت تقوم بالتطوير أصليًا بإستعمال Java و XML ، فأنت لن تحتاج ذلك . 
    أما عن كونك مشترك في دورة تطوير التطبيقات بإستخدام Javascript فأظن أن معرفة بأساسيات اللغتين ستكون كافية جدا . 
  25. إجابة Adnane Kadri سؤال في ظهور محتوى وسم meta الوصف في رأس الصفحة كنص في المتصفح كانت الإجابة المقبولة   
    قد أحسنت , هاته الطريقة عملية جدا . وذلك لكون هاته المعلومات معلومات وصفية . أي أنها لا يجدر أن تظهر في الصفحة و إنما لأغراض أخرى مثل تحسين محركات البحث أو تحسين الظهور . 
    فعوضا عن طباعة HTML يقترح فلترة المحتوى و استخراج النصوص من محتوى الـ html فقط .
    خصوصا في حالات من مثل الحاجة إلى هذا الحقل في أغراض أخرى , مثال : 
    وجود حقل واحد للمقالة و لوصف صفحة المقالة في جدول المقالات في قواعد البيانات .   أي أن كل محتوى كالتالي : 
    <p style="text-align:center;"> هاته فقرة تخص وصف الصفحة </p> <h2> هذا عنوان يخص وصف الصفحة أيضا</h2> يصبح : 
    هاته فقرة تخص وصف الصفحة هذا عنوان يخص وصف الصفحة أيضا ليمكن إستيعابها في الخاصية content كالتالي : 
    <meta name="description" content=" هاته فقرة تخص وصف الصفحة هذا عنوان يخص وصف الصفحة أيضا" > مما يعني أنه هذا لن يسبب المشكلة السابقة .
    يمكنك إنشاء دالة للفلترة و تحويل كل محتوى html إلى محتوى نصي بمنطق مشابه : 
    $text = '<p style="text-align"> هاته فقرة </p> <h2> هذا عنوان </h2>'; $cleaner_input = strip_tags($text); echo $cleaner_input; وهو نفس ما اقترحته سابقا . 
×
×
  • أضف...