herzult/php-ssh
A lightweight PHP library for running SSH commands locally or remotely with a fluent API. Execute commands, capture stdout/stderr and exit codes, handle timeouts, and compose pipelines—useful for deployments, server automation, and remote task orchestration.
Installation
composer require herzult/php-ssh
Add to composer.json if not using autoloading:
"autoload": {
"psr-4": {
"App\\": "app/",
"Herzult\\SSH\\": "vendor/herzult/php-ssh/src/"
}
}
Run composer dump-autoload.
First Use Case: Connecting to a Server
use Herzult\SSH\Connection;
$connection = new Connection('user@example.com', 'password');
$connection->connect();
Where to Look First
src/Herzult/SSH/Connection.php for core functionality and src/Herzult/SSH/Command.php for executing commands.tests/ for real-world usage examples.Basic Command Execution
$connection = new Connection('user@example.com', 'password');
$connection->connect();
$output = $connection->exec('ls -la');
echo $output;
Handling Output and Errors
try {
$output = $connection->exec('ls /nonexistent');
echo $output;
} catch (Herzult\SSH\Exception\SSHException $e) {
echo "Error: " . $e->getMessage();
}
Streaming Output for Large Files
$connection->exec('cat largefile.log', function ($line) {
echo $line;
});
SFTP File Operations
$connection->put('local.txt', 'remote.txt');
$connection->get('remote.txt', 'local_copy.txt');
Reusing Connections
$connection = new Connection('user@example.com', 'password');
$connection->connect();
// Reuse connection for multiple commands
$connection->exec('cd /path');
$connection->exec('pwd');
Integration with Laravel
// app/Providers/AppServiceProvider.php
public function register()
{
$this->app->singleton('ssh', function () {
return new Herzult\SSH\Connection(config('ssh.host'), config('ssh.password'));
});
}
config/ssh.php.
return [
'host' => 'user@example.com',
'password' => env('SSH_PASSWORD'),
];
// app/Facades/SSH.php
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
class SSH extends Facade {
protected static function getFacadeAccessor() { return 'ssh'; }
}
Usage:
SSH::exec('ls -la');
Parallel SSH Commands
Use PHP’s parallel package or pthreads to run multiple SSH commands concurrently (if supported by the server).
Automated Deployments
$connection->exec('git pull origin main');
$connection->exec('php artisan migrate');
$connection->exec('sudo service nginx restart');
Log Aggregation
$servers = ['user@server1.com', 'user@server2.com'];
foreach ($servers as $server) {
$connection = new Connection($server, 'password');
$connection->exec('tail -n 100 /var/log/app.log', function ($line) {
Log::info($line);
});
}
Server Monitoring
$output = $connection->exec('df -h');
if (strpos($output, '90%') !== false) {
Alert::send('Disk space low on server!');
}
Dynamic Command Building
$command = "docker-compose up " . ($debug ? "-d" : "");
$connection->exec($command);
Deprecated Package
No Native SSH Key Support
Connection class or use a wrapper like phpseclib.Limited Error Handling
SSHException) may not cover all edge cases. Wrap calls in try-catch blocks.Blocking Operations
exec() is synchronous. For long-running commands, use streaming or run in a queue (e.g., Laravel Queues).No Built-in Retry Logic
$attempts = 0;
while ($attempts < 3) {
try {
$connection->exec('command');
break;
} catch (\Exception $e) {
$attempts++;
sleep(2);
}
}
Resource Leaks
$connection->disconnect() after use to free resources.__destruct() or a context manager (e.g., Laravel’s illuminate/support/Manager) to ensure cleanup.Enable Verbose Output
Connection class to log raw SSH traffic:
class DebugConnection extends Herzult\SSH\Connection {
public function exec($command) {
error_log("Executing: $command");
return parent::exec($command);
}
}
Check Underlying PHP SSH Functions
ssh2_connect(), ssh2_exec(), etc. Debug these functions directly if issues arise.Test Locally First
linuxserver/openssh-server) to test commands before deploying to production.Extend for Custom Features
restartService(), checkDiskSpace()):
class CustomSSH extends Herzult\SSH\Connection {
public function restartNginx() {
$this->exec('sudo service nginx restart');
}
}
Use Laravel’s Cache for Connections
$connection = Cache::remember('ssh_connection', 3600, function () {
return new Connection('user@example.com', 'password');
});
Combine with Other Packages
phpseclib for advanced SSH features (e.g., SFTP, key auth) and herzult/php-ssh for simplicity where it works.Environment-Specific Config
.env for credentials:
SSH_HOST=user@example.com
SSH_PASSWORD=securepassword
config/ssh.php:
'host' => env('SSH_HOST'),
'password' => env('SSH_PASSWORD'),
Queue Long-Running Tasks
SSH::dispatch(new ProcessCommand('user@example.com', 'long-running-command'));
Define a job:
class ProcessCommand implements ShouldQueue {
protected $server;
protected $command;
public function handle() {
$connection = new Connection($this->server, 'password');
$connection->exec($this->command);
}
}
Mock for Testing
Mockery to test SSH interactions without real connections:
$mock = Mockery::mock(Herzult\SSH\Connection::class);
$mock->shouldReceive('exec')->andReturn('mocked output');
How can I help you explore Laravel packages today?