zendframework/zend-mvc-plugin-fileprg
A Zend Framework MVC controller plugin that implements the File Post/Redirect/Get pattern, letting you validate uploads before redirecting and preserve file upload state across requests.
First, a reality check: this is not a Laravel package. zendframework/zend-mvc-plugin-fileprg is a controller plugin for Zend Framework 2/3 (now Laminas) MVC — it gives you a File Post/Redirect/Get workflow so an uploaded file survives a redirect (e.g. when validation fails and you re-render the form). If you're on Laravel, there is nothing to install here; the equivalent is $request->file() + $request->flash() / withInput(), or putting the file reference in the session and re-rendering the Blade form. Use this package only if you maintain ZF/Laminas apps.
composer require zendframework/zend-mvc-plugin-fileprg:^1.1
Release 1.1.0 is purely platform work: PHP 7.1 and 7.2 are now supported, HHVM is dropped. No API changes, so it's a safe composer update — and it's the version to pin if you're still on the Zend namespace but running a modern PHP 7.x runtime.
First use case: a form with a single file input where an invalid submission should not force the user to re-pick the file.
Where to look first:
Zend\Mvc\Plugin\FilePrg\FilePrg — read __invoke(); it's short and documents the three return states.Zend\InputFilter\FileInput and Zend\Filter\File\RenameUpload docs — the plugin only reports what your input filter did.laminas/laminas-mvc-plugin-fileprg — the maintained successor; the repo you're on is archived.The canonical controller action. The plugin returns one of three things, and your action branches on all three:
use Zend\InputFilter\FileInput;
use Zend\Filter\File\RenameUpload;
public function uploadAction()
{
$form = $this->form; // injected UploadForm
$prg = $this->fileprg($form); // optionally: ('route', ['id' => 42])
if ($prg instanceof \Zend\Http\PhpEnvironment\Response) {
return $prg; // POST was valid: 302 back to this URL
}
if ($prg === false) {
return ['form' => $form]; // GET with no pending data: blank form
}
// GET after the redirect: $prg holds the filtered data
$form->setData($prg);
if ($form->isValid()) {
$this->attachmentService->persist($form->getData());
return $this->redirect()->toRoute('uploads');
}
return ['form' => $form]; // stale data, re-render
}
Make the form's input a FileInput, not the default Input. This is the single most common integration failure. The default input type ignores $_FILES entirely, so isValid() passes and you get an empty value.
$inputFilter->add([
'name' => 'attachment',
'type' => FileInput::class,
'required' => true,
'filters' => [[
'name' => RenameUpload::class,
'options' => [
'target' => './data/uploads',
'randomize' => true,
'use_upload_name' => true,
'overwrite' => false,
],
]],
'validators' => [[
'name' => \Zend\Validator\File\Size::class,
'options' => ['max' => '2MB'],
]],
]);
Use RenameUpload in the filter chain rather than moving the file in your controller. The plugin stores filtered data in the session, so a renamed/relocated file is what survives the redirect — leaving the move until the final branch means you're relying on a PHP temp path that may already be gone.
Persist in the post-redirect branch, not the POST branch. Treat the POST branch as "validate + redirect" and the second GET as "the user's intent is confirmed". This keeps the write idempotent-ish (a refresh of the final page still has the data) and matches the plugin's contract.
Wrap it behind a service. Controllers using $this->fileprg() directly are hard to unit test; either inject the plugin (it's a normal AbstractPlugin with setSessionManager() / setRedirect()) or move the three-branch logic into a small handler and keep the controller branch-free.
Laravel translation of the same pattern, if you're porting:
$request->validate(['attachment' => 'required|file|max:2048']);
if ($request->hasFile('attachment')) {
$path = $request->file('attachment')->store('uploads');
session()->put('pending_attachment', $path);
return redirect()->route('uploads.confirm');
}
$path = session()->pull('pending_attachment');
enctype="multipart/form-data" on the <form>, or the plugin receives an empty file set and silently validates. Check this before debugging anything else.Zend\Session\Container; if Zend\Session isn't wired into your ServiceManager/session_manager config, you get a container instantiation error rather than a helpful message. ZF skeleton apps need Zend\Session enabled explicitly.$prg === false vs $prg instanceof Response vs array. Use strict comparisons. A loose if ($prg) on a falsy-but-present array is a classic source of "form renders as if nothing was submitted".false on an invalid POST; it does not repopulate $form with the submitted values. Call $form->setData($this->getRequest()->getPost()) in that branch or the user loses non-file fields.^1.1 is a drop-in for ^1.0. If any of your CI runs on HHVM, that job now fails to install — remove it rather than pinning 1.0.x.laminas/laminas-mvc-plugin-fileprg (namespace Laminas\Mvc\Plugin\FilePrg, same API, class-rename via the migration tooling). Budget for the rename rather than planning new features here.FilePrg and override the session-container accessors — the class is small and the container namespace is the natural seam.How can I help you explore Laravel packages today?