Oh Dear is the all-in-one monitoring tool for your entire website. We monitor uptime, SSL certificates, broken links, scheduled tasks and more. You'll get a notifications for us when something's wrong. All that paired with a developer friendly API and kick-ass documentation. O, and you'll also be able to create a public status page under a minute. Start monitoring using our free trial now.

A PHP package to execute commands via SSH

Original – by Freek Van der Herten – 3 minute read

Our team released a new package called spatie/ssh. This package allows you to execute commands via an SSH connection.

With the package installed, you can execute an SSH command like this:

$process = Ssh::create('user', 'example.com')->execute('your favorite command');

It will return an instance of Symfony's Process.

Here's how to check if your command ran ok:

$process->isSuccessful();

And this is how you can get the output:

$process->getOutput();

To run multiple commands, pass an array to the execute method.

$process = Ssh::create('user', 'example.com')->execute([
   'first command',
   'second command',
]);

The package has a few extra options, head over to the readme on GitHub, to learn more.

Why we built this

I'm currently building a package called spatie/laravel-backup-server. It will be the spiritual successor of spatie/laravel-backup. Laravel Backup is usually installed into the Laravel app, and it will copy that app to some other storage. Laravel Backup Server will take a different approach: it will SSH into each server that needs to be backed up and will copy all the files on to itself.

The package will also be able to, before and after the actual copying of files starts, execute some commands.

Let's take a look at how that is implemented. In laravel-backup-server a Source is a model that represents something that needs to be backed up.

On that model we have an executeSshCommands methods that looks like this:

/** @test */
public function executeSshCommands(array $commands): Process
{
    $ssh = new Ssh($this->ssh_user, $this->host);

    if ($this->ssh_port) {
        $ssh->usePort($this->ssh_port);
    }

    if ($this->ssh_private_key_file) {
        $ssh->usePrivateKey($this->ssh_private_key_file);
    }

    return $ssh->execute($commands);
}

In that method, we get some of the attributes of the model and use them to connect to a host. Inside the backup procure that executeSshCommands is getting called.

Here's how we test that commands in the pre_backup_commands do actually succeed (there's a separate test for post_backup_comands. In the test, we create a new file using the touch command, which will be performed via SSH. Later in the test, we assert that the created file is part of the backup.

/** @test */
public function it_can_perform_a_pre_backup_command()
{
    $this->container->addFiles(__DIR__ . '/stubs/serverContent/testServer', '/src');

    $this->source->update(['pre_backup_commands' => ['cd /src', 'touch newfile.txt']]);

    $this->artisan('backup-server:backup')->assertExitCode(0);

    $this->assertTrue($this->source->backups()->first()->has('src/newfile.txt'));

    $this->assertEquals(Backup::STATUS_COMPLETED, $this->source->backups()->first()->status);
}

$container in the test above is a local docker container, which we've set up to have a target to ssh into, you can read more on that in this blog post.

Here's another test that proves the backup fails should any of the commands in the pre_backup_commands fails.

In closing

spatie/ssh is probably the easiest way to perform a quick SSH command. It doesn't have a lot of features, but that's ok. It's intended as something very lightweight. This isn't the first package our team has built. Here's a list with all the stuff we released previously.

Stay up to date with all things Laravel, PHP, and JavaScript.

You can follow me on these platforms:

On all these platforms, regularly share programming tips, and what I myself have learned in ongoing projects.

Every month I send out a newsletter containing lots of interesting stuff for the modern PHP developer.

Expect quick tips & tricks, interesting tutorials, opinions and packages. Because I work with Laravel every day there is an emphasis on that framework.

Rest assured that I will only use your email address to send you the newsletter and will not use it for any other purposes.

Comments

What are your thoughts on "A PHP package to execute commands via SSH"?

Comments powered by Laravel Comments
Want to join the conversation? Log in or create an account to post a comment.

Webmentions

Laurent Lemaire retweeted on 14th February 2020
Philo Hermans liked on 13th February 2020
Niels liked on 13th February 2020
Edwin I Arellano liked on 13th February 2020
Niko Halink liked on 12th February 2020
Khai Rahman retweeted on 12th February 2020
Khai Rahman liked on 12th February 2020
Salman Zafar liked on 12th February 2020
William Mandai liked on 12th February 2020
Peter Sowah liked on 12th February 2020
Joe Grainger liked on 12th February 2020
ダビッド トレス retweeted on 12th February 2020
ダビッド トレス liked on 12th February 2020
ujwal dhakal liked on 12th February 2020
Spatie retweeted on 12th February 2020
Kennedy Tedesco liked on 12th February 2020
Wyatt liked on 12th February 2020
Aaron Francis liked on 12th February 2020
Ihor Vorotnov • 25% liked on 12th February 2020
Robin Dirksen liked on 12th February 2020
Freek Van der Herten replied on 12th February 2020
Thanks for the kinds words 🙂 You tell me what the differences are, never worked with that one directly.
Jay Hughes replied on 12th February 2020
How would you say this differs from the old Collective Remote package? Can’t wait to try it out and hoping to replace that package with yours. Everything I use from @spatie_be is great!
Simon Bennett retweeted on 12th February 2020
Alexandr Nita retweeted on 12th February 2020
Owen Voke (pxgamer) retweeted on 12th February 2020
Ahmad Ismail retweeted on 12th February 2020
Edify Real Life Integrity liked on 12th February 2020
Oliver Musovski liked on 12th February 2020
Crazy Web Developers liked on 12th February 2020
Benjamin Crozat liked on 12th February 2020
Andrew liked on 12th February 2020
Francisco Barreto liked on 12th February 2020
Kiran Krishnan liked on 12th February 2020
Alexandr Nita liked on 12th February 2020
Victor Yoalli 🌌 liked on 12th February 2020
Owen Voke (pxgamer) liked on 12th February 2020