$_GET['role'] ?? 'shipper', 'full_name' => '', 'email' => '', 'phone' => '', 'country_id' => '', 'city_id' => '', 'address_line' => '', 'company_name' => '', 'bank_account' => '', 'bank_name' => '', 'bank_branch' => '', 'is_company' => '0', ]; $countries = db()->query("SELECT id, name_en, name_ar FROM countries ORDER BY name_en ASC")->fetchAll(); $cities = db()->query("SELECT id, country_id, name_en, name_ar FROM cities ORDER BY name_en ASC")->fetchAll(); if ($_SERVER['REQUEST_METHOD'] === 'POST') { validate_csrf_token(); $role = $_POST['role'] ?? 'shipper'; $fullName = trim($_POST['full_name'] ?? ''); $email = trim($_POST['email'] ?? ''); $phone = trim($_POST['phone'] ?? ''); $countryId = (int)($_POST['country_id'] ?? 0); $cityId = (int)($_POST['city_id'] ?? 0); $addressLine = trim($_POST['address_line'] ?? ''); $companyName = trim($_POST['company_name'] ?? ''); $passwordRaw = (string)($_POST['password'] ?? ''); $values = [ 'role' => $role, 'full_name' => $fullName, 'email' => $email, 'phone' => $phone, 'country_id' => $countryId > 0 ? (string)$countryId : '', 'city_id' => $cityId > 0 ? (string)$cityId : '', 'address_line' => $addressLine, 'company_name' => $companyName, 'bank_account' => trim($_POST['bank_account'] ?? ''), 'bank_name' => trim($_POST['bank_name'] ?? ''), 'bank_branch' => trim($_POST['bank_branch'] ?? ''), 'is_company' => isset($_POST['is_company']) ? '1' : '0', ]; if (!in_array($role, ['shipper', 'truck_owner'], true)) { $errors[] = 'Invalid role selected.'; } if ($fullName === '') { $errors[] = 'Full name is required.'; } if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { $errors[] = 'Please provide a valid email address.'; } if ($phone === '') { $errors[] = 'Phone number is required.'; } if ($countryId <= 0 || $cityId <= 0) { $errors[] = 'Please select country and city.'; } else { $cityCheck = db()->prepare("SELECT COUNT(*) FROM cities WHERE id = ? AND country_id = ?"); $cityCheck->execute([$cityId, $countryId]); if ((int)$cityCheck->fetchColumn() === 0) { $errors[] = 'Selected city does not belong to selected country.'; } } if ($addressLine === '') { $errors[] = 'Address is required.'; } if (strlen($passwordRaw) < 6) { $errors[] = 'Password must be at least 6 characters.'; } if ($role === 'shipper' && $companyName === '') { $errors[] = 'Company name is required for shipper registration.'; } if (!$errors) { $password = password_hash($passwordRaw, PASSWORD_DEFAULT); $pdo = db(); try { $pdo->beginTransaction(); $status = ($role === 'truck_owner') ? 'pending' : 'active'; $stmt = $pdo->prepare("INSERT INTO users (email, password, full_name, role, status) VALUES (?, ?, ?, ?, ?)"); $stmt->execute([$email, $password, $fullName, $role, $status]); $userId = (int)$pdo->lastInsertId(); if ($role === 'shipper') { $shipperStmt = $pdo->prepare( "INSERT INTO shipper_profiles (user_id, company_name, phone, country_id, city_id, address_line) VALUES (?, ?, ?, ?, ?, ?)" ); $shipperStmt->execute([$userId, $companyName, $phone, $countryId, $cityId, $addressLine]); } else { $uploadDir = __DIR__ . '/uploads/profiles/' . $userId . '/'; if (!is_dir($uploadDir)) { mkdir($uploadDir, 0775, true); } $allowed = ['image/jpeg' => 'jpg', 'image/png' => 'png', 'image/webp' => 'webp']; $maxSize = 8 * 1024 * 1024; $saveImage = static function (string $tmpName, int $size, string $prefix) use ($uploadDir, $allowed, $maxSize): ?string { if ($size <= 0 || $size > $maxSize) { return null; } $mime = mime_content_type($tmpName) ?: ''; if (!isset($allowed[$mime])) { return null; } $filename = uniqid($prefix, true) . '.' . $allowed[$mime]; $target = $uploadDir . $filename; if (!move_uploaded_file($tmpName, $target)) { return null; } return 'uploads/profiles/' . basename($uploadDir) . '/' . $filename; }; $idCardPaths = []; if (is_uploaded_file($_FILES['id_card_front']['tmp_name'] ?? '')) { $path = $saveImage($_FILES['id_card_front']['tmp_name'], (int)$_FILES['id_card_front']['size'], 'id_front_'); if ($path) $idCardPaths[] = $path; } if (is_uploaded_file($_FILES['id_card_back']['tmp_name'] ?? '')) { $path = $saveImage($_FILES['id_card_back']['tmp_name'], (int)$_FILES['id_card_back']['size'], 'id_back_'); if ($path) $idCardPaths[] = $path; } if (count($idCardPaths) < 2) { $errors[] = 'Please upload ID front and back.'; } if (!$errors) { $ownerStmt = $pdo->prepare( "INSERT INTO truck_owner_profiles (user_id, phone, country_id, city_id, address_line, bank_account, bank_name, bank_branch, id_card_path, is_company) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" ); $ownerStmt->execute([ $userId, $phone, $countryId, $cityId, $addressLine, $values['bank_account'], $values['bank_name'], $values['bank_branch'], json_encode($idCardPaths, JSON_UNESCAPED_SLASHES), $values['is_company'] ]); } } if ($errors) { $pdo->rollBack(); } else { $pdo->commit(); $user = [ 'id' => $userId, 'email' => $email, 'full_name' => $fullName, 'role' => $role, 'phone' => $phone ]; try { require_once __DIR__ . '/includes/NotificationService.php'; NotificationService::send('welcome_message', $user, [], $lang); } catch (Throwable $e) { error_log('Failed to send welcome notification: ' . $e->getMessage()); } $saved = true; $saved_role = $role; } } catch (Throwable $e) { if ($pdo->inTransaction()) { $pdo->rollBack(); } if (stripos($e->getMessage(), 'Duplicate entry') !== false) { $errors[] = 'This email is already registered.'; } else { $errors[] = 'Registration failed. Please try again.'; } } } } render_header('Shipper & Truck Owner Registration'); ?>
= e(t('reg_subtitle')) ?>