sf2h/sftp-bundle
Symfony bundle that adds SFTP integration, with configurable connections and services for secure file transfers, uploads, downloads, and remote file management in PHP applications.
Architecture fit. The first thing a TPM needs to flag is a stack mismatch: sf2h/sftp-bundle is a Symfony bundle, not a Laravel package. Its value is split between a thin SFTP wrapper (built on phpseclib) and Symfony-specific plumbing — a DependencyInjection/*Extension, Resources/config/services.*, and bundle registration — none of which is meaningful in a Laravel service-container world. The real reusable asset is the phpseclib-backed client logic, which is small enough to read in an afternoon. In a Laravel codebase the natural fit is league/flysystem-sftp-v3 behind Laravel's Storage facade, which is maintained, integrates with the filesystem abstraction, and is what the rest of the ecosystem uses.
Integration feasibility. Low technical effort, low strategic value. Extracting the client into a Laravel service provider is a few hours; the harder question is whether the extracted code is worth owning. The bundle's advertised surface is "quite simple functions" — connect, list, get, put — with no evidence of connection pooling, retry/backoff, atomic rename-on-write, resumable transfers, or host-key verification. All of those are things you will build or bolt on regardless.
Technical risk. High, concentrated in sustainability rather than capability:
composer.json constraints determine whether you inherit that debt.Key questions to put to engineering and the business:
E_ALL?league/flysystem-sftp-v3, or an ext-ssh2 wrapper) we should conform to instead?Stack fit. Treat this as a reference implementation, not a dependency. Read it for the phpseclib invocation pattern, then implement against league/flysystem-sftp-v3 exposed through a Storage::disk('sftp_<partner>') driver. That keeps SFTP behind Laravel's filesystem contract, gives you put/get/exists/files for free, and makes the transport swappable to local disk or S3 in tests. If a spike shows the bundle's client does something Flysystem cannot (unlikely), vendor the minimum code into app/Support/Sftp/ with the license header retained — do not install the bundle and do not add Symfony's DI layer.
Migration path.
SftpGateway interface (push, pull, list, exists) so no application code ever imports phpseclib or Flysystem directly.Compatibility. Verify ext-openssl and ext-mbstring are present in every runtime (phpseclib needs pure-PHP crypto otherwise), confirm container images are not missing ext-ssh2 if we later prefer it for performance, and check that composer's platform config matches production. Pin phpseclib explicitly in our own composer.json rather than inheriting a transitively resolved version.
Sequencing. Requirements and endpoint inventory → interface definition → spike → transport decision (Flysystem vs. vendored code) → implementation with observability → parallel run against one partner → cutover per partner → retire. Do not start with the library choice; start with the endpoint inventory and data classification.
Maintenance. Effectively zero upstream maintenance. The package has been quiet for over four years with negligible adoption, so the realistic model is adopt-and-fork: we own the code, the phpseclib upgrade path, and the security review. Budget a recurring line item for that, or avoid it entirely by using Flysystem.
Support. No vendor, no maintainer SLA, no issue-tracker activity to rely on. Escalation is internal — name an owning team and an on-call rotation before the first production file moves. For partner-facing file exchange, the failure conversation is with the counterparty, not with GitHub.
Scaling. SFTP is connection-per-transfer, and pure-PHP crypto is CPU-bound: throughput per core will be materially lower than an ext-ssh2 or native sftp binary path for large payloads. Expect to need a queue worker per concurrent transfer, bounded concurrency to avoid overwhelming partner servers, and a chunked/streamed read path so multi-hundred-MB files don't land in PHP memory. None of this is provided by the package.
Failure modes to instrument explicitly:
put returns true but the file lands in the wrong directory.Mitigate with: temp-file write then atomic rename, checksum verification post-transfer, structured logs per transfer (partner, filename, bytes, duration, attempt), alerting on missed arrival windows, and a dead-letter queue for failed pushes.
Ramp-up. The API is trivially learnable — a mid-level PHP developer is productive in hours. The real ramp is organizational: understanding each partner's directory layout, naming conventions, retry expectations, and cutoff times. Plan roughly one engineering week to production-harden a single integration, plus partner-specific onboarding time, and treat the package itself as contributing almost nothing to that estimate.
How can I help you explore Laravel packages today?