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

Secure Array Files Laravel Package

movex-ukraine/secure-array-files

A PHP package for securely storing arrays in files. It persists array data to disk while guarding against unsafe unserialization, offering Laravel apps a simple file-backed alternative to databases or caches for configuration and small datasets.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Laravel Nova field that stores uploaded files as an array of objects on a single attribute (typically a json/text column) rather than as separate media records, and serves those files back through a download response. Install it like any Nova field:

composer require <vendor>/<package>
php artisan vendor:publish --tag=<package>-config   # if a config is shipped
php artisan migrate                                 # only if it ships a migration

Look first at the field's constructor/fluent API (make(), disk, path, accepted types, max size) and at the config file if one is published — that's where the storage disk and download behaviour are decided.

Minimum wiring:

  1. Migration — add a nullable json column to the resource's table.
  2. Model — add the attribute to $casts so the array round-trips:
    protected $casts = ['attachments' => 'array'];
    
  3. Nova Resource — attach the field:
    FileArray::make('Attachments')
        ->disk('private')
        ->maxFiles(5);
    

First real use case: a record that needs a handful of supporting documents (contracts, receipts, photos) without spinning up a full Media model. You upload several files in one form, they land on a private disk, the field persists [{name, path, size, mime}], and the detail view exposes a download action that streams the file back through Laravel rather than a public URL.

Implementation Patterns

Field definition per context. Define the field once for forms, then constrain it on index/detail so you don't render N download links per row:

FileArray::make('Attachments')
    ->disk('private')
    ->path('records/'.auth()->id())
    ->acceptedTypes(['.pdf', '.jpg', '.png'])
    ->maxSize(10240)          // KB, if supported
    ->hideFromIndex();

Storing vs. appending. Most implementations treat the form submission as the source of truth: whatever is in the array after the request is what gets persisted. Decide early whether users replace the set or append to it — if you need append semantics with a create/update split, handle it in beforeSave/afterSave on the field or in the model observer rather than fighting the field.

Reading the array outside Nova. Because it's plain JSON on the model, you get full flexibility:

foreach ($record->attachments as $file) {
    Storage::disk('private')->download($file['path'], $file['name']);
}

Wrap that in a controller + route and put the authorization in a policy — do not rely on the Nova field's download endpoint for non-Nova consumers.

Custom download behaviour. If the field exposes a download callback (->downloadUsing(fn ($file) => response()->download(...))) or a configurable route/controller, use it to inject authorisation checks, audit logging, or on-the-fly decryption. That is the cleanest extension point for "secure" requirements.

Testing. Use Storage::fake('private') and UploadedFile::fake()->create(...), then assert the persisted JSON shape rather than the raw disk contents. Assert on $record->attachments[0]['path'] so you're testing the contract, not the package's internal naming.

Backfilling data. If you're migrating from single-file columns or another media package, write a one-off command that maps old paths into the array-of-objects shape and run it before flipping the field over. Keep the legacy column until you've verified downloads.

Gotchas and Tips

  • array vs. object casting. A plain array cast gives you arrays, not objects — callbacks and view code that expect $file->path will break. Use AsArrayObject if the package's docs assume object access, and be consistent across Nova and your own controllers.
  • Disk visibility. "Secure" only holds if the disk is private/local with no storage:link exposure. Verify a raw URL to the stored path 403s. If the package defaults to public, override it explicitly in every field definition.
  • Orphaned files on update/delete. Array-of-objects fields rarely clean up after themselves. Add a model deleted hook and a diff in updating to remove files no longer present, otherwise the disk grows forever.
  • JSON column limits. MySQL json is fine; older text columns truncate silently at 64KB, which bites once you store many files or verbose metadata. Check the migration.
  • Index view performance. Rendering download links for every row on the index triggers storage calls (existence checks, signed URLs). Use ->hideFromIndex() or a ->displayUsing() that renders a count.
  • Content-Disposition and streaming. If downloads open inline in the browser or arrive with mangled filenames, the response headers (not the field) are the problem — check whether the package uses download() vs inline(), and whether filenames are sanitised for non-ASCII.
  • Signed/temporary URL expiry. If downloads are signed, long-lived detail pages will hand out dead links. Either regenerate on render or use a short-lived route hit through a controller.
  • Validation is on you. Client-side acceptedTypes is advisory. Add server-side mimes:/max: rules in the Nova resource's rules() — MIME sniffing beats trusting the extension.
  • Debugging checklist. File missing? Check in order: disk name matches config/filesystems.php, the stored path has no leading slash, the file actually exists (Storage::disk(...)->exists()), and the authenticated user passes the policy. Log the persisted array on save once — it's the fastest way to see what the package is really writing.
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.
alphabalex/messaging-made-easy
rawphp/warp
shootkiran/merobug
narakode/fineauth
numencode/wn-syncops-plugin
ibnnajjaar/mib-global-pay
ably/pubsub-server
mstfkhazaal/defender
mfonte/base62x
karnoweb/metapilot
tobya/bcsapiwrapper
swalker2/cpanel
vish4395/laravel-translation-manager
morningtrain/economic
teksite/systeminfo-laravel
atomcms/voting
run6/weather
siokas/laravelembeddirectives
adamlien/pkuuids
gilsonsouza/lara-doc-generator