Enable Discovery debug logging for production troubleshooting
- Add DISCOVERY_LOG_LEVEL=debug - Add DISCOVERY_SHOW_PROGRESS=true - Temporary changes for debugging InitializerProcessor fixes on production
This commit is contained in:
159
tests/debug/test-csrf-multipart.php
Normal file
159
tests/debug/test-csrf-multipart.php
Normal file
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Test script to verify CSRF token handling in multipart/form-data requests
|
||||
* This simulates what happens when a form is submitted via JavaScript with FormData
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/../../vendor/autoload.php';
|
||||
|
||||
use App\Framework\Cache\Driver\InMemoryCache;
|
||||
use App\Framework\Cache\SmartCache;
|
||||
use App\Framework\Http\Parser\HttpRequestParser;
|
||||
use App\Framework\Http\Parser\ParserCache;
|
||||
|
||||
// Create a mock multipart/form-data request similar to what JavaScript FormData sends
|
||||
function createMultipartRequest(): array
|
||||
{
|
||||
$boundary = '----WebKitFormBoundary7MA4YWxkTrZu0gW';
|
||||
$contentType = "multipart/form-data; boundary=$boundary";
|
||||
|
||||
// Simulate multipart body with CSRF tokens
|
||||
$body = "--$boundary\r\n";
|
||||
$body .= "Content-Disposition: form-data; name=\"_form_id\"\r\n\r\n";
|
||||
$body .= "contact_form\r\n";
|
||||
$body .= "--$boundary\r\n";
|
||||
$body .= "Content-Disposition: form-data; name=\"_token\"\r\n\r\n";
|
||||
$body .= "abc123token456\r\n";
|
||||
$body .= "--$boundary\r\n";
|
||||
$body .= "Content-Disposition: form-data; name=\"name\"\r\n\r\n";
|
||||
$body .= "John Doe\r\n";
|
||||
$body .= "--$boundary\r\n";
|
||||
$body .= "Content-Disposition: form-data; name=\"email\"\r\n\r\n";
|
||||
$body .= "john@example.com\r\n";
|
||||
$body .= "--$boundary--\r\n";
|
||||
|
||||
return [
|
||||
'server' => [
|
||||
'REQUEST_METHOD' => 'POST',
|
||||
'REQUEST_URI' => '/contact',
|
||||
'CONTENT_TYPE' => $contentType,
|
||||
'HTTP_HOST' => 'localhost',
|
||||
],
|
||||
'body' => $body,
|
||||
'expected_post' => [
|
||||
'_form_id' => 'contact_form',
|
||||
'_token' => 'abc123token456',
|
||||
'name' => 'John Doe',
|
||||
'email' => 'john@example.com',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
// Test 1: Normal multipart parsing (should work with custom parsers)
|
||||
function testMultipartParsing()
|
||||
{
|
||||
echo "=== Test 1: Normal Multipart Parsing ===\n";
|
||||
|
||||
$data = createMultipartRequest();
|
||||
$cache = new ParserCache(new SmartCache(new InMemoryCache()));
|
||||
$parser = new HttpRequestParser($cache);
|
||||
|
||||
try {
|
||||
$request = $parser->parseRequest(
|
||||
method: $data['server']['REQUEST_METHOD'],
|
||||
uri: $data['server']['REQUEST_URI'],
|
||||
server: $data['server'],
|
||||
rawBody: $data['body']
|
||||
);
|
||||
|
||||
echo "✓ Request parsed successfully\n";
|
||||
echo "Method: " . $request->method->value . "\n";
|
||||
echo "Parsed body data: " . json_encode($request->parsedBody->data) . "\n";
|
||||
|
||||
// Check if CSRF tokens are present
|
||||
$formId = $request->parsedBody->get('_form_id');
|
||||
$token = $request->parsedBody->get('_token');
|
||||
|
||||
if ($formId && $token) {
|
||||
echo "✓ CSRF tokens found: form_id='$formId', token='$token'\n";
|
||||
} else {
|
||||
echo "✗ CSRF tokens missing!\n";
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
echo "✗ Error: " . $e->getMessage() . "\n";
|
||||
}
|
||||
|
||||
echo "\n";
|
||||
}
|
||||
|
||||
// Test 2: Simulate empty php://input scenario (this tests our fallback)
|
||||
function testEmptyInputFallback()
|
||||
{
|
||||
echo "=== Test 2: Empty php://input Fallback ===\n";
|
||||
|
||||
// Simulate the scenario where php://input is empty but $_POST has data
|
||||
// This is what actually happens with multipart/form-data
|
||||
global $_POST;
|
||||
$originalPost = $_POST;
|
||||
|
||||
$_POST = [
|
||||
'_form_id' => 'contact_form',
|
||||
'_token' => 'fallback_token_123',
|
||||
'name' => 'Jane Doe',
|
||||
'email' => 'jane@example.com',
|
||||
];
|
||||
|
||||
$cache = new ParserCache(new SmartCache(new InMemoryCache()));
|
||||
$parser = new HttpRequestParser($cache);
|
||||
|
||||
try {
|
||||
$request = $parser->parseRequest(
|
||||
method: 'POST',
|
||||
uri: '/contact',
|
||||
server: [
|
||||
'REQUEST_METHOD' => 'POST',
|
||||
'REQUEST_URI' => '/contact',
|
||||
'CONTENT_TYPE' => 'multipart/form-data; boundary=test',
|
||||
'HTTP_HOST' => 'localhost',
|
||||
],
|
||||
rawBody: '' // Empty body simulates php://input being empty
|
||||
);
|
||||
|
||||
echo "✓ Request parsed with empty body\n";
|
||||
echo "Parsed body data: " . json_encode($request->parsedBody->data) . "\n";
|
||||
|
||||
// Check if fallback worked
|
||||
$formId = $request->parsedBody->get('_form_id');
|
||||
$token = $request->parsedBody->get('_token');
|
||||
|
||||
if ($formId === 'contact_form' && $token === 'fallback_token_123') {
|
||||
echo "✓ Fallback to \$_POST worked correctly!\n";
|
||||
} else {
|
||||
echo "✗ Fallback failed: form_id='$formId', token='$token'\n";
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
echo "✗ Error: " . $e->getMessage() . "\n";
|
||||
} finally {
|
||||
$_POST = $originalPost; // Restore original $_POST
|
||||
}
|
||||
|
||||
echo "\n";
|
||||
}
|
||||
|
||||
// Run tests
|
||||
echo "Testing CSRF Token Handling in Multipart Requests\n";
|
||||
echo "================================================\n\n";
|
||||
|
||||
testMultipartParsing();
|
||||
testEmptyInputFallback();
|
||||
|
||||
echo "Test completed!\n";
|
||||
echo "\n";
|
||||
echo "If both tests pass, the CSRF token issue should be resolved.\n";
|
||||
echo "The key improvement is that HttpRequestParser now uses \$_POST as fallback\n";
|
||||
echo "when php://input is empty for multipart/form-data requests.\n";
|
||||
Reference in New Issue
Block a user