Table of Contents

  1. Ext: sg_forms
  2. Upcoming: Default spam protection

Ext: sg_forms

License: GNU GPL, Version 2

Repository: https://gitlab.sgalinski.de/typo3/sg_forms

Please report bugs here: https://gitlab.sgalinski.de/typo3/sg_forms

About

This extension provides additional functionality for the forms extension

The backend Form Submissions module provides:

  • a form overview with submission counts
  • a root selection view listing pages that contain form submissions
  • an explicit empty state when no form submissions exist on any accessible page
  • grouped submission list view per form (paginated)
  • single submission detail view
  • in-context actions (back, export CSV, delete)
  • filter-aware empty states
  • CSV exports with contextual filenames (sgforms-*.csv)
  • per-form configurable visible columns in submission list
  • "new since last visit" indicators in form overview
  • language-aware frontend page links in submission detail views
  • translation-aware submission grouping by main form identifier
  • restoring a deleted main form definition also restores related deleted translation files

Legacy submissions without a stored language context continue to link to the default language version of the frontend page in the submission detail view.

Database Schema

The internal submission table is declared in TCA. ext_tables.sql remains the authoritative source for its existing primary key, parent index, and legacy signed integer columns until the project-wide schema migration is verified.

Setup

Setup custom forms storage

All you need to be able to store the form yaml files in our project theme is to create the following folder: * web/typo3conf/ext/project_theme/Resources/Private/Forms*

Don't forget to include the Typoscript in your template!

CAPTCHA protection

Enable CAPTCHA for an individual form with the Enable CAPTCHA checkbox in the form editor. The globally enabled provider, its credentials, rendering and server-side validation are configured exclusively by sg_captcha. Failed requests are redisplayed with the shared CAPTCHA validation message, including programmatic submissions without browser constraint validation.

Form upgrades

The sgforms_migrate_form_definitions wizard combines localized YAML imports and CAPTCHA option migration. It also updates legacy CAPTCHA options in forms already stored in the database. Imports and CAPTCHA updates must succeed before source YAML files are removed. File deletion requires explicit confirmation; declining it keeps the wizard pending. See UPGRADE.md for the migration steps.

Default spam protection

All frontend forms, including existing form definitions, receive the default spam check. A signed challenge is bound to the form and site. Final submissions made in less than five seconds, with a missing, expired or reused challenge, or beyond the submission rate limit are rejected before finishers run. The existing honeypot remains enabled unless Disable honeypot is selected; Check link spam and CAPTCHA remain opt-in.

The challenge endpoint is /sg-forms/spam-challenge/. JavaScript adds the token to the form and preserves it across multi-step forms in sessionStorage; a same-origin image sets an HttpOnly cookie as a fallback. No form definition or Fluid template changes are required.

The only spam-protection option in Extension Configuration is Enable automatic spam protection (enableDefaultSpamProtection, enabled by default). Temporarily disable it if the automatic check prevents legitimate submissions, for example while resolving a blocked challenge endpoint. Re-enable it after fixing the cause. This switch affects the signed challenge, timing check and rate limits; honeypot, link checks and CAPTCHA keep their own settings.

The protection uses fixed limits maintained in the services:

Check Fixed limit Scope and purpose
Minimum delay 5 seconds after challenge issuance Reject immediate automated submissions; elapsed time carries across form steps.
Challenge validity 2 hours Allow longer editing sessions while limiting token and replay-cache lifetime.
Challenge requests 60 per minute Per client IP and site across all forms; includes JavaScript and fallback image requests.
Accepted submissions 8 per minute Per client IP, form and site; prevent repeated submissions and finisher execution.

Rate limits use fixed one-minute buckets, not a rolling window. Visitors sharing a public IP also share the corresponding limits. Changing form identifiers cannot bypass the challenge-request limit. These implementation limits are not Extension Configuration options.

Double Opt-In finisher

TYPO3 14 forms can request a double opt-in through the Request double opt-in finisher. It sends the configured sg_mail template to the selected email form field. Leave the template key empty to create a generic, form-specific sg_mail template automatically on the first submission. The mail receives all form-value markers plus {doubleOptInUrl}. The public GET /double-opt-in/confirm/?token=... middleware hashes the token, confirms it once, sends the optional follow-up sg_mail template, and redirects to the configured confirmation page without the token.

Configure the email field, DOI template, confirmation page UID, validity in hours, status-field name, and optional follow-up recipients/CC/BCC/reply-to in the Form Editor. doubleOptInConfirmed is the default status field. The submission is always stored, whether or not SaveSubmissionFinisher is additionally configured. Its value is stored as 0 and becomes 1 atomically at confirmation. Enable Send follow-up mail to send a post-confirmation mail; leaving its template key empty creates a generic form-specific template automatically.

When both finishers are configured, they share one submission identifier regardless of their order and never create a duplicate submission. sg_mail must be installed and the selected templates must exist. The existing sgforms:deleteOldFormSubmissions retention task removes expired pending DOI records immediately. Confirmed DOI records, including confirmed_at as the confirmation evidence, remain until the configured submission retention ends. Expiry is enforced immediately even before cleanup runs.

PDF Finisher

The PdfFinisher can fill an existing PDF form with submitted form values and optionally attach it to admin/user mails. Filling PDF forms requires mikehaertl/php-pdftk and a working pdftk binary on the server.

For local DDEV environments, make sure pdftk is installed in the web container via .ddev/config.yaml:

webimage_extra_packages: [ build-essential, python3, pdftk]

In the form editor:

  1. Add the Fill PDF with form values finisher.
  2. Select a PDF template file (sys_file with AcroForm fields).
  3. Click Load PDF fields to import all PDF field names into the mapping table.
  4. Map each imported PDF field to a TYPO3 form field identifier (Text, Textarea, Email, Checkbox, LinkedCheckbox, RadioButton, SingleSelect, MultiSelect, CountrySelect) or to a virtual value (CURRENT_DATE, CURRENT_TIME, CURRENT_DATETIME, CURRENT_TIMESTAMP).
  5. Optionally enable Start generated PDF download on confirmation page (one-time, deletes file after first access) to automatically trigger the PDF download after submit.
  6. Flatten generated PDF (make it non-editable) is enabled by default. Disable it if you want to keep output fields editable/highlighted.

For checkbox/radio/select mappings, the PDF field name and PDF export value definitions must match the TYPO3 values you submit (for example the selected radio option value). The editor currently does not enforce type compatibility, so integrators/editors need to ensure the mapping is semantically correct.

Generated PDFs are stored in fileadmin/sg_forms/Temp/PdfAttachments. The frontend download link uses a temporary token (default TTL: 1 hour) and is consumed on first valid access. On this first access, the generated PDF is streamed and then deleted. Integrators should still schedule cleanup for this directory, because generated PDFs can remain there when no frontend download is rendered/clicked, for example when PDFs are only attached to emails. Schedule the dedicated form submission PDF cleanup command for this:

vendor/bin/typo3 sgforms:cleanup:form-submission-pdfs --retention-period=24

The retention period is specified in hours. Adjust it to the project's retention requirements. Form Framework upload folders in 1:/form_uploads/ are cleaned up by TYPO3 core's form:cleanup:uploads command.

The tx_sgforms_migrateformuploadcleanuptask upgrade wizard creates cleanup tasks through DataHandler with form-style argument values. TYPO3 validates these values and converts array arguments to their runtime representation before storing the scheduler task.

The one-time download URL is GET /api/public/v1/forms/pdf-download?token={token}. Invalid or expired tokens return a 404 RFC 7807 Problem JSON response; valid downloads are streamed with no-store cache headers.

Extension Configuration

Toggle Translation Grouping

By default, the backend module groups translated form definitions under their parent form. If you want to disable this behavior and see all form definitions as separate entries (e.g., in multi-site setups with separate language handling), you can toggle this behavior in the extension configuration of sg_forms in the TYPO3 Backend.

The setting groupTranslations can be found in the extension configuration under the "general" category.

Search in Form Manager

The overridden Form Manager view includes a search field above the form list. It filters forms by:

  • form name (label)
  • form persistenceIdentifier

Upcoming: Default spam protection

After updating, run the TYPO3 database schema update to create the cache_sg_forms_spam and cache_sg_forms_spam_tags tables, then flush caches. No form definition migration is needed. Existing frontend forms are protected by default, and submissions under five seconds are rejected before finishers. Integrations that submit forms programmatically must first request a signed challenge and include it in the final POST. The global emergency switch and fixed limits are documented in the README. The existing per-form checkLinkSpam, disableHoneypot, and enableCaptcha settings keep their previous behavior.

Version 8 Breaking Changes

  • TYPO3 14.3 or newer is required for this major version.

Upgrade to TYPO3 14

  • Apply TYPO3's database schema update after installing the Double Opt-In feature. It creates tx_sgforms_doubleoptin, which stores token hashes, expiry/status metadata and a configuration snapshot. Ensure sg_mail is installed before enabling the finisher, clear TYPO3 caches, and test the confirmation URL in each site language.

  • The backend warning for sgforms:deleteOldFormSubmissions now offers administrators a button to create the task. It creates an active daily task at 03:00 with a 30-day retention period. Review the retention period in the Scheduler module and adapt it to the project's data-retention policy if necessary.

  • sg_forms no longer registers sg_ajax endpoints. Add sgalinski/sg-apicore to the project dependencies; Composer installs it transitively with this version.

  • Replace custom calls to ?type=<pageType>&tx_sgajax[...] with GET /api/public/v1/forms/pdf?token=<download-token>. Send JSON requests with Accept: application/json and handle unsuccessful responses as RFC 7807 Problem JSON.

  • CAPTCHA widgets, public CAPTCHA routes and their configuration are now provided exclusively by sg_captcha.

  • Clear TYPO3 caches and check the enabled CAPTCHA provider and confirmation-PDF download in every configured site language.

  • Apart from the scheduler migration below, no extension-specific manual migration is required for this release.

  • The generic sgforms:deleteOldUploads command is superseded for Form Framework uploads by TYPO3 core's form:cleanup:uploads command. Run the Configure TYPO3 form upload cleanup scheduler task upgrade wizard once: it creates a scheduler task for form:cleanup:uploads 1:/form_uploads/ when none exists and migrates known scheduler tasks for /fileadmin/form_uploads and the generated form submission PDF directory. The default task runs daily and keeps uploads for 14 days. Existing legacy tasks retain their configured interval and retention period.

  • Use sgforms:cleanup:form-submission-pdfs --retention-period=<hours> for generated form submission PDFs. The old generic command remains available temporarily for project-specific directories that cannot be migrated automatically; move those cleanups to an appropriate project command before the next major version.

  • Submission storage is now declared in TCA for schema generation. Keep ext_tables.sql until the project-wide index replacement and database analyzer verification are complete.

  • Review any project-specific overrides or integrations that depend on internal templates, JavaScript modules, hooks, events, middlewares, or PHP APIs provided by this extension.

Form definitions in TYPO3 14

Run Migrate form definitions and CAPTCHA options (sgforms_migrate_form_definitions) after applying the database schema updates. It replaces the separate localized-import and CAPTCHA-option wizards. The new identifier also makes the combined migration available when the old wizards were already marked done.

For file-based forms, explicitly confirm the migration in the Install Tool or an interactive CLI run. The wizard imports default-language forms and translations, updates tt_content references, converts the legacy useAltcha, useFriendlyCaptcha and useInvisibleRecaptcha flags to enableCaptcha, and deletes source YAML files only after both migration steps succeed. Existing enableCaptcha values are preserved. Keep database and YAML backups until the forms have been checked in each site language.

Non-interactive runs cannot implicitly confirm source-file deletion and fail without marking the wizard done. Installations using only database forms can migrate their CAPTCHA options without the file-deletion confirmation. Do not run TYPO3 Form's formFileFormsToDatabaseMigration separately: sg_forms keeps it out of the wizard registry and marks it completed after the combined migration succeeds.

Version 7 Breaking Changes

  • Dropped TYPO3 12 support
  • Dropped PHP 8.0, 8.1 and 8.2 support

Submission storage update

The submission table now stores the frontend site language uid for new rows in language_uid.

  • Existing submissions keep working without a manual migration.
  • Legacy rows keep language_uid = 0, so the submission detail view links to the default language version of the page.

Version 6 Breaking Changes

  • Dropped TYPO3 10 and 11 support
  • Dropped PHP 7 support
  • Removed FormManagerController xClass in favor of a less invasive hook
  • Removed the V11 switch, falsely introduced in the previous version
  • Changed JavaScript files from requireJS to JavaScript modules

Version 4 Breaking Changes

IMPORTANT: If you migrate to TYPO3 11 ensure that you move all forms from "Resources/Private" to "Resources/Public". TYPO3 disallows the access to the private folder for forms. Also note that you might need to change the "allowedExtensionPaths" configuration option inside the project_theme.

All content elements must be manually changed to the new form path.


UPDATE tt_content SET pi_flexform = REPLACE(pi_flexform, "Resources\/Private", "Resources\/Public") WHERE CType = "form_formframework";

Also ensure that you check the editor permissions. All of them need to be adapted to the new structure. Keep the form access permissions empty if no forms should be disallowed!


UPDATE be_users SET tx_sgforms_permissions = REPLACE(tx_sgforms_permissions, "Resources\/Private", "Resources\/Public");

More Stuff:

  • Dropped TYPO3 9 support
  • Dropped PHP 7.3 support
  • new BE Templates for Bootstrap 5/ TYPO3 V11, check possbile overrides

Version 3 Breaking Changes

  • Dropped TYPO3 8 support