# Event Form Production Fixes V2 - Header Placement Fix

**Last Updated:** 2026-01-28

## Critical Issue Fixed

### Headers Set Before Includes (CRITICAL FIX)

**Problem:**

- Headers were set at the very beginning of the file BEFORE includes
- If any included file (`hubspot-config.php`, `hubspot-api-helpers.php`, `logger.php`) output anything (whitespace, BOM, errors), headers would fail silently or cause CORB errors
- This worked locally but failed in production where error reporting may be different

**Root Cause:**

- Production PHP may have different error reporting settings
- Included files may output warnings/errors that aren't visible locally
- Headers must be sent before ANY output, including from included files

**Solution:**

- Moved headers to AFTER includes, matching working APIs (`collect-lead.php`, `submit-template.php`)
- Removed aggressive output buffering at file start
- Only use output buffering in `outputJsonResponse()` helper function

**Pattern (Now Matches Working APIs):**

```php
// ✅ CORRECT: Includes FIRST (like collect-lead.php, submit-template.php)
require_once __DIR__ . '/../config/hubspot-config.php';
require_once __DIR__ . '/../config/hubspot-api-helpers.php';
require_once __DIR__ . '/../helpers/logger.php';

// THEN set headers AFTER includes
header('Content-Type: application/json; charset=utf-8');
header('X-Content-Type-Options: nosniff');
header('Cache-Control: no-cache, must-revalidate');
```

## Additional Fixes

### 1. Removed Defensive Directory Creation

**Problem:** Attempted to create directories defensively, but can't change permissions in production.

**Solution:** Removed directory creation code. Logger already handles missing directories gracefully and falls back to `error_log()`.

### 2. Fixed Lock Directory Path

**Problem:** Lock directory path was `/../../writable/locks` but diagnostics expected `/../locks`.

**Solution:** Changed to `/../locks` to match diagnostics expectations.

### 3. Simplified Shutdown Handler

**Problem:** Shutdown handler didn't check `headers_sent()` before setting headers.

**Solution:** Added `headers_sent()` check to prevent errors in production.

### 4. Updated Output Helper

**Problem:** `outputJsonResponse()` didn't check if headers were already sent.

**Solution:** Added `headers_sent()` check and improved buffer cleanup.

## Files Modified

- `v2/api/event-lead-capture.php` - Restructured header placement, removed directory creation, fixed lock path
- `docs/systems/forms/EVENT_FORM_IMPLEMENTATION.md` - Updated troubleshooting with header placement pattern
- `docs/systems/forms/EVENT_FORM_PRODUCTION_FIXES.md` - Updated with header placement fix

## Key Differences from Working APIs

### Working APIs (`collect-lead.php`, `submit-template.php`):

1. ✅ Headers set AFTER includes
2. ✅ Simple header setup
3. ✅ No output buffering at start
4. ✅ No defensive directory creation
5. ✅ Simpler error handling

### Event API (Now Fixed):

1. ✅ Headers set AFTER includes (FIXED)
2. ✅ Enhanced headers with charset, X-Content-Type-Options
3. ✅ Output buffering only in helper function (FIXED)
4. ✅ No directory creation (FIXED)
5. ✅ Simplified shutdown handler (FIXED)

## Testing Checklist

- [x] Headers set AFTER includes
- [x] No output buffering at file start
- [x] Directory creation removed
- [x] Lock directory path fixed
- [x] Logger handles missing directories gracefully
- [x] All error paths return valid JSON
- [x] Shutdown handler checks headers_sent()
- [x] Output helper checks headers_sent()
- [ ] Test in production browser DevTools
- [ ] Verify no CORB errors
- [ ] Verify form submissions reach HubSpot

## Next Steps

1. Deploy to production
2. Test form submission in browser DevTools
3. Verify response headers are correct
4. Check for CORB errors in console
5. Verify data appears in HubSpot
