added website and fixed server
This commit is contained in:
@@ -59,7 +59,9 @@ function callCyberPanelApi(string $panelUrl, string $endpoint, string $username,
|
||||
|
||||
$payload = [
|
||||
'adminUser' => $username,
|
||||
'adminPass' => $password
|
||||
'adminPass' => $password,
|
||||
'username' => $username,
|
||||
'password' => $password
|
||||
];
|
||||
|
||||
$ch = curl_init();
|
||||
@@ -165,7 +167,27 @@ try {
|
||||
|
||||
$versionResult = callCyberPanelApi($panelUrl, 'cyberPanelVersion', $username, $password);
|
||||
$packagesResult = callCyberPanelApi($panelUrl, 'listPackage', $username, $password);
|
||||
if (
|
||||
!$versionResult['success'] &&
|
||||
!$packagesResult['success']
|
||||
) {
|
||||
$failUpdate = $db->prepare("
|
||||
UPDATE cyberpanel_servers
|
||||
SET
|
||||
last_status = 'offline',
|
||||
last_check = NOW()
|
||||
WHERE id = :id
|
||||
");
|
||||
|
||||
$failUpdate->execute([
|
||||
':id' => $serverId
|
||||
]);
|
||||
|
||||
jsonResponse(false, 'CyberPanel API authentication failed.', [
|
||||
'version_response' => $versionResult,
|
||||
'packages_response' => $packagesResult
|
||||
]);
|
||||
}
|
||||
$version = '-';
|
||||
$packagesCount = 0;
|
||||
|
||||
|
||||
@@ -0,0 +1,452 @@
|
||||
<?php
|
||||
ini_set('display_errors', 0);
|
||||
error_reporting(E_ALL);
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
require_once __DIR__ . '/../class/db-functions.php';
|
||||
|
||||
$db = DBHandlerSelect::getInstance()->getConnection();
|
||||
|
||||
function jsonResponse(bool $success, string $message, array $extra = []): void
|
||||
{
|
||||
echo json_encode(array_merge([
|
||||
'success' => $success,
|
||||
'message' => $message
|
||||
], $extra));
|
||||
exit;
|
||||
}
|
||||
|
||||
function getCyberpanelEncryptionKey(): string
|
||||
{
|
||||
return hash('sha256', 'CHANGE_THIS_SECRET_KEY_FOR_CYBERPANEL_DASHBOARD');
|
||||
}
|
||||
|
||||
function decryptCyberpanelPassword(string $encryptedPassword): string
|
||||
{
|
||||
if ($encryptedPassword === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
$key = getCyberpanelEncryptionKey();
|
||||
$decoded = base64_decode($encryptedPassword);
|
||||
|
||||
if (!$decoded || strpos($decoded, '::') === false) {
|
||||
return '';
|
||||
}
|
||||
|
||||
[$ivBase64, $encrypted] = explode('::', $decoded, 2);
|
||||
$iv = base64_decode($ivBase64);
|
||||
|
||||
if (!$iv) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$decrypted = openssl_decrypt(
|
||||
$encrypted,
|
||||
'AES-256-CBC',
|
||||
$key,
|
||||
0,
|
||||
$iv
|
||||
);
|
||||
|
||||
return $decrypted ?: '';
|
||||
}
|
||||
|
||||
function readCookieFromJar(string $cookieFile, string $cookieName): string
|
||||
{
|
||||
if (!file_exists($cookieFile)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$lines = file($cookieFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
||||
|
||||
foreach ($lines as $line) {
|
||||
if (strpos($line, '#') === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$parts = preg_split('/\s+/', $line);
|
||||
|
||||
if (count($parts) >= 7 && $parts[5] === $cookieName) {
|
||||
return $parts[6];
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
function cyberpanelGet(string $url, string $cookieFile): array
|
||||
{
|
||||
$ch = curl_init();
|
||||
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_URL => $url,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_HEADER => false,
|
||||
CURLOPT_COOKIEJAR => $cookieFile,
|
||||
CURLOPT_COOKIEFILE => $cookieFile,
|
||||
CURLOPT_TIMEOUT => 30,
|
||||
CURLOPT_CONNECTTIMEOUT => 15,
|
||||
CURLOPT_SSL_VERIFYHOST => false,
|
||||
CURLOPT_SSL_VERIFYPEER => false,
|
||||
CURLOPT_USERAGENT => 'Mozilla/5.0 CyberPanelDashboard'
|
||||
]);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$curlError = curl_error($ch);
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
return [
|
||||
'http_code' => $httpCode,
|
||||
'curl_error' => $curlError,
|
||||
'raw' => $response
|
||||
];
|
||||
}
|
||||
|
||||
function cyberpanelPostJson(string $url, array $payload, string $cookieFile, string $csrfToken, string $referer): array
|
||||
{
|
||||
$headers = [
|
||||
'Content-Type: application/json',
|
||||
'Accept: application/json',
|
||||
'X-Csrftoken: ' . $csrfToken,
|
||||
'Referer: ' . $referer
|
||||
];
|
||||
|
||||
$ch = curl_init();
|
||||
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_URL => $url,
|
||||
CURLOPT_POST => true,
|
||||
CURLOPT_POSTFIELDS => json_encode($payload),
|
||||
CURLOPT_HTTPHEADER => $headers,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_HEADER => false,
|
||||
CURLOPT_COOKIEJAR => $cookieFile,
|
||||
CURLOPT_COOKIEFILE => $cookieFile,
|
||||
CURLOPT_TIMEOUT => 30,
|
||||
CURLOPT_CONNECTTIMEOUT => 15,
|
||||
CURLOPT_SSL_VERIFYHOST => false,
|
||||
CURLOPT_SSL_VERIFYPEER => false,
|
||||
CURLOPT_USERAGENT => 'Mozilla/5.0 CyberPanelDashboard'
|
||||
]);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$curlError = curl_error($ch);
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
$json = json_decode((string)$response, true);
|
||||
|
||||
return [
|
||||
'http_code' => $httpCode,
|
||||
'curl_error' => $curlError,
|
||||
'raw' => $response,
|
||||
'json' => is_array($json) ? $json : null
|
||||
];
|
||||
}
|
||||
|
||||
function normalizeWebsiteItems(array $fetchJson): array
|
||||
{
|
||||
$items = [];
|
||||
|
||||
if (isset($fetchJson['data'])) {
|
||||
if (is_string($fetchJson['data'])) {
|
||||
$decodedData = json_decode($fetchJson['data'], true);
|
||||
if (is_array($decodedData)) {
|
||||
$items = $decodedData;
|
||||
}
|
||||
} elseif (is_array($fetchJson['data'])) {
|
||||
$items = $fetchJson['data'];
|
||||
}
|
||||
} elseif (isset($fetchJson['websites']) && is_array($fetchJson['websites'])) {
|
||||
$items = $fetchJson['websites'];
|
||||
} elseif (isset($fetchJson['records']) && is_array($fetchJson['records'])) {
|
||||
$items = $fetchJson['records'];
|
||||
}
|
||||
|
||||
$websites = [];
|
||||
|
||||
foreach ($items as $item) {
|
||||
if (!is_array($item)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$domain = $item['domain'] ?? $item['domainName'] ?? $item['website'] ?? $item['name'] ?? '';
|
||||
$owner = $item['admin'] ?? $item['owner'] ?? $item['user'] ?? $item['websiteOwner'] ?? '';
|
||||
$ownerUsername = $item['owner_username'] ?? $item['ownerUsername'] ?? $item['username'] ?? $owner ?? '';
|
||||
$package = $item['package'] ?? $item['packageName'] ?? '';
|
||||
$phpVersion = $item['php_version'] ?? $item['phpVersion'] ?? $item['php'] ?? '';
|
||||
$sslStatus = $item['ssl']['status'] ?? $item['ssl_status'] ?? $item['sslStatus'] ?? 'unknown';
|
||||
$diskUsage = $item['diskUsed'] ?? $item['disk_usage'] ?? $item['diskUsage'] ?? '';
|
||||
$status = $item['status'] ?? $item['state'] ?? 'unknown';
|
||||
|
||||
if ($domain === '') {
|
||||
foreach ($item as $value) {
|
||||
if (is_string($value) && preg_match('/^[a-z0-9.-]+\.[a-z]{2,}$/i', trim($value))) {
|
||||
$domain = trim($value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($domain !== '') {
|
||||
$websites[] = [
|
||||
'domain' => $domain,
|
||||
'owner' => $owner,
|
||||
'owner_username' => $ownerUsername,
|
||||
'package' => $package,
|
||||
'php_version' => $phpVersion,
|
||||
'ssl_status' => $sslStatus,
|
||||
'disk_usage' => $diskUsage,
|
||||
'status' => strtolower(trim((string)$status)),
|
||||
'php_version' => trim((string)$phpVersion),
|
||||
'ssl_status' => strtolower(trim((string)$sslStatus)),
|
||||
'disk_usage' => trim((string)$diskUsage),
|
||||
'raw' => $item
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $websites;
|
||||
}
|
||||
|
||||
try {
|
||||
$serverId = isset($_POST['server_id']) ? (int)$_POST['server_id'] : 0;
|
||||
|
||||
if ($serverId <= 0) {
|
||||
jsonResponse(false, 'Missing server ID.');
|
||||
}
|
||||
|
||||
$stmt = $db->prepare("
|
||||
SELECT
|
||||
id,
|
||||
panel_url,
|
||||
username,
|
||||
password_encrypted,
|
||||
api_enabled
|
||||
FROM cyberpanel_servers
|
||||
WHERE id = :id
|
||||
LIMIT 1
|
||||
");
|
||||
|
||||
$stmt->execute([
|
||||
':id' => $serverId
|
||||
]);
|
||||
|
||||
$server = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (!$server) {
|
||||
jsonResponse(false, 'Server not found.');
|
||||
}
|
||||
|
||||
if ((int)$server['api_enabled'] !== 1) {
|
||||
jsonResponse(false, 'API disabled for this server.');
|
||||
}
|
||||
|
||||
$panelUrl = rtrim($server['panel_url'], '/');
|
||||
$username = $server['username'];
|
||||
$password = decryptCyberpanelPassword($server['password_encrypted']);
|
||||
|
||||
if ($password === '') {
|
||||
jsonResponse(false, 'Password cannot be decrypted.');
|
||||
}
|
||||
|
||||
$cookieFile = tempnam(sys_get_temp_dir(), 'cyberpanel_cookie_');
|
||||
|
||||
/*
|
||||
* Step 1: open CyberPanel first to obtain csrftoken cookie.
|
||||
*/
|
||||
$initialGet = cyberpanelGet($panelUrl . '/', $cookieFile);
|
||||
|
||||
if ($initialGet['curl_error'] !== '') {
|
||||
@unlink($cookieFile);
|
||||
jsonResponse(false, 'CyberPanel initial GET failed: ' . $initialGet['curl_error']);
|
||||
}
|
||||
|
||||
$csrfToken = readCookieFromJar($cookieFile, 'csrftoken');
|
||||
|
||||
if ($csrfToken === '') {
|
||||
@unlink($cookieFile);
|
||||
jsonResponse(false, 'CSRF token not found from CyberPanel.', [
|
||||
'http_code' => $initialGet['http_code'],
|
||||
'raw_preview' => substr(strip_tags((string)$initialGet['raw']), 0, 1000)
|
||||
]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Step 2: login with csrf token.
|
||||
*/
|
||||
$login = cyberpanelPostJson(
|
||||
$panelUrl . '/verifyLogin',
|
||||
[
|
||||
'username' => $username,
|
||||
'password' => $password,
|
||||
'languageSelection' => 'english'
|
||||
],
|
||||
$cookieFile,
|
||||
$csrfToken,
|
||||
$panelUrl . '/'
|
||||
);
|
||||
|
||||
if ($login['curl_error'] !== '') {
|
||||
@unlink($cookieFile);
|
||||
jsonResponse(false, 'CyberPanel login cURL error: ' . $login['curl_error']);
|
||||
}
|
||||
|
||||
if (!$login['json']) {
|
||||
@unlink($cookieFile);
|
||||
jsonResponse(false, 'CyberPanel login did not return JSON.', [
|
||||
'http_code' => $login['http_code'],
|
||||
'raw_preview' => substr(strip_tags((string)$login['raw']), 0, 1000)
|
||||
]);
|
||||
}
|
||||
|
||||
$loginOk = false;
|
||||
|
||||
if (isset($login['json']['loginStatus']) && $login['json']['loginStatus']) {
|
||||
$loginOk = true;
|
||||
}
|
||||
|
||||
if (isset($login['json']['status']) && (int)$login['json']['status'] === 1) {
|
||||
$loginOk = true;
|
||||
}
|
||||
|
||||
if (!$loginOk) {
|
||||
@unlink($cookieFile);
|
||||
jsonResponse(false, 'CyberPanel login failed.', [
|
||||
'login_response' => $login['json']
|
||||
]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Step 3: after login, read sessionid and fetch websites.
|
||||
*/
|
||||
|
||||
|
||||
$csrfTokenAfterLogin = readCookieFromJar($cookieFile, 'csrftoken');
|
||||
|
||||
if ($csrfTokenAfterLogin !== '') {
|
||||
$csrfToken = $csrfTokenAfterLogin;
|
||||
}
|
||||
|
||||
$fetch = cyberpanelPostJson(
|
||||
$panelUrl . '/websites/fetchWebsitesList',
|
||||
[
|
||||
'page' => 1,
|
||||
'recordsToShow' => 1000
|
||||
],
|
||||
$cookieFile,
|
||||
$csrfToken,
|
||||
$panelUrl . '/websites/listWebsites'
|
||||
);
|
||||
|
||||
@unlink($cookieFile);
|
||||
|
||||
if ($fetch['curl_error'] !== '') {
|
||||
jsonResponse(false, 'fetchWebsitesList cURL error: ' . $fetch['curl_error']);
|
||||
}
|
||||
|
||||
if (!$fetch['json']) {
|
||||
jsonResponse(false, 'fetchWebsitesList did not return JSON.', [
|
||||
'http_code' => $fetch['http_code'],
|
||||
'raw_preview' => substr(strip_tags((string)$fetch['raw']), 0, 1000)
|
||||
]);
|
||||
}
|
||||
|
||||
if (
|
||||
isset($fetch['json']['error_message']) &&
|
||||
stripos($fetch['json']['error_message'], 'session') !== false
|
||||
) {
|
||||
jsonResponse(false, 'CyberPanel session not accepted.', [
|
||||
'fetch_response' => $fetch['json']
|
||||
]);
|
||||
}
|
||||
|
||||
$websites = normalizeWebsiteItems($fetch['json']);
|
||||
|
||||
$upsert = $db->prepare("
|
||||
INSERT INTO cyberpanel_websites
|
||||
(
|
||||
server_id,
|
||||
domain,
|
||||
website_owner,
|
||||
owner_username,
|
||||
package_name,
|
||||
php_version,
|
||||
ssl_status,
|
||||
website_status,
|
||||
disk_usage,
|
||||
raw_json,
|
||||
last_sync
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
:server_id,
|
||||
:domain,
|
||||
:website_owner,
|
||||
:owner_username,
|
||||
:package_name,
|
||||
:php_version,
|
||||
:ssl_status,
|
||||
:website_status,
|
||||
:disk_usage,
|
||||
:raw_json,
|
||||
NOW()
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
website_owner = VALUES(website_owner),
|
||||
owner_username = VALUES(owner_username),
|
||||
package_name = VALUES(package_name),
|
||||
php_version = VALUES(php_version),
|
||||
ssl_status = VALUES(ssl_status),
|
||||
website_status = VALUES(website_status),
|
||||
disk_usage = VALUES(disk_usage),
|
||||
raw_json = VALUES(raw_json),
|
||||
last_sync = NOW()
|
||||
");
|
||||
|
||||
$inserted = 0;
|
||||
|
||||
$inserted = 0;
|
||||
|
||||
foreach ($websites as $website) {
|
||||
$upsert->execute([
|
||||
':server_id' => $serverId,
|
||||
':domain' => $website['domain'],
|
||||
':website_owner' => $website['owner'],
|
||||
':owner_username' => $website['owner_username'] ?: null,
|
||||
':package_name' => $website['package'] ?: null,
|
||||
':php_version' => $website['php_version'] ?: null,
|
||||
':ssl_status' => $website['ssl_status'] ?: 'unknown',
|
||||
':website_status' => $website['status'] ?: 'unknown',
|
||||
':disk_usage' => $website['disk_usage'] ?: null,
|
||||
':raw_json' => json_encode($website['raw'], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)
|
||||
]);
|
||||
|
||||
$inserted++;
|
||||
}
|
||||
|
||||
$update = $db->prepare("
|
||||
UPDATE cyberpanel_servers
|
||||
SET
|
||||
last_status = 'online',
|
||||
last_check = NOW()
|
||||
WHERE id = :server_id
|
||||
");
|
||||
|
||||
$update->execute([
|
||||
':server_id' => $serverId
|
||||
]);
|
||||
|
||||
jsonResponse(true, 'Websites synced successfully.', [
|
||||
'count' => $inserted,
|
||||
'websites' => $websites,
|
||||
'raw_response' => $fetch['json']
|
||||
]);
|
||||
} catch (Throwable $e) {
|
||||
jsonResponse(false, 'Sync websites error: ' . $e->getMessage());
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
<?php
|
||||
ini_set('display_errors', 0);
|
||||
error_reporting(E_ALL);
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
require_once __DIR__ . '/../class/db-functions.php';
|
||||
|
||||
$db = DBHandlerSelect::getInstance()->getConnection();
|
||||
|
||||
function jsonResponse(bool $success, string $message, array $extra = []): void
|
||||
{
|
||||
echo json_encode(array_merge([
|
||||
'success' => $success,
|
||||
'message' => $message
|
||||
], $extra));
|
||||
exit;
|
||||
}
|
||||
|
||||
function getCyberpanelEncryptionKey(): string
|
||||
{
|
||||
return hash('sha256', 'CHANGE_THIS_SECRET_KEY_FOR_CYBERPANEL_DASHBOARD');
|
||||
}
|
||||
|
||||
function decryptCyberpanelPassword(string $encryptedPassword): string
|
||||
{
|
||||
if ($encryptedPassword === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
$key = getCyberpanelEncryptionKey();
|
||||
$decoded = base64_decode($encryptedPassword);
|
||||
|
||||
if (!$decoded || strpos($decoded, '::') === false) {
|
||||
return '';
|
||||
}
|
||||
|
||||
[$ivBase64, $encrypted] = explode('::', $decoded, 2);
|
||||
$iv = base64_decode($ivBase64);
|
||||
|
||||
if (!$iv) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$decrypted = openssl_decrypt(
|
||||
$encrypted,
|
||||
'AES-256-CBC',
|
||||
$key,
|
||||
0,
|
||||
$iv
|
||||
);
|
||||
|
||||
return $decrypted ?: '';
|
||||
}
|
||||
|
||||
function callCyberPanel(string $panelUrl, string $endpoint, string $username, string $password, array $payload = []): array
|
||||
{
|
||||
$url = rtrim($panelUrl, '/') . '/' . ltrim($endpoint, '/');
|
||||
|
||||
$payload = array_merge([
|
||||
'adminUser' => $username,
|
||||
'adminPass' => $password
|
||||
], $payload);
|
||||
|
||||
$ch = curl_init();
|
||||
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_URL => $url,
|
||||
CURLOPT_POST => true,
|
||||
CURLOPT_POSTFIELDS => json_encode($payload),
|
||||
CURLOPT_HTTPHEADER => [
|
||||
'Content-Type: application/json',
|
||||
'Accept: application/json'
|
||||
],
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_TIMEOUT => 25,
|
||||
CURLOPT_CONNECTTIMEOUT => 15,
|
||||
CURLOPT_SSL_VERIFYHOST => false,
|
||||
CURLOPT_SSL_VERIFYPEER => false
|
||||
]);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$curlError = curl_error($ch);
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
$json = json_decode($response, true);
|
||||
|
||||
return [
|
||||
'endpoint' => $endpoint,
|
||||
'url' => $url,
|
||||
'http_code' => $httpCode,
|
||||
'curl_error' => $curlError,
|
||||
'is_json' => is_array($json),
|
||||
'json' => $json,
|
||||
'raw_preview' => substr(strip_tags((string)$response), 0, 700)
|
||||
];
|
||||
}
|
||||
|
||||
try {
|
||||
$serverId = isset($_POST['server_id']) ? (int)$_POST['server_id'] : 0;
|
||||
|
||||
if ($serverId <= 0) {
|
||||
jsonResponse(false, 'Missing server ID.');
|
||||
}
|
||||
|
||||
$stmt = $db->prepare("
|
||||
SELECT
|
||||
id,
|
||||
panel_url,
|
||||
username,
|
||||
password_encrypted
|
||||
FROM cyberpanel_servers
|
||||
WHERE id = :id
|
||||
LIMIT 1
|
||||
");
|
||||
|
||||
$stmt->execute([
|
||||
':id' => $serverId
|
||||
]);
|
||||
|
||||
$server = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (!$server) {
|
||||
jsonResponse(false, 'Server not found.');
|
||||
}
|
||||
|
||||
$password = decryptCyberpanelPassword($server['password_encrypted']);
|
||||
|
||||
if ($password === '') {
|
||||
jsonResponse(false, 'Password cannot be decrypted.');
|
||||
}
|
||||
|
||||
$tests = [];
|
||||
|
||||
$tests[] = callCyberPanel(
|
||||
$server['panel_url'],
|
||||
'websites/fetchWebsitesList',
|
||||
$server['username'],
|
||||
$password
|
||||
);
|
||||
|
||||
$tests[] = callCyberPanel(
|
||||
$server['panel_url'],
|
||||
'websites/listWebsites',
|
||||
$server['username'],
|
||||
$password
|
||||
);
|
||||
|
||||
$tests[] = callCyberPanel(
|
||||
$server['panel_url'],
|
||||
'api/listWebsites',
|
||||
$server['username'],
|
||||
$password
|
||||
);
|
||||
|
||||
jsonResponse(true, 'Website API test completed.', [
|
||||
'tests' => $tests
|
||||
]);
|
||||
} catch (Throwable $e) {
|
||||
jsonResponse(false, 'Website API test error: ' . $e->getMessage());
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user