A self-hosted, open-source form submission handler that works with any website. Accept form submissions from anywhere, store them in your own database, and get email notifications - all without limits.
The perfect alternative to Netlify Forms, Formspree, or other hosted form services.
| Feature | Netlify Forms | Formspree | PHP Any Form Handler |
|---|---|---|---|
| Monthly submissions | 100 (free) | 50 (free) | Unlimited |
| Self-hosted | No | No | Yes |
| Data ownership | No | No | 100% yours |
| Multi-tenant | No | No | Yes |
| Custom database | No | No | Yes |
| No vendor lock-in | No | No | Yes |
| Cost | $19+/mo | $10+/mo | Free |
- Universal Form Handler - Works with any HTML form from any website
- Multi-Tenant Support - Host multiple clients/projects with separate databases
- Email Notifications - Get notified via SMTP when forms are submitted
- JSON Storage - Flexible schema-less storage using MySQL JSON columns
- Simple Dashboard - View submissions with just a Tenant ID (no password needed)
- CORS Support - Accept submissions from any domain
- Bot Protection - Built-in honeypot field to catch spam bots
- Hidden Field Overrides - Override recipients dynamically per form
- Secure by Design - SQL injection protection, XSS prevention, input sanitization
git clone https://github.com/yourusername/php-any-form-handler.git
cd php-any-form-handler
composer installCopy the example config and customize it:
cp configs/example.json configs/mysite.jsonEdit configs/mysite.json:
{
"tenant_id": "my-company",
"database": {
"host": "localhost",
"port": 3306,
"name": "forms_mycompany",
"username": "db_user",
"password": "db_password"
},
"email": {
"enabled": true,
"to": ["admin@mycompany.com"],
"cc": [],
"bcc": ["archive@mycompany.com"],
"from_email": "forms@myserver.com",
"from_name": "Contact Form",
"subject_prefix": "[Website Contact]"
},
"smtp": {
"host": "smtp.gmail.com",
"port": 587,
"encryption": "tls",
"username": "your-email@gmail.com",
"password": "your-app-password"
},
"allowed_origins": ["https://mycompany.com", "https://www.mycompany.com"]
}Create a MySQL database and run the schema:
mysql -u root -p -e "CREATE DATABASE forms_mycompany"
mysql -u root -p forms_mycompany < schema.sqlPoint your web server's document root to the public/ folder.
Apache (.htaccess already included):
DocumentRoot /var/www/php-any-form-handler/publicNginx:
server{listen80;server_name forms.myserver.com;root /var/www/php-any-form-handler/public;indexindex.php;location / {try_files$uri$uri/ /index.php?$query_string;}location~\.php$ {fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;include fastcgi_params;}}<formaction="https://forms.myserver.com/index.php" method="POST"><!-- Required: Your config ID --><inputtype="hidden" name="configId" value="mysite"><!-- Optional: Form identifier --><inputtype="hidden" name="_formname" value="contact"><!-- Optional: Redirect after submission --><inputtype="hidden" name="_redirect" value="https://mycompany.com/thank-you"><!-- Honeypot: Hide this with CSS --><inputtype="text" name="_honeypot" style="display:none" tabindex="-1" autocomplete="off"><!-- Your form fields --><inputtype="text" name="name" placeholder="Your Name" required><inputtype="email" name="email" placeholder="Your Email" required><inputtype="tel" name="phone" placeholder="Phone Number"><textareaname="message" placeholder="Your Message" required></textarea><buttontype="submit">Send Message</button></form>Hidden Field Reference
Control form behavior with these hidden fields:
| Field | Required | Description |
|---|---|---|
configId | Yes | Which tenant config to load |
_formname | No | Identifier for this form (shown in dashboard) |
_redirect | No | URL to redirect after successful submission |
_honeypot | No | Bot trap - must be empty (hide with CSS) |
_subject | No | Override email subject line |
tomail | No | Override recipient email(s) |
cc | No | Override CC recipients |
bcc | No | Override BCC recipients |
View your submissions at /dashboard.php. Just enter your Tenant ID - no password required.
Dashboard URL:https://forms.myserver.com/dashboard.php
The dashboard provides:
- List of all form submissions
- Filter by form name
- Pagination for large datasets
- View full submission details including IP and referrer
Host multiple clients by creating separate config files:
configs/
├── client-a.json → Tenant ID: "client-a-company"
├── client-b.json → Tenant ID: "client-b-corp"
├── my-personal.json → Tenant ID: "personal-site"
└── example.json → Template (ignored by git)
Each tenant gets:
- Their own database (complete data isolation) or use a shared database
- Custom email settings
- Separate dashboard access
- Independent allowed origins
{
"success": true,
"message": "Form submitted successfully"
}{
"success": false,
"error": "Missing configId parameter"
}If _redirect is set, users are redirected instead of receiving JSON.
- SQL Injection: All queries use PDO prepared statements
- XSS Prevention: All output is escaped with
htmlspecialchars() - Bot Protection: Honeypot field catches automated submissions
- CORS Control: Per-tenant allowed origins configuration
- Directory Traversal: Config IDs are sanitized
- Config Protection:
.htaccessblocks direct access to config files
- PHP 8.1 or higher
- MySQL 5.7+ or MariaDB 10.2+ (with JSON support)
- Composer
- Web server (Apache/Nginx)
php-any-form-handler/
├── public/ # Web root
│ ├── index.php # Form submission endpoint
│ ├── dashboard.php # Tenant dashboard
│ └── assets/css/style.css # Dashboard styles
├── src/
│ ├── ConfigLoader.php # Loads tenant configurations
│ ├── Database.php # MySQL/JSON storage
│ ├── FormHandler.php # Core processing logic
│ ├── Mailer.php # Email notifications
│ └── Response.php # CORS & JSON responses
├── configs/
│ └── example.json # Config template
├── templates/
│ ├── dashboard-login.php # Login page
│ └── dashboard-list.php # Submissions list
├── composer.json
├── schema.sql
└── README.md
Contributions are welcome! Here's how you can help:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- File upload support
- Webhook notifications (Slack, Discord)
- Rate limiting
- reCAPTCHA integration
- Export submissions to CSV
- Email templates customization
- PostgreSQL support
- REST API for submissions
- Admin dashboard for managing tenants
If this project saves you money or time, consider buying me a coffee!
Your support helps keep this project maintained and free for everyone.
This project is open source and available under the MIT License.
- PHPMailer - Email sending library
- Built as a free alternative to paid form handling services
Made with determination to keep the web open and self-hosted.
Ping me on https://softlancersolutions.com in case you need installation help and support for your system.