Search by

muckiware / restic

tfreyda

php client for restic backup tool

Package info

github.com/muckiware/restic

pkg:composer/muckiware/restic

Statistics

Installs: 1 399

Dependents: 1

Suggesters: 0

Stars: 2

Open Issues: 3

v1.4.1 2026-01-15 11:42 UTC

README

PHP client for restic backup tool. This library provides a simple way to create and manage backups with restic. It uses repositories as storage for backups.

Latest Stable Version Total Downloads PHP Version Require Dependents License

Requirements

Installation

composer require muckiware/restic

Upgrading to 1.5.0

Version 1.5.0 fixes a critical command injection. Commands are no longer assembled as shell strings but as argument lists executed without a shell.

If you only use Backup, Manage and Restore, nothing changes. If you implement CommandLineInterface yourself, getCommandLine() now returns array:

public static function getCommandLine(Configuration $configuration): array
{
    $command = [
        $configuration->getBinaryPath(),
        '--repo='.$configuration->getRepositoryPath(),
        'backup',
    ];

    if ($configuration->isJsonOutput()) {
        $command[] = '--json';
    }

    $command[] = '--';
    $command[] = (string) $configuration->getBackupPath();

    return $command;
}

Option values must be a single element ('--host='.$host, not '--host', $host), and positional arguments belong after '--'. Configuration setters reject values starting with a dash and throw InvalidConfigurationException.

ResultEntity::getCommandLine() also changes: it now returns the shell-escaped string Symfony's Process::getCommandLine() produces for an array commandline, with every token single-quoted (e.g. '/usr/bin/restic' '--repo=/srv/repo' 'backup' instead of /usr/bin/restic --repo=/srv/repo backup). If you log, display or re-parse this value, update accordingly.

The setter guards only validate the shape of a value, not whether it is trustworthy — a value like rest:http://attacker/ or s3:https://attacker/ passes the guard but redirects the backup to an attacker-controlled server. If you accept a repository path or similar value from untrusted input (e.g. an HTTP request), you must whitelist the allowed scheme or prefix yourself; this library does not do it for you.

Usage

How to use the library. This php client interacts with the restic binary to create, manage and restore backups in and of a repository. The first step is always to create a backup repository as storage for the backup data. After that, you can create backups in this repository and check the backup data. And at least if its necessary, you can restore the backup data.

Location of backup repository

The backup repository can be located on the local file system, or on an external S3 storage. Currently this library supports AWS / AmazonS3 as external storage for the backup repository. More details about the Amazon Bucket configuration in the restic documentation https://restic.readthedocs.io/en/latest/080_examples.html#setting-up-restic-with-amazon-s3

Overview commands

This gives you an overview of the possible methods of the framework. The default value for repositoryLocationTypes is local.

MuckiRestic\Library\Backup\Backup::[method];

<?php declare(strict_types=1);

use MuckiRestic\Library\Backup;

class MyClass
{
    public function myMethod(): void
    {
        try {
        
            $backupClient = Backup::create();
            //configuration settings
            ...
            $backupClient->[method]
            ...
Method Parameter variable name [type of variable] Description
createRepository() $overwrite[bool],
$repositoryLocationTypes[RepositoryLocationTypes] (optional)
Creates a new backup repository
createBackup() $repositoryLocationTypes[RepositoryLocationTypes] (optional) Creates a backup with and creates a new snapshot in the backup repository
checkBackup() $repositoryLocationTypes[RepositoryLocationTypes] (optional) Checks a repository and reads all data for testing

MuckiRestic\Library\Backup\Manage::[method];

<?php declare(strict_types=1);

use MuckiRestic\Library\Manage;

class MyClass
{
    public function myMethod(): void
    {
        try {
        
            $manageClient = Manage::create();
            //configuration settings
            ...
            $manageClient->[method]
            ...
Method Parameter variable name [type of variable] Description
getSnapshots() $repositoryLocationTypes[RepositoryLocationTypes] (optional) Get a list of all snapshots in specific repository
removeSnapshots() $repositoryLocationTypes[RepositoryLocationTypes] (optional) Removes snapshots by snapshot ids
removeSnapshotById() $repositoryLocationTypes[RepositoryLocationTypes] (optional) Removes a snapshot by specific snapshot id
executePrune() $repositoryLocationTypes[RepositoryLocationTypes] (optional) Performance a clean up of old items after a remove command. Its saved hd space.
getRepositoryStats() $repositoryLocationTypes[RepositoryLocationTypes] (optional) Get a list of statistic values of a specific repository

MuckiRestic\Library\Restore::[method];

<?php declare(strict_types=1);

use MuckiRestic\Library\Restore;

class MyClass
{
    public function myMethod(): void
    {
        try {
        
            $restoreClient = Restore::create();
            //configuration settings
            ...
            $restoreClient->[method]
            ...
Method Parameter variable name [type of variable] Description
createRestore() $overwrite[bool],
$repositoryLocationTypes[RepositoryLocationTypes] (optional)
Creates a restore of a specific snapshot

Process timeouts

Every restic command is executed as a separate process with a time limit. The limit applies to all three clients — Backup, Manage and Restore — because they share the same configuration base, so you set it once on the client you are working with.

Method Parameter variable name [type of variable] Description
setProcessTimeout() $seconds[float|null] Wall clock limit for one restic process. Default 3600.0
getProcessTimeout() Returns the current wall clock limit
setProcessIdleTimeout() $seconds[float|null] Abort the process after this long without output. Default null, disabled
getProcessIdleTimeout() Returns the current idle limit

Both accept an integer as well; setProcessTimeout(7200) is fine.

Wall clock timeout

The default is one hour. A first backup, or a prune on a repository that has grown over time, regularly takes longer than that, so raise it for large repositories:

$backupClient = Backup::create();
$backupClient->setProcessTimeout(14400);   // four hours

Pass null to remove the limit entirely. Do that only where something else can stop a runaway process — a message queue worker with its own --time-limit, for example:

$backupClient->setProcessTimeout(null);    // no limit

0 and negative values are rejected with an InvalidConfigurationException. This is deliberate: Symfony reads a timeout of 0 as "no limit", and an integer field left empty in a configuration UI yields exactly 0. Without the check, a forgotten setting would silently produce a backup process that can never time out. Use null when you mean it.

Idle timeout

The idle timeout is off by default. When set, the process is aborted if restic produces no output for that long, which catches a hung process without putting a ceiling on a legitimately long run:

$backupClient->setProcessTimeout(null);        // a backup may take as long as it needs
$backupClient->setProcessIdleTimeout(300);     // but five minutes of silence means it is stuck

Be careful when combining this with setJsonOutput(false). With --json restic emits status messages continuously, so silence is a reliable signal. Without it, and for check, prune and unlock, output can pause for longer stretches during normal operation and a low idle timeout will cut a healthy run short.

Create a new backup repository

You will need first the backup object of the library, for to use the createRepository method. Import this class with use MuckiRestic\Library\Backup;. The Backup-class has a static create-method for to get the Backup object, like this $backupClient = Backup::create();. With this create, you have access to all the Backup methods. The $backupClient->createRepository() method initialize a new repository and need the required parameters password and the repositoryPath. The repositoryPath is where the backup data will be stored and the password is used to encrypt the backup data. It's required for all operations on the repository. It has to be set by the two setting methods $backupClient->setRepositoryPassword('1234') and $backupClient->setRepositoryPath('./path_to_repository')
Optionally you can set the path for the restic binary, with $backupClient->setBinaryPath('./bin/restic_0.17.3_linux_386'). This is necessary if the restic binary is not installed in the local system.

The method createRepository() returns the object ResultEntity.

The method getOutput of the object ResultEntity returns the output of the restic command. If an error occurs, an exception will be thrown.

Example for local repository

<?php declare(strict_types=1);

use MuckiRestic\Library\Backup;

class BackupService
{
    public function createRepository(): void
    {
        try {
        
            $backupClient = Backup::create();
            $backupClient->setBinaryPath('./bin/restic_0.17.3_linux_386'); //optional
            $backupClient->setRepositoryPassword('12345%ASDEee'); //required
            $backupClient->setRepositoryPath('./path_to_repository'); //required

            echo $backupClient->createRepository()->getOutput();
        
        } catch (\Exception $e) {
            echo $e->getMessage();
        }
    }
}

Example for Amazon S3 storage

<?php declare(strict_types=1);

use MuckiRestic\Core\RepositoryLocationTypes;
use MuckiRestic\Library\Backup;

class BackupService
{
    public function createRepository(): void
    {
        try {
        
            $backupClient = Backup::create();
            $backupClient->setBinaryPath('./bin/restic_0.17.3_linux_386'); //optional
            $backupClient->setRepositoryPassword('12345%ASDEee'); //required
            $backupClient->setAwsAccessKeyId('AABBCCDDYUI4T123WIZY'); //required
            $backupClient->setAwsSecretAccessKey('xLqWLrN1yfrJ+r2zlnpoMY3eDXdHmdnne8T+Y2XZ'); //required
            $backupClient->setAwsRegion('eu-central-1'); //required
            $backupClient->setAwsS3Endpoint('s3:https://s3.amazonaws.com/my-restic-bucket'); //required
            $backupClient->setAwsS3BucketName('my-restic-bucket'); //required

            echo $backupClient->createRepository(RepositoryLocationTypes::AWSS3)->getOutput();
        
        } catch (\Exception $e) {
            echo $e->getMessage();
        }
    }
}

Create a backup

Next step, create a backup into the repository by using the method $backupClient->createBackup(). Also, this method will returns the object ResultEntity. The backup path is required for the backup operation. It has to be set by the method $backupClient->setBackupPath('./path_to_backup_folder').
Every backup process creates a new snapshot of the backup data in the repository. These snapshots are represented by an individually hash string.

Example for local repository

<?php declare(strict_types=1);

use MuckiRestic\Library\Backup;

class BackupService
{
    public function createBackup(): void
    {
        try {
        
            $backupClient = Backup::create();
            $backupClient->setBinaryPath('./bin/restic_0.17.3_linux_386'); //optional
            $backupClient->setRepositoryPassword('12345%ASDEee'); //required
            $backupClient->setRepositoryPath('./path_to_repository'); //required
            $backupClient->setBackupPath('./path_to_backup_folder'); //required
            
            echo $backupClient->createBackup()->getOutput();
        
        } catch (\Exception $e) {
            echo $e->getMessage();
        }
    }
}

Example for Amazon S3 storage

<?php declare(strict_types=1);

use MuckiRestic\Core\RepositoryLocationTypes;
use MuckiRestic\Library\Backup;

class BackupService
{
    public function createBackup(): void
    {
        try {
        
            $backupClient = Backup::create();
            $backupClient->setBinaryPath('./bin/restic_0.17.3_linux_386'); //optional
            $backupClient->setRepositoryPassword('12345%ASDEee'); //required
            $backupClient->setBackupPath('./path_to_backup_folder'); //required
            $backupClient->setAwsAccessKeyId('AABBCCDDYUI4T123WIZY'); //required
            $backupClient->setAwsSecretAccessKey('xLqWLrN1yfrJ+r2zlnpoMY3eDXdHmdnne8T+Y2XZ'); //required
            $backupClient->setAwsRegion('eu-central-1'); //required
            $backupClient->setAwsS3Endpoint('s3:https://s3.amazonaws.com/my-restic-bucket'); //required
            $backupClient->setAwsS3BucketName('my-restic-bucket'); //required
            
            echo $backupClient->createBackup(RepositoryLocationTypes::AWSS3)->getOutput();
        
        } catch (\Exception $e) {
            echo $e->getMessage();
        }
    }
}

Check the backup

After the backup process, it makes sense to check the backup data. The method $backupClient->checkBackup() will return the object ResultEntity. The method getOutput of the object ResultEntity returns the output of the restic command simple as string. If an error occurs, an exception will be thrown.

Example for local repository

<?php declare(strict_types=1);

use MuckiRestic\Library\Backup;

class BackupService
{
    public function createBackup(): void
    {
        try {
        
            $backupClient = Backup::create();
            $backupClient->setBinaryPath('./bin/restic_0.17.3_linux_386'); //optional
            $backupClient->setRepositoryPassword('1234'); //required
            $backupClient->setRepositoryPath('./path_to_repository'); //required
            
            echo $backupClient->checkBackup()->getOutput();
        
        } catch (\Exception $e) {
            echo $e->getMessage();
        }
    }
}

Example for Amazon S3 storage

<?php declare(strict_types=1);

use MuckiRestic\Core\RepositoryLocationTypes;
use MuckiRestic\Library\Backup;

class BackupService
{
    public function createBackup(): void
    {
        try {
        
            $backupClient = Backup::create();
            $backupClient->setBinaryPath('./bin/restic_0.17.3_linux_386'); //optional
            $backupClient->setRepositoryPassword('1234'); //required
            $backupClient->setAwsAccessKeyId('AABBCCDDYUI4T123WIZY'); //required
            $backupClient->setAwsSecretAccessKey('xLqWLrN1yfrJ+r2zlnpoMY3eDXdHmdnne8T+Y2XZ'); //required
            $backupClient->setAwsRegion('eu-central-1'); //required
            $backupClient->setAwsS3Endpoint('s3:https://s3.amazonaws.com/my-restic-bucket'); //required
            $backupClient->setAwsS3BucketName('my-restic-bucket'); //required
            
            echo $backupClient->checkBackup(RepositoryLocationTypes::AWSS3)->getOutput();
        
        } catch (\Exception $e) {
            echo $e->getMessage();
        }
    }
}

Manage backups

The library provides methods for to manage backups. Import this class with use MuckiRestic\Library\Manage;.

Get list of snapshots

You can get list of all snapshots of a repository with the method $manageClient->getSnapshots(). The method getSnapshots returns the object ResultEntity. The method getOutput of the object ResultEntity returns the output of the restic command simple as string. If an error occurs, an exception will be thrown.

Example for local repository

<?php declare(strict_types=1);

use MuckiRestic\Library\Manage;

class ManageService
{
    public function getSnapshotList(): void
    {
        try {
        
            $manageClient = Manage::create();
            $manageClient->setBinaryPath('./bin/restic_0.17.3_linux_386'); //optional
            $manageClient->setRepositoryPassword('1234'); //required
            $manageClient->setRepositoryPath('./path_to_repository'); //required
            
            echo $manageClient->getSnapshots()->getOutput();
        
        } catch (\Exception $e) {
            echo $e->getMessage();
        }
    }
}

Example for Amazon S3 storage

<?php declare(strict_types=1);

use MuckiRestic\Core\RepositoryLocationTypes;
use MuckiRestic\Library\Manage;

class ManageService
{
    public function getSnapshotList(): void
    {
        try {
        
            $manageClient = Manage::create();
            $manageClient->setBinaryPath('./bin/restic_0.17.3_linux_386'); //optional
            $manageClient->setRepositoryPassword('1234'); //required
            $manageClient->setAwsAccessKeyId('AABBCCDDYUI4T123WIZY'); //required
            $manageClient->setAwsSecretAccessKey('xLqWLrN1yfrJ+r2zlnpoMY3eDXdHmdnne8T+Y2XZ'); //required
            $manageClient->setAwsRegion('eu-central-1'); //required
            $manageClient->setAwsS3Endpoint('s3:https://s3.amazonaws.com/my-restic-bucket'); //required
            $manageClient->setAwsS3BucketName('my-restic-bucket'); //required
            
            echo $manageClient->getSnapshots(RepositoryLocationTypes::AWSS3)->getOutput();
        
        } catch (\Exception $e) {
            echo $e->getMessage();
        }
    }
}

Remove snapshot by id

You can remove a snapshot of a repository by id with the method $manageClient->getSnapshots(). The method getSnapshots returns the object ResultEntity. The method getOutput of the object ResultEntity returns the output of the restic command simple as string. If an error occurs, an exception will be thrown.

Example

<?php declare(strict_types=1);

use MuckiRestic\Library\Manage;

class ManageService
{
    public function getSnapshotList(): void
    {
        try {
        
            $manageClient = Manage::create();
            $manageClient->setBinaryPath('./bin/restic_0.17.3_linux_386'); //optional
            $manageClient->setRepositoryPassword('1234'); //required
            $manageClient->setRepositoryPath('./path_to_repository'); //required
            $manageClient->setSnapshotId('snapshot_id'); //required
            
            echo $manageClient->removeSnapshotById()->getOutput();
        
        } catch (\Exception $e) {
            echo $e->getMessage();
        }
    }
}

Example for Amazon S3 storage

<?php declare(strict_types=1);

use MuckiRestic\Core\RepositoryLocationTypes;
use MuckiRestic\Library\Manage;

class ManageService
{
    public function getSnapshotList(): void
    {
        try {
        
            $manageClient = Manage::create();
            $manageClient->setBinaryPath('./bin/restic_0.17.3_linux_386'); //optional
            $manageClient->setRepositoryPassword('1234'); //required
            $manageClient->setSnapshotId('snapshot_id'); //required
            $manageClient->setAwsAccessKeyId('AABBCCDDYUI4T123WIZY'); //required
            $manageClient->setAwsSecretAccessKey('xLqWLrN1yfrJ+r2zlnpoMY3eDXdHmdnne8T+Y2XZ'); //required
            $manageClient->setAwsRegion('eu-central-1'); //required
            $manageClient->setAwsS3Endpoint('s3:https://s3.amazonaws.com/my-restic-bucket'); //required
            $manageClient->setAwsS3BucketName('my-restic-bucket'); //required
            
            echo $manageClient->removeSnapshotById(RepositoryLocationTypes::AWSS3)->getOutput();
        
        } catch (\Exception $e) {
            echo $e->getMessage();
        }
    }
}

Remove old snapshots

You can remove old snapshots of a repository with the method $manageClient->removeSnapshots(). This is kind a like a cleanup run for the repository. The method removeSnapshots returns as always the object ResultEntity. The method getOutput of the object ResultEntity returns the output of the restic command simple as string. If an error occurs, an exception will be thrown.
This cleanup run needs to be setup with the keep-parameters, which defined the number of daily, weekly, monthly and yearly snapshots to keep. The method setKeepDaily(int $keepDaily), setKeepWeekly(int $keepWeekly), setKeepMonthly(int $keepMonthly) and setKeepYearly(int $keepYearly) are used to set the keep-parameters.

default keep-parameters

Parameter value
$keepDaily 7
$keepWeekly 5
$keepMonthly 12
$keepYearly 75
More details about the keep-parameters you can find in the restic documentation https://restic.readthedocs.io/en/latest/060_forget.html#removing-snapshots-according-to-a-policy

Example for local repository

<?php declare(strict_types=1);

use MuckiRestic\Library\Manage;

class ManageService
{
    public function removeOldSnapshots(): void
    {
        try {
        
            $manageClient = Manage::create();
            $manageClient->setBinaryPath('./bin/restic_0.17.3_linux_386'); //optional
            $manageClient->setRepositoryPassword('1234'); //required
            $manageClient->setRepositoryPath('./path_to_repository'); //required
            $manageClient->setKeepDaily(1); //optional
            $manageClient->setKeepWeekly(2); //optional
            $manageClient->setKeepMonthly(4); //optional
            $manageClient->setKeepYearly(5); //optional
            
            echo $manageClient->removeSnapshots()->getOutput();
        
        } catch (\Exception $e) {
            echo $e->getMessage();
        }
    }
}

Example for Amazon S3 storage

<?php declare(strict_types=1);

use MuckiRestic\Core\RepositoryLocationTypes;
use MuckiRestic\Library\Manage;

class ManageService
{
    public function removeOldSnapshots(): void
    {
        try {
        
            $manageClient = Manage::create();
            $manageClient->setBinaryPath('./bin/restic_0.17.3_linux_386'); //optional
            $manageClient->setRepositoryPassword('1234'); //required
            $manageClient->setKeepDaily(1); //optional
            $manageClient->setKeepWeekly(2); //optional
            $manageClient->setKeepMonthly(4); //optional
            $manageClient->setKeepYearly(5); //optional
            $manageClient->setAwsAccessKeyId('AABBCCDDYUI4T123WIZY'); //required
            $manageClient->setAwsSecretAccessKey('xLqWLrN1yfrJ+r2zlnpoMY3eDXdHmdnne8T+Y2XZ'); //required
            $manageClient->setAwsRegion('eu-central-1'); //required
            $manageClient->setAwsS3Endpoint('s3:https://s3.amazonaws.com/my-restic-bucket'); //required
            $manageClient->setAwsS3BucketName('my-restic-bucket'); //required
            
            echo $manageClient->removeSnapshots(RepositoryLocationTypes::AWSS3)->getOutput();
        
        } catch (\Exception $e) {
            echo $e->getMessage();
        }
    }
}

Restore a backup

You can restore a backup from a repository with the method $restoreClient->restoreBackup(). The method restoreBackup returns also the object ResultEntity. The method getOutput of the object ResultEntity returns the output of the restic command simple as string. If an error occurs, an exception will be thrown.
As default the method restoreBackup will restore the latest snapshot. Optionally you can set the snapshot hash with the method setRestoreItem(string $snapshotHash). The snapshot hash you can get from the method getSnapshots.

Example for local repository

<?php declare(strict_types=1);

use MuckiRestic\Library\Restore;

class RestoreService
{
    public function createRestore(): void
    {
        try {
        
            $restoreClient = Restore::create();
            $restoreClient->setBinaryPath('./bin/restic_0.17.3_linux_386'); //optional
            $restoreClient->setRepositoryPassword('1234'); //required
            $restoreClient->setRepositoryPath('./path_to_repository'); //required
            $restoreClient->setRestoreTarget('./path_to_restore_folder'); //required
            $restoreClient->setRestoreItem('snapshot_hash'); //optional
            
            echo $restoreClient->createRestore()->getOutput();
        
        } catch (\Exception $e) {
            echo $e->getMessage();
        }
    }
}

Example for Amazon S3 storage

<?php declare(strict_types=1);

use MuckiRestic\Core\RepositoryLocationTypes;
use MuckiRestic\Library\Restore;

class RestoreService
{
    public function createRestore(): void
    {
        try {
        
            $restoreClient = Restore::create();
            $restoreClient->setBinaryPath('./bin/restic_0.17.3_linux_386'); //optional
            $restoreClient->setRepositoryPassword('1234');
            $restoreClient->setRestoreTarget('./path_to_restore_folder');
            $restoreClient->setRestoreItem('snapshot_hash'); //optional
            $restoreClient->setAwsAccessKeyId('AABBCCDDYUI4T123WIZY'); //required
            $restoreClient->setAwsSecretAccessKey('xLqWLrN1yfrJ+r2zlnpoMY3eDXdHmdnne8T+Y2XZ'); //required
            $restoreClient->setAwsRegion('eu-central-1'); //required
            $restoreClient->setAwsS3Endpoint('s3:https://s3.amazonaws.com/my-restic-bucket'); //required
            $restoreClient->setAwsS3BucketName('my-restic-bucket'); //required
            
            echo $restoreClient->createRestore(RepositoryLocationTypes::AWSS3)->getOutput();
        
        } catch (\Exception $e) {
            echo $e->getMessage();
        }
    }
}

Use as cli app

Checkout the App folder for to run as cli command

bin/console muwa:restic:client --help

Get version of restic binary

bin/console muwa:restic:client --Version

Init a new backup repository

bin/console muwa:restic:client --Init <Repository> <Password>
  • Repository - Free of choice, where the backup data will be stored.
  • Password - Password for the backup repository, which is used to encrypt the backup data. It's required for all operations on the repository. Init a new backup repository

Create a backup

bin/console muwa:restic:client --Backup <Repository> <Password> <Backup>
  • Repository - Path to the backup repository
  • Password - Password for the backup repository.
  • Backup - Path to data which should be backed up. This can be a single file or a folder. If the path is a folder, all files and subfolders will be backed up.

Check the backup, by getting a list of all snapshots

bin/console muwa:restic:client --Snapshots <Repository> <Password>
  • Repository - Path to the backup repository
  • Password - Password for the backup repository.

Remove specific snapshot

bin/console muwa:restic:client --Snapshots <Repository> <Password> -r --snapshotId <SnapshotId>
  • Repository - Path to the backup repository
  • Password - Password for the backup repository.

Remove old snapshots

bin/console muwa:restic:client --Forget <Repository> <Password>
  • Repository - Path to the backup repository
  • Password - Password for the backup repository.

Testing

Run phpunit tests

./vendor/bin/phpunit --configuration=phpunit.xml
./vendor/bin/phpunit --configuration=phpunit_without_integration.xml

Run phpstan tests

composer run-script phpstan

License

MIT License (MIT). Please see LICENSE File for more information.

Notice

If you run muckiware/restic on a ddev/Docker environment, you could get a read/error of the backup files. In this case, check the mutagen status, and enable the mutagen sync. This library is only checked on a Linux and MacOS environment. All components are also available for Windows, but no warranty that is also working on a Windows environment.