![]() Server : Apache/2 System : Linux server-15-235-50-60 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64 User : gositeme ( 1004) PHP Version : 8.2.29 Disable Function : exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname Directory : /home/gositeme/domains/soundstudiopro.com/private_html/ |
<?php
// Include security functions
require_once 'includes/security.php';
// Validate admin access
validateAdminAccess();
// Rate limiting for API
if (!checkRateLimit('admin_api', 100, 60)) {
http_response_code(429);
echo json_encode(['error' => 'Rate limit exceeded']);
exit;
}
header('Content-Type: application/json');
require_once 'config/database.php';
$pdo = getDBConnection();
if (!$pdo) {
http_response_code(500);
echo json_encode(['error' => 'Database connection failed']);
exit;
}
try {
// Parse input - support both GET and POST (JSON body)
$input = [];
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$raw_input = file_get_contents('php://input');
if (!empty($raw_input)) {
$input = json_decode($raw_input, true) ?? [];
}
}
// Get action from either GET, POST, or JSON body
$action = sanitizeString($_GET['action'] ?? $input['action'] ?? $_POST['action'] ?? 'stats');
// Validate action parameter
$validActions = ['stats', 'recent_activity', 'user_details', 'update_user', 'delete_user', 'track_details', 'get_user_details', 'block_user', 'unblock_user', 'block_ip', 'login_as_user', 'return_to_admin', 'make_admin', 'remove_admin', 'change_password', 'upgrade_to_pro', 'test_db_connection', 'check_file_permissions', 'check_disk_space', 'clear_cache', 'delete_track', 'retry_track', 'delete_orphaned_track', 'assign_orphaned_track', 'transfer_track', 'retry_all_failed'];
if (!in_array($action, $validActions)) {
http_response_code(400);
echo json_encode(['error' => 'Invalid action: ' . $action]);
exit;
}
switch ($action) {
case 'stats':
// Get comprehensive statistics
$stats = [];
// User stats
$stmt = $pdo->prepare("SELECT COUNT(*) as total FROM users");
$stmt->execute();
$stats['totalUsers'] = $stmt->fetch()['total'];
$stmt = $pdo->prepare("SELECT COUNT(*) as total FROM users WHERE created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY)");
$stmt->execute();
$stats['newUsers'] = $stmt->fetch()['total'];
$stmt = $pdo->prepare("SELECT COUNT(*) as total FROM users WHERE plan IN ('starter', 'pro')");
$stmt->execute();
$stats['premiumUsers'] = $stmt->fetch()['total'];
// Track stats
$stmt = $pdo->prepare("SELECT COUNT(*) as total FROM music_tracks");
$stmt->execute();
$stats['totalTracks'] = $stmt->fetch()['total'];
$stmt = $pdo->prepare("
SELECT
COUNT(CASE WHEN status = 'complete' THEN 1 END) as completed,
COUNT(CASE WHEN status = 'processing' THEN 1 END) as processing,
COUNT(CASE WHEN status = 'failed' THEN 1 END) as failed
FROM music_tracks
");
$stmt->execute();
$trackStats = $stmt->fetch();
$stats['trackStats'] = $trackStats;
$stmt = $pdo->prepare("
SELECT COUNT(*) as total
FROM music_tracks
WHERE created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY)
");
$stmt->execute();
$stats['newTracks'] = $stmt->fetch()['total'];
// Duration stats
$stmt = $pdo->prepare("
SELECT
AVG(duration) as avg_duration,
MIN(duration) as min_duration,
MAX(duration) as max_duration,
COUNT(CASE WHEN duration < 60 THEN 1 END) as short_tracks,
COUNT(CASE WHEN duration >= 60 AND duration < 180 THEN 1 END) as medium_tracks,
COUNT(CASE WHEN duration >= 180 THEN 1 END) as long_tracks
FROM music_tracks
WHERE status = 'complete' AND duration > 0
");
$stmt->execute();
$stats['durationStats'] = $stmt->fetch();
echo json_encode(['success' => true, 'data' => $stats]);
break;
case 'recent_activity':
// Get recent activity
$stmt = $pdo->prepare("
SELECT
mt.id,
mt.title,
mt.status,
mt.duration,
mt.created_at,
u.name as user_name,
u.plan
FROM music_tracks mt
JOIN users u ON mt.user_id = u.id
ORDER BY mt.created_at DESC
LIMIT 20
");
$stmt->execute();
$recentActivity = $stmt->fetchAll();
echo json_encode(['success' => true, 'data' => $recentActivity]);
break;
case 'top_users':
// Get top users
$stmt = $pdo->prepare("
SELECT
u.id,
u.name,
u.plan,
COUNT(mt.id) as total_tracks,
COUNT(CASE WHEN mt.status = 'complete' THEN 1 END) as completed_tracks,
COUNT(CASE WHEN mt.status = 'processing' THEN 1 END) as processing_tracks,
COUNT(CASE WHEN mt.status = 'failed' THEN 1 END) as failed_tracks,
MAX(mt.created_at) as last_activity
FROM users u
LEFT JOIN music_tracks mt ON u.id = mt.user_id
GROUP BY u.id, u.name, u.plan
ORDER BY total_tracks DESC
LIMIT 15
");
$stmt->execute();
$topUsers = $stmt->fetchAll();
echo json_encode(['success' => true, 'data' => $topUsers]);
break;
case 'user_stats':
// Get user track statistics
$stmt = $pdo->prepare("
SELECT
u.name,
u.plan,
COUNT(CASE WHEN mt.status = 'complete' THEN 1 END) as completed,
COUNT(CASE WHEN mt.status = 'processing' THEN 1 END) as processing,
COUNT(CASE WHEN mt.status = 'failed' THEN 1 END) as failed
FROM users u
LEFT JOIN music_tracks mt ON u.id = mt.user_id
GROUP BY u.id, u.name, u.plan
HAVING completed > 0 OR processing > 0 OR failed > 0
ORDER BY (completed + processing + failed) DESC
");
$stmt->execute();
$userStats = $stmt->fetchAll();
echo json_encode(['success' => true, 'data' => $userStats]);
break;
case 'plan_stats':
// Get plan statistics
$stmt = $pdo->prepare("
SELECT
u.plan,
COUNT(u.id) as user_count,
COUNT(mt.id) as total_tracks,
COUNT(CASE WHEN mt.status = 'complete' THEN 1 END) as completed_tracks,
AVG(mt.duration) as avg_duration
FROM users u
LEFT JOIN music_tracks mt ON u.id = mt.user_id
GROUP BY u.plan
ORDER BY user_count DESC
");
$stmt->execute();
$planStats = $stmt->fetchAll();
echo json_encode(['success' => true, 'data' => $planStats]);
break;
case 'retry_failed':
// Bulk retry failed tracks
$stmt = $pdo->prepare("
SELECT id, user_id, title
FROM music_tracks
WHERE status = 'failed'
ORDER BY created_at DESC
");
$stmt->execute();
$failedTracks = $stmt->fetchAll();
$retried = 0;
foreach ($failedTracks as $track) {
// Update status to processing
$updateStmt = $pdo->prepare("
UPDATE music_tracks
SET status = 'processing', updated_at = NOW()
WHERE id = ?
");
$updateStmt->execute([$track['id']]);
$retried++;
}
echo json_encode([
'success' => true,
'message' => "Retried $retried failed tracks",
'retried' => $retried
]);
break;
case 'assign_orphaned_track':
// Assign orphaned track to user
$track_id = $input['track_id'] ?? null;
$user_id = $input['user_id'] ?? null;
if (!$track_id || !$user_id) {
echo json_encode(['success' => false, 'message' => 'Track ID and User ID are required']);
break;
}
// Verify track is orphaned
$stmt = $pdo->prepare("SELECT id FROM music_tracks WHERE id = ? AND (user_id IS NULL OR user_id = 0)");
$stmt->execute([$track_id]);
if (!$stmt->fetch()) {
echo json_encode(['success' => false, 'message' => 'Track is not orphaned or does not exist']);
break;
}
// Verify user exists
$stmt = $pdo->prepare("SELECT id FROM users WHERE id = ?");
$stmt->execute([$user_id]);
if (!$stmt->fetch()) {
echo json_encode(['success' => false, 'message' => 'User does not exist']);
break;
}
// Assign track to user
$stmt = $pdo->prepare("UPDATE music_tracks SET user_id = ?, updated_at = NOW() WHERE id = ?");
$stmt->execute([$user_id, $track_id]);
echo json_encode(['success' => true, 'message' => 'Track assigned successfully']);
break;
case 'assign_all_orphaned_tracks':
// Assign all orphaned tracks to admin user
$admin_user_id = $_SESSION['user_id'] ?? null;
if (!$admin_user_id) {
echo json_encode(['success' => false, 'message' => 'Admin user not found']);
break;
}
// Get all orphaned tracks
$stmt = $pdo->prepare("
SELECT id FROM music_tracks
WHERE user_id IS NULL OR user_id = 0
");
$stmt->execute();
$orphaned_tracks = $stmt->fetchAll();
$assigned_count = 0;
foreach ($orphaned_tracks as $track) {
$updateStmt = $pdo->prepare("UPDATE music_tracks SET user_id = ?, updated_at = NOW() WHERE id = ?");
$updateStmt->execute([$admin_user_id, $track['id']]);
$assigned_count++;
}
echo json_encode([
'success' => true,
'message' => "Assigned $assigned_count orphaned tracks to admin",
'assigned_count' => $assigned_count
]);
break;
case 'delete_orphaned_track':
// Delete orphaned track
$track_id = $input['track_id'] ?? null;
if (!$track_id) {
echo json_encode(['success' => false, 'message' => 'Track ID is required']);
break;
}
// Verify track is orphaned
$stmt = $pdo->prepare("SELECT id FROM music_tracks WHERE id = ? AND (user_id IS NULL OR user_id = 0)");
$stmt->execute([$track_id]);
if (!$stmt->fetch()) {
echo json_encode(['success' => false, 'message' => 'Track is not orphaned or does not exist']);
break;
}
// Delete track
$stmt = $pdo->prepare("DELETE FROM music_tracks WHERE id = ?");
$stmt->execute([$track_id]);
echo json_encode(['success' => true, 'message' => 'Track deleted successfully']);
break;
case 'transfer_track':
// Transfer track to different user
$track_id = $input['track_id'] ?? null;
$user_id = $input['user_id'] ?? null;
if (!$track_id || !$user_id) {
echo json_encode(['success' => false, 'message' => 'Track ID and User ID are required']);
break;
}
// Verify track exists
$stmt = $pdo->prepare("SELECT id, user_id FROM music_tracks WHERE id = ?");
$stmt->execute([$track_id]);
$track = $stmt->fetch();
if (!$track) {
echo json_encode(['success' => false, 'message' => 'Track does not exist']);
break;
}
// Verify user exists
$stmt = $pdo->prepare("SELECT id FROM users WHERE id = ?");
$stmt->execute([$user_id]);
if (!$stmt->fetch()) {
echo json_encode(['success' => false, 'message' => 'User does not exist']);
break;
}
// Transfer track to user
$stmt = $pdo->prepare("UPDATE music_tracks SET user_id = ?, updated_at = NOW() WHERE id = ?");
$stmt->execute([$user_id, $track_id]);
echo json_encode(['success' => true, 'message' => 'Track transferred successfully']);
break;
case 'retry_track':
// Retry failed track
$track_id = $input['track_id'] ?? null;
if (!$track_id) {
echo json_encode(['success' => false, 'message' => 'Track ID is required']);
break;
}
// Verify track exists and is failed
$stmt = $pdo->prepare("SELECT id, status FROM music_tracks WHERE id = ?");
$stmt->execute([$track_id]);
$track = $stmt->fetch();
if (!$track) {
echo json_encode(['success' => false, 'message' => 'Track does not exist']);
break;
}
if ($track['status'] !== 'failed') {
echo json_encode(['success' => false, 'message' => 'Track is not in failed status']);
break;
}
// Update status to processing
$stmt = $pdo->prepare("UPDATE music_tracks SET status = 'processing', updated_at = NOW() WHERE id = ?");
$stmt->execute([$track_id]);
echo json_encode(['success' => true, 'message' => 'Track retry initiated']);
break;
case 'delete_track':
// Delete any track (admin only)
$track_id = $input['track_id'] ?? null;
if (!$track_id) {
echo json_encode(['success' => false, 'message' => 'Track ID is required']);
break;
}
// Verify track exists
$stmt = $pdo->prepare("SELECT id FROM music_tracks WHERE id = ?");
$stmt->execute([$track_id]);
if (!$stmt->fetch()) {
echo json_encode(['success' => false, 'message' => 'Track does not exist']);
break;
}
try {
// Start transaction
$pdo->beginTransaction();
// Helper function to safely delete from a table (ignores if table doesn't exist)
$safeDelete = function($table, $track_id) use ($pdo) {
try {
$stmt = $pdo->prepare("DELETE FROM {$table} WHERE track_id = ?");
$stmt->execute([$track_id]);
return true;
} catch (PDOException $e) {
// Ignore "table doesn't exist" errors, but log others
if (strpos($e->getMessage(), "doesn't exist") === false) {
error_log("Error deleting from {$table}: " . $e->getMessage());
}
return false;
}
};
// Delete related data first (foreign key constraints)
// Note: Order matters - delete child records before parent
// Use safe delete to handle missing tables gracefully
$safeDelete('audio_variations', $track_id);
$safeDelete('track_likes', $track_id);
$safeDelete('track_comments', $track_id);
$safeDelete('track_downloads', $track_id);
$safeDelete('track_plays', $track_id);
$safeDelete('track_views', $track_id);
$safeDelete('track_votes', $track_id);
$safeDelete('track_shares', $track_id);
$safeDelete('track_purchases', $track_id);
$safeDelete('playlist_tracks', $track_id);
$safeDelete('sales', $track_id);
// Delete the main track
$stmt = $pdo->prepare("DELETE FROM music_tracks WHERE id = ?");
$stmt->execute([$track_id]);
// Verify deletion
$verify_stmt = $pdo->prepare("SELECT id FROM music_tracks WHERE id = ?");
$verify_stmt->execute([$track_id]);
if ($verify_stmt->fetch()) {
$pdo->rollBack();
echo json_encode(['success' => false, 'message' => 'Track deletion failed - track still exists']);
break;
}
// Commit transaction
$pdo->commit();
echo json_encode(['success' => true, 'message' => 'Track deleted successfully']);
} catch (Exception $e) {
if ($pdo->inTransaction()) {
$pdo->rollBack();
}
echo json_encode(['success' => false, 'message' => 'Error deleting track: ' . $e->getMessage()]);
}
break;
case 'update_user':
// Update user credits
error_log("Admin API: update_user called with user_id=" . ($_GET['user_id'] ?? 'null') . ", credits=" . ($_GET['credits'] ?? 'null'));
$user_id = validateInteger($_GET['user_id'] ?? null);
$credits = validateInteger($_GET['credits'] ?? null, 0, 10000);
error_log("Admin API: validated user_id=" . ($user_id ?? 'null') . ", credits=" . ($credits ?? 'null'));
if (!$user_id || $credits === null) {
error_log("Admin API: validation failed - user_id=" . ($user_id ?? 'null') . ", credits=" . ($credits ?? 'null'));
http_response_code(400);
echo json_encode(['error' => 'Invalid user ID or credits']);
break;
}
$stmt = $pdo->prepare("UPDATE users SET credits = ? WHERE id = ?");
$result = $stmt->execute([$credits, $user_id]);
error_log("Admin API: update result=" . ($result ? 'success' : 'failed') . ", rows affected=" . $stmt->rowCount());
echo json_encode(['success' => true, 'message' => 'User updated successfully']);
break;
case 'login_as_user':
// Login as another user
$user_id = validateInteger($_GET['user_id'] ?? null);
if (!$user_id) {
http_response_code(400);
echo json_encode(['error' => 'Invalid user ID']);
break;
}
// Get user data
$stmt = $pdo->prepare("SELECT id, name, email, plan, credits, is_admin FROM users WHERE id = ?");
$stmt->execute([$user_id]);
$user = $stmt->fetch();
if (!$user) {
http_response_code(404);
echo json_encode(['error' => 'User not found']);
break;
}
// Store original admin session data
$_SESSION['original_admin_id'] = $_SESSION['user_id'];
$_SESSION['original_admin_name'] = $_SESSION['user_name'];
$_SESSION['original_admin_email'] = $_SESSION['user_email'];
$_SESSION['original_admin_plan'] = $_SESSION['plan'];
$_SESSION['original_admin_credits'] = $_SESSION['credits'];
$_SESSION['original_admin_is_admin'] = $_SESSION['is_admin'];
$_SESSION['is_impersonating'] = true;
// Update session to login as this user
$_SESSION['user_id'] = $user['id'];
$_SESSION['user_name'] = $user['name'];
$_SESSION['user_email'] = $user['email'];
$_SESSION['plan'] = $user['plan'];
$_SESSION['credits'] = $user['credits'];
$_SESSION['is_admin'] = $user['is_admin'];
echo json_encode(['success' => true, 'message' => 'Logged in as user']);
break;
case 'make_admin':
// Make user an admin
$user_id = validateInteger($_GET['user_id'] ?? null);
if (!$user_id) {
http_response_code(400);
echo json_encode(['error' => 'Invalid user ID']);
break;
}
$stmt = $pdo->prepare("UPDATE users SET is_admin = 1 WHERE id = ?");
$stmt->execute([$user_id]);
echo json_encode(['success' => true, 'message' => 'User is now an admin']);
break;
case 'remove_admin':
// Remove admin privileges
$user_id = validateInteger($_GET['user_id'] ?? null);
if (!$user_id) {
http_response_code(400);
echo json_encode(['error' => 'Invalid user ID']);
break;
}
// Don't allow removing admin from self
if ($user_id == $_SESSION['user_id']) {
http_response_code(400);
echo json_encode(['error' => 'Cannot remove admin privileges from yourself']);
break;
}
$stmt = $pdo->prepare("UPDATE users SET is_admin = 0 WHERE id = ?");
$stmt->execute([$user_id]);
echo json_encode(['success' => true, 'message' => 'Admin privileges removed']);
break;
case 'change_password':
// Change user password
$user_id = validateInteger($_GET['user_id'] ?? null);
$new_password = $_POST['new_password'] ?? '';
if (!$user_id) {
http_response_code(400);
echo json_encode(['error' => 'Invalid user ID']);
break;
}
if (empty($new_password)) {
http_response_code(400);
echo json_encode(['error' => 'Password is required']);
break;
}
if (strlen($new_password) < 6) {
http_response_code(400);
echo json_encode(['error' => 'Password must be at least 6 characters long']);
break;
}
// Verify user exists
$stmt = $pdo->prepare("SELECT id, email FROM users WHERE id = ?");
$stmt->execute([$user_id]);
$user = $stmt->fetch();
if (!$user) {
http_response_code(404);
echo json_encode(['error' => 'User not found']);
break;
}
// Hash the new password
$hashed_password = password_hash($new_password, PASSWORD_DEFAULT);
// Update password
$stmt = $pdo->prepare("UPDATE users SET password = ? WHERE id = ?");
$stmt->execute([$hashed_password, $user_id]);
echo json_encode(['success' => true, 'message' => 'Password changed successfully']);
break;
case 'upgrade_to_pro':
// Upgrade user to Pro plan
$user_id = validateInteger($_GET['user_id'] ?? null);
if (!$user_id) {
http_response_code(400);
echo json_encode(['error' => 'Invalid user ID']);
break;
}
// Verify user exists
$stmt = $pdo->prepare("SELECT id, email, plan FROM users WHERE id = ?");
$stmt->execute([$user_id]);
$user = $stmt->fetch();
if (!$user) {
http_response_code(404);
echo json_encode(['error' => 'User not found']);
break;
}
if ($user['plan'] === 'pro') {
http_response_code(400);
echo json_encode(['error' => 'User is already on Pro plan']);
break;
}
// Upgrade to Pro
$stmt = $pdo->prepare("UPDATE users SET plan = 'pro' WHERE id = ?");
$stmt->execute([$user_id]);
echo json_encode(['success' => true, 'message' => 'User upgraded to Pro plan successfully']);
break;
case 'delete_user':
// Delete user and all their tracks
$user_id = $_GET['user_id'] ?? null;
if (!$user_id) {
http_response_code(400);
echo json_encode(['error' => 'Invalid user ID']);
break;
}
// Don't allow deleting self
if ($user_id == $_SESSION['user_id']) {
http_response_code(400);
echo json_encode(['error' => 'Cannot delete yourself']);
break;
}
// Start transaction
$pdo->beginTransaction();
try {
// Delete user's tracks first
$stmt = $pdo->prepare("DELETE FROM music_tracks WHERE user_id = ?");
$stmt->execute([$user_id]);
// Delete user
$stmt = $pdo->prepare("DELETE FROM users WHERE id = ?");
$stmt->execute([$user_id]);
$pdo->commit();
echo json_encode(['success' => true, 'message' => 'User deleted successfully']);
} catch (Exception $e) {
$pdo->rollback();
http_response_code(500);
echo json_encode(['error' => 'Error deleting user: ' . $e->getMessage()]);
}
break;
case 'return_to_admin':
// Return to original admin session
if (!isset($_SESSION['is_impersonating']) || !$_SESSION['is_impersonating']) {
http_response_code(400);
echo json_encode(['error' => 'Not currently impersonating a user']);
break;
}
// Restore original admin session data
$_SESSION['user_id'] = $_SESSION['original_admin_id'];
$_SESSION['user_name'] = $_SESSION['original_admin_name'];
$_SESSION['user_email'] = $_SESSION['original_admin_email'];
$_SESSION['plan'] = $_SESSION['original_admin_plan'];
$_SESSION['credits'] = $_SESSION['original_admin_credits'];
$_SESSION['is_admin'] = $_SESSION['original_admin_is_admin'];
// Clean up impersonation data
unset($_SESSION['original_admin_id']);
unset($_SESSION['original_admin_name']);
unset($_SESSION['original_admin_email']);
unset($_SESSION['original_admin_plan']);
unset($_SESSION['original_admin_credits']);
unset($_SESSION['original_admin_is_admin']);
unset($_SESSION['is_impersonating']);
echo json_encode(['success' => true, 'message' => 'Returned to admin session']);
break;
case 'get_user_details':
// Get detailed user information
$user_id = validateInteger($_GET['user_id'] ?? null);
if (!$user_id) {
http_response_code(400);
echo json_encode(['error' => 'Invalid user ID']);
break;
}
$stmt = $pdo->prepare("
SELECT id, name, email, credits, plan, is_admin, is_blocked,
block_reason, last_login_ip, last_login_at,
failed_login_attempts, last_failed_login, created_at
FROM users WHERE id = ?
");
$stmt->execute([$user_id]);
$user = $stmt->fetch();
if (!$user) {
http_response_code(404);
echo json_encode(['error' => 'User not found']);
break;
}
echo json_encode(['success' => true, 'user' => $user]);
break;
case 'block_user':
// Block a user
$user_id = validateInteger($_GET['user_id'] ?? null);
if (!$user_id) {
http_response_code(400);
echo json_encode(['error' => 'Invalid user ID']);
break;
}
// Don't allow blocking self
if ($user_id == $_SESSION['user_id']) {
http_response_code(400);
echo json_encode(['error' => 'Cannot block yourself']);
break;
}
$stmt = $pdo->prepare("
UPDATE users SET
is_blocked = 1,
block_reason = 'Blocked by admin',
blocked_at = NOW()
WHERE id = ?
");
$stmt->execute([$user_id]);
// Log security event
$stmt = $pdo->prepare("
INSERT INTO security_events (event_type, details, user_id, admin_id, ip_address, user_agent)
VALUES (?, ?, ?, ?, ?, ?)
");
$stmt->execute([
'user_blocked',
'User blocked by admin',
$user_id,
$_SESSION['user_id'],
$_SERVER['REMOTE_ADDR'] ?? 'unknown',
$_SERVER['HTTP_USER_AGENT'] ?? 'unknown'
]);
echo json_encode(['success' => true, 'message' => 'User blocked successfully']);
break;
case 'unblock_user':
// Unblock a user
$user_id = validateInteger($_GET['user_id'] ?? null);
if (!$user_id) {
http_response_code(400);
echo json_encode(['error' => 'Invalid user ID']);
break;
}
$stmt = $pdo->prepare("
UPDATE users SET
is_blocked = 0,
block_reason = NULL,
blocked_at = NULL
WHERE id = ?
");
$stmt->execute([$user_id]);
// Log security event
$stmt = $pdo->prepare("
INSERT INTO security_events (event_type, details, user_id, admin_id, ip_address, user_agent)
VALUES (?, ?, ?, ?, ?, ?)
");
$stmt->execute([
'user_unblocked',
'User unblocked by admin',
$user_id,
$_SESSION['user_id'],
$_SERVER['REMOTE_ADDR'] ?? 'unknown',
$_SERVER['HTTP_USER_AGENT'] ?? 'unknown'
]);
echo json_encode(['success' => true, 'message' => 'User unblocked successfully']);
break;
case 'block_ip':
// Block an IP address
$ip_address = $_GET['ip_address'] ?? null;
if (!$ip_address || !filter_var($ip_address, FILTER_VALIDATE_IP)) {
http_response_code(400);
echo json_encode(['error' => 'Invalid IP address']);
break;
}
// Check if IP is already blocked
$stmt = $pdo->prepare("SELECT id FROM ip_blacklist WHERE ip_address = ?");
$stmt->execute([$ip_address]);
if ($stmt->fetch()) {
http_response_code(400);
echo json_encode(['error' => 'IP address is already blocked']);
break;
}
$stmt = $pdo->prepare("
INSERT INTO ip_blacklist (ip_address, reason, blocked_by)
VALUES (?, ?, ?)
");
$stmt->execute([
$ip_address,
'Blocked by admin due to suspicious activity',
$_SESSION['user_id']
]);
// Log security event
$stmt = $pdo->prepare("
INSERT INTO security_events (event_type, details, admin_id, ip_address, user_agent)
VALUES (?, ?, ?, ?, ?)
");
$stmt->execute([
'ip_blocked',
'IP address blocked: ' . $ip_address,
$_SESSION['user_id'],
$_SERVER['REMOTE_ADDR'] ?? 'unknown',
$_SERVER['HTTP_USER_AGENT'] ?? 'unknown'
]);
echo json_encode(['success' => true, 'message' => 'IP address blocked successfully']);
break;
case 'test_db_connection':
// Test database connection
try {
$test_stmt = $pdo->prepare("SELECT 1 as test");
$test_stmt->execute();
$result = $test_stmt->fetch();
if ($result && $result['test'] == 1) {
echo json_encode(['success' => true, 'message' => 'Database connection successful']);
} else {
echo json_encode(['success' => false, 'error' => 'Database test query failed']);
}
} catch (Exception $e) {
echo json_encode(['success' => false, 'error' => 'Database connection failed: ' . $e->getMessage()]);
}
break;
case 'check_file_permissions':
// Check file permissions
$critical_files = [
'config/database.php',
'admin.php',
'includes/header.php',
'utils/audiofiles.php'
];
$results = [];
foreach ($critical_files as $file) {
$results[$file] = [
'exists' => file_exists($file),
'readable' => is_readable($file),
'writable' => is_writable($file)
];
}
$all_good = true;
foreach ($results as $file => $perms) {
if (!$perms['exists'] || !$perms['readable']) {
$all_good = false;
break;
}
}
echo json_encode([
'success' => $all_good,
'results' => $results,
'message' => $all_good ? 'All file permissions are correct' : 'Some file permissions need attention'
]);
break;
case 'check_disk_space':
// Check disk space
$total_space = disk_total_space('.');
$free_space = disk_free_space('.');
$used_space = $total_space - $free_space;
$usage_percent = ($used_space / $total_space) * 100;
$status = $usage_percent < 80 ? 'good' : ($usage_percent < 90 ? 'warning' : 'critical');
echo json_encode([
'success' => $usage_percent < 90,
'total_gb' => round($total_space / 1024 / 1024 / 1024, 2),
'free_gb' => round($free_space / 1024 / 1024 / 1024, 2),
'used_gb' => round($used_space / 1024 / 1024 / 1024, 2),
'usage_percent' => round($usage_percent, 2),
'status' => $status,
'message' => "Disk usage: {$usage_percent}%"
]);
break;
case 'clear_cache':
// Clear all cache
try {
// Clear file cache
$cache_dir = 'cache/';
if (is_dir($cache_dir)) {
$files = glob($cache_dir . '*.json');
foreach ($files as $file) {
if (is_file($file)) {
unlink($file);
}
}
}
// Clear session cache
session_cache_limiter('nocache');
echo json_encode(['success' => true, 'message' => 'Cache cleared successfully']);
} catch (Exception $e) {
echo json_encode(['success' => false, 'error' => 'Cache clear failed: ' . $e->getMessage()]);
}
break;
default:
http_response_code(400);
echo json_encode(['error' => 'Invalid action']);
}
} catch (Exception $e) {
error_log("Admin API Error: " . $e->getMessage());
http_response_code(500);
echo json_encode(['error' => 'Internal server error']);
}
?>