2026-02-16 07:23:55 +01:00
2026-06-02 22:24:35 +02:00
2026-06-02 22:24:35 +02:00
2026-02-15 17:31:47 +01:00
2026-06-02 22:24:35 +02:00

SFTPsync

Small PHP CLI utility to synchronize directories and manage files on a remote server over SFTP.

What It Does

  • Sync local directory to remote (--sync)
  • Sync remote directory to local (--sync-down)
  • Delete one remote file (--delete)
  • Delete remote directory recursively (--delete-dir)
  • Combine multiple actions in one run (executed in CLI order)
  • Skip selected paths during sync or delete using repeatable rules

Requirements

  • PHP 8+ (CLI)
  • PHP ssh2 extension enabled (ssh2_connect, ssh2_sftp, ...)
  • Network access from your machine to the target SFTP host

Quick Start

From repository root:

php src/SFTPsync.php --host example.com --user myuser --password mypass --sync ./local /var/www/app

If --host, --user, or --password is missing, the script asks for it interactively (TTY only).

CLI Usage

php src/SFTPsync.php --host <host> --user <user> --password <password> [--port <port>] <actions...>

Actions (repeatable)

  • --sync <local_dir> <remote_dir>: upload local changes to remote
  • --sync-down <remote_dir> <local_dir>: download remote changes to local
  • --delete <remote_file>: delete one remote file
  • --delete-dir <remote_dir>: delete remote directory recursively (with safety checks)

Options

  • --host <host>: required (or prompted)
  • --user <user>: required (or prompted)
  • --password <password>: required (or prompted)
  • --port <port>: optional, default 22
  • --print-relative: show paths relative to action root in logs
  • --no-print-skip: suppress SKIP status lines during execution
  • --skip <pattern>: repeatable, exact names/paths or glob patterns (*, ?), applied to --sync and --sync-down
  • --skip-delete <pattern>: repeatable, exact names/paths or glob patterns (*, ?), applied to --delete and --delete-dir
  • -h, --help: show help

Examples

# Upload local -> remote
php src/SFTPsync.php --host example.com --user u --password p --sync ./app /srv/app

# Download remote -> local
php src/SFTPsync.php --host example.com --user u --password p --sync-down /srv/backups ./backups

# Multiple actions in one run (executed left-to-right)
php src/SFTPsync.php --host example.com --user u --password p \
  --sync ./a /remote/a \
  --delete /remote/a/old.zip \
  --sync-down /remote/logs ./logs

# Skip selected entries during sync
php src/SFTPsync.php --host example.com --user u --password p \
  --skip .git --skip node_modules --skip "*.log" --skip "cache/*" \
  --sync ./app /srv/app

# Delete remote directory but keep selected subpaths
php src/SFTPsync.php --host example.com --user u --password p \
  --skip-delete .well-known --skip-delete uploads/keep \
  --delete-dir /srv/app

Sync Behavior

For each file pair, transfer happens when:

  • target file does not exist, or
  • file size differs, or
  • source mtime is newer than target mtime

After upload/download, mtime is propagated to the target when possible.

Skip Rule Matching

  • Rule without wildcard characters (example: node_modules) keeps exact matching.
  • Exact rule without slash (example: node_modules) matches any path segment with that name.
  • Exact rule with slash (example: cache/tmp) matches that subpath within a relative path.
  • Rule containing * or ? is treated as a glob pattern. * matches any characters, and ? matches one character.
  • Glob rule without slash (example: *.log) can match file or directory names at any depth.
  • Glob rule with slash (example: src/temp/*.log or cache/*) is matched against relative paths.
  • Rules are normalized to forward slashes.

Examples:

  • --skip=*.bat skips test.bat and tools/deploy.bat, but not test.bat.txt.
  • --skip=*.log skips app.log and src/temp/test.log, but not app.log.1.
  • --skip=backup-* skips backup-2025, backup-old, and backup-test.
  • --skip=cache/* skips content under cache.
  • --skip=node_modules and --skip=.git keep the original exact-name behavior.

Safety Notes

  • --delete-dir refuses dangerous roots such as empty path, /, ., .., and similar dot paths.
  • Delete operations run only on the remote side.
  • Path handling normalizes slashes and trims duplicate separators.

Exit Codes

  • 0 success
  • 1 runtime/SFTP error
  • 2 invalid CLI arguments

Output

The script prints status lines (MKDIR, UPLOAD, DOWNLOAD, DELETE, RMDIR, SKIP, ERROR) and a final summary with operation counters.

Use --no-print-skip if you want to keep skipped-item accounting in the final summary but hide individual SKIP log lines during the run.

Description
PHP utility for synchronize local and remote directories over SFTP.
Readme MIT 78 KiB
Languages
PHP 100%