marcel-maqsood / mezzio-middleware-formhandler
中间件表单处理器是一个PSR-15中间件,它为Laminas/Mezzio应用程序中的表单数据提供处理功能
Requires
- php: ~8.0.0 || ~8.1.0 || ~8.2.0
- laminas/laminas-diactoros: ^3.0
- laminas/laminas-json: ^3.1
- laminas/laminas-servicemanager: ^3.4
- mezzio/mezzio-problem-details: ^1.0
- psr/container: ^1.0
- psr/http-server-middleware: ^1.0
- swiftmailer/swiftmailer: ^6.2
- true/punycode: ^2.1
- twig/twig: ^3.9.3
README
这个库允许您处理您的表单,检查缺失的字段,并且仅使用您真正期望提交的字段。
安装
运行以下命令以安装此库
$ composer require marcel-maqsood/mezzio-middleware-formhandler:dev-master
信息
如果您的表单中有在配置中未定义的字段,由于安全原因,处理器将不会使用它们。"adapter"不再是对DataAdapters的正确关键字,现在关键字是"adapters",因为Formhandler现在能够一次使用多个适配器。
请注意:如果"adapters"包含一个条目"null",那么在该条目之后的适配器将不会使用,因为null会将数据传递到管道中。
文档
在文档的底部,我将向您展示如何快速构建配置的示例。
实现
要实现中间件,请将您的路由文件中的路由添加一个路由,将请求传递给中间件
$app->route(
'/formhandler[/]',
[
MazeDEV\FormularHandlerMiddleware\FormularHandlerMiddleware::class,
],
['POST'],
'formHandler'
);
由于我们的FormHandler现在是真正的中间件,您甚至可以像这样实现它
$app->route( '/formhandler[/]', [ MazeDEV\FormularHandlerMiddleware\FormularHandlerMiddleware::class, App\Handler\YourHandler::class ], ['POST'], 'formHandler' );
之后,请确保在您的config/autoload文件夹中提供一个配置文件,该文件包含中间件需要检查表单的所有内容。我们建议您使用我们的配置文件/config/form-config.local.php,将其粘贴到您的/config/autoload/文件夹中,并根据您的需要调整它。
所需数据
表单处理器需要JSON-、Multidata-或纯POST请求才能正常运行,并以JSON响应,描述正在发生的事情。
- 您可以通过常规方式提交表单(按钮type="submit" form method="post")或通过AJAX来调用表单处理器。如果您通过AJAX进行操作,可以使用我们的基础JavaScript来根据处理器的需求准备表单。
重要提示
-
本项目包含一个基本的JavaScript
/js/FormToJSON.js,当使用AJAX请求时,它对于将数据发送到表单处理器非常重要。您可以实现自己的逻辑,但您可能需要从开始。 -
在您的表单中定义一个
<input type="hidden" name="data[config]" value="YourFormName">字段至关重要。该字段为我们表单处理器提供有关必须验证的表单的必要信息。 -
此外,每个输入必须以"data"开头,如下所示:
<input type="hidden" name="data[config]" value="aValue"/>。如果未遵循此格式,则输入将不会被我们的表单处理器识别。
HTML示例
```html
<form id="aId" method="post">
<input type="hidden" name="data[config]" value="aValue"/>
<div class="row mb-1">
<div class="col-6">
<input id="surname" name="data[nachname]" type="text" class="form-control bg-dark"
placeholder="Surname" required/>
</div>
<div class="col-6">
<input id="Name" name="data[name]" type="text" class="form-control bg-dark"
placeholder="Name" required/>
</div>
</div>
<div class="row mt-3">
<div class="col-12">
<div class="form-group">
<label class="text-muted label-center">Empty Fields will be ignored.</label>
<button id="submit" type="submit" class="btn btn-success w-100">Submit</button>
</div>
</div>
</div>
</form>
```
适配器
目前有3个工作适配器
- phpmail
定义如下'adapters' => [ 'phpmail' => [ 'reply-to' => [ 'status' => true, 'field' => 'mail', ], 'recipients' => ['example@example.com'], 'subject' => 'subject', 'sender' => 'sender@example.com', 'senderName' => 'Form', 'template' => 'app::test', ], ],
phpmail通过PHP方法:mail()发送邮件(正如您可能期望的那样)。 - smtpmail
定义如下'adapters' => [ 'smtpmail' => [ //same as on phpmail but includes: 'email_transfer' => [ 'method' => 'smtpmail', 'config' => [ 'service' => 'smtp.googlemail.com', 'port' => '465', 'encryption' => 'ssl', 'email' => 'example@gmail.com', 'password' => 'examplepw', ], ], ], ],
smtpmail通过Swift_SmtpTransport发送邮件。您可以(如后所述)实现它们作为全局或本地适配器,全局适配器将覆盖本地适配器。 - null
定义如下'adapters' => null,
如果您定义'adapters' => null,我们的表单处理器将验证后的表单传递到路由中的下一个处理器,该处理器可以对其进行自己的操作。
本地适配器
适配器字段必须直接在表单定义中
'forms' => [ 'contact' => [ 'fields' => [ ... ], 'adapters' => [ null ], ], ],
全局适配器
全局适配器定义在配置的最顶部
'mazeform' => [ 'adapters' => [ 'globalTestAdapter-1' => [ [ 'method' => 'smtpmail', 'recipients' => ['example@example.com'], 'subject' => 'base subject all forms that uses this specific adaper has', 'sender' => 'example@example.com', 'senderName' => 'form', 'template' => 'app::test', 'email_transfer' => [ 'config' => [ 'service' => 'smtp.googlemail.com', 'port' => '465', 'encryption' => 'ssl', 'email' => 'example@gmail.com', 'password' => 'examplepw', ], ], ], ], ], ],
如果您定义了一个全局适配器并希望使用它,请直接在您的表单配置的适配器字段中填写其名称(在本例中:globalTestAdapter-1)。
'forms' => [ 'contact' => [ 'fields' => [ ... ], 'adapters' => [ 'globalTestAdapter-1', 'secondAdapter', null ], ], ],
收件人
由于您的表单应该能够发送自动回复,您可以在 php 'recipients' 中定义任意数量的收件人,并且还可以使用 '%submit%',这样处理程序会将此变量映射到您表单中提交的第一个“电子邮件”字段,例如:max.mustermann@mustermail.de,这样max就会知道您的系统已经注意到。
电子邮件模板
您在配置中指定的模板可以通过twig动态生成,然而,从v1.0.23版本开始,模板字段必须包含有效的模板名称。
'template' => 'app::test'
您使用的变量必须是您表单的有效字段,并且也在您的配置中定义。
电子邮件主题
与电子邮件模板类似,电子邮件主题也支持twig渲染器,但是主题不支持模板名称,它是一个纯字符串: 'subject' => 'base subject all forms that uses this specific adaper has {{ some_twig_variable }}'
回复到头
电子邮件适配器可以处理“回复到”电子邮件头,您可以在适配器配置中定义它,如下所示:
'reply-to' => [ 'status' => true, 'field' => 'mail' ],
回复到仅当
- 回复到已定义且以下内容正确时才有效:
- 状态已定义且为true;
- 字段已定义(并且在配置中存在)或未定义(但在此情况下,您的配置中的一个字段必须是电子邮件类型)
'forms' => [ 'contact' => [ 'fields' => [ 'someFieldName' => [ 'type' => 'email', ], ], 'adapters' => [ ... ], ], ],
CSRF保护
由于您的表单将在某个时候存储在数据库中或通过电子邮件发送,我们的FormHandler可以检查CSRF令牌以保护您的应用程序免受膨胀。
要使用CSRF保护,您必须安装Mezzio-CSRF并正确配置它。您不需要将字段定义为必需的,但我们建议使用'required' => 'true',只有这样,您的请求才能保证得到CSRF保护。
之后,请确保将其中一个字段定义为'type' => 'csrf'
'contactForm' => [ 'fields' => [ 'somename' => [ 'required' => true 'type' => 'csrf', ], ] ]
如果请求提交了无效的CSRF令牌,我们的FormHandler将不会进一步处理请求,而是将带有附加属性'csrfError'的请求传递到管道中,您可以在您的代码中使用此属性。
if($request->getAttribute('csrfError') != null) { //your error handling goes here... }
多层提交数组
由于您的应用程序可能会发送和接收嵌套数组,例如在联系表单中,我们的处理程序能够从嵌套数组中检索电子邮件字段:您只需将字段定义为 'type' => 'array'即可使用此行为。
'contactForm' => [ 'fields' => [ 'contact' => [ 'type' => 'array', 'childs' => [ 'salutation' => [ 'required' => true, 'type' => 'text' ], 'name' => [ 'required' => true, 'type' => 'text' ], 'surname' => [ 'required' => true, 'type' => 'text' ], 'email' => [ 'required' => true, 'type' => 'email' ], 'tel' => [ 'required' => true, 'type' => 'int' ], ] //in this case, there is no ], ], 'adapters' => [ ... ], ],
必需属性
Formhandler可以检查您的表单中的字段是否为必需的,如果缺失则不接受请求。如果您未定义必需或必需为false,处理程序可能无法获取该字段的值,因为它在请求中缺失。如果您想将字段设置为必需,请将此添加到字段的配置中。
'required' => true
示例
'mazeform' => [ 'adapters' => [ 'globalExampleAdapter-1' => [ [ 'method' => 'smtpmail', 'recipients' => ['recipient@example.com'], 'subject' => 'base subject all forms that uses this specific adaper has', 'sender' => 'example@example.com', 'senderName' => 'Kontaktformular', 'template' => 'app::test', 'email_transfer' => [ 'config' => [ 'service' => 'smtp.example.com', 'port' => '465', 'encryption' => 'ssl', 'email' => 'example@example.com', 'password' => 'yourPassword', ], ], ], ], ], 'forms' => [ 'contact' => [ 'fields' => [ 'name' => [ 'required' => true, ], 'company' => [ ], 'street' => [ ], 'city' => [ ], 'country' => [ 'required' => true, ], 'phone' => [ 'required' => true, ], 'mail' => [ 'required' => true, 'type' => 'email', ], 'message' => [ 'required' => true, ], 'somefield' => [ 'required' => true, 'type' => 'csrf' ] ], 'adapters' => [ 'globalExampleAdapter-1', null ], ], 'otherForm' => [ 'fields' => [ 'name' => [ 'required' => true, ], 'company' => [ ], 'street' => [ ], 'city' => [ ], 'country' => [ 'required' => false, ], 'phone' => [ 'required' => true, ], 'mail' => [ 'required' => true, 'type' => 'email', ], 'message' => [ 'required' => true, ], 'somefield' => [ 'required' => true, 'type' => 'csrf' ] ], 'adapters' => [ [ 'method' => 'phpmail', 'reply-to' => [ 'status' => true, 'field' => 'mail' ], 'recipients' => ['example@example.com'], 'subject' => 'example subject', 'sender' => 'sender@example.com', 'senderName' => 'Form', 'template' => 'app::test', ], [ 'method' => 'smtpmail', 'recipients' => ['recipient@example.com'], 'subject' => 'base subject all forms that uses this specific adaper has', 'sender' => 'example@example.com', 'senderName' => 'Kontaktformular', 'template' => 'app::test', 'email_transfer' => [ 'config' => [ 'service' => 'smtp.example.com', 'port' => '465', 'encryption' => 'ssl', 'email' => 'example@example.com', 'password' => 'yourPassword', ], ], ], ], ], ], ],
致谢
此捆绑包由designpark开发,并由ElectricBrands分叉。为了在不产生更多混乱的情况下维护此项目,它现在已分叉到我的GitHub上。(实际上,主要是我在开发它)。
许可
MIT许可证(MIT)。有关更多信息,请参阅许可文件。