'Unauthorized']); exit; } $user_id = $_SESSION['user_id']; $action = $_GET['action'] ?? ''; $username = $_GET['username'] ?? ''; if (empty($username)) { echo json_encode(['success' => false, 'error' => 'Username required']); exit; } // Helper to check if a function is enabled function is_enabled($func) { return function_exists($func) && !in_array($func, array_map('trim', explode(',', ini_get('disable_functions')))); } if (!is_enabled('shell_exec')) { echo json_encode(['success' => false, 'error' => 'PHP function shell_exec is disabled on this server. Contact your hosting provider.']); exit; } // Find node path function get_node_path() { $path = trim((string)shell_exec('which node')); if ($path && file_exists($path)) return $path; $common_paths = ['/usr/local/bin/node', '/usr/bin/node', '/bin/node', '/opt/node/bin/node']; foreach ($common_paths as $p) { if (file_exists($p)) return $p; } return 'node'; // Fallback to PATH } $node = get_node_path(); // Create logs directory if not exists $logs_dir = __DIR__ . '/../logs'; if (!is_dir($logs_dir)) { @mkdir($logs_dir, 0755, true); } $pid_file = "$logs_dir/bridge_{$username}_{$user_id}.pid"; $log_file = "$logs_dir/bridge_{$username}_{$user_id}.log"; function is_running($pid_file) { if (!file_exists($pid_file)) return false; $pid = (int)file_get_contents($pid_file); if ($pid <= 0) return false; // Check if process exists (posix_getpgid is safer but might be disabled) if (function_exists('posix_getpgid')) { return @posix_getpgid($pid) !== false; } // Fallback to pgrep or ps $output = shell_exec("ps -p $pid"); return (strpos($output, (string)$pid) !== false); } function kill_process($pid_file, $username, $user_id) { if (file_exists($pid_file)) { $pid = (int)file_get_contents($pid_file); if ($pid > 0) { shell_exec("kill -9 $pid > /dev/null 2>&1"); } @unlink($pid_file); } // Also try pkill as backup shell_exec("pkill -f \"node .*tiktok_bridge.js $username .* $user_id\""); } if ($action === 'start') { // 1. Kill any existing bridge kill_process($pid_file, $username, $user_id); // 2. Start new bridge $bridge_script = __DIR__ . '/../tiktok_bridge.js'; // Check if node_modules exist if (!is_dir(__DIR__ . '/../node_modules')) { echo json_encode(['success' => false, 'error' => 'node_modules folder not found. Please run "npm install" on your server.']); exit; } $cmd = sprintf( "%s %s %s %s %s %s %s %s > %s 2>&1 & echo $!", $node, escapeshellarg($bridge_script), escapeshellarg($username), escapeshellarg(DB_HOST), escapeshellarg(DB_USER), escapeshellarg(DB_PASS), escapeshellarg(DB_NAME), escapeshellarg($user_id), escapeshellarg($log_file) ); $pid = trim((string)shell_exec($cmd)); if ($pid > 0) { file_put_contents($pid_file, $pid); echo json_encode([ 'success' => true, 'message' => "Bridge started for @$username", 'pid' => $pid, 'log' => "logs/" . basename($log_file) ]); } else { echo json_encode([ 'success' => false, 'error' => "Failed to start bridge. Check $log_file for errors.", 'node_path' => $node ]); } } elseif ($action === 'stop') { kill_process($pid_file, $username, $user_id); echo json_encode(['success' => true, 'message' => "Bridge stopped for @$username"]); } elseif ($action === 'status') { $running = is_running($pid_file); // Check log for errors if not running but was supposed to $last_log = ""; if (!$running && file_exists($log_file)) { $last_log = trim((string)shell_exec("tail -n 5 " . escapeshellarg($log_file))); } echo json_encode([ 'success' => true, 'running' => $running, 'last_log' => $last_log ]); } elseif ($action === 'debug') { // Special action to check environment $env = [ 'php_version' => PHP_VERSION, 'shell_exec_enabled' => is_enabled('shell_exec'), 'node_path' => $node, 'node_version' => trim((string)shell_exec("$node -v")), 'npm_version' => trim((string)shell_exec("npm -v")), 'node_modules_exists' => is_dir(__DIR__ . '/../node_modules'), 'db_host' => DB_HOST, 'db_user' => DB_USER, 'os' => PHP_OS, ]; echo json_encode(['success' => true, 'env' => $env]); } else { echo json_encode(['success' => false, 'error' => 'Invalid action']); }