Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Tc Lib File Laravel Package

tecnickcom/tc-lib-file

PHP utilities for low-level file access and byte-level reading. Provides local and remote file reads with host/path allowlists, big-endian binary byte readers, a prefixed temp-file cache, and typed exceptions. Part of the TCPDF ecosystem. Requires PHP 8.2+ with curl and pcre.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

What it actually is. tecnickcom/tc-lib-file is a narrow, low-level primitive library, not an application framework component. It exposes four small classes — File (allowlisted local/remote reads via cURL), Byte (big-endian binary readers over an in-memory string), Cache (prefixed temp-file lifecycle with age-based pruning), and Dir (writable-ancestor lookup) — plus a single Exception type. There is no Laravel service provider, no config file, no facade, no queue/event integration, and no opinion about where files live. Adoption cost is therefore almost entirely integration and governance work we would do ourselves, not library configuration.

Where it earns its place. Laravel's native primitives do not overlap much here. Storage/File facades give us path abstractions but no byte-level structured readers; Http gives us an HTTP client but no host allowlist with redirect-target revalidation and a memory-bounded response cap. If our roadmap includes PDF manipulation, font subsetting/embedding, image header inspection, TTF/OTF table parsing, or any binary format work, Byte plus the File allowlist semantics are genuinely useful. If our roadmap is CRUD + JSON APIs, this package has essentially zero surface area for us and the correct decision is to decline.

Architecture fit. Fits as an infrastructure-layer dependency consumed through a thin internal adapter, not called directly from controllers or jobs. The strict-deny default posture (allowedHosts and allowedPaths both empty by default) is the right default and composes well with a Laravel config-driven singleton. The API is small and stable enough to wrap: roughly a dozen public methods across four classes.

Integration feasibility. High in mechanical terms: composer require, PHP 8.2+ matches current Laravel 11/12 runtime expectations, PSR-4 autoload, no global state beyond K_PATH_CACHE. Two hard prerequisites: ext-curl must be present (it is disabled on some hardened images) and 64-bit PHP is assumed by getULong/getLong — a 32-bit build would produce wrong values rather than an error, which is the dangerous failure class.

Technical risk.

Risk Severity Notes
License ambiguity High README states GNU LGPL v3; GitHub/Packagist metadata reports NOASSERTION. These must reconcile before adoption. LGPL in a distributed on-prem appliance imposes relinking/source-availability obligations; SaaS use is generally unaffected but needs counsel sign-off, not engineering judgment.
Single-maintainer / bus factor Medium 8 stars, 0 dependents. Mitigated by the parent TCPDF/tc-lib-pdf ecosystem (~100M installs claim) meaning the maintainer is established, but this specific leaf package has no independent community.
Release metadata anomaly Medium "Last release: 2026-10-17" is inconsistent with observed time; verify actual tag cadence and whether this is an active or effectively frozen package before planning upgrades.
Silent setCachePath() fallback Medium Falls back to K_PATH_CACHE without error when the given path is a stream wrapper or non-writable. A misconfigured cache path degrades silently.
Reserved cURL callbacks Medium CURLOPT_WRITEFUNCTION, PROGRESSFUNCTION, XFERINFOFUNCTION, NOPROGRESS, and (with redirects) HEADERFUNCTION are overwritten. Any platform-wide cURL instrumentation, tracing, or egress proxy implemented at that layer will conflict.
Default maxRemoteSize 50 MB Medium Buffers in memory, measured post-decompression (zip-bomb exposure). Default is too generous for shared PHP-FPM pools.
Windows canonicalization gaps Medium 8.3 short names, ADS (file.txt:stream), trailing dots/spaces, and reserved device names are not expanded before allowlist matching — a path-confusion surface if allowlist inputs are ever user-influenced on Windows hosts.
Platform-dependent path semantics Low–Medium Case sensitivity is auto-probed per volume; macOS Unicode folding requires ext-intl or degrades to byte comparison. Behavior differs across our Linux CI and any macOS developer machines.

Key questions for the maintainer / our own review.

  1. Which license governs — LGPL v3 per README, or the NOASSERTION value reported by GitHub? Can we get an explicit LICENSE file and SPDX identifier confirmation?
  2. Is there a stated support window or semantic-versioning commitment for the File allowlist API, given it is a security boundary?
  3. What is the real release cadence and CVE-response process for this package specifically (not the parent PDF stack)?
  4. Is the intended usage model "only via tc-lib-pdf," or is standalone use in a web request path a supported scenario with respect to the 50 MB default?
  5. Can maxRemoteSize and the reserved-cURL-callback list be considered stable public contract, or are they subject to change in a minor release?

Integration Approach

Stack fit. Adopt behind a single internal service — e.g. App\Support\BinaryFile\BinaryFileService — bound as a singleton. Nothing in the application should import Com\Tecnick\File\* directly; enforce that with a PHPStan/architecture rule or a Deptrac layer so the dependency stays swappable. This is the single highest-leverage decision, because it converts a legal/maintenance risk into a one-file change.

Configuration shape. A dedicated config/binary-file.php sourcing allowed_hosts, allowed_paths, max_remote_size, max_redirects, cache_path, and case_sensitive_paths from env. Allowlists must be explicit per environment; never derive them from request input, and never use '*'. Fail fast at boot (a provider register() assertion) if allowedPaths is empty in production — a silent strict-deny in prod looks identical to "file not found" and will burn an on-call rotation.

Laravel-idiomatic mapping. Use storage_path('app/...') values as allowedPaths entries, and be aware the library canonicalizes via realpath(), so symlinked release directories (current -> releases/42) and Forge/Vapor-style layouts resolve correctly — verify this explicitly in staging rather than assuming. For local reads, prefer this package's fopenLocal/fReadInt path only where byte-level access is actually required; for whole-file moves, deletes, and uploads, keep using Storage. Do not let this package become a second, competing filesystem abstraction.

Compatibility. Pin the version in composer.json with a caret constraint but commit the lockfile, and treat minor bumps as reviewable because the allowlist is a security boundary. Conflicting global concerns to audit before rollout: any cURL wrapper or middleware (conflicts with reserved callbacks), open_basedir settings (documented interaction with CURLOPT_FOLLOWLOCATION), and upload_tmp_dir overrides that change the cache fallback target. Set maxRemoteSize to a realistic per-endpoint value (single-digit MB) rather than inheriting 50 MB.

Migration path. This is net-new adoption, not a replacement, so "migration" means consolidating scattered raw file_get_contents/curl_init/fopen calls behind the adapter. Sequence:

  1. Blocker — legal clearance. License reconciliation and written sign-off on LGPL v3 obligations for our distribution model. Do not start engineering before this closes.
  2. Spike (1 sprint). Adapter + config + provider + two real call sites (one local byte read, one allowlisted remote fetch). Success criteria: byte output matches a known-good reference for a real font/image/PDF fixture.
  3. Security review. Threat-model the allowlist: who supplies the path/URL, how entries are provisioned, Windows-host behavior if applicable, redirect target validation, and size caps. Add negative tests (NUL bytes, control characters, traversal, off-allowlist hosts, redirect to a non-allowlisted host).
  4. Harden. Lower maxRemoteSize, set CURLOPT_MAXREDIRS explicitly, assert getCachePath() matches configured path at boot to catch the silent fallback, and add a scheduled deleteOlderThan() job if the cache is used.
  5. Roll out behind a feature flag to the consuming feature, with the adapter logging allowlist rejections as a distinct, alertable event.
  6. Retire direct raw file/curl usage in the touched modules and add the architecture rule to CI.

Operational Impact

Maintenance. Very low churn expected — the API surface is four classes and the domain (reading bytes, opening files) is stable. Ongoing cost is dominated by governance, not code: tracking upstream releases, re-reviewing allowlist code on minor bumps, and the license obligation itself. Budget a recurring few hours per quarter plus a dependency-bot PR review, not a standing allocation. The zero-dependents figure cuts both ways: no transitive supply-chain surface, but also no ecosystem pressure testing.

Support. Single-maintainer, sponsor-funded project. There is no commercial SLA, no security contact process documented for this package in isolation, and no evidence of an LTS branch. Our mitigation is the adapter boundary: if the package is abandoned, the replacement surface is one file plus the tests. The parent TCPDF ecosystem's longevity is a genuine positive signal but should not be relied on as a commitment for this leaf package.

Scaling. Horizontal scaling is mostly clean — no shared state, no daemon, cache files are per-instance and keyed with a CSPRNG suffix so concurrent workers do not collide. Two caveats. First, memory: remote fetches buffer fully in memory, capped by maxRemoteSize as post-decompression bytes; under concurrency this multiplies against memory_limit and can produce OOM-kills rather than clean errors. Second, cache locality: the cache directory resolves to K_PATH_CACHE, then upload_tmp_dir, then the system temp dir — on multi-node or ephemeral-container deployments that means per-node, per-lifetime caches. That is acceptable for scratch data but must not be mistaken for a durable store; delete() only ever touches its own prefix, so no cross-tenant deletion hazard, but also no protection against unbounded growth if pruning is not scheduled.

Failure modes and observability. Expect four distinct signatures and instrument each: (a) \RangeException from out-of-bounds Byte reads — a programming error, should page nobody but must be caught to avoid 500s; (b) \Com\Tecnick\File\Exception for cURL option rejection, unresolvable cache directory, and invalid cache key arguments — configuration-shaped, alertable; (c) false returns for unreadable URLs and unfollowed redirects — the most dangerous signature, because it is indistinguishable from "empty file" unless the adapter raises; wrap it and convert to a typed exception; (d) silent allowlist denial, which presents as "file not found" and will misdirect incident response. Emit a structured log line on every rejection with the attempted host/path prefix so triage is possible without code archaeology. Also surface a metric for cache directory size and file count if the Cache class is used in a hot path.

Ramp-up. Low for a competent PHP engineer: the API is small, the README is unusually good, and the failure semantics are documented. Realistic ramp is 1–2 days to productive, with the caveats concentrated in three places that deserve explicit onboarding notes: (1) allowlist normalization and matching rules (ports, IPv6 bracketing, punycode, trailing root dot, case sensitivity, NFC folding); (2) the by-reference quirk on isValidURL()/isValidFile() versus the by-value isAllowedUrl()/isAllowedFile() — a genuine footgun that will appear in code review; (3) the reserved cURL callback list, which will silently override anything a developer tries to set for tracing. Assign a single owner for the adapter and the allowlist configuration; the blast radius of a wrong allowlist entry is the entire file-access boundary.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager