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

Mustafa Suleiman

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

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

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

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

    495

كل منشورات العضو Mustafa Suleiman

  1. كل شيء كما هو، فقط استبدل الكود بداخل كتلة الشرط if ($_SERVER["REQUEST_METHOD"] == "POST")
  2. عليك جلب التاريخ start_date من جدول employees وتاريخ الميلاد و الجنس من people، ثم حساب العمر وسنوات الخدمة فى نفس لحظة تقديم الطلب، ثم أضف التحقق من الرصيد المستحق أو الحد الأقصى لكل نوع إجازة، ومن شرط 15 يوم المتصلة فى السنة، ومنع طلب أيام أكثر من المسموح أو أقل من المطلوب. بدل الجزء التالي لديك في الكود داخل if ($_SERVER["REQUEST_METHOD"] == "POST") : if ($_SERVER["REQUEST_METHOD"] == "POST") { $emp_id = (int)$_POST['emp_id']; $type = $_POST['type']; $start_date = $_POST['start_date']; $end_date = $_POST['end_date']; $reason = $_POST['reason']; $companion = isset($_POST['companion']) ? 1 : 0; $created_at = date('Y-m-d H:i:s'); $errors = []; if (!$type) $errors[] = 'يجب تحديد نوع الإجازة'; if (!$start_date) $errors[] = 'يجب إدخال تاريخ بداية الإجازة'; if (!$end_date) $errors[] = 'يجب إدخال تاريخ المباشرة'; if ($end_date <= $start_date) $errors[] = 'تاريخ المباشرة يجب أن يكون بعد بداية الإجازة'; if ($errors) { echo implode('<br>',$errors); exit; } $stmt = $con->prepare("SELECT e.start_date , p.birth_date , p.gender FROM employees e JOIN people p ON p.id = e.person_id WHERE e.person_id = ?"); $stmt->bind_param("i",$emp_id); $stmt->execute(); $stmt->bind_result($hire_date,$birth_date,$gender); if(!$stmt->fetch()){ echo 'لم يتم العثور على بيانات الموظف'; exit; } $stmt->close(); $stmt = $con->prepare("SELECT COUNT(*) FROM vacations WHERE emp_id = ? AND accept = 0"); $stmt->bind_param("i",$emp_id); $stmt->execute(); $stmt->bind_result($pending); $stmt->fetch(); $stmt->close(); if($pending){ echo 'هناك إجازة قيد الإجراء لهذا الموظف.'; exit; } $start = new DateTime($start_date); $end = new DateTime($end_date); $requested_days = $start->diff($end)->days + 1; $current_year = (int)$start->format('Y'); switch ($type) { case 'اجازة سنوية': $to = new DateTime($end_date); $age = $to->diff( new DateTime($birth_date) )->y; $service_years = $to->diff( new DateTime($hire_date) )->y; $annual_quota = ($age >= 50 || $service_years >= 20) ? 45 : 30; $stmt = $con->prepare("SELECT COALESCE(SUM(DATEDIFF(end_date,start_date)+1),0) FROM vacations WHERE emp_id = ? AND type = 'اجازة سنوية' AND accept = 1 AND YEAR(start_date)=?"); $stmt->bind_param("ii",$emp_id,$current_year); $stmt->execute(); $stmt->bind_result($used); $stmt->fetch(); $stmt->close(); $remaining = $annual_quota - $used; if ($remaining <= 0){ echo 'استهلك الموظف كامل رصيده السنوى لهذا العام.'; exit; } if ($requested_days > $remaining){ echo "الرصيد المتبقى $remaining يوم ولا يمكنك طلب $requested_days يوم."; exit; } if ($requested_days < 15){ $stmt = $con->prepare("SELECT COUNT(*) FROM vacations WHERE emp_id = ? AND type='اجازة سنوية' AND accept = 1 AND YEAR(start_date)=? AND (DATEDIFF(end_date,start_date)+1) >= 15"); $stmt->bind_param("ii",$emp_id,$current_year); $stmt->execute(); $stmt->bind_result($have15); $stmt->fetch(); $stmt->close(); if(!$have15){ echo 'يجب أن يتمتع الموظف بحد أدنى 15 يوم متصلة فى السنة.'; exit; } } break; case 'اجازة مرضية': $stmt = $con->prepare("SELECT COALESCE(SUM(DATEDIFF(end_date,start_date)+1),0) FROM vacations WHERE emp_id = ? AND type = 'اجازة مرضية' AND accept = 1 AND YEAR(start_date)=?"); $stmt->bind_param("ii",$emp_id,$current_year); $stmt->execute(); $stmt->bind_result($used); $stmt->fetch(); $stmt->close(); if ($requested_days > 45){ echo 'الحد الأقصى المستمر للإجازة المرضية هو 45 يوم.'; exit; } if ( ($used + $requested_days) > 60 ){ $left = 60 - $used; echo "المتبقى من رصيد الإجازة المرضية هذا العام هو $left يوم."; exit; } break; case 'اجازة الحج': $stmt = $con->prepare("SELECT COUNT(*) FROM vacations WHERE emp_id=? AND type='اجازة الحج' AND accept=1"); $stmt->bind_param("i",$emp_id); $stmt->execute(); $stmt->bind_result($taken); $stmt->fetch(); $stmt->close(); if($taken){ echo 'تمّ الحصول على إجازة الحج من قبل، لا تُمنح إلا مرة واحدة.'; exit; } if ($requested_days > 20){ echo 'الحد الأقصى لإجازة الحج 20 يوم.'; exit; } break; case 'اجازة زواج': $stmt = $con->prepare("SELECT COUNT(*) FROM vacations WHERE emp_id=? AND type='اجازة زواج' AND accept=1"); $stmt->bind_param("i",$emp_id); $stmt->execute(); $stmt->bind_result($taken); $stmt->fetch(); $stmt->close(); if($taken){ echo 'تمّ الحصول على إجازة زواج سابقًا، لا تُمنح إلا مرة واحدة.'; exit; } if ($requested_days > 14){ echo 'الحد الأقصى لإجازة الزواج هو 14 يوم.'; exit; } break; case 'اجازة وفاة الزوج': if ($gender != 'أنثى'){ echo 'إجازة وفاة الزوج خاصة بالإناث فقط.'; exit; } $stmt = $con->prepare("SELECT COUNT(*) FROM vacations WHERE emp_id=? AND type='اجازة وفاة الزوج' AND accept=1"); $stmt->bind_param("i",$emp_id); $stmt->execute(); $stmt->bind_result($taken); $stmt->fetch(); $stmt->close(); if($taken){ echo 'تمّ الحصول على هذه الإجازة سابقًا، لا تُمنح إلا مرة واحدة.'; exit; } if ($requested_days != 130){ echo 'مدة الإجازة هى 4 أشهر و10 أيام (130 يوم) ويجب إدخال المدة كاملة.'; exit; } break; default: echo 'نوع الإجازة غير معروف'; exit; } $interval = $start->diff($end); $years = $interval->y; $months = $interval->m; $days_only = $requested_days; $stmt = $con->prepare("INSERT INTO vacations (emp_id,years,months,days,reason,companion,type,start_date,end_date,created_at) VALUES (?,?,?,?,?,?,?,?,?,?)"); $stmt->bind_param("iiiisissss", $emp_id,$years,$months,$days_only,$reason,$companion, $type,$start_date,$end_date,$created_at); if($stmt->execute()){ echo "<script> Swal.fire({title:'تم',text:'تم إضافة الإجازة بنجاح',icon:'success'}); </script>"; echo '<meta http-equiv="refresh" content="2;url=vacations.php">'; } else { echo 'حدث خطأ أثناء الحفظ: '.$stmt->error; } $stmt->close(); }
  3. قم بفتح منفذ الأوامر م نفذ الأمر التالي لتشغيل خادم apache و mysql: sudo /opt/lampp/lampp start ثم توجه لرابط المشروع في المتصفح مجددًا.
  4. هل السؤال خاص بأحد الدروس؟ في حال ذلك، ستجد أسفل فيديو الدرس في نهاية الصفحة صندوق تعليقات كما هنا، أرجو طرح الأسئلة أسفل الدرس وليس هنا في قسم أسئلة البرمجة حيث نطرح الأسئلة العامة الغير متعلقة بمحتوى الدورة أو الدرس، وذلك لمساعدتك بشكل أفضل.
  5. الفكرة كالتالي، ستطلب من المستخدم إدخال بريده الإلكتروني المرتبط بالحساب ولو البريد الإلكتروني موجود في قاعدة البيانات، قم بإنشاء رمز وهو Token فريد ومؤقت ثم إرسال رابط إلى البريد الإلكتروني يحتوي على الرمز الفريد. وعند النقر على الرابط، اسمح للمستخدم بتعيين كلمة مرور جديدة. لذا قاعدة البيانات يجب أن تحتوي على جدول لتخزين الرموز المؤقتة associated مع المستخدم ووقت الانتهاء: CREATE TABLE password_resets ( id INT AUTO_INCREMENT PRIMARY KEY, email VARCHAR(255) NOT NULL, token VARCHAR(255) NOT NULL, expires_at DATETIME NOT NULL ); ونموذج طلب إعادة التعيين: <form action="request_reset.php" method="POST"> <input type="email" name="email" required placeholder="أدخل بريدك الإلكتروني"> <button type="submit">استعادة كلمة المرور</button> </form> ثم تثبيت مكتبة PHPMailer: composer require phpmailer/phpmailer ثم إنشاء منطق وإرسال رمز إعادة التعيين من خلال ملف وليكن باسم request_reset.php: <?php require 'vendor/autoload.php'; require 'db.php'; use PHPMailer\PHPMailer\PHPMailer; use PHPMailer\PHPMailer\Exception; if ($_SERVER["REQUEST_METHOD"] == "POST") { $email = filter_var($_POST["email"], FILTER_SANITIZE_EMAIL); $stmt = $pdo->prepare("SELECT id FROM users WHERE email = ?"); $stmt->execute([$email]); if ($stmt->rowCount() > 0) { $token = bin2hex(random_bytes(32)); $expires = date("Y-m-d H:i:s", strtotime('+1 hour')); $stmt = $pdo->prepare("INSERT INTO password_resets (email, token, expires_at) VALUES (?, ?, ?)"); $stmt->execute([$email, $token, $expires]); $reset_link = "https://mustafa.com/reset_password.php?token=$token"; $mail = new PHPMailer(true); try { $mail->isSMTP(); $mail->Host = 'smtp.yourmailserver.com'; $mail->SMTPAuth = true; $mail->Username = 'ضع الإيميل هنا@yourdomain.com'; $mail->Password = 'الباسورد هنا'; $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; $mail->Port = 587; $mail->setFrom('no-reply@yourdomain.com', 'Support'); $mail->addAddress($email); $mail->isHTML(true); $mail->Subject = 'إعادة تعيين كلمة المرور'; $mail->Body = "لقد طلبت إعادة تعيين كلمة المرور. اضغط على الرابط التالي:<br><a href='$reset_link'>$reset_link</a><br>إذا لم تطلب ذلك، تجاهل الرسالة."; $mail->send(); echo "تم إرسال رابط استعادة كلمة المرور إلى بريدك الإلكتروني إذا كان موجودًا في النظام."; } catch (Exception $e) { echo "حدث خطأ أثناء إرسال البريد الإلكتروني."; } } else { echo "تم إرسال رابط استعادة كلمة المرور إلى بريدك الإلكتروني إذا كان موجودًا في النظام."; } } ?> ثم ملف إعادة تعيين كلمة المرور reset_password.php: <?php if (!isset($_GET['token'])) exit('رمز غير صالح!'); $token = $_GET['token']; require 'db.php'; $stmt = $pdo->prepare("SELECT email FROM password_resets WHERE token = ? AND expires_at > NOW()"); $stmt->execute([$token]); $user = $stmt->fetch(); if (!$user) exit('الرابط غير صالح أو انتهت صلاحيته!'); if ($_SERVER["REQUEST_METHOD"] == "POST") { $new_password = $_POST["password"]; $hashed = password_hash($new_password, PASSWORD_DEFAULT); $stmt = $pdo->prepare("UPDATE users SET password = ? WHERE email = ?"); $stmt->execute([$hashed, $user['email']]); $stmt = $pdo->prepare("DELETE FROM password_resets WHERE email = ?"); $stmt->execute([$user['email']]); echo "تم تحديث كلمة المرور بنجاح!"; exit; } ?> <form method="POST"> <input type="password" name="password" required placeholder="كلمة المرور الجديدة"> <button type="submit">إعادة تعيين كلمة المرور</button> </form> لاحظ password_hash وpassword_verify لحفظ والتحقق من كلمة المرور، والأفضل تحديد صلاحية رمز إعادة التعيين لمدة محدودة مثلاً ساعة واحدة، ولا يجب توضيح هل البريد متوفر أم لا في الاستجابة لتجنب هجمات التخمين. أيضًا لمنع هجمات إعادة الإرسال، احذف الرمز بعد استخدامه مباشرة.
  6. لم تذكر السبب؟ هل هو لمجال العمل الحر؟ ما الدافع لتعلمه؟ عامًة ليس عليك ذلك نفس الأمر بالنسبة لتعلم لغة جديدة خاصة بالواجهة الخلفية ولتكن C# أو Go أو بايثون، أو حتى إطار خاص بلغة PHP مثل إطار NativePHP. كن مرنًا ولا تجعل نفسك محصورًا في تقنية معينة، أي أن تكون مهندس برمجيات software engineer وليس مطور programmer فقط. وإلا ستبقى محصورًا فقط في المشاريع التي تتطلب لارافل، وفي حال هناك مشروع يتطلب Odoo فلن تتمكن من تقديم عرض عليه أو العمل عليه في حال كنت في شركة. كل ما ستتعلمه سيضيف إليك وليس العكس، وتصبح قادر على العمل على مشاريع أكثر في مجال العمل الحر أو تنفيذ ما تريد في حال تعمل بمفردك أو تضيف إلى مهارة وزيادة قيمتك عند العمل في الشركات. بالطبع لا أقصد أن تقوم بتشتيت نفسك في بدايات تعلمك، لكن بعد الوصول لمستوى متوسط في تخصص معين، كن مرنًا ولا تخف من تعلم تقنية جديدة.
  7. من خلال تبويب دوراتي، فبعد الضغط عليه سيظهر لك الدورات التي اشتركت بها تحت دوراتي.
  8. حسب ما ذكرت أنت تريد المنطق التالي: كل 6 شهور للموظف = 15 يوم رصيد إجازة سنوية يبدأ التراكم بعد سنة من التعيين، لو تاريخ التعيين 12-01-1999، يبدأ التراكم من 12-01-2000. كل إجازة تخصم من الرصيد المتراكم وليس السنوي فقط. يجوز للموظف أن يأخذ أي عدد من الإجازات السنوية متى ما توفر له رصيد. لا يوجد سقف سنوي للإجازة، متاح أن يحصل الموظف على إجازتين طويلتين في سنتين متتاليتين لو له رصيد. والكود لديك يتبع المنطق السابق لا مشكلة، لكن المنطق به بعض التعقيد في التواريخ غير ضروري، ويكفي أن تبدأ من تاريخ التعيين + سنة واحدة، وتكرر كل 6 شهور حتى اليوم، أو تستطيع التمرير حتى تاريخ نهاية الإجازة المطلوبة لو أردت مزيد من الدقة. وعند تمرير المتغيرات للدالة هنا: $start_date_calc = new DateTime($employee['start_date']); $start_date_calc->modify('+1 year'); $start_date_calc = $start_date_calc->format('Y-m-d'); $stmt = $con->prepare("SELECT SUM(days) as total_days FROM vacations WHERE emp_id = ? AND accept = 1"); $used_days = $row['total_days'] ? $row['total_days'] : 0; $vacation_balance = calculateVacationBalance($start_date_calc, $used_days); الكود يعمل لكن الأفضل، تنفيذ المنطق بحيث لو الموظف متقدم بطلب إجازة تبدأ في تاريخ مستقبلي 1-1-2026، إذًا يجب جمع الأيام كلها حتى تلك اللحظة أي الإجازات المنتهية قبل 1-1-2026، وتراكم الرصيد أيضاً حتى نفس التاريخ، وهكذا تجعل التحقق دقيق، حتى لو سجل الموظف أكثر من إجازة في نفس الوقت لا يحدث تجاوز للرصيد، كالتالي: <?php include('header.php'); error_reporting(0); ini_set('display_errors', 0); function calculateVacationBalance($hireDate, $toDate, $usedDays) { $start = new DateTime($hireDate); $start->modify('+1 year'); $to = new DateTime($toDate); $totalAccruedDays = 0; while ($start <= $to) { $totalAccruedDays += 15; $start->modify('+6 months'); } $totalAccruedDays -= $usedDays; return $totalAccruedDays; } ?> <head> <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script> <link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/css/select2.min.css" rel="stylesheet" /> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/js/select2.min.js"></script> <style> .rak { width: 400px; height: 300px; font-size: 14px !important;} </style> </head> <div class="col-md-9 pan1"> <ol class="breadcrumb" style="background-color: #fff;padding-top:8px;padding-bottom:8px;color:#000;font-size:16px;"> <li><a href="vacations.php">الاجازات</a></li> <li class="active">اضافة اجازة جديد</li> </ol> </div> </div> <div class="row"> <div class="col-md-9 pan1"> <div class="panel" style="color:#000;"> <div class="panel-body" style="font-size:14px; padding-left:40px;padding-right:40px;padding-bottom:25px;padding-top:25px;"> <form method="POST" enctype="multipart/form-data"> <div class="row"> <div class="col-md-4"> <div class="form-group" style="margin-top:10px;"> <label>الموظف</label> <select name="emp_id" id=""> <?php $sql = "SELECT e.person_id, p.name FROM employees e JOIN people p ON e.person_id = p.id;"; $result = $con->query($sql); while ($row = $result->fetch_assoc()) { echo "<option value='{$row['person_id']}'>{$row['name']}</option>"; } ?> </select> </div> </div> <div class="col-md-4"> <div class="form-group" style="margin-top:10px;"> <label>نوع الاجازة</label> <select name="type" id=""> <option value="اجازة مرضية">اجازة مرضية</option> <option value="اجازة وضع">اجازة وضع</option> <option value="اجازة بدون مرتب">اجازة بدون مرتب</option> <option value="اجازة زواج">اجازة زواج</option> <option value="اجازة سنوية">اجازة سنوية</option> </select> </div> </div> <div class="col-md-4"> <div class="form-group" style="margin-top:10px;"> <label>تاريخ البداية</label> <input name="start_date" type="date" class="form-control"> </div> </div> </div> <div class="row"> <div class="col-md-4"> <div class="form-group" style="margin-top:10px;"> <label>تاريخ المباشرة</label> <input name="end_date" type="date" class="form-control"> </div> </div> <div class="col-md-4"> <div class="form-group" style="margin-top:10px;"> <label>سبب الاجازة</label> <input name="reason" type="text" class="form-control" placeholder="ادخل سبب الاجازة"> </div> </div> <div class="col-md-4"> <div class="form-group" style="margin-top:10px;"> <label>الموافقة مسبقا</label> <input name="companion" type="checkbox" class="form-control"> </div> </div> </div> <div class="row"> <div class="col-md-4"> <div class="form-group" style="margin-top:10px;"> <button name="submit" type="submit" class="btn btn-primary">إضافة <span class="ion-android-add"></span></button> <button type="reset" class="btn btn-danger">إلغاء <span class="ion-android-delete"></span></button> </div> </div> </div> </form> <?php if ($_SERVER["REQUEST_METHOD"] == "POST") { $emp_id = $_POST['emp_id']; $type = $_POST['type']; $start_date = $_POST['start_date']; $end_date = $_POST['end_date']; $reason = $_POST['reason']; $companion = isset($_POST['companion']) ? 1 : 0; $created_at = date('Y-m-d H:i:s'); $start = new DateTime($start_date); $end = new DateTime($end_date); $interval = $start->diff($end); $years = $interval->y; $months = $interval->m; $days = $interval->d; $requested_days = $end->diff($start)->days; $errors = []; if (empty($type)) { $errors[] = 'يجب تحديد نوع الإجازة'; } if (empty($start_date)) { $errors[] = 'يجب إدخال تاريخ بداية الإجازة'; } if (empty($end_date)) { $errors[] = 'يجب إدخال تاريخ المباشرة'; } if ($end <= $start) { $errors[] = 'تاريخ المباشرة يجب أن يكون بعد بداية الإجازة'; } if (!empty($errors)) { echo implode('<br>', $errors); exit; } mysqli_begin_transaction($con); try { $stmt = $con->prepare("SELECT * FROM employees WHERE person_id = ?"); $stmt->bind_param("i", $emp_id); $stmt->execute(); $employee = $stmt->get_result()->fetch_assoc(); $stmt->close(); if (!$employee) { echo "لم يتم العثور على بيانات الموظف"; exit; } // تحقق لا يوجد إجازة قيد الإجراء $stmt = $con->prepare("SELECT COUNT(*) FROM vacations WHERE emp_id = ? AND accept = 0"); $stmt->bind_param("i", $emp_id); $stmt->execute(); $stmt->bind_result($count); $stmt->fetch(); $stmt->close(); if ($count > 0) { echo "عذرًا، هنالك إجازة قيد الإجراء للموظف الحالي، الرجاء التحقق."; exit(); } $stmt = $con->prepare("SELECT * FROM people WHERE id = ?"); $stmt->bind_param("i", $emp_id); $stmt->execute(); $people = $stmt->get_result()->fetch_assoc(); $stmt->close(); if ($type == "اجازة وضع" && $people['gender'] == "ذكر") { echo "عذرًا، لا يمكن إعطاء هذا النوع من الإجازة للموظف المختار."; exit(); } if ($type == "اجازة زواج") { $stmt = $con->prepare("SELECT COUNT(*) FROM vacations WHERE emp_id = ? AND type = ? "); $stmt->bind_param("is", $emp_id, $type); $stmt->execute(); $stmt->bind_result($count); $stmt->fetch(); $stmt->close(); if ($count > 0) { echo "عذرًا، الموظف المختار قد حصل على إجازة زواج مسبقًا."; exit(); } $stmt = $con->prepare("SELECT start_date, end_date FROM vacations WHERE emp_id = ? AND type = ?"); $stmt->bind_param("is", $emp_id, $type); $stmt->execute(); $stmt->bind_result($s, $e); $stmt->fetch(); $stmt->close(); if ($s && $e) { $days = (new DateTime($e))->diff(new DateTime($s))->days; if ($days > 14) { echo "عذرًا، إجازة الزواج لا يمكن أن تتجاوز أسبوعين."; exit(); } } } if ($type == "اجازة سنوية") { $hire_date = $employee['start_date']; $requested_start_str = $start->format('Y-m-d'); $stmt = $con->prepare(" SELECT COALESCE(SUM(DATEDIFF(end_date, start_date)),0) AS used FROM vacations WHERE emp_id = ? AND type = 'اجازة سنوية' AND accept = 1 AND end_date <= ? "); $stmt->bind_param("is", $emp_id, $requested_start_str); $stmt->execute(); $stmt->bind_result($used_days); $stmt->fetch(); $stmt->close(); $vacation_balance = calculateVacationBalance($hire_date, $requested_start_str, $used_days); if ($vacation_balance < $requested_days) { echo "عذرًا، لا يمكن إنشاء الإجازة لعدم توفر الرصيد الكافي. رصيدك: $vacation_balance يوم، والطلب: $requested_days يوم"; exit(); } } if ($type == "اجازة بدون مرتب" ) { $days = 365; } $stmt = $con->prepare("INSERT INTO vacations (emp_id, years, months, days, reason, companion, type, start_date, end_date, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); $start_date_formatted = $start->format('Y-m-d'); $end_date_formatted = $end->format('Y-m-d'); $stmt->bind_param("iiiisissss", $emp_id, $years, $months, $requested_days, // الآن أصبحت days هي فارق الأيام $reason, $companion, $type, $start_date_formatted, $end_date_formatted, $created_at ); if ($stmt->execute()) { echo "<script> Swal.fire({ title: 'رسالة تأكيد', text: 'تم إضافة بيانات اجازة موظف بنجاح!', icon: 'success', customClass: 'rak', }); </script>"; echo '<meta http-equiv="refresh" content="2;url=vacations.php" />'; } $stmt->close(); mysqli_commit($con); } catch (Exception $e) { mysqli_rollback($con); echo "خطأ: " . $e->getMessage(); exit; } } ?> </div> </div> </div> </div> <?php include('footer.php'); ?>
  9. هل تنوي دراسة بايثون بشكل عام، أم تنوي التخصص في مجال معين؟ أرجو قراءة التالي أولاً ثم أخبرني بقرارك لتحديد طريقة الدراسة المناسبة:
  10. في بدايات التعلم أو عند تعلم شيء جديد، فترة أسبوع ستؤدي إلى نسيان كم كبير من المعلومات فهناك ما يسمى بمنحني النسيان، حيث في بداية تخزين المعلومات، يكون الاسترجاع سهلًا ودقيقًا، ولكن مع مرور الوقت، يتلاشى الاسترجاع ويصبح أصعب، ويشير منحنى النسيان إلى أن هناك فترة تتلاشى خلالها المعلومات بشكل سريع في البداية، ولكن مع مرور الوقت، يصبح معدل النسيان أقل وأقل، ويتم الحفاظ على الجوهر الأساسي للمعلومات المهمة. فبعد مرور يوم واحد من التعلم، هناك انخفاض في الاسترجاع الدقيق للمعلومات، ويعتمد مدى النسيان على عوامل مثل طبيعة المعلومات ومدى تكرارها وأهميتها بالنسبة للشخص تتراوح نسبة النسيان بعد مرور يوم واحد بين 20% إلى 40% من المعلومات. وبعد 3 أيام من 50% إلى 70% وبعد مرور أسبوع ترتفع النسبة إلى 70% وحتى 90%، وذلك في حال لم تقم بإعادة تكرار ما تعلمته وذلك من خلال تنفيذ مشاريع للتطبيق على ما تعلمته وتثبيت المعلومات واستخدام ما سبق وتعلم أمور جديدة. بعد تثبيت ما تعلمته تستطيع الإنقطاع لمدة أسبوع أو شهر لا مشكلة، وكلما زاد عمق الخبرة لديك زادت الفترة التي تستطيع الإنقطاع بها، ولا مشكلة في نسيان تفاصيل الـ Syntax وأسماء الدوال في مكتبات لم تعد تستخدمها يوميًا فلن تضيع الأساسيات بسهولة. فالمعرفة العميقة ترتبط في الدماغ بمسارات عصبية أقوى تكونت عبر سنوات من الاستخدام وحل المشكلات المتنوعة، وإعادة تنشيطها تتطلب وقتًا أقصر بكثير من تعلمها لأول مرة.
  11. طالما POC سنتجاهل الكثير من الأمور، الأسهل الإعتماد على المكتبات التالية من خلال بايثون فقط. streamlit pandas fastapi uvicorn asyncio ومن خلال ما سبق ستتمكني من تخزين البيانات في DataFrame بالذاكرة أو إلى ملف CSV لو أردتي، وإظهار إحصاء يومي بسيط عن طريق streamlit بالإضافة إلى قيمة حيّة مُحدثة كل ثانية. استخدمي fastapi كـ API وwebsocket ومولد بيانات بكتابة دالة تُنشئ قيماً عشوائية أو شبه عشوائية كل ثانية تمثّل خط الطول، خط العرض، الارتفاع، السرعة، عدد الركاب وخلافه.
  12. تم توضيح الأمر من قبل بخصوص جزئية التعلم المُعزز لكن كإعادة للإفادة، جوهر الفكرة واحد من حيث مباديء التعلم المعزز، وهي: لدينا عامل أو Agent يتخذ قرارات متتابعة. وبيئة تصف قيود الطيران والمطارات. الهدف هو تعظيم مكافأة مرتبطة بسلامة الرحلة، الدقة الزمنية، الكلفة التشغيلية، ورضا الركاب. بالتالي نحتاج إلى معلومات عن: نقطة البداية الوجهة بوابة الإقلاع عدد الركاب - ويجب إعادة تعريف الـ State وتضمين كل ما يحتاجه العامل لإتخاذ قرار الخطوة التالية، وليكن التالي: الموقع المكاني ويشمل (خط العرض، خط الطول، الارتفاع) أو خلية مجردة على شبكة 3-D داخل ممرات جوية. الاتّجاه Heading والسرعة True Airspeed مطار الإقلاع، بوابة الإقلاع، مدرج الإقلاع. مطار الوجهة، بوابة الوجهة، المدرج المطلوب. عدد الركاب أو الحمولة (قد يؤثر في الوقود/الأداء). حالة الوقود المتبقّي. ظروف الطقس أو كثافة الحركة الجوية في القطاع الحالي. Slot Time أو هامش التأخير المسموح. ولتجنُب انفجار حجم الحالات أوما يعرف بـ State-Space Explosion لا بد من إسقاط بعض التفصيلات غير الجوهرية أو استعمال تمثيل متصل مع شبكات عصبية كـ Deep Q-Network وActor-Critic بدلاً من جدول Q-Table. - وفي الـ Action Space سيتضمن: تغيير الارتفاع صعود أو هبوط بدرجات معينة. تعديل السرعة. الانعطاف بزاوية محددة، أقصد الإتجاه. اختيار مسار Taxiing على أرض المطار من المدرج إلى البوابة أو العكس. طلب تأخير الإقلاع أو تغيير بوابة الالتحام Gate Swap. - بالنسبة لـ Reward Function لا بد من صياغة مكافأة تُحقق التوازن بين عوامل عدة: الوصول في الموعد المحدد. تقليل استهلاك الوقود وانبعاثات CO₂. تفادي مناطق ازدحام أو أحوال جوية خطرة. عدم التسبب في تعارض مع طائرات أخرى. الحفاظ على راحة الركاب من خلال معدل صعود وهبوط آمن كالتالي: عقوبة كبيرة عند الاقتراب لمسافة أقل من الحد الأدنى أو عند تأخير كبير. عقوبة للحالات غير الصالحة كنفاد الوقود، تجاوز حدود المجال الجوي، إلخ... - ولإختيار خوارزمية التعلم المناسبة فالطيران نظام مستمر واسع الأبعاد، لذا Q-table لا يكفي. الحل الأنسب Deep Reinforcement Learning مع شبكات عصبية، DQN للأفعال المحدودة، أو PPO و SAC للأفعال المتصلة. وفي حالة تعدُد الطائرات فسيتم الأمر من خلال Multi-Agent RL مع مشاركة جزئية للمعلومات أو Centralised Training – Decentralised Execution. - أما منصة المحاكاة المناسبة يتوفر التالي: BlueSky محاكي مفتوح لمسارات جوية 4-D ويُستخدم كثيراً في أبحاث التوجيه. X-Plane / MS Flight Simulator مع وصلات SDK للتحكم. Microsoft Project AirSim المخصص للطائرات بدون طيار والقابل للتعديل. Open Skies أو Eurocontrol BADA models لبيانات الأداء. وتستطيعي الحصول على بيانات جداول الرحلات الحقيقية من خلال OAG و OpenFlights، وتاريخ أحوال الطقس من https://www.ncei.noaa.gov والازدحام الجوي من https://opensky-network.org . بحيث تُغلفين المحاكي في كلاس gym.Env ليُطبق step()‎, reset()‎, render()‎. - مع العلم أنه يوجد بعض القواعد ويجب أن تتم بإضافة طبقات أمان وتحقق عن طريق قيود صريحة لضمان عدم انتهاك قواعد الطيران، والتعامل مع حالات نادرة كفشل محرك أو سوء طقس فجائي. هل ستقومين بدراسة تقنيات خاصة بالواجهة الأمامية والخلفية مثل لغة جافاسكريبت والتقنيات الخاصة مثل Next.js؟ الأفضل تعلم ذلك. لكن لو تريدين التنفيذ عن طريق بايثون، فلديكِ إطار Django أو Flask والأخير أسهل لإنشاء الـ API والواجهة الأمامية من خلال القوالب، ولتبسيط الأمر لن نستخدم قواعد بيانات، ولا بروكر رسائل، ولا WebSocket، فقط مجرد استعلام GET كل ثانية يفي بالغرض للعرض الحي، ولا حاجة لـ Gymnasium أو مكتبات معقدة نسبيًا للتبسيط المطلق. لكن للمساعدة بشكل أفضل أرجو توضيح ما تنوين القيام به، وهل ستقومين بذلك بمفردك؟ وهل تريدين أبسط طريقة ممكنة أم تريدين استخدام Gym وخريطة مثلاً من Leaflet؟ ومخطّطات للإحصاءات؟ أيضًا WebSocket للأحداث الفورية كتوضيح موقع الطائرة كل ثانية؟ فالطريقة السابقة هي الأبسط.
  13. بإمكانك إجراء الإختبار أكثر من مرة لحين إجتيازه بنجاح، لكن الأفضل الاستعداد جيدًا للحفاظ على وقتك ومجهودك، وسيتم سؤالك في المسارات التي أنهيتها فقط وليس جميع المسارات، بشرط إتمام 4 مسارات كحد أدنى. الدورة مُقسمة إلى مسارات وكل مسار مُقسم إلى أقسام، وبعد إنهاء 4 مسارات من الدورة على الأقل، أو الدورة بالكامل عليك رفع المشاريع التي قمت بها بالدورة على حسابك في github، ثم التحدث لمركز المساعدة وإخبارهم أنك تريد التقدم للإختبار وتوفير روابط المشاريع على github. آلية الإختبار هي: محادثة صوتيّة لمدة 30 دقيقة يطرح المدرّب عليك أسئلة متعلّقة بالدورة والأمور التي نفّذتها خلالها. يحدد لك المدرّب مشروعًا مرتبطًا بما قمت به أثناء الدورة لتنفيذه خلال فترة محددة تتراوح بين أسبوع إلى أسبوعين. محادثة صوتيّة أخرى لمدّة 30 دقيقة يناقش بها مشروعك وما نفذته وتطرح أسئلة خلالها. والدورة متاحة لك مدى الحياة وذلك يتضمن التحديثات أيضًا، والأفضل إنهاء الدورة بالكامل لتحقيق استفادة
  14. هل استخدمت الكود السابق؟ سأفترض ذلك، ستحتاج إلى إضافة شرط يتحقق من أن حقل البحث ليس فارغًا وعدد أحرفه 3 أو أكثر وبالطبع تستطيع تغيير الرقم كما تريد. وتتوفر دالة mb_strlen() وهي دالة مُدمجة في PHP لحساب طول النص أي عدد الأحرف وتحسب عدد البايتات وليس عدد الأحرف الحقيقية عند استخدام ترميزات متعددة البايت مثل UTF-8 وهو الترميز الخاص باللغة العربية لذا سنستخدمها. وللعلم التحقق يتم على السيرفر، والأفضل إضافة تحقق من خلال الجافاسكربت أيضًا داخل الصفحة لمنع الإرسال قبل التحقق من الإدخال. <?php $servername = "localhost"; $username = "root"; $password = ""; $dbname = "test_db"; $conn = new mysqli($servername, $username, $password, $dbname); if ($conn->connect_error) { die("فشل الاتصال: " . $conn->connect_error); } $conn->set_charset("utf8"); if (isset($_POST['search'])) { $search_term = trim($_POST['search_term']); if (empty($search_term)) { $error = "يرجى إدخال كلمة للبحث!"; } elseif (mb_strlen($search_term, "UTF-8") < 3) { $error = "كلمة البحث يجب أن تكون 3 أحرف على الأقل!"; } else { $sql = "SELECT email FROM users WHERE name LIKE ?"; $stmt = $conn->prepare($sql); $like_term = "%" . $search_term . "%"; $stmt->bind_param("s", $like_term); $stmt->execute(); $result = $stmt->get_result(); if ($result->num_rows > 0) { while ($row = $result->fetch_assoc()) { $results[] = $row['email']; } } else { $error = "لا توجد نتائج مطابقة."; } $stmt->close(); } } $conn->close(); ?> <!DOCTYPE html> <html lang="ar"> <head> <meta charset="UTF-8"> <title>البحث في قاعدة البيانات</title> <script> function validateForm() { var searchTerm = document.getElementById('search_term').value.trim(); if (searchTerm.length < 3) { alert('يجب إدخال 3 أحرف على الأقل للبحث.'); return false; } return true; } </script> </head> <body> <h2>البحث في قاعدة البيانات</h2> <form method="POST" action="" onsubmit="return validateForm();"> <label for="search_term">أدخل اسم المستخدم للبحث:</label> <input type="text" id="search_term" name="search_term" required> <button type="submit" name="search">بحث</button> </form> <?php if (isset($error)) { echo "<p style='color:red;'>$error</p>"; } if (isset($results) && !empty($results)) { foreach ($results as $email) { echo "البريد الإلكتروني: " . htmlspecialchars($email) . "<br>"; } } ?> </body> </html>
  15. من خلال إنشاء متغير وتحديد قيمة له للإشارة إلى رقم الخلفية الحالية وعند الإنتقال للخلفية التالية يتم تعديل قيمة ذلك المتغير، ثم تشغيل وإيقاف الأصوات بناءًا على حلقة تكرار دائمة وشرط if. لكن لو أضفت عدد خلفيات كبير فالأفضل استخدام الأحداث بمعنى إرسال حدث باسم الخلفية 2 مثلاً ثم تشغيل الصوت بناءًا على ذلك الحدث عند استقباله.
  16. ستجد أسفل فيديو الدرس في نهاية الصفحة صندوق تعليقات كما هنا، أرجو طرح الأسئلة أسفل الدرس وليس هنا في قسم أسئلة البرمجة حيث نطرح الأسئلة العامة الغير متعلقة بمحتوى الدورة أو الدرس، وذلك لمساعدتك بشكل أفضل.
  17. لا يتم رفعها أو نشرها، فـ HTML5 لغة توصيف لإنشاء هيكل صفحات الويب، وتطوير اللعبة من خلال لغات الويب يعتمد على HTML5 بالإضافة إلى JavaScript وCSS معًا لتطوير الألعاب التي تعمل في المتصفحات. حيث HTML لتحديد الهيكلية وCSS لتنسيق الشكل والمظهر وJavaScript للمنطق التفاعلي والبرمجة كتحريك الشخصيات أو إدارة اللعب، بالإضافة إلى ملفات إضافية كالصور، الصوتيات، أو مكتبات مثل Phaser أو Three.js. بينما الرفع أو النشر يعني جعل تلك الملفات متاحة على خادم ويب بمعنى استضافة حتى يتمكن المستخدمون من الوصول إليها عبر الإنترنت.
  18. للوهلة الأولى الموقع يحتاج إلى توفير حقل بحث من أجل الوصول السريع للمنطقة الخاصة بالمستخدم، تستطيع استخدام Algolia أو أي خدمة أخرى لتوفير البحث بدلاً من قائمة الروابط الطويلة وأبقي القائمة في أسفل الصفحة لمن يُفضل التصفّح اليدوي. أيضًا ميزة تحديد المنطقة تلقائيًا عن طريق الـ GPS لعرض أوقات الصلاة مباشرة دون الحاجة إلى اختيار المدينة يدويًا. ثم أضف ميزة إشعارات Push Notifications عبر المتصفح أو تطبيق مصاحب لتذكير المستخدمين بأوقات الصلاة. واعرض الصلاة القادمة بشكل بارز مع عداد تنازلي للوقت المتبقي، ويا حبذا لو قمت بعرض آيات قرآنية أو ذكر بتخصيص جزء من الصفحة كركن معلومة اليوم به آية أو حديث أو تذكير فقهي قصير يظهر أسفل الجدول، يتبدّل يوميًا. كالتالي: ويتغيّر لون البطاقة قبل الأذان بخمس دقائق كتنبيه بصري فوري. وعرض التاريخ الميلادي والهجري بالموقع ولو قمت بعرض السنن الخاصة بكل صلاة أمر ممتاز أيضًا. أيضًا شريط تقدّم اليوم كخط أفقي من الفجر للعشاء يُظهر موضعنا الحالي في اليوم، وميزة تحديد القبلة من خلال البوصلة. من حيث التصميم، فالموقع بحاجة إلى تحسين التصميم وأول هام بطاقة لكل صلاة بها أيقونة، اسم، وقت، عدّاد صغير، لون مخصص، استخدام Grid بسيط ليظهر في سطرين على سطح المكتب وسطر واحد قابل للتمرير على الجوال.
  19. مجال الدورة هو تطوير تطبيقات الويب من خلال بايثون، بالتالي التركيز الأكبر على شرح أساسيات بايثون وتطبيقات عملية عليها لتوظيف ما تعلمته وترسيخه، ثم تعلم إطارات الويب وهم Flask و Django ثم نتعلم odoo والذي يُتيح لك أيضًا تطوير تطبيقات ويب خاصة بالـ ERP و CRM وPOS. وذلك ما يؤهلك لأحد التخصصات التالية: مطور Full-stack لبناء مواقع الويب والمتاجر الإلكترونية أي قادر على تطوير الواجهة الأمامية والخلفية أيضًا من خلال Django و Flask. مطور واجهة خلفية Back-End فقط. مطور odoo بعد ذلك يتم التطرق لمجالات أخرى خاصة بلغة بايثون ومنها تحليل البيانات والذكاء الاصطناعي، وتوضيح كيفية توظيف ذلك في المشاريع العملية من خلال مسار دمج تقنيات الذكاء الاصطناعي مع تطبيقات بايثون. ويتم شرح الأساسيات فقط لأنّ ذلك ليس تخصصها بل تخصص دورة الذكاء الاصطناعي بالأكاديمية.
  20. أي كائن نستطيع التكرار عليه من خلال حلقة for أو تمريره إلى دالة iter() للحصول على Iterator أي مكرر، فهو كائن قابل للتكرار Iterable بمعنى يحتوي على عناصر يمكن الوصول إليها واحدًا تلو الآخر بسبب الدالة الداخلية __iter__() التي تُعيد كائن Iterator كالتالي: my_list = [1, 2, 3] for item in my_list: print(item) أما Iterator وهو المُكرّر فذلك لتتبع عملية التكرار وإرجاع العناصر واحدًا تلو الآخر، ويتم إنشاؤه من Iterable أي كائن قابل للتكرار باستخدام دالة iter() ويحتوي على دالتين داخليتين وليس دالة واحدة كما في Iterable، وهما: __iter__() تُعيد الكائن نفسه. __next__() تُعيد العنصر التالي في التسلسل، وإن لم يتوفر عناصر، تُطلق استثناء. والكائنات من نوع Iterator تُستهلك، أي بمجرد استنفاد العناصر، لا تستطيع إعادة استخدامها إلا بإنشاء Iterator جديد. my_list = [1, 2, 3] iterator = iter(my_list) print(next(iterator)) print(next(iterator)) print(next(iterator)) #print(next(iterator)) قم بتجربة الكود السابق وستحصل على عناصر المصفوفة، ولو أزلت تعليق السطر الأخير ستحصل على خطأ StopIteration: StopIteration حيث لم يعد هناك عناصر باقية في المُكرر. بالتالي كل Iterator هو Iterable لأنه يحتوي على __iter__() وليس كل Iterable هو Iterator لأنه لا يحتوي على __next__() دائمًا. وتستطيع تحويل Iterable إلى Iterator باستخدام iter()، واستخدام next() للوصول إلى العناصر يدويًا. my_string = "hello" #ذلك كائن قابل للتكرار iterator = iter(my_string) # Iterator مكرر print(next(iterator)) print(next(iterator)) # لطباعة العناصر الباقية في المكرر for char in iterator: print(char)
  21. تستطيع التقدم للإمتحان فور إتمام 4 مسارات كحد أدنى من الدورة وتنفيذ المشاريع العملية التي جاءت بها ورفعها على مستودع خاص لكل مشروع على حسابك في GitHub، حيث يجب توفير روابط تلك المشاريع عند التقدم للإختبار. الدروة مُقسمة إلى مسارات وكل مسار بداخله أقسام، وسيتم سؤالك في المسارات التي أنهيتها فقط، بمعنى لو أنهيت 6 مسارات مثلاً سيتم إختبارك بها، لكن ذلك لا يعني عدم إتمام الدورة بالكامل لتحقيق استفادة، تلك الميزة متاحة في حال أراد البعض دراسة مسارات معينة وليس كامل الدورة، في حال كان لديه خبرة سابقة بمجال الدورة وأراد تحسين مهاراته في جزء معين. والأسئلة خاصة بالجانب العملي أكثر وليس النظر لقياس مدى استيعابك لما قمت به وهل قمت بنقل الأكواد فقط أم استوعبت ما تم. الشهادة في أكاديمية حسوب دليل على أنك استوعبت المحتوى وليس شهادة حضور فقط، أي ما تستطيع القيام به وليس ما شاهدته.
  22. لا يتم تثبيته إفتراضيًا مع بايثون، ستحتاج إلى تحديد ذلك أثناء التثبيت وأحد مهامه تشغيل الكود من خلال إصدار بايثون معين، كالتالي: py -3.9 app.py لاحظ أمر py وهو الخاص بـ python launcher أيضًا تستطيع استخدامه بدلاً من أمر python أي كاختصار: py app.py وتلك هي مهمته فقط لإدارة إصدارات بايثون.
  23. ستجد أسفل فيديو الدرس في نهاية الصفحة صندوق تعليقات كما هنا، أرجو طرح الأسئلة أسفل الدرس وليس هنا في قسم أسئلة البرمجة حيث نطرح الأسئلة العامة الغير متعلقة بمحتوى الدورة أو الدرس، وذلك لمساعدتك بشكل أفضل.
  24. ليس كذلك، فلا يتم إنشاء نسخة كاملة من بايثون، بل نسخ الملفات الأساسية فقط الخاصة بمُفسر اللغة وهي الملفات التنفيذية python.exe و pip ومجلد lib/ الذي يحتوي على بنية لتثبيت الحزم الخاصة بالبيئة، وذلك في مجلد البيئة الإفتراضية. ولكن المُفسر في البيئة الإفتراضية يٌشير إلى المُفسر الأصلي المُثبت على النظام أي يقوم بتشغيله هو وليس مُفسر مختلف، الإختلاف هو ضبط مسار البيئة الافتراضية لكي تكون نشطة وتثبيت الحزم بها بدلاً من تثبيتها في النطاق العام. لذا المكتبات المُضمنة في اللغة كـ os، sys وغيرهم لا تُنسخ، بل تُستخدم من تثبيت بايثون الأصلي لتوفير المساحة. أما Docker فهو أمر مختلف تمامًا، الترجمة الحرفية هي حاوية وبالتبعية الأمر أشبه بحجرة مغلقة معزولة تمامًا وتضع بداخلها كل ما تريد لتشغيل المشروع بغض النظر عن نوع نظام التشغيل، طالما Docker مثبت على النظام تستطيع تشغيل الحاوية والتي بها المشروع كما هو تمامًا على جميع الأجهزة ولن يختلف شيء من جهاز لآخر. وذلك له فوائد كثيرة ستجد تفصيلها هنا:
×
×
  • أضف...