From 88788e6ea1bebf5f9e1c777b073a67d475a19e64 Mon Sep 17 00:00:00 2001 From: Hamza-Ayed Date: Sat, 23 May 2026 18:52:17 +0300 Subject: [PATCH] Deploy: 2026-05-23 18:52:17 --- backend/api/test-render.php | 22 +++++++++--- backend/includes/WhatsApp.php | 66 +++++++++++++++++++++++++++-------- 2 files changed, 69 insertions(+), 19 deletions(-) diff --git a/backend/api/test-render.php b/backend/api/test-render.php index abc709a..f9cb3f9 100644 --- a/backend/api/test-render.php +++ b/backend/api/test-render.php @@ -25,30 +25,32 @@ try { $fontDir = realpath(__DIR__ . '/../fonts'); $roboto = $fontDir ? $fontDir . '/Roboto-Bold.ttf' : ''; $lora = $fontDir ? $fontDir . '/Lora-Bold.ttf' : ''; +$cairo = $fontDir ? $fontDir . '/Cairo-Bold.ttf' : ''; $results = [ 'font_dir' => $fontDir, 'roboto_path' => $roboto, 'lora_path' => $lora, + 'cairo_path' => $cairo, 'roboto_exists' => file_exists($roboto), 'lora_exists' => file_exists($lora), + 'cairo_exists' => file_exists($cairo), 'php_errors_during_init' => $errors ]; // Reset captured errors for rendering phase $errors = []; -$im = imagecreatetruecolor(100, 100); +$im = imagecreatetruecolor(200, 200); $color = imagecolorallocate($im, 0, 0, 0); -function testFont($im, $fontPath, $color) { +function testFontDigits($im, $fontPath, $color) { if (!$fontPath || !file_exists($fontPath)) { return ['error' => 'File does not exist']; } $fontResults = []; for ($i = 0; $i <= 9; $i++) { - // Run WITHOUT @ to trigger the error handler $res = imagettftext($im, 12, 0, 10, 50, $color, $fontPath, (string)$i); if ($res === false) { $fontResults[$i] = 'Failed'; @@ -59,8 +61,18 @@ function testFont($im, $fontPath, $color) { return $fontResults; } -$results['Roboto-Bold.ttf'] = testFont($im, $roboto, $color); -$results['Lora-Bold.ttf'] = testFont($im, $lora, $color); +$results['Roboto-Bold.ttf_digits'] = testFontDigits($im, $roboto, $color); +$results['Lora-Bold.ttf_digits'] = testFontDigits($im, $lora, $color); +$results['Cairo-Bold.ttf_digits'] = testFontDigits($im, $cairo, $color); + +// Test Arabic text rendering specifically for Cairo +if ($cairo && file_exists($cairo)) { + $res = imagettftext($im, 14, 0, 10, 100, $color, $cairo, 'ﻖﻘﺤﺘﻠﺎ ﺰﻣﺮ'); // رمز التحقق (RTL shaped) + $results['Cairo-Bold.ttf_arabic_render'] = ($res === false) ? 'Failed' : 'Success'; +} else { + $results['Cairo-Bold.ttf_arabic_render'] = 'File not found'; +} + $results['rendering_errors'] = $errors; imagedestroy($im); diff --git a/backend/includes/WhatsApp.php b/backend/includes/WhatsApp.php index 23225e9..19723ff 100644 --- a/backend/includes/WhatsApp.php +++ b/backend/includes/WhatsApp.php @@ -117,7 +117,8 @@ class WhatsAppClient { // Use Fontsource dedicated jsDelivr CDN endpoint for direct TTF files $fonts = [ 'Roboto-Bold.ttf' => 'https://cdn.jsdelivr.net/fontsource/fonts/roboto@latest/latin-700-normal.ttf', - 'Lora-Bold.ttf' => 'https://cdn.jsdelivr.net/fontsource/fonts/lora@latest/latin-700-normal.ttf' + 'Lora-Bold.ttf' => 'https://cdn.jsdelivr.net/fontsource/fonts/lora@latest/latin-700-normal.ttf', + 'Cairo-Bold.ttf' => 'https://cdn.jsdelivr.net/fontsource/fonts/cairo@latest/arabic-700-normal.ttf' ]; foreach ($fonts as $filename => $url) { @@ -188,6 +189,7 @@ class WhatsAppClient { // --- 1. Check if TTF is available and fonts are loaded --- $useTtf = false; $availableFonts = []; + $arabicFont = ''; if (function_exists('imagettftext')) { $fontDir = realpath(__DIR__ . '/../fonts'); if ($fontDir) { @@ -197,6 +199,11 @@ class WhatsAppClient { if (file_exists($fontDir . '/Lora-Bold.ttf') && @filesize($fontDir . '/Lora-Bold.ttf') > 20000) { $availableFonts[] = $fontDir . '/Lora-Bold.ttf'; } + if (file_exists($fontDir . '/Cairo-Bold.ttf') && @filesize($fontDir . '/Cairo-Bold.ttf') > 20000) { + $arabicFont = $fontDir . '/Cairo-Bold.ttf'; + // We can also use Cairo for drawing OTP digits for extra variety! + $availableFonts[] = $fontDir . '/Cairo-Bold.ttf'; + } if (!empty($availableFonts)) { $useTtf = true; } @@ -260,21 +267,52 @@ class WhatsAppClient { // --- 3. Draw Random Header Label with Variable Font --- $labels = [ - 'Verification Code:', - 'Your OTP:', - 'Security Key:', - 'Access Number:', - 'Auth Code:', - 'Login Pin:', - 'Secret Key:', - 'Your Number:', - 'One Time Pass:', - 'Code:' + // English labels of varying word count + ['text' => 'Verification Code:', 'lang' => 'en'], + ['text' => 'Your OTP:', 'lang' => 'en'], + ['text' => 'Security Key:', 'lang' => 'en'], + ['text' => 'Access Number:', 'lang' => 'en'], + ['text' => 'Auth Code:', 'lang' => 'en'], + ['text' => 'Login Pin:', 'lang' => 'en'], + ['text' => 'Secret Key:', 'lang' => 'en'], + ['text' => 'Your Number:', 'lang' => 'en'], + ['text' => 'One Time Pass:', 'lang' => 'en'], + ['text' => 'Code:', 'lang' => 'en'], + ['text' => 'App Verification PIN:', 'lang' => 'en'], + ['text' => 'System Access Key:', 'lang' => 'en'], + ['text' => 'Dynamic Access PIN:', 'lang' => 'en'], + ['text' => 'Secure Verification Code:', 'lang' => 'en'], + ['text' => 'Account Code:', 'lang' => 'en'], + ['text' => 'Secure Passcode:', 'lang' => 'en'], + + // Pre-shaped Arabic labels (written RTL for GD engine) + ['text' => 'ﻖﻘﺤﺘﻠﺎ ﺰﻣﺮ', 'lang' => 'ar'], // رمز التحقق + ['text' => 'ﻥﺎﻣﺃﻟﺍ ﺩﻮﻛ', 'lang' => 'ar'], // كود الأمان + ['text' => 'ﺪﻴﻜﺃﺘﻠﺍ ﺰﻣﺮ', 'lang' => 'ar'], // رمز التأكيد + ['text' => 'ﻒﻳﺮﻌﺘﻟﺍ ﻢﻗﺭ', 'lang' => 'ar'] // رقم التعريف ]; - $label = $labels[array_rand($labels)]; - $labelFont = random_int(3, 5); // Random built-in font (3, 4, or 5) - imagestring($im, $labelFont, 20, 10, $label, $textColor); + $selectedLabel = $labels[array_rand($labels)]; + $label = $selectedLabel['text']; + + if ($useTtf) { + // Select font: Cairo-Bold for Arabic, random for English + $labelFont = ($selectedLabel['lang'] === 'ar' && $arabicFont) + ? $arabicFont + : $availableFonts[array_rand($availableFonts)]; + + // Draw smooth TTF label (y=28 is baseline position, roughly equivalent to y=10 box) + $size = ($selectedLabel['lang'] === 'ar') ? 14 : 12; // Adjust size for Arabic readability + imagettftext($im, $size, 0, 20, 28, $textColor, $labelFont, $label); + } else { + // Fallback: draw using built-in font (convert Arabic to English fallback to avoid garbage text) + $fallbackLabel = $label; + if ($selectedLabel['lang'] === 'ar') { + $fallbackLabel = 'Verification Code:'; + } + $labelFont = random_int(3, 5); + imagestring($im, $labelFont, 20, 10, $fallbackLabel, $textColor); + } // Draw a bounding border imagerectangle($im, 0, 0, 299, 99, $noiseColor);