diff --git a/backend/auth/otp/verify.php b/backend/auth/otp/verify.php index a6d5b82..f11625f 100644 --- a/backend/auth/otp/verify.php +++ b/backend/auth/otp/verify.php @@ -177,8 +177,10 @@ try { $isRegistered = false; $driverData = null; - $chkStmt = $con->prepare("SELECT id, first_name, last_name, email, phone FROM driver WHERE phone = ?"); - $chkStmt->execute([$encryptionHelper->encryptData($phone_number)]); + global $blindIndex; + $phoneBidx = $blindIndex ? $blindIndex->index('driver.phone', $phone_number) : null; + $chkStmt = $con->prepare("SELECT id, first_name, last_name, email, phone FROM driver WHERE phone = ? OR (? IS NOT NULL AND phone_bidx = ?)"); + $chkStmt->execute([$encryptionHelper->encryptData($phone_number), $phoneBidx, $phoneBidx]); $driver = $chkStmt->fetch(PDO::FETCH_ASSOC); // Generate driverID for unregistered users (hash of phone) @@ -268,13 +270,14 @@ try { $stmtUpd->bindParam(':id', $matchedRowId, PDO::PARAM_INT); $stmtUpd->execute(); - // Check registration status $isRegistered = false; $passengerData = null; $passengerID = ''; - $chkStmt = $con->prepare("SELECT id, first_name, last_name, email, phone FROM passengers WHERE phone = ?"); - $chkStmt->execute([$encryptionHelper->encryptData($phone_number)]); + global $blindIndex; + $phoneBidx = $blindIndex ? $blindIndex->index('passengers.phone', $phone_number) : null; + $chkStmt = $con->prepare("SELECT id, first_name, last_name, email, phone FROM passengers WHERE phone = ? OR (? IS NOT NULL AND phone_bidx = ?)"); + $chkStmt->execute([$encryptionHelper->encryptData($phone_number), $phoneBidx, $phoneBidx]); $passenger = $chkStmt->fetch(PDO::FETCH_ASSOC); if ($passenger) { diff --git a/backend/auth/passenger/register.php b/backend/auth/passenger/register.php index fb0f7de..100674a 100644 --- a/backend/auth/passenger/register.php +++ b/backend/auth/passenger/register.php @@ -63,7 +63,7 @@ try { $firstName_encrypted = $encryptionHelper->encryptData($firstName); $lastName_encrypted = $encryptionHelper->encryptData($lastName); $email_encrypted = $encryptionHelper->encryptData($email); - $uniqueId = substr(md5($phoneNumber), 0, 20); + $uniqueId = substr(md5($phoneNumber), 0, 16); $password_hashed = password_hash($email . $uniqueId, PASSWORD_DEFAULT); $unknown_encrypted = $encryptionHelper->encryptData("unknown yet"); @@ -77,12 +77,13 @@ try { // (مهلة أوسع من صلاحية الرمز نفسه [5 دقائق] لإعطاء وقت كافٍ لإكمال // نموذج التسجيل بعد التحقق مباشرة). $step = 4.5; + $otpSearchKey = otpPhoneKey($phoneNumber); $verifyCheckStmt = $con->prepare( "SELECT id FROM phone_verification_passenger WHERE phone_number = ? AND verified = 1 AND created_at > DATE_SUB(NOW(), INTERVAL 30 MINUTE) LIMIT 1" ); - $verifyCheckStmt->execute([$phoneNumber_encrypted]); + $verifyCheckStmt->execute([$otpSearchKey]); if ($verifyCheckStmt->rowCount() === 0) { error_log("$logTag Step 4.5 Error: Phone number not verified via OTP."); jsonError("Phone number must be verified before registration."); diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index cbb9dd7..c654706 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -30,8 +30,8 @@ services: # التقسيم لأبعد من هذا لا يضيف أداءً — نفس الصورة، نفس النواة. php: build: - context: ./php - dockerfile: Dockerfile.fpm + context: .. + dockerfile: docker/php/Dockerfile.fpm args: PHP_VERSION: "${PHP_VERSION:-8.2}" volumes: @@ -67,7 +67,9 @@ services: # ‏TLS على هذا المنفذ (‎https://…:2020‎) فتتجمّد المصافحة وينتهي بـ timeout. # ‏nginx على المضيف يستمع على 2020 بالشهادة ويمرّر إلى 12020 هنا. # ‏انظر nginx/siro-sockets-tls.conf - - "127.0.0.1:12020:2020" + # ‏المنفذ قابل للضبط: على سيرفر تعمل عليه أكثر من نسخة (siro/tripz/intaleq) + # ‏يتصادم 12020 الثابت فلا تبدأ الحاوية أصلاً. اضبط DRIVER_SOCKET_PORT في .env. + - "127.0.0.1:${DRIVER_SOCKET_PORT:-12020}:2020" # ‏و2021 داخلي فقط: الباك إند يناديه عبر http://socket_driver:2021 depends_on: - redis @@ -90,7 +92,7 @@ services: ports: # ‏نفس منطق سوكيت السائقين: nginx على المضيف يستمع على 3030 بالشهادة # ‏ويمرّر إلى 13030 هنا. و3031 داخلي فقط (http://socket_passenger:3031). - - "127.0.0.1:13030:3030" + - "127.0.0.1:${PASSENGER_SOCKET_PORT:-13030}:3030" depends_on: - redis mem_limit: 512m diff --git a/docker/php/Dockerfile.fpm b/docker/php/Dockerfile.fpm index 46c4e5c..afc2698 100644 --- a/docker/php/Dockerfile.fpm +++ b/docker/php/Dockerfile.fpm @@ -6,4 +6,9 @@ ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/do RUN chmod +x /usr/local/bin/install-php-extensions && \ install-php-extensions mysqli pdo_mysql redis opcache gd zip @composer +# تثبيت مكتبات سيرفر المدفوعات (firebase/php-jwt وغيره) +# هذا يخبز vendor/ داخل الصورة مباشرة حتى لا يعتمد على مجلد خارجي +COPY payment_server/v2/composer.json payment_server/v2/composer.lock /var/www/v2/ +RUN cd /var/www/v2 && composer install --no-dev --no-interaction --optimize-autoloader + WORKDIR /var/www diff --git a/payment_server/v2/main/connect.php b/payment_server/v2/main/connect.php index f30bd57..b5874c9 100755 --- a/payment_server/v2/main/connect.php +++ b/payment_server/v2/main/connect.php @@ -1,54 +1,61 @@ false, - PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, + PDO::ATTR_EMULATE_PREPARES => false, + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, - PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES UTF8" + PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES UTF8", ]; - $user = getenv('DB_PAYMENT_USER') ?: (getenv('USER') ?: 'root'); - $pass = getenv('DB_PAYMENT_PASS') ?: (getenv('PASS') ?: getenv('MYSQL_ROOT_PASSWORD')); $con = new PDO($dsn, $user, $pass, $options); - -// echo $con; - // --- JWT Authentication --- - include "functions.php"; // Include the functions file - - $decodedToken = authenticateJWT(); // Call the authentication function + // 5. JWT Authentication + include __DIR__ . "/functions.php"; + $decodedToken = authenticateJWT(); } catch (PDOException $e) { - error_log($e->getMessage()); - http_response_code(500); // Internal Server Error + error_log('[WALLET] DB Error: ' . $e->getMessage()); + http_response_code(500); echo json_encode(['error' => 'A database error occurred.']); exit; } diff --git a/payment_server/v2/main/ride/cliq/create_cliq_invoice.php b/payment_server/v2/main/ride/cliq/create_cliq_invoice.php index 6365bee..b96aae4 100755 --- a/payment_server/v2/main/ride/cliq/create_cliq_invoice.php +++ b/payment_server/v2/main/ride/cliq/create_cliq_invoice.php @@ -7,7 +7,7 @@ try { $userId = filterRequest("user_id"); $userType = filterRequest("user_type"); $amount = filterRequest("amount"); - $cliqPhone = filterRequest("cliq_phone"); + $cliqPhone = filterRequest("cliq_phone") ?: filterRequest("click_phone"); // التطبيق يرسل click_phone $phone = filterRequest("phone"); if (empty($userId) || empty($userType) || !is_numeric($amount) || $amount <= 0 || empty($cliqPhone)) { @@ -37,14 +37,12 @@ try { $upd = $con->prepare(" UPDATE cliq_invoices SET amount = :amount, - phone = :phone, cliq_phone = :cliq_phone, updated_at = NOW() WHERE id = :id "); $upd->execute([ ':amount' => $amount, - ':phone' => $phone ?: null, ':cliq_phone' => $cliqPhone, ':id' => $existing['id'], ]); @@ -62,15 +60,14 @@ try { $ins = $con->prepare(" INSERT INTO cliq_invoices - (invoice_number, user_id, user_type, phone, amount, cliq_phone, status, created_at, updated_at) + (invoice_number, user_id, user_type, amount, cliq_phone, status, created_at, updated_at) VALUES - (:invoice_number, :user_id, :user_type, :phone, :amount, :cliq_phone, 'pending', NOW(), NOW()) + (:invoice_number, :user_id, :user_type, :amount, :cliq_phone, 'pending', NOW(), NOW()) "); $ins->execute([ ':invoice_number' => $invoiceNumber, ':user_id' => $userId, ':user_type' => $userType, - ':phone' => $phone ?: null, ':amount' => $amount, ':cliq_phone' => $cliqPhone ]); diff --git a/payment_server/v2/main/ride/passengerWallet/getWalletByPassenger.php b/payment_server/v2/main/ride/passengerWallet/getWalletByPassenger.php index 0a256ea..e81caf1 100755 --- a/payment_server/v2/main/ride/passengerWallet/getWalletByPassenger.php +++ b/payment_server/v2/main/ride/passengerWallet/getWalletByPassenger.php @@ -3,13 +3,13 @@ include "../../connect.php"; $passenger_id = filterRequest("passenger_id"); $sql = "SELECT - COALESCE(dummy.passenger_id, '$passenger_id') AS passenger_id, - COALESCE(SUM(pw.balance), 0) AS total, -- Adjust column to represent payments + COALESCE(dummy.passenger_id, :passenger_id) AS passenger_id, + COALESCE(SUM(pw.balance), 0) AS total, COALESCE(p.first_name, '') AS first_name, COALESCE(p.last_name, '') AS last_name, COALESCE(p.phone, '') AS phone FROM - (SELECT '$passenger_id' AS passenger_id) AS dummy + (SELECT :passenger_id2 AS passenger_id) AS dummy LEFT JOIN `passengerWallet` pw ON pw.passenger_id = dummy.passenger_id LEFT JOIN passengers p ON p.id = dummy.passenger_id GROUP BY @@ -17,17 +17,13 @@ GROUP BY LIMIT 0, 25; "; $stmt = $con->prepare($sql); -$stmt->execute(); +$stmt->execute(['passenger_id' => $passenger_id, 'passenger_id2' => $passenger_id]); -if ($stmt->rowCount() > 0) { - // Fetch the record - $row = $stmt->fetchAll(PDO::FETCH_ASSOC); - - printSuccess( $row); - -} - else{ - // Print a failure message - printFailure($message = "No wallet record found"); +// LEFT JOIN يُرجع دائماً صفاً واحداً على الأقل (balance=0 إذا لم توجد محفظة) +$row = $stmt->fetchAll(PDO::FETCH_ASSOC); +if (!empty($row)) { + printSuccess($row); +} else { + printFailure("No wallet record found"); } ?> \ No newline at end of file