PHPackages                             shyim/composer-binary-downloader - 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. shyim/composer-binary-downloader

ActiveComposer-plugin

shyim/composer-binary-downloader
================================

Generic Composer plugin that downloads platform-specific binaries — FFI shared libraries, CLI tools, WASM modules — from GitHub releases or any URL, driven by composer.json extra configuration

0.1.0(today)025↑2900%MITPHPPHP &gt;=8.2CI passing

Since Aug 1Pushed today1 watchersCompare

[ Source](https://github.com/shyim/composer-binary-downloader)[ Packagist](https://packagist.org/packages/shyim/composer-binary-downloader)[ RSS](/packages/shyim-composer-binary-downloader/feed)WikiDiscussions main Synced today

READMEChangelog (1)Dependencies (3)Versions (2)Used By (0)

composer-binary-downloader
==========================

[](#composer-binary-downloader)

A generic Composer plugin that downloads platform-specific binaries. Any package declares what it needs in `composer.json`; the plugin fetches the right build for the host on `composer install`.

It replaces the pattern of writing a bespoke Composer plugin per native dependency — download from GitHub releases, verify the checksum, unpack, put the file where the loader expects it — with configuration.

Works for anything shipped as a per-platform release asset:

- **FFI shared libraries** (`.so` / `.dylib` / `.dll`) — the original use case
- **CLI tools** — a Rust or Go binary your package shells out to
- **WASM modules**, ICU data, model files, or any other platform-specific blob

The engine does not care which: it fetches an asset, verifies it, and puts one file at a configured path.

Install
-------

[](#install)

```
composer require shyim/composer-binary-downloader
```

Composer plugins must be allowed explicitly:

```
{
    "config": {
        "allow-plugins": { "shyim/composer-binary-downloader": true }
    }
}
```

Configure
---------

[](#configure)

Add `extra.binaries` to the package that needs the binary. Every installed package is scanned, as is the root project, so a wrapper package declares its native dependency once. Consumers approve the package a single time — via the interactive prompt or an `extra.allow-binaries` entry (see [Security](#security-allow-binaries)) — and need no other setup.

```
{
    "name": "shyim/sasso-ffi",
    "require": { "shyim/composer-binary-downloader": "^1.0" },
    "extra": {
        "binaries": {
            "sasso": {
                "version": "0.8.2",
                "repository": "shyim/sasso",
                "asset": "{name}-v{version}-{target}-c-api.{ext}",
                "archive": "tar.xz",
                "path": "bin/{target}/{library}",
                "targets": {
                    "x86_64-apple-darwin":        "libsasso.dylib",
                    "aarch64-apple-darwin":       "libsasso.dylib",
                    "x86_64-unknown-linux-gnu":   "libsasso.so",
                    "aarch64-unknown-linux-gnu":  "libsasso.so",
                    "x86_64-unknown-linux-musl":  "libsasso.so",
                    "aarch64-unknown-linux-musl": "libsasso.so",
                    "x86_64-pc-windows-msvc":     { "library": "sasso.dll", "archive": "zip" }
                },
                "checksums": {
                    "aarch64-apple-darwin": "5f511055100a96c935a734c783b880567fd65e54a87a51c583b7ca8223cee9e7"
                }
            }
        }
    }
}
```

The library lands at `vendor/shyim/sasso-ffi/bin/aarch64-apple-darwin/libsasso.dylib`.

### Options

[](#options)

KeyRequiredDefaultMeaning`version`yes—Release version. A leading `v` is stripped. `"self"` uses the declaring package's own version — see below.`repository`yes\*—`owner/repo` for GitHub releases.`tag`no`v{version}`Release tag template. Use `{version}` for projects that tag without the `v`.`url`yes\*—Full URL template; use instead of `repository` for S3, GitLab, self-hosted.`asset`no`{name}-v{version}-{target}.{ext}`Published asset file name.`archive`no`tar.gz``tar.gz`, `tar.xz`, `tar.bz2`, `tar`, `zip`, or `none`.`library`yes\*\*—Shared-library file name inside the archive.`path`no`lib/{target}/{library}`Install path, relative to the declaring package.`targets`yes—Map of target triple to per-target settings (or a library-name string).`checksums`no—Map of target triple to expected sha256.`env-prefix`noupper-cased library namePrefix for the environment variables below.`optional`no`true`When `false`, a download failure aborts `composer install`.`bin`no—Expose the tool as a `vendor/bin` command: `true` (named after the binary) or a command name.`download`no`eager``lazy` defers the download to first use instead of fetching at `composer install`.\* One of `repository` or `url` is required. \*\* Not required when `archive` is `none`; the asset's own name is used.

Per-target settings (`asset`, `library`, `archive`, `checksum`, `url`) override the library-wide value — real pipelines ship a `.zip` of `foo.dll` on Windows and a `.tar.gz` of `libfoo.so` elsewhere.

### Placeholders

[](#placeholders)

Usable in `asset`, `url`, `library`, and `path`:

PlaceholderExpands to`{name}`The library key (`sasso`)`{version}`The configured version`{target}`Target triple (`aarch64-apple-darwin`)`{arch}`Architecture (`aarch64`)`{os}`Rest of the triple (`apple-darwin`)`{ext}`Archive extension (`tar.xz`); the library extension when `archive` is `none``{libext}`Shared-library extension for the **target** (`dylib`, `so`, `dll`)`{binext}`Executable extension for the **target** (`.exe` on Windows, empty elsewhere)`{goos}` / `{goarch}`Go-style names for the **target** (`linux`/`darwin`/`windows`, `amd64`/`arm64`) — matches goreleaser asset naming like `tool_1.0_linux_amd64``{library}`Resolved library file name (`path` only)`{libext}` and `{binext}` follow the target rather than the host, so cross-target prefetching names files correctly. `{binext}` includes the dot, so `"library": "mytool{binext}"` yields `mytool.exe` on Windows and `mytool`elsewhere without a per-target override.

### CLI tools on vendor/bin

[](#cli-tools-on-vendorbin)

A binary can be a command, not just a library. `"bin"` exposes it in Composer's bin-dir, and `"download": "lazy"` defers the fetch to first use — together they reproduce the pattern tools like `frosh/shopmon-cli` hand-write in a bin stub, as pure configuration:

```
{
    "name": "frosh/shopmon-cli",
    "require": { "shyim/composer-binary-downloader": "^1.0" },
    "extra": {
        "binaries": {
            "shopmon-cli": {
                "version": "self",
                "repository": "FriendsOfShopware/shopmon-cli",
                "tag": "{version}",
                "asset": "{name}_{version}_{goos}_{goarch}.{ext}",
                "archive": "tar.gz",
                "library": "shopmon-cli{binext}",
                "path": "bin/{version}/{target}/shopmon-cli{binext}",
                "bin": true,
                "download": "lazy",
                "targets": {
                    "x86_64-unknown-linux-gnu": {},
                    "aarch64-unknown-linux-gnu": {},
                    "x86_64-apple-darwin": {},
                    "aarch64-apple-darwin": {}
                }
            }
        }
    }
}
```

Any project requiring this package gets `vendor/bin/shopmon-cli`. Running it downloads the release on first use (with a notice on stderr), then executes it with stdin/stdout/stderr and the exit code passed straight through — via a true `exec` where `pcntl` is available, a waiting child process otherwise.

The pieces:

- **`"version": "self"`** — the binary version is the Composer package's own version. Tagging the wrapper repo releases both; `extra` never needs a version bump. A branch install (`dev-main`) has no tagged release, so it fails at parse time with a message saying exactly that.
- **`"bin": true`** — generate a proxy named after the binary (or pass a string for a different command name, e.g. `"bin": "rg"` for ripgrep). Generated proxies carry a marker; the plugin never overwrites or deletes a bin-dir file it did not generate, and removes its own when the declaration goes away.
- **`"download": "lazy"`** — nothing fetched during `composer install`; the proxy (or `Binaries::install()`) fetches on demand. `composer binary:install`and `--target` prefetch it anyway — an image build asking explicitly should not be refused.
- **`{version}` in `path`** — an upgrade fetches the new release instead of finding the old file at the same path and skipping it.
- **`{goos}`/`{goarch}`** — goreleaser asset naming from one template.

Downloaded files are `chmod 0755`, so the tool is runnable as fetched. PHP code can call the same binary via `Binaries::path('shopmon-cli')`.

For a package that must work even with plugins disabled, skip `"bin"` and ship a two-line stub as your own `bin` entry — Composer core links those without any plugin:

```
#!/usr/bin/env php
