# DWSK Website — PHP Form Backend

This package replaces the previous Formspree integration with a self-hosted
PHP backend for the **Order Now**, **Careers**, and **Contact / Get a Quote**
forms. It is built for **PHP 8.2+** and tested against a typical **Truehost
cPanel** shared-hosting environment (no database required).

## 1. What's included

```
index.html                 <- your website (already updated to call the PHP endpoints)
get_csrf_token.php         <- issues a CSRF token the frontend attaches to every submission
submit_order.php           <- handles the Order Now form
submit_application.php     <- handles the Careers form
submit_contact.php         <- handles the Contact Us / Get a Quote form
composer.json              <- optional PHPMailer dependency
includes/
  config.php                <- ALL settings you need to edit live here
  helpers.php                <- validation, security, file-handling functions
  mailer.php                 <- PHPMailer/SMTP + native mail() fallback + branded email template
  .htaccess                  <- blocks direct browser access to includes/
assets/
  dwsk-logo.png               <- logo used in outgoing emails (upload this to /assets/ on your server)
uploads/
  orders/.htaccess            <- blocks public access to uploaded order documents
  careers/.htaccess           <- blocks public access to uploaded CVs
logs/.htaccess               <- blocks public access to log files (created automatically on first submission)
```

## 2. Upload instructions (Truehost cPanel)

1. Log in to cPanel → **File Manager** → open `public_html` (or your domain's document root).
2. Upload every file/folder above, preserving the folder structure exactly.
3. Confirm PHP version: cPanel → **Select PHP Version** → choose **8.2** (or newer) for this domain.
4. Folder permissions:
   - `uploads/orders/` and `uploads/careers/` → **755** (writable by PHP, not publicly listable — the included `.htaccess` blocks browser access regardless).
   - `logs/` → **755** (created automatically the first time a form is submitted, but you can pre-create it and set 755 to be safe).
   - All `.php` files → **644**.
5. You do **not** need a database — submissions are emailed and also recorded as JSON lines in `logs/orders.log`, `logs/careers.log`, and `logs/contact.log` for your own backup/reference.

## 3. Required configuration (`includes/config.php`)

Open this file and update:

- `SITE_URL` — your live domain (used to build the logo URL for emails).
- `ADMIN_EMAIL_ORDERS`, `ADMIN_EMAIL_CAREERS`, `ADMIN_EMAIL_CONTACT` — already set to your real addresses (`orders@`, `careers@`, `info@dynamicwritingservices.com`). Change if needed.
- SMTP block (`SMTP_ENABLED`, `SMTP_HOST`, etc.) — see Section 4.
- `RECAPTCHA_ENABLED` / `RECAPTCHA_SECRET_KEY` — optional, see Section 6.

## 4. Email sending: SMTP (recommended) vs. fallback

By default (`SMTP_ENABLED = false`), the backend sends email using PHP's
built-in `mail()` function. This works out of the box on most cPanel hosts,
but deliverability (landing in inbox vs. spam) is often better with real
SMTP credentials — e.g., your existing `info@dynamicwritingservices.com`
mailbox, or a transactional service like SendGrid/Mailgun/Brevo.

To switch on SMTP via PHPMailer:

1. Install PHPMailer (choose ONE):
   - **Via Composer** (if your host gives you SSH/Terminal access in cPanel):
     ```
     cd public_html
     composer install
     ```
   - **Without Composer**: download PHPMailer manually from
     https://github.com/PHPMailer/PHPMailer/releases, and place its `src/`
     files so that `vendor/autoload.php` exists (or adapt `includes/mailer.php`
     to `require` the three PHPMailer class files directly — see comments in
     that file).
2. In `includes/config.php`, set:
   ```php
   define('SMTP_ENABLED', true);
   define('SMTP_HOST', 'mail.dynamicwritingservices.com'); // your real mail server
   define('SMTP_PORT', 587);
   define('SMTP_SECURE', 'tls');
   define('SMTP_USERNAME', 'no-reply@dynamicwritingservices.com');
   define('SMTP_PASSWORD', 'your-real-mailbox-password');
   ```
3. Test by submitting each of the three forms and checking both the admin
   inbox and the client confirmation email.

If you skip this step entirely, the site still works — it just uses the
native `mail()` fallback (which also supports attachments).

## 5. Security features already built in

- **CSRF protection** — `get_csrf_token.php` issues a session-bound token; each
  submit_*.php verifies it before processing anything.
- **Honeypot field** — a hidden `website_url` input on every form; real visitors
  never see or fill it, so any submission with it filled in is silently
  discarded (the bot is shown a fake "success" so it doesn't adapt).
- **Rate limiting** — max 3 submissions per IP per 60 seconds (flat-file based,
  no database needed); tune via `RATE_LIMIT_WINDOW_SECONDS` / `RATE_LIMIT_MAX_SUBMISSIONS`.
- **File upload security**:
  - Extension whitelist (`.pdf`, `.doc`, `.docx`) AND real MIME-type detection
    via `finfo` (a renamed `.exe` won't pass just because it's called `cv.pdf`).
  - 10 MB per-file limit, up to 6 files per submission.
  - Files are renamed to random hex strings on save — the original filename
    (and any path it might contain) is never trusted or used on disk.
  - `uploads/orders/` and `uploads/careers/` are blocked from direct browser
    access entirely (via `.htaccess`) — you retrieve files through cPanel
    **File Manager** or FTP/SFTP, not a public URL.
- **XSS prevention** — every piece of user input is HTML-escaped before being
  placed into the notification/confirmation emails.
- **No SQL used at all** — submissions are logged to flat JSON-line files, so
  there's no database and therefore no SQL-injection surface.
- **Directory traversal prevention** — `basename()` and random filenames
  ensure a malicious filename like `../../wp-config.php` can never escape the
  intended upload folder.

## 6. Optional: Google reCAPTCHA

Not enabled by default (rate limiting + honeypot already cover most spam).
To turn it on:

1. Get a reCAPTCHA v2/v3 site key + secret key from
   https://www.google.com/recaptcha/admin
2. Add the widget/script to the relevant form in `index.html` (not included by
   default to avoid pulling in a third-party script unless you want it).
3. In `includes/config.php`: set `RECAPTCHA_ENABLED = true` and paste your
   `RECAPTCHA_SECRET_KEY`. The verification call in `includes/helpers.php`
   (`recaptcha_passes()`) is already wired up and ready.

## 7. Submission references

Every submission gets a unique, human-readable reference:

- Orders: `DWSK-ORD-20260718-0001`
- Careers: `DWSK-APP-20260718-0001`
- Contact/Quote: `DWSK-QRY-20260718-0001`

The number resets daily and is shown to the client (in their confirmation
email and on-screen message) and included in the internal notification email,
so you can quickly cross-reference a client's message with your inbox.

## 8. What each form now does (no more email/WhatsApp hand-off)

- **Order Now**: client fills the form, optionally attaches multiple
  documents, and submits — everything happens on the page. They see an
  on-page confirmation + toast notification, and a confirmation email lands
  in their inbox automatically.
- **Careers**: same pattern; at least one document (CV) is required.
- **Contact / Get a Quote**: same pattern, with optional attachments.

## 9. Testing checklist before going live

- [ ] Submit each form with valid data + a valid PDF/DOC/DOCX attachment →
      confirm you receive the admin email at the right address, with the
      attachment, and the client address receives its confirmation.
- [ ] Submit with an invalid email → should show "Invalid email address."
- [ ] Submit a >10MB file → should show "File exceeds 10 MB."
- [ ] Submit an unsupported file type (e.g. `.zip`, `.exe` renamed to `.pdf`)
      → should show "Unsupported file type." (MIME check catches renamed files.)
- [ ] Submit the Careers form with no file → should show "Please upload your
      document."
- [ ] Confirm `uploads/orders/` and `uploads/careers/` are NOT browsable
      directly (e.g. visiting `https://yourdomain.com/uploads/orders/` in a
      browser should be blocked/forbidden).
- [ ] Check `logs/orders.log`, `logs/careers.log`, `logs/contact.log` are
      being written to after each test submission.
