191 lines
6.4 KiB
PHP
191 lines
6.4 KiB
PHP
<?php
|
|
/**
|
|
* WhatsApp Gateway Client Helper
|
|
*/
|
|
|
|
class WhatsAppClient {
|
|
private static $gatewayUrl;
|
|
private static $secret;
|
|
private static $sessionKey;
|
|
|
|
private static function init() {
|
|
if (!self::$gatewayUrl) {
|
|
self::$gatewayUrl = rtrim(defined('WHATSAPP_GATEWAY_URL') ? WHATSAPP_GATEWAY_URL : 'http://localhost:3732', '/');
|
|
self::$secret = defined('WHATSAPP_WEBHOOK_SECRET') ? WHATSAPP_WEBHOOK_SECRET : '';
|
|
self::$sessionKey = defined('WHATSAPP_SESSION_KEY') ? WHATSAPP_SESSION_KEY : 'otp_session';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if a phone number is registered on WhatsApp.
|
|
*
|
|
* @param string $phone Phone number in E.164 format (e.g. +96279XXXXXXXX)
|
|
* @return bool True if registered, false otherwise
|
|
*/
|
|
public static function isAvailable($phone) {
|
|
self::init();
|
|
|
|
$cleanPhone = preg_replace('/[^\d]/', '', $phone); // Strip '+' and other non-digits
|
|
|
|
$payload = json_encode([
|
|
'session_key' => self::$sessionKey,
|
|
'phone' => $cleanPhone
|
|
]);
|
|
|
|
$ch = curl_init(self::$gatewayUrl . '/api/contacts/check');
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
curl_setopt($ch, CURLOPT_POST, true);
|
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
|
|
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
|
'Content-Type: application/json',
|
|
'X-Webhook-Secret: ' . self::$secret
|
|
]);
|
|
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
|
|
$response = curl_exec($ch);
|
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
curl_close($ch);
|
|
|
|
if ($httpCode === 200 && $response) {
|
|
$data = json_decode($response, true);
|
|
if (isset($data['status']) && $data['status'] === 'success') {
|
|
return isset($data['data']['exists']) && $data['data']['exists'] === true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Send OTP message via WhatsApp Gateway.
|
|
*
|
|
* @param string $phone Destination phone number
|
|
* @param string $message Message text
|
|
* @param string|null $imageBase64 Optional base64 image data
|
|
* @return bool True if successfully sent
|
|
*/
|
|
public static function sendMessage($phone, $message, $imageBase64 = null) {
|
|
self::init();
|
|
|
|
$cleanPhone = preg_replace('/[^\d]/', '', $phone);
|
|
|
|
$payloadData = [
|
|
'session_key' => self::$sessionKey,
|
|
'phone' => $cleanPhone,
|
|
'message' => $message
|
|
];
|
|
|
|
if ($imageBase64) {
|
|
$payloadData['image'] = $imageBase64;
|
|
}
|
|
|
|
$payload = json_encode($payloadData);
|
|
|
|
$ch = curl_init(self::$gatewayUrl . '/api/messages/send');
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
curl_setopt($ch, CURLOPT_POST, true);
|
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
|
|
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
|
'Content-Type: application/json',
|
|
'X-Webhook-Secret: ' . self::$secret
|
|
]);
|
|
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
|
|
$response = curl_exec($ch);
|
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
curl_close($ch);
|
|
|
|
if ($httpCode === 200 && $response) {
|
|
$data = json_decode($response, true);
|
|
return isset($data['status']) && $data['status'] === 'success';
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Generate dynamic base64-encoded image containing OTP code using GD library.
|
|
*
|
|
* @param string $otp 4-digit OTP code
|
|
* @return string Base64 encoded PNG image
|
|
*/
|
|
public static function generateOtpImageBase64($otp) {
|
|
// Create a 300x100 image
|
|
$im = imagecreatetruecolor(300, 100);
|
|
if (!$im) {
|
|
return '';
|
|
}
|
|
|
|
// Colors
|
|
$bgColor = imagecolorallocate($im, 240, 244, 248); // Soft grey-blue
|
|
$textColor = imagecolorallocate($im, 33, 37, 41); // Dark charcoal
|
|
$noiseColor = imagecolorallocate($im, 200, 210, 220); // Light noise
|
|
|
|
// Fill background
|
|
imagefill($im, 0, 0, $bgColor);
|
|
|
|
// --- 1. Draw Big OTP Text by Scaling ---
|
|
// Create a small image for the OTP
|
|
$otpWidth = 45; // 3 chars * 15px width roughly
|
|
$otpHeight = 20;
|
|
$otpIm = imagecreatetruecolor($otpWidth, $otpHeight);
|
|
$otpBg = imagecolorallocate($otpIm, 240, 244, 248);
|
|
$otpFg = imagecolorallocate($otpIm, 13, 110, 253);
|
|
imagefill($otpIm, 0, 0, $otpBg);
|
|
|
|
$chars = str_split($otp);
|
|
$x = 2;
|
|
foreach ($chars as $char) {
|
|
$y = random_int(0, 5); // Slight vertical jitter
|
|
imagestring($otpIm, 5, $x, $y, $char, $otpFg);
|
|
$x += 14; // Font 5 width is approx 9px, leaving some space
|
|
}
|
|
|
|
// Scale it up by 3x onto the main image
|
|
$scale = 3;
|
|
$dstWidth = $otpWidth * $scale;
|
|
$dstHeight = $otpHeight * $scale;
|
|
|
|
// Place it randomly in the bottom right-ish area
|
|
$dstX = random_int(80, 150);
|
|
$dstY = random_int(30, 40);
|
|
|
|
imagecopyresampled($im, $otpIm, $dstX, $dstY, 0, 0, $dstWidth, $dstHeight, $otpWidth, $otpHeight);
|
|
imagedestroy($otpIm);
|
|
|
|
// --- 2. Add Background Noise (Lines & Dots) ---
|
|
// Drawing noise *after* the OTP helps to obstruct it slightly from OCR
|
|
for ($i = 0; $i < 6; $i++) {
|
|
imageline($im, random_int(0, 300), random_int(0, 100), random_int(0, 300), random_int(0, 100), $noiseColor);
|
|
}
|
|
for ($i = 0; $i < 100; $i++) {
|
|
imagesetpixel($im, random_int(0, 300), random_int(0, 100), $noiseColor);
|
|
}
|
|
|
|
// --- 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:'
|
|
];
|
|
$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);
|
|
|
|
// Draw a bounding border
|
|
imagerectangle($im, 0, 0, 299, 99, $noiseColor);
|
|
|
|
// Capture output
|
|
ob_start();
|
|
imagepng($im);
|
|
$imageData = ob_get_clean();
|
|
imagedestroy($im);
|
|
|
|
return base64_encode($imageData);
|
|
}
|
|
}
|