Files
SFTPsync/README.md

126 lines
4.5 KiB
Markdown

# 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:
```bash
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
```text
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
```bash
# 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.