| Server IP : 213.255.246.8 / Your IP : 216.73.217.0 Web Server : Apache System : Linux dublin.stapolin.com 5.14.0-362.18.1.el9_3.x86_64 #1 SMP PREEMPT_DYNAMIC Mon Jan 29 07:05:48 EST 2024 x86_64 User : stapolin ( 1019) PHP Version : 8.4.24 Disable Function : exec,passthru,shell_exec,system MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /home/stapolin/public_html/dash.stapolin.com/api/ |
Upload File : |
<?php
/**
* Trigger a remote update on one site (core, plugins, or themes).
* POST: website_id, action (core|plugins|themes), plugins[] or themes[] (optional; use "all" for all).
* Requires login. The website must have WordPress username and Application Password set (Basic auth).
*/
require_once __DIR__ . '/../config.php';
require_once __DIR__ . '/../includes/auth.php';
require_once __DIR__ . '/../includes/functions.php';
require_once __DIR__ . '/../includes/database.php';
header('Content-Type: application/json');
requireLogin();
$input = json_decode(file_get_contents('php://input'), true) ?: [];
$websiteId = isset($input['website_id']) ? (int) $input['website_id'] : (isset($_POST['website_id']) ? (int) $_POST['website_id'] : 0);
$action = isset($input['action']) ? trim($input['action']) : (isset($_POST['action']) ? trim($_POST['action']) : '');
$plugins = isset($input['plugins']) ? $input['plugins'] : (isset($_POST['plugins']) ? (array) $_POST['plugins'] : []);
$themes = isset($input['themes']) ? $input['themes'] : (isset($_POST['themes']) ? (array) $_POST['themes'] : []);
if (!$websiteId || !in_array($action, ['core', 'plugins', 'themes'], true)) {
http_response_code(400);
echo json_encode(['success' => false, 'error' => 'Missing or invalid website_id or action (core|plugins|themes).']);
exit;
}
$db = getDb();
$website = $db->fetchOne('SELECT * FROM st_websites WHERE website_id = ?', [$websiteId]);
if (!$website) {
http_response_code(404);
echo json_encode(['success' => false, 'error' => 'Website not found.']);
exit;
}
$hasWpManager = !empty($website['wp_manager_client_id']) && !empty($website['wp_manager_client_secret']);
$useMaintenance = !$hasWpManager && !empty($website['maintenance_secret']);
if (
!$hasWpManager
&& !$useMaintenance
&& (empty($website['wp_auth_username']) || empty($website['wp_auth_app_password']))
) {
http_response_code(400);
echo json_encode(['success' => false, 'error' => 'This website has no connection method. Configure WP Manager Companion (pairing), a connection secret (Stapolin Maintenance), or WordPress username + Application Password in website settings.']);
exit;
}
// Prefer WP Manager when configured, then Stapolin Maintenance, then Application Password
if ($hasWpManager) {
// Map action to WP Manager admin-ajax types
if ($action === 'core') {
$resp = wp_manager_ajax_update($website, 'core', 'wordpress', $timeout);
if ($resp['error'] !== null) {
echo json_encode(['success' => false, 'error' => 'Request failed: ' . $resp['error']]);
exit;
}
$decoded = json_decode($resp['body'], true);
if ($resp['code'] >= 200 && $resp['code'] < 300) {
echo json_encode(is_array($decoded) ? $decoded : ['success' => true, 'message' => 'Core update triggered via WP Manager']);
} else {
$msg = is_array($decoded) && isset($decoded['message']) ? $decoded['message'] : (is_array($decoded) && isset($decoded['error']) ? $decoded['error'] : trim(substr((string) $resp['body'], 0, 300)));
echo json_encode(['success' => false, 'error' => 'WP Manager returned ' . $resp['code'] . ': ' . $msg]);
}
exit;
}
if ($action === 'plugins') {
if (empty($plugins)) {
echo json_encode(['success' => true, 'message' => 'No plugins selected for update']);
exit;
}
$results = [];
foreach ($plugins as $pluginFile) {
$slug = trim((string) $pluginFile);
if ($slug === '') {
continue;
}
$resp = wp_manager_ajax_update($website, 'plugin', $slug, $timeout);
$decoded = json_decode($resp['body'], true);
$results[] = [
'plugin' => $slug,
'code' => $resp['code'],
'error' => $resp['error'],
'response' => $decoded,
];
}
echo json_encode([
'success' => true,
'message' => 'Plugin updates triggered via WP Manager',
'results' => $results,
]);
exit;
}
if ($action === 'themes') {
if (empty($themes)) {
echo json_encode(['success' => true, 'message' => 'No themes selected for update']);
exit;
}
$results = [];
foreach ($themes as $stylesheet) {
$slug = trim((string) $stylesheet);
if ($slug === '') {
continue;
}
$resp = wp_manager_ajax_update($website, 'theme', $slug, $timeout);
$decoded = json_decode($resp['body'], true);
$results[] = [
'theme' => $slug,
'code' => $resp['code'],
'error' => $resp['error'],
'response' => $decoded,
];
}
echo json_encode([
'success' => true,
'message' => 'Theme updates triggered via WP Manager',
'results' => $results,
]);
exit;
}
}
if ($useMaintenance) {
$maintenanceAction = $action === 'core' ? 'run_core_update' : ($action === 'plugins' ? 'run_plugin_update' : 'run_theme_update');
$params = $action === 'core' ? [] : ($action === 'plugins' ? ['plugins' => $plugins] : ['themes' => $themes]);
$resp = stapolin_maintenance_request($website, $maintenanceAction, $params, 120);
if ($resp['error'] !== null) {
echo json_encode(['success' => false, 'error' => 'Request failed: ' . $resp['error']]);
exit;
}
$decoded = json_decode($resp['body'], true);
if ($resp['code'] >= 200 && $resp['code'] < 300) {
echo json_encode(is_array($decoded) ? $decoded : ['success' => true, 'message' => 'Done']);
} else {
$msg = is_array($decoded) && isset($decoded['error']) ? $decoded['error'] : trim(substr($resp['body'], 0, 300));
echo json_encode(['success' => false, 'error' => 'Site returned ' . $resp['code'] . ': ' . $msg]);
}
exit;
}
$baseUrl = rtrim($website['website_url'], '/');
$timeout = 120;
if ($action === 'core') {
$url = $baseUrl . '/wp-json/stapolin/v1/run-core-update';
$body = json_encode([]);
} elseif ($action === 'plugins') {
$url = $baseUrl . '/wp-json/stapolin/v1/run-plugin-update';
$body = json_encode(['plugins' => $plugins]);
} else {
$url = $baseUrl . '/wp-json/stapolin/v1/run-theme-update';
$body = json_encode(['themes' => $themes]);
}
$ch = curl_init($url);
$authOpts = get_website_curl_basic_auth($website);
$headers = array_merge(
isset($authOpts[CURLOPT_HTTPHEADER]) ? $authOpts[CURLOPT_HTTPHEADER] : [],
['Content-Type: application/json']
);
$curlOpts = [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $body,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => $timeout,
CURLOPT_CONNECTTIMEOUT => 15,
CURLOPT_HTTPHEADER => $headers,
];
curl_setopt_array($ch, $authOpts + $curlOpts);
$responseBody = curl_exec($ch);
$code = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
$err = curl_error($ch);
curl_close($ch);
if ($err !== '') {
echo json_encode(['success' => false, 'error' => 'Request failed: ' . $err]);
exit;
}
$decoded = json_decode($responseBody, true);
if ($code >= 200 && $code < 300) {
echo json_encode(is_array($decoded) ? $decoded : ['success' => true, 'message' => 'Done']);
} else {
$msg = is_array($decoded) && isset($decoded['message']) ? $decoded['message'] : (is_array($decoded) && isset($decoded['error']) ? $decoded['error'] : trim(substr($responseBody, 0, 300)));
echo json_encode(['success' => false, 'error' => 'Site returned ' . $code . ': ' . $msg]);
}