PHP $_POST Array Empty Bug: Troubleshooting Form Data Submission with Suhosin Patch


1 views

Here's the scenario we're investigating:

The form submits correctly according to HTTP headers:

Content-Type: application/x-www-form-urlencoded
Content-Length: 51
test%5B1%5D=a&test%5B2%5D=b&test%5B3%5D=c&action=Go

But PHP receives it as:

array(2) {
  ["test"]=>
  string(0) ""
  ["action"]=>
  string(2) "Go"
}
string(16) "test=&action=Go&"

After extensive testing, we identified the pattern:

  • Works on Windows servers
  • Fails on Ubuntu with PHP 5.2.4 + Suhosin
  • Works on some Ubuntu/Suhosin configurations

The working vs non-working php.ini comparison shows:

270c270
< memory_limit = 32M
---
> memory_limit = 16M
415c415
< variables_order = "EGCSP"
---
> variables_order = "EGPCS"
491d490
< include_path = ".:"
1253a1253,1254
> extension=mcrypt.so

Option 1: Manually parse the input

// Parse the raw input data
$input = file_get_contents("php://input");
parse_str($input, $_POST);

Option 2: Disable Suhosin's variable filtering

; In php.ini or .htaccess
suhosin.post.max_vars = 0
suhosin.request.max_vars = 0

Option 3: Change array naming convention

<!-- Instead of test[1], use: -->
<input type="text" name="test_1" />

The issue stems from Suhosin's aggressive input filtering combined with PHP's variable parsing. When receiving array-style form names (test[1]), Suhosin's security layer may incorrectly sanitize the input before PHP processes it, especially when:

  • variables_order doesn't include POST data (P)
  • Suhosin's max_vars limits are too restrictive
  • There are conflicts with multipart form handling

For mission-critical applications, implement this comprehensive solution:

function get_safe_post_data() {
    $input = file_get_contents("php://input");
    
    // Handle both application/x-www-form-urlencoded and multipart/form-data
    if (empty($_POST) && !empty($input)) {
        if (strpos($_SERVER['CONTENT_TYPE'], 'multipart/form-data') !== false) {
            // Handle file uploads specially
            return array_merge($_POST, $_FILES);
        } else {
            parse_str($input, $result);
            return $result;
        }
    }
    
    return $_POST;
}

// Usage:
$cleanPost = get_safe_post_data();

I recently encountered a puzzling scenario where form data submitted via POST wasn't properly populating the $_POST array. Here's the exact situation:

";
var_dump($_POST);
var_dump(file_get_contents("php://input"));
echo "

";
?>

The issue manifests differently across environments:

  • Windows servers: Works correctly
  • Ubuntu with PHP 5.2.4 + Suhosin: Fails
  • Another Ubuntu with same PHP/Suhosin: Works

Using Live HTTP Headers, we can see the data is actually being sent:

Content-Type: application/x-www-form-urlencoded
Content-Length: 51
test%5B1%5D=a&test%5B2%5D=b&test%5B3%5D=c&action=Go

The php.ini comparison revealed:

270c270
< memory_limit = 32M
---
> memory_limit = 16M
415c415
< variables_order = "EGCSP"
---
> variables_order = "EGPCS"
491d490
< include_path = ".:"

Here are some approaches that might help:

// Alternative parsing method
function parse_raw_http_request(array &$a_data)
{
    $input = file_get_contents('php://input');
    preg_match_all('/&([^=]+)=([^&]*)/', $input, $matches);
    foreach ($matches[1] as $i => $name) {
        $a_data[$name] = urldecode($matches[2][$i]);
    }
}

Or try modifying the form encoding:

The Suhosin patch might be interfering with array variable parsing. Try these:

  1. Disable Suhosin temporarily
  2. Check Suhosin's suhosin.post.max_array_depth setting
  3. Verify suhosin.post.max_vars isn't too low

For immediate results:

// Temporary solution
$post_data = parse_str(file_get_contents("php://input"), $_POST);

But the proper fix involves:

  1. Upgrading PHP to a newer version
  2. Reviewing Suhosin configuration
  3. Testing with different content types