PHPackages                             jakubboucek/psync - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [File &amp; Storage](/categories/file-storage)
4. /
5. jakubboucek/psync

ActiveLibrary[File &amp; Storage](/categories/file-storage)

jakubboucek/psync
=================

A tool for automated deploy/download of PHP applications source code between local PC and crappy webhosting.

v1.2.0(2w ago)213↓50%MITPHPPHP &gt;=8.4

Since Jun 14Pushed 2w agoCompare

[ Source](https://github.com/jakubboucek/psync)[ Packagist](https://packagist.org/packages/jakubboucek/psync)[ Docs](https://github.com/jakubboucek/psync)[ RSS](/packages/jakubboucek-psync/feed)WikiDiscussions master Synced 1w ago

READMEChangelog (3)Dependencies (5)Versions (4)Used By (0)

PHP sync (rsync for PHP) tool for crappy webhostings
====================================================

[](#php-sync-rsync-for-php-tool-for-crappy-webhostings)

*A tool for automated deploy/download of PHP applications source code between local PC and crappy webhosting.*

There is nothing worse than babysitting a PHP application on a hosting that, in this day and age, still speaks nothing but FTP. No SSH, no rsync, no Git deploy — just a lonely FTP port and your patience. You drag files in Total Commander, never quite sure what is *actually* on the server, and if you ever need to pull a changed file back *down* to compare it… good luck. (Editing straight on the server and then trying to keep things in sync is, of course, even worse ;-)

**psync** is rsync for exactly these crappy webhostings. You upload one small PHP file (the *agent*) over FTP once, and from then on you drive it over HTTP from your machine. Unlike one-way FTP deployers, psync is **bidirectional**: it can `compare` both sides, `upload` your local changes, and `download` whatever got changed on the server — even for applications with tens of thousands of files, and while politely respecting the tiny time/memory/upload limits of cheap shared hosting.

- **Client:** PHP 8.4+ (installed as `composer global`)
- **Agent (server):** PHP 7.4+, no Composer dependencies (just `ext-sodium`)

How it works
------------

[](#how-it-works)

1. **Install once.** `psync install` generates an **Ed25519** key pair and renders the agent — a single self-contained PHP file containing only the **public** key. You upload it via FTP into your **agent-dir** (where it must be reachable over HTTP). The **private** key goes into your local config and nowhere else, so even a leaked agent file lets nobody forge a request. The agent gets a **randomized filename** (`psync-agent-.php`) so its URL can't be scanned for, and it carries a header comment that tells anyone who later stumbles on it that it is a maintenance tool — not a backdoor — and is safe to delete. After a version bump, `psync re-install` re-renders the agent reusing your layout (rotating the key by default) — you re-upload it.

    The agent's reach is a **fixed scope baked in at install** — the path from where the agent file lives (**agent-dir**) to the top of the synchronized tree (**sync-root**). The two need not coincide: the synced tree may sit **above** the agent (frameworks like Nette/Laravel/Symfony keep their code above the public dir), **below** it (manage just `system/logs/` from an agent at the site root), or on a **sibling** branch. The scope is hardcoded and never taken from a request, so it stays a fixed boundary; the client cross-checks it against your config on every run.
2. **Every call is a signed HTTP request.** The client signs each request with the private key; the agent verifies it with the public key, plus a timestamp and nonce against replay. It therefore works even over plain HTTP, which many of these hostings still serve.
3. **Comparison is two-phase**, the way rsync stays fast. First a quick listing of name + size + mtime on both sides. Only for files of equal size but different mtime does the agent compute an `md5` — in batches sized to fit the server's limits. A local state cache remembers the verdict, so a file whose only difference is a wobbly FTP mtime is not re-hashed on every run.
4. **Transfers are streamed and safe.** Files move in a compact binary framing (optionally gzipped), never loaded whole into memory. Each file is written **atomically** (temp file + rename) and stamped with the source's mtime. Deletion is opt-in (`--delete`) and shielded by a protect-list.
5. **It survives crashes.** Because shared hosting loves to kill a request mid-flight, every operation is idempotent and **resumable** — if it dies, just run it again and the finished files are skipped.

Installation
------------

[](#installation)

```
composer global require jakubboucek/psync
```

Configuration
-------------

[](#configuration)

`psync install` generates and fills in `.psync.php`. All paths are **relative to the config file's own directory** (the project-root):

```
