定制 jturbide/form-to-email 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

jturbide/form-to-email

Composer 安装命令:

composer require jturbide/form-to-email

包简介

A lightweight PHP 8.5+ library to process form submissions, validate fields, and send structured email notifications with configurable templates and error codes.

README 文档

README

Build Status Docs Downloads

Coverage Psalm Level PHPStan Code Style

A lightweight, extensible PHP 8.5+ library for secure form processing, validation, sanitization, transformation, and structured email delivery. Built for modern PHP projects with strict typing, predictable pipelines, and framework-agnostic design.

🚀 Quick start (tl;dr)

Install the package:

composer require jturbide/form-to-email

Create a form definition, create a mailer, and handle a request:

<?php

use FormToEmail\Core\FieldDefinition;
use FormToEmail\Core\FormDefinition;
use FormToEmail\Enum\FieldRole;
use FormToEmail\Filter\HtmlEscapeFilter;
use FormToEmail\Filter\RemoveEmojiFilter;
use FormToEmail\Filter\RemoveUrlFilter;
use FormToEmail\Filter\SanitizeEmailFilter;
use FormToEmail\Filter\StripTagsFilter;
use FormToEmail\Filter\TrimFilter;
use FormToEmail\Http\FormToEmailController;
use FormToEmail\Mail\PHPMailerAdapter;
use FormToEmail\Rule\EmailRule;
use FormToEmail\Rule\IncludeRule;
use FormToEmail\Rule\LengthRule;
use FormToEmail\Rule\RequiredRule;
use FormToEmail\Transformer\LowercaseTransformer;

require_once __DIR__ . '/../vendor/autoload.php';

$form = new FormDefinition()
    ->add(new FieldDefinition('name', roles: [FieldRole::SenderName], processors: [
        new TrimFilter(),
        new RequiredRule(),
    ]))
    ->add(new FieldDefinition('email', roles: [FieldRole::SenderEmail], processors: [
        new SanitizeEmailFilter(),
        new EmailRule(),
        new LowercaseTransformer(),
    ]))
    ->add(new FieldDefinition('contact_reason', processors: [
        new IncludeRule(['sales', 'support', 'billing']),
    ]))
    ->add(new FieldDefinition('number_of_units', roles: [FieldRole::Body], processors: [
        new LengthRule(max: 10),
    ]))
    ->add(new FieldDefinition('message', roles: [FieldRole::Body], processors: [
        new RemoveUrlFilter(),
        new RemoveEmojiFilter(),
        new StripTagsFilter(),
        new RequiredRule(),
        new HtmlEscapeFilter(),
    ]));

$mailer = new PHPMailerAdapter(
    useSmtp: true,
    host: 'mail.example.com',
    username: 'no-reply@example.com',
    password: 'secret',
    fromEmail: 'no-reply@example.com',
    fromName: 'Website Contact Form'
);

new FormToEmailController($form, $mailer, ['contact@example.com'])->handle();

Serve the file

php -s localhost:8000 ./

Send a XHR request

curl -X POST -H "Content-Type: application/json" -d '{
  "name": "Julien",
  "email": "julien@example.com",
  "contact_reason": "support",
  "number_of_units": 12,
  "message": "Hello world!"
}' http://localhost:8000/contact.php

See the result

{
  "code": "ok"
}

🆕 Recent updates

  • IncludeRule validates a field against a predefined allow-list and supports array inputs for checkbox and multi-select fields.
  • Default template rendering now safely handles mixed field values:
    • numeric scalars are stringified before HTML/text rendering
    • arrays and objects are JSON-encoded instead of causing rendering errors
  • Error interpolation and template rendering share a single internal stringification helper for consistent output behavior.
  • The project, docs, and CI now target PHP 8.5.

📚 Examples

Explore runnable examples in the examples/ directory. They cover both safe local exploration and real SMTP-backed delivery.

When an example uses handle() and real HTTP I/O, start the built-in server from the project root:

php -S localhost:8000

Examples list:

  • Basic example (safe local flow, includes logging)

    • File: examples/basic-example.php
    • Description: Uses handleRequest() with an in-memory mailer so you can inspect the generated MailPayload without SMTP.
    • Run:
      php examples/basic-example.php
  • SMTP basic (use handle() and real HTTP I/O)

    • File: examples/smtp-basic.php
    • Description: Minimal production-style endpoint using PHPMailerAdapter over SMTP; replace host, credentials, and recipients with your own.
    • Run:
      curl -sS -X POST -H 'Content-Type: application/json' \
        -d '{"name":"Alice","email":"alice@example.com","message":"Hello!"}' \
        http://localhost:8000/examples/smtp-basic.php | jq
  • Handle request without exit (capture response array)

    • File: examples/handle-request-json.php
    • Description: Demonstrates FormToEmailController::handleRequest() by simulating $_SERVER and raw JSON; prints both a successful and a failing response.
    • Run (CLI, no web server needed):
      php examples/handle-request-json.php
  • Advanced validators and processors

    • File: examples/advanced-validators.php
    • Description: Shows allow-lists, mixed-value fields, longer processor chains, and the structured validation payload returned on failure.
    • Run (CLI):
      php examples/advanced-validators.php
  • Custom JSON logging

    • File: examples/custom-logging.php
    • Description: Configures Logger to JSON format, writes to examples/form.log, and demonstrates both validation-failure and success logging.
    • Run (CLI):
      php examples/custom-logging.php

Tip: Examples are excluded from the Composer package and CI checks; they are for learning and local exploration.

✨ Core Features

Field Definitions & Validation

  • Multiple validators per field (RegexRule, CallbackRule, EmailRule, etc.)
  • Rich per-field error arrays for enhanced frontend UX
  • Enum-based field roles (SenderEmail, Subject, Body, etc.)
  • Composable and reusable rules (RequiredRule, IncludeRule, LengthRule, RegexRule, etc.)

Unified Processor Pipeline (Filters, Transformers, Validators)

  • Single FieldProcessor interface powering all processing stages
  • Deterministic execution order: exactly the order you declare
  • Configurable per-field pipeline with early bailout support
  • Fully reusable across forms for consistent data behavior

Filters & Sanitizers

  • First-class sanitization layer with composable filters
  • Advanced built-in filters:
    • SanitizeEmailFilter — RFC 6531/5321 aware, IDN-safe
    • RemoveEmojiFilter — removes emoji and pictographic symbols
    • NormalizeNewlinesFilter — consistent \n normalization
    • HtmlEscapeFilter — secure HTML output for templates
    • RemoveUrlFilter — aggressively removes embedded URLs
    • CallbackFilter — supports custom callable filters

Transformers

  • Mutate values post-sanitization, pre-validation
  • Includes built-ins: LowercaseTransformer, CallbackTransformer, etc.
  • Ideal for formatting, slugifying, or normalizing input values

Email Composition & Delivery

  • Dual HTML and plain-text templates (fully customizable)
  • PHPMailerAdapter by default — pluggable architecture for other adapters
  • Enum-based structured responses (ResponseCode::Success, ResponseCode::ValidationError, etc.)
  • Automatic field-role mapping to email metadata
  • Safe rendering of numeric and mixed scalar field values in default email templates

Logging & Observability

  • Built-in Logger for form submission tracking
  • Supports multiple formats: raw text, JSON, and syslog-compatible
  • Optional toggles for successful or failed submission logging
  • Fully tested with configurable verbosity and custom formatters

Architecture & Quality

  • Framework-agnostic — works with plain PHP, Symfony, Laravel, or any custom stack
  • 100 % typed and static-analysis-clean (Psalm / PHPStan / Qodana / SonarQube)
  • 445 PHPUnit tests with full coverage (core, filters, transformers, rules, adapters, logger)
  • Predictable and deterministic pipeline ensuring consistent validation behavior

🧩 Advanced Configuration

Built-in Adapters

  • MailerAdapter (interface) — minimal contract for sending mail.
  • PHPMailerAdapter — default adapter backed by PHPMailer.
  • MailPayload — immutable value object that carries to, subject, htmlBody, textBody, replyTo*.

Swap adapters by implementing MailerAdapter and injecting your implementation into FormToEmailController.

Built-in Filters

All filters implement Filter and the unified FieldProcessor contract. Use them to sanitize or normalize raw input.

  • TrimFilter — trims leading/trailing whitespace.
  • StripTagsFilter — removes HTML tags.
  • HtmlEscapeFilter — escapes HTML for safe rendering.
  • SanitizeTextFilter — general text cleanup (safe subset).
  • SanitizeEmailFilter — RFC 5321/6531 aware, IDN-safe normalization.
  • SanitizePhoneFilter — digits-first cleanup for phone inputs.
  • NormalizeNewlinesFilter — converts mixed newlines to \n.
  • RemoveUrlFilter — removes URLs aggressively.
  • RemoveEmojiFilter — strips emoji and pictographs.
  • CallbackFilter — custom callable filter per field.
  • ...more to come!

Tip: Prefer filters early to make downstream validation predictable.

Built-in Rules (Validators)

Rules implement Rule (and FieldProcessor) and add ValidationError entries when constraints fail.

  • RequiredRule — value must be present/non-empty.
  • IncludeRule — value must belong to an allowed set of developer-defined options.
  • EmailRule — email syntax validation (works with IDN-normalized values).
  • RegexRule — arbitrary pattern checks.
  • LengthRule / MinLengthRule / MaxLengthRule — string length constraints.
  • CallbackRule — custom boolean/callback validation.
  • ...more to come!

Errors use ErrorDefinition with machine-readable code, message, and context.

Example: allowed values

use FormToEmail\Rule\IncludeRule;

$field = new FieldDefinition('contact_reason', processors: [
    new IncludeRule(['sales', 'support', 'billing']),
]);

Example: multi-select values

$field = new FieldDefinition('topics', processors: [
    new IncludeRule(['news', 'events', 'offers']),
]);

If the frontend sends ['news', 'offers'], the rule passes. If it sends ['news', 'unknown'], the rule adds a structured invalid_value error with the rejected entries in the error context.

Built-in Transformers

Transformers modify values after sanitization but generally before rules.

  • LowercaseTransformer — lowercases strings.
  • UcFirstTransformer — capitalizes first letter
  • CallbackTransformer — custom mapping logic.
  • ...more to come!

Keep formatting here (slugify, case changes, phone canonicalization) so rules validate the final shape.

Processor Order

Execution is exactly the order you define in each FieldDefinition. A good default convention is:

Filters → Rules (Validators) → Transformers

Explicit order example

$field = new FieldDefinition('username', roles: [], processors: [
    new HtmlEscapeFilter(),
    new TrimFilter(),
    new LowercaseTransformer(),
    new RegexRule('/^[a-z0-9_]{3,20}$/'),
]);

Incremental API

$field = new FieldDefinition('username');
$field->addFilter(new HtmlEscapeFilter());
$field->addFilter(new TrimFilter());
$field->addProcessor(new LowercaseTransformer());
$field->addRule(new RegexRule('/^[a-z0-9_]{3,20}$/'));

Chaining

$field = (new FieldDefinition('username'))
    ->addFilter(new HtmlEscapeFilter())
    ->addFilter(new TrimFilter())
    ->addProcessor(new LowercaseTransformer())
    ->addRule(new RegexRule('/^[a-z0-9_]{3,20}$/'));

The library does not reorder processors for you. Define the pipeline you want. As a rule of thumb: sanitize first, validate, then transform to final form.

Value Types And Rendering

The validation pipeline accepts mixed values because frontend payloads are not always strings.

Practical implications:

  • Filters that operate on text should usually pass non-string values through unchanged.
  • Rules should decide explicitly whether non-string values are valid, ignored, or rejected.
  • Default HTML and plain-text email templates safely stringify numeric scalars and JSON-encode arrays/objects.

That means payloads like:

{
  "numberOfUnits": 12,
  "topics": ["news", "offers"]
}

will render safely in generated emails without requiring you to cast everything to strings first.

Custom Processors (Advanced)

Implement the unified processor contract to add your own behavior:

use FormToEmail\Core\{FieldProcessor, FieldDefinition, FormContext};

final class SlugifyTransformer implements FieldProcessor {
    public function process(mixed $value, FieldDefinition $field, FormContext $context): mixed {
        $s = strtolower(trim((string)$value));
        $s = preg_replace('/[^a-z0-9]+/', '-', $s) ?? '';
        return trim($s, '-');
    }
}

Register it like any other processor:

$field = (new FieldDefinition('title'))
    ->addProcessor(new SlugifyTransformer());

You can also stack your own custom ones:

$field->addProcessor(new CallbackTransformer(
    static fn(mixed $v): mixed => is_string($v) ? preg_replace('/\s+/', ' ', $v) : $v
));

🧭 Future Roadmap

This library already covers the essentials for form validation, sanitization, transformation, and email delivery. However, there’s still plenty of room for evolution (as always). While most of the following items aren’t priorities for my own use cases, I’m open to implementing them if they’re valuable to you or your project.

✅ Completed

  • Sanitization filters ✅
  • Data transformers ✅
  • Unified processor pipeline ✅
  • Comprehensive unit test coverage ✅
  • Submission logging system ✅

🧠 Planned / Proposed

  • reCAPTCHA v3 integration — prevent bot submissions without user friction
  • File attachments — safely handle uploaded files via configurable limits
  • Sender confirmation & double opt-in — ensure sender authenticity before sending
  • Spam protection / honeypot — lightweight anti-spam defense
  • Webhook + API notifications — trigger external systems on successful submissions
  • Rate limiting & IP throttling — basic abuse protection for public endpoints
  • Additional mailer adapters — e.g. Symfony Mailer, AWS SES, Postmark
  • SmartEmailRule — enhanced email validation with MX/DNS deliverability checks

💡 Want a feature sooner?

Open a GitHub issue or start a discussion — contributions and ideas are always welcome!

🧪 Quality Assurance

This library is built for reliability, maintainability, and modern PHP ecosystems.

  • 100 % strictly typed — every file uses declare(strict_types=1)
  • 100 % code coverage — verified through both unit and integration tests
  • Modern PHP 8.5 syntax — strict typing, readonly constructs, attributes, and enhanced type safety
  • Continuous Integration — fully validated via GitHub Actions with PHPUnit, Psalm, and PHPStan
  • Comprehensive test coverage — 445 PHPUnit tests covering core, filters, transformers, rules, HTTP flow, templates, and mail adapters
  • Deterministic pipeline — predictable processor order with verified behavior across all test cases

🪪 License

BSD 3-Clause License © Julien Turbide

jturbide/form-to-email 适用场景与选型建议

jturbide/form-to-email 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 27 次下载、GitHub Stars 达 1, 最近一次更新时间为 2025 年 11 月 03 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「mail」 「form」 「email」 「validation」 「phpmailer」 「Microservice」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 jturbide/form-to-email 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 jturbide/form-to-email 我们能提供哪些服务?
定制开发 / 二次开发

基于 jturbide/form-to-email 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 27
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 1
  • 点击次数: 20
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 1
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: BSD-3-Clause
  • 更新时间: 2025-11-03