Files
nabeh/backend/app/Services/WooCommerceService.php
2026-05-22 23:55:19 +03:00

120 lines
4.1 KiB
PHP

<?php
namespace App\Services;
use App\Models\WooCommerceStore;
/**
* WooCommerceService
* Interacts with WooCommerce REST API of merchant stores securely.
*/
class WooCommerceService
{
/**
* Fetch order from WooCommerce by ID and verify customer phone
*/
public static function fetchOrder(array $store, int $orderId, ?string $customerPhone = null): ?array
{
$credentials = WooCommerceStore::getDecryptedCredentials($store);
$storeUrl = rtrim($credentials['store_url'], '/');
$url = $storeUrl . '/wp-json/wc/v3/orders/' . $orderId;
// Basic Authentication header
$auth = base64_encode($credentials['consumer_key'] . ':' . $credentials['consumer_secret']);
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Basic ' . $auth,
'Content-Type: application/json'
]);
curl_setopt($ch, CURLOPT_TIMEOUT, 15);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // Handle local dev self-signed certs gracefully
$res = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode !== 200) {
error_log("[WooCommerce API Error] Failed to fetch order $orderId from $storeUrl. HTTP: $httpCode, Response: $res");
return null;
}
$order = json_decode($res, true);
if (!$order) {
return null;
}
// Security check: Match customer phone if provided
if ($customerPhone) {
$orderPhone = $order['billing']['phone'] ?? $order['shipping']['phone'] ?? '';
if (!self::comparePhones($customerPhone, $orderPhone)) {
error_log("[WooCommerce Security Warning] Order $orderId phone ($orderPhone) does not match customer phone ($customerPhone)");
return ['unauthorized' => true];
}
}
return $order;
}
/**
* Fetch recent orders from WooCommerce
*/
public static function fetchRecentOrders(array $store, int $perPage = 30): ?array
{
$credentials = WooCommerceStore::getDecryptedCredentials($store);
$storeUrl = rtrim($credentials['store_url'], '/');
$url = $storeUrl . '/wp-json/wc/v3/orders?per_page=' . $perPage;
// Basic Authentication header
$auth = base64_encode($credentials['consumer_key'] . ':' . $credentials['consumer_secret']);
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Basic ' . $auth,
'Content-Type: application/json'
]);
curl_setopt($ch, CURLOPT_TIMEOUT, 15);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // Handle local dev self-signed certs gracefully
$res = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode !== 200) {
error_log("[WooCommerce API Error] Failed to fetch orders from $storeUrl. HTTP: $httpCode, Response: $res");
return null;
}
return json_decode($res, true);
}
/**
* Compare two phone numbers by matching their trailing digits (ignoring country codes/symbols)
*/
public static function comparePhones(string $phone1, string $phone2): bool
{
$clean1 = preg_replace('/\D/', '', $phone1);
$clean2 = preg_replace('/\D/', '', $phone2);
if (empty($clean1) || empty($clean2)) {
return false;
}
// Compare trailing 9 digits (common standard for Saudi and international numbers)
$len1 = strlen($clean1);
$len2 = strlen($clean2);
$matchLen = min(9, $len1, $len2);
if ($matchLen < 6) {
// If phone numbers are very short, require exact match
return $clean1 === $clean2;
}
return substr($clean1, -$matchLen) === substr($clean2, -$matchLen);
}
}