🐘
sftp_connector_copy.php
Back
📝 Php ⚡ Executable Ctrl+S: Save • Ctrl+R: Run • Ctrl+F: Find
<?php error_reporting(E_ALL); ini_set('display_errors', 0); ini_set('log_errors', 1); ob_start(); header('Content-Type: application/json'); header('Access-Control-Allow-Origin: *'); header('Access-Control-Allow-Methods: POST, OPTIONS'); header('Access-Control-Allow-Headers: Content-Type'); if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { exit(0); } class AdvancedSFTPConnector { private $connection; private $sftp; private $debug_info = []; public function __construct() { if (!extension_loaded('ssh2')) { throw new Exception('SSH2 extension is not installed'); } } public function connect($host, $port, $username, $password) { try { $this->debug_info = []; $this->debug_info['php_version'] = PHP_VERSION; $this->debug_info['ssh2_version'] = phpversion('ssh2'); $this->debug_info['openssl_version'] = defined('OPENSSL_VERSION_TEXT') ? OPENSSL_VERSION_TEXT : 'Unknown'; // Step 1: Establish SSH connection with more compatible settings $this->debug_info['step'] = 'Attempting SSH connection'; $methods = [ 'kex' => 'diffie-hellman-group14-sha256,diffie-hellman-group-exchange-sha256,diffie-hellman-group1-sha1', 'hostkey' => 'rsa-sha2-512,rsa-sha2-256,ssh-rsa,ssh-dss', 'client_to_server' => [ 'crypt' => 'aes128-ctr,aes192-ctr,aes256-ctr,aes128-cbc,3des-cbc', 'mac' => 'hmac-sha2-256,hmac-sha1', 'comp' => 'none' ], 'server_to_client' => [ 'crypt' => 'aes128-ctr,aes192-ctr,aes256-ctr,aes128-cbc,3des-cbc', 'mac' => 'hmac-sha2-256,hmac-sha1', 'comp' => 'none' ] ]; $this->connection = ssh2_connect($host, $port, $methods); if (!$this->connection) { throw new Exception("SSH connection failed to {$host}:{$port}"); } $this->debug_info['ssh_connected'] = true; // Step 2: Get server banner and fingerprint $this->debug_info['server_fingerprint'] = ssh2_fingerprint($this->connection); // Step 3: Authentication $this->debug_info['step'] = 'Attempting authentication'; $auth_methods = ssh2_auth_none($this->connection, $username); $this->debug_info['available_auth_methods'] = $auth_methods; if (!ssh2_auth_password($this->connection, $username, $password)) { throw new Exception("Authentication failed for user {$username}. Available methods: " . implode(', ', $auth_methods)); } $this->debug_info['auth_success'] = true; // Step 4: Test basic SSH functionality first $this->debug_info['step'] = 'Testing SSH exec'; $stream = ssh2_exec($this->connection, 'echo "SSH_OK"'); if ($stream) { stream_set_blocking($stream, true); $output = stream_get_contents($stream); fclose($stream); $this->debug_info['ssh_exec_test'] = trim($output); } // Step 5: Try different approaches for SFTP initialization $this->debug_info['step'] = 'Initializing SFTP subsystem'; // Approach 1: Direct SFTP initialization $this->sftp = ssh2_sftp($this->connection); if ($this->sftp) { $this->debug_info['sftp_method'] = 'direct'; return $this->testSftpConnection(); } // Approach 2: Wait and retry usleep(1000000); // 1 second $this->sftp = ssh2_sftp($this->connection); if ($this->sftp) { $this->debug_info['sftp_method'] = 'delayed_retry'; return $this->testSftpConnection(); } // Approach 3: Check if sftp-server exists and retry $stream = ssh2_exec($this->connection, 'which sftp-server || echo "NOT_FOUND"'); if ($stream) { stream_set_blocking($stream, true); $sftp_server_path = trim(stream_get_contents($stream)); fclose($stream); $this->debug_info['sftp_server_path'] = $sftp_server_path; if ($sftp_server_path !== 'NOT_FOUND' && !empty($sftp_server_path)) { usleep(500000); $this->sftp = ssh2_sftp($this->connection); if ($this->sftp) { $this->debug_info['sftp_method'] = 'after_server_check'; return $this->testSftpConnection(); } } } // Approach 4: Try with explicit subsystem request $stream = ssh2_exec($this->connection, '/usr/lib/openssh/sftp-server'); if ($stream) { fclose($stream); usleep(500000); $this->sftp = ssh2_sftp($this->connection); if ($this->sftp) { $this->debug_info['sftp_method'] = 'explicit_subsystem'; return $this->testSftpConnection(); } } throw new Exception("Could not initialize SFTP subsystem after multiple attempts. Debug info: " . json_encode($this->debug_info)); } catch (Exception $e) { if ($this->connection) { ssh2_disconnect($this->connection); } return $e->getMessage(); } } private function testSftpConnection() { try { // Test SFTP functionality $this->debug_info['step'] = 'Testing SFTP functionality'; // Try to stat the home directory $stat = ssh2_sftp_stat($this->sftp, '.'); if ($stat !== false) { $this->debug_info['sftp_stat_home'] = 'success'; } else { $this->debug_info['sftp_stat_home'] = 'failed'; } // Try to stat the root directory $stat_root = ssh2_sftp_stat($this->sftp, '/'); if ($stat_root !== false) { $this->debug_info['sftp_stat_root'] = 'success'; } else { $this->debug_info['sftp_stat_root'] = 'failed'; } // Try to get realpath $realpath = ssh2_sftp_realpath($this->sftp, '.'); if ($realpath !== false) { $this->debug_info['sftp_realpath'] = $realpath; } else { $this->debug_info['sftp_realpath'] = 'failed'; } $this->debug_info['sftp_initialized'] = true; return true; } catch (Exception $e) { $this->debug_info['sftp_test_error'] = $e->getMessage(); throw new Exception("SFTP subsystem initialized but functionality test failed: " . $e->getMessage()); } } public function getDebugInfo() { return $this->debug_info; } public function listDirectory($path = '.') { try { if (!$this->sftp) { throw new Exception("SFTP not initialized"); } // Normalize path if (empty($path) || $path === '') { $path = '.'; } $handle = opendir("ssh2.sftp://{$this->sftp}{$path}"); if (!$handle) { // Try with realpath $realPath = ssh2_sftp_realpath($this->sftp, $path); if ($realPath) { $handle = opendir("ssh2.sftp://{$this->sftp}{$realPath}"); } if (!$handle) { throw new Exception("Could not open directory: {$path}"); } } $files = []; while (($file = readdir($handle)) !== false) { if ($file !== '.' && $file !== '..') { $fullPath = rtrim($path, '/') . '/' . $file; $stat = ssh2_sftp_stat($this->sftp, $fullPath); if ($stat !== false) { $isDir = ($stat['mode'] & 0x4000) == 0x4000; $files[] = [ 'name' => $file, 'path' => $fullPath, 'size' => $stat['size'] ?? 0, 'modified' => isset($stat['mtime']) ? date('Y-m-d H:i:s', $stat['mtime']) : 'Unknown', 'is_dir' => $isDir ]; } } } closedir($handle); usort($files, function($a, $b) { if ($a['is_dir'] && !$b['is_dir']) return -1; if (!$a['is_dir'] && $b['is_dir']) return 1; return strcasecmp($a['name'], $b['name']); }); return $files; } catch (Exception $e) { return false; } } public function deleteFile($remotePath) { try { $stat = ssh2_sftp_stat($this->sftp, $remotePath); if ($stat && ($stat['mode'] & 0x4000) == 0x4000) { if (ssh2_sftp_rmdir($this->sftp, $remotePath)) { return true; } return "Failed to delete directory (may not be empty)"; } else { if (ssh2_sftp_unlink($this->sftp, $remotePath)) { return true; } return "Failed to delete file"; } } catch (Exception $e) { return $e->getMessage(); } } public function createDirectory($path) { try { if (ssh2_sftp_mkdir($this->sftp, $path, 0755, true)) { return true; } return "Failed to create directory"; } catch (Exception $e) { return $e->getMessage(); } } public function disconnect() { if ($this->connection) { ssh2_disconnect($this->connection); } } } // Handle API requests if ($_SERVER['REQUEST_METHOD'] === 'POST') { $input = json_decode(file_get_contents('php://input'), true); if (json_last_error() !== JSON_ERROR_NONE) { ob_clean(); echo json_encode([ 'success' => false, 'message' => 'Invalid JSON input: ' . json_last_error_msg(), ]); exit; } $action = $input['action'] ?? ''; $response = ['success' => false, 'message' => '', 'data' => null]; try { if (extension_loaded('ssh2')) { $connector = new AdvancedSFTPConnector(); $connectorType = 'SSH2 Extension'; } else { throw new Exception('SSH2 extension not available'); } switch ($action) { case 'connect': $result = $connector->connect( $input['host'] ?? '', $input['port'] ?? 22, $input['username'] ?? '', $input['password'] ?? '' ); if ($result === true) { session_start(); $_SESSION['sftp_connected'] = true; $_SESSION['sftp_config'] = [ 'host' => $input['host'], 'port' => $input['port'] ?? 22, 'username' => $input['username'], 'password' => $input['password'] ]; $response['success'] = true; $response['message'] = "Connected successfully via {$connectorType}"; $response['debug'] = $connector->getDebugInfo(); } else { $response['message'] = $result; $response['debug'] = $connector->getDebugInfo(); } break; case 'list': session_start(); if (isset($_SESSION['sftp_connected'])) { $config = $_SESSION['sftp_config']; $connector = new AdvancedSFTPConnector(); $connectResult = $connector->connect( $config['host'], $config['port'], $config['username'], $config['password'] ); if ($connectResult !== true) { $response['message'] = 'Reconnection failed: ' . $connectResult; $response['debug'] = $connector->getDebugInfo(); break; } $files = $connector->listDirectory($input['path'] ?? '/'); if ($files !== false) { $response['success'] = true; $response['data'] = $files; } else { $response['message'] = 'Failed to list directory'; } } else { $response['message'] = 'Not connected to SFTP server'; } break; case 'delete': session_start(); if (isset($_SESSION['sftp_connected'])) { $config = $_SESSION['sftp_config']; $connector = new AdvancedSFTPConnector(); $connectResult = $connector->connect( $config['host'], $config['port'], $config['username'], $config['password'] ); if ($connectResult !== true) { $response['message'] = 'Reconnection failed: ' . $connectResult; break; } $result = $connector->deleteFile($input['path'] ?? ''); if ($result === true) { $response['success'] = true; $response['message'] = 'File deleted successfully'; } else { $response['message'] = $result; } } else { $response['message'] = 'Not connected to SFTP server'; } break; case 'create_folder': session_start(); if (isset($_SESSION['sftp_connected'])) { $config = $_SESSION['sftp_config']; $connector = new AdvancedSFTPConnector(); $connectResult = $connector->connect( $config['host'], $config['port'], $config['username'], $config['password'] ); if ($connectResult !== true) { $response['message'] = 'Reconnection failed: ' . $connectResult; break; } $result = $connector->createDirectory($input['path'] ?? ''); if ($result === true) { $response['success'] = true; $response['message'] = 'Directory created successfully'; } else { $response['message'] = $result; } } else { $response['message'] = 'Not connected to SFTP server'; } break; case 'disconnect': session_start(); unset($_SESSION['sftp_connected']); unset($_SESSION['sftp_config']); if (isset($connector)) { $connector->disconnect(); } $response['success'] = true; $response['message'] = 'Disconnected successfully'; break; case 'test': $response['success'] = true; $response['message'] = 'SFTP connector responding'; $response['data'] = [ 'ssh2_loaded' => extension_loaded('ssh2'), 'ssh2_version' => extension_loaded('ssh2') ? phpversion('ssh2') : 'N/A', 'php_version' => PHP_VERSION, 'openssl_version' => defined('OPENSSL_VERSION_TEXT') ? OPENSSL_VERSION_TEXT : 'N/A', 'time' => date('Y-m-d H:i:s') ]; break; default: $response['message'] = 'Invalid action: ' . $action; } } catch (Exception $e) { $response['message'] = 'Server error: ' . $e->getMessage(); $response['debug'] = $e->getTraceAsString(); } ob_clean(); echo json_encode($response); } else { ob_clean(); echo json_encode([ 'success' => false, 'message' => 'Only POST requests are allowed' ]); } ?>