processwire-issues icon indicating copy to clipboard operation
processwire-issues copied to clipboard

Are URL hooks supposed to support access to php://input when the request is sent as application/x-www-form-urlencoded?

Open adrianbj opened this issue 2 months ago • 6 comments

Hi @ryancramerdesign - sorry, not sure if this is a bug, intentional, or unavoidable.

I send application/json and application/x-www-form-urlencoded payloads to an endpoint created with a URL hook and file_get_contents('php://input') works as expected with application/json, but not with application/x-www-form-urlencoded.

Is there a way that application/x-www-form-urlencoded data could be made available via $event? Or populated to $_POST?

adrianbj avatar Oct 23 '25 21:10 adrianbj

I don't think PW has anything to do with that, I'm guessing it's something else? Does it work without PW?

On Thu, Oct 23, 2025, 6:00 PM Adrian Jones @.***> wrote:

adrianbj created an issue (processwire/processwire-issues#2149) https://github.com/processwire/processwire-issues/issues/2149

Hi @ryancramerdesign https://github.com/ryancramerdesign - sorry, not sure if this is a bug, intentional, or unavoidable.

I send application/json and application/x-www-form-urlencoded payloads to an endpoint created with a URL hook and file_get_contents('php://input') works as expected with application/json, but not with application/x-www-form-urlencoded.

Is there a way that application/x-www-form-urlencoded data could be made available via $event?

— Reply to this email directly, view it on GitHub https://github.com/processwire/processwire-issues/issues/2149, or unsubscribe https://github.com/notifications/unsubscribe-auth/AACQEUHVZQ7AOYLQCKHMLYD3ZFFXDAVCNFSM6AAAAACKBWXZXWVHI2DSMVQWIX3LMV43ASLTON2WKOZTGU2DMNZVGU3DONY . You are receiving this because you were mentioned.Message ID: @.***>

ryancramerdesign avatar Oct 24 '25 15:10 ryancramerdesign

It even works in a .php file that bootstraps PW

adrianbj avatar Oct 24 '25 15:10 adrianbj

@adrianbj Can you confirm that the request method is POST? (I think that's required for php://input)

Also, I think that data sent with a content type of application/x-www-form-urlencoded or multipart/form-data means there won't be a php://input since PHP parses that content type internally? Though the php.ini setting enable_post_data_reading might be one way to change that.

ryancramerdesign avatar Oct 24 '25 18:10 ryancramerdesign

@ryancramerdesign - file_get_contents('php://input') works just fine with a POST request with application/x-www-form-urlencoded content type in my PW bootstrapped endpoint.php file, so it's not an issue with how it's coming in.

You can testing very easily will a url hook with this inside it:

bd(file_get_contents('php://input'));

vs putting that in a endpoint.php file in the root of the site that bootstraps PW.

It returns an empty string when called inside the URL hook.

PS - I've tried $input->post and $_POST and neither work.

As a reminder, everything works with application/json

adrianbj avatar Oct 24 '25 18:10 adrianbj

@adrianbj Do you want to post the code you are using? Here's what I used to test, but was not able to duplicate the issue:

/site/ready.php

$wire->addHook('/hello/world', function($event) { 
  $data = file_get_contents("php://input");
  return "php://input contains: " .  print_r($data, true);
}); 

/test.php

<?php namespace ProcessWire; 
include("./index.php"); 
$http = new WireHttp();
$http->setHeader('content-type', 'application/x-www-form-urlencoded');
$response = $http->post('http://localhost:8888/hello/world', '{ "hello": "world", "foo": "bar" }');
print_r($response); 

output:

php://input contains: { "hello": "world", "foo": "bar" }

I also tried giving post() an array of vars instead:

$response = $http->post('http://localhost:8888/hello/world', [ 'hello' => 'world', 'foo' => 'bar' ]);

and got this:

php://input contains: hello=world&foo=bar

These both seem like the correct responses?

ryancramerdesign avatar Oct 24 '25 20:10 ryancramerdesign

Hi @ryancramerdesign - I wonder if it's because even though you are setting the content type to application/x-www-form-urlencoded you are actually posting JSON.

In my case, the incoming headers are:

'Content-Type' => 'application/x-www-form-urlencoded'
'Content-Length' => '8001'
'X-Slack-Request-Timestamp' => '1761341771'
'X-Slack-Signature' => 'xxxxxxxxxxxxxxx'
'Accept' => 'application/json,*/*'
'Accept-Encoding' => 'gzip,deflate'
'User-Agent' => 'Slackbot 1.0 (+https://api.slack.com/robots)'
'Host' => 'mysite.com'
'Mod-Rewrite' => 'On'

and php://input is actually urlencoded - something like this:

'payload=%7B%22type%22%3A%22block_actions%22%2C%22user%22%3A%7B%22id%22%...............'

adrianbj avatar Oct 24 '25 21:10 adrianbj