22

I'm sorry for confusing title of the question, I'll try to clarify what the issue is.

I'm doing some work with Mongrel2 server and I'm writing a PHP handler that has access to raw HTTP request data. Because I have PHP behind Mongrel2, there is no automatic creation of $_POST, $_GET, $_COOKIE and $_REQUEST variables.

The question is - is there a way that I can send the raw HTTP request to a PHP function (or anything) that will produce the superglobal variables that are usually available when using Apache + PHP?

Note: I could parse the HTTP request manually and create those variables myself, but I wasn't able to find any documentation on how exactly PHP does this HTTP parsing and importing into superglobals. If possible, I'd like to automate this process of superglobal creation without having to parse HTTP requests myself.

Thank you for any input.

Furicane
  • 1,167
  • 6
  • 18
  • 8
    +1, Finally some good question in PHP :) – Starx May 07 '13 at 15:20
  • 1
    Have you tried $postdata = file_get_contents("php://input"); ? Not sure if it will work for you, but worth a try. – vascowhite May 07 '13 at 15:20
  • @vascowhite - yes, I have, but the issue is that I'm receiving the headers via ZeroMQ sockets, therefore nothing's being written to the php://input. All I have is a message I got from Mongrel2 (in Netstring format) which I'm supposed to parse. What I'd like is to use existing PHP functionality because it somehow parses HTTP requests that Apache sends to it. Now, the communication between Apache <> PHP process and parsing the request is what's mistery to me :) – Furicane May 07 '13 at 15:24
  • PHP probably does this internally without exposing the methods it uses to do so. I understand why you would want to use existing functionality, but I'm not aware of any that will apply to your particular case. Looks like you'll have to roll your own. I'm sure somebody with more knowledge than me on PHP internals will be able to help, try posting a link to this question in the PHP chat room, there are some very knowledgable people in there. – vascowhite May 07 '13 at 15:29
  • @vascowhite - thanks, I'll try that! – Furicane May 07 '13 at 15:30

4 Answers4

7

Creating these variables is handled deep within the guts of PHP, in main/php_variables.c, in the php_auto_globals_create_get() and similar functions. From PHP 5.4.3:

static zend_bool php_auto_globals_create_get(const char *name, uint name_len TSRMLS_DC)
{
        zval *vars;

        if (PG(variables_order) && (strchr(PG(variables_order),'G') || strchr(PG(variables_order),'g'))) {
                sapi_module.treat_data(PARSE_GET, NULL, NULL TSRMLS_CC);
                vars = PG(http_globals)[TRACK_VARS_GET];
        } else {
                ALLOC_ZVAL(vars);
                array_init(vars);
                INIT_PZVAL(vars);
                if (PG(http_globals)[TRACK_VARS_GET]) {
                        zval_ptr_dtor(&PG(http_globals)[TRACK_VARS_GET]);
                }
                PG(http_globals)[TRACK_VARS_GET] = vars;
        }

        zend_hash_update(&EG(symbol_table), name, name_len + 1, &vars, sizeof(zval *), NULL);
        Z_ADDREF_P(vars);

        return 0; /* don't rearm */
}

This ends up calling directly into the SAPI (e.g, Apache module / CGI / FastCGI / whatever) to fetch variables. I don't think there's any way you can alter the way this works if you're in a weird environment where GET/POST/etc variables aren't where PHP expects them to be.

duskwuff -inactive-
  • 171,163
  • 27
  • 219
  • 269
  • 2
    You can always patch Mongrel2 to put them where PHP expects them though – Vinko Vrsalovic May 07 '13 at 15:38
  • Depends entirely on how PHP is being run. If the request data isn't all present when PHP is starting up, I don't think it's possible to get PHP to parse it later. – duskwuff -inactive- May 07 '13 at 15:40
  • @VinkoVrsalovic - I can't. The point of Mongrel2 (not Mongrel the Ruby server, Mongrel TWO the language agnostic server) is that it doesn't know what language it's working with, it's just sending messages to an endpoint and that's it. – Furicane May 07 '13 at 15:44
  • @duskwuff - so basically, I'd have to create an extension that'd wrap the C functionality and compile it with PHP so I can have it exposed from within PHP? There's really no other way? – Furicane May 07 '13 at 15:44
  • @Furicane: Your best bet would be to either write a new Mongrel2 SAPI for PHP, or an external adapter to another SAPI that PHP has (such as FastCGI). Trying to do this in PHP code is not going to work. – duskwuff -inactive- May 07 '13 at 16:52
  • @duskwuff - thanks for your reply, I'll accept your answer because it does point out *where* PHP does it. Sadly, I can't write a Mongrel2 SAPI or create the adapter for FastCGI within realistic time-frame for the project I'm working on, therefore I'll roll out my own solution written in PHP. – Furicane May 08 '13 at 10:35
0

I am trying to contribute to this question with the knowledge I know.

Sending a HTTP Request with such headers can duplicate POST variable

POST /somepage.php HTTP/1.1
Host: www.domain.com
User-Agent: Mozilla/12.0
Content-Length: 31
Content-Type: application/x-www-form-urlencoded

parameter=value&testcode=value1

Also you might want to check the HttpRequest libray of PHP. [Start here]. For POST data you can override the previous POST content using HttpRequest::setPostFields() and set your own data for it.

HttpRequest::setPostFields(array(
    "parameter" => "value"
));
Starx
  • 72,283
  • 42
  • 174
  • 253
0

Found on php.net maybe this will be useful:

$_POST = array();
$str = 'first=value&amp;arr[]=foo+bar&amp;arr[]=baz';
parse_str(html_entity_decode($str), $_POST);
print_r($_POST);

Array
(
    [first] => value
    [arr] => Array
        (
            [0] => foo bar
            [1] => baz
        )

)

Note:

The magic_quotes_gpc setting affects the output of this function, as parse_str() uses the same mechanism that PHP uses to populate the $_GET, $_POST, etc. variables.

http://php.net/manual/en/function.parse-str.php

beiller
  • 3,025
  • 1
  • 9
  • 17
  • It's easy to deal with $_POST, the problem lies when I use multipart forms which sends files etc., and PHP parses all requests accurately. Rolling my own solution would need testing, and I'm repeating - it's easy to do so for $_POST / $_GET, it's the $_FILES that's the issue. – Furicane May 07 '13 at 15:39
  • parse headers you can grab the file maybe. The header should contain a simple MD5 field that is the file contents. Its not that complicated. – beiller May 07 '13 at 15:45
  • 1
    Without trying to be rude, have you read my question and what http_parse_headers actually does? It's not what I'm after. – Furicane May 07 '13 at 15:47
  • Parse headers is admittedly not for incoming data, but if you looked at that page you will see many users' functions that can be used. Also it may be used probably as is. Also your question makes no mention of $_FILES so I'm not sure why you are now saying its the issue. You need to roll your own solution end of story. Read the links I sent and good luck. – beiller May 07 '13 at 15:52
-5

$_POST, $_GET, $_COOKIE and $_REQUEST are available in PHP every time, also if php was run in command-line. These arrays are writable, you can add values to $_POST array and get one in any other places.

This code fully correct and workable if run it from console:

<?php

$_POST['test'] = '1';
echo "\$_POST in global scope:\n";
var_dump($_POST);

function p() {
     echo "\$_POST in function scope:\n";

     var_dump($_POST);

     echo "Others super-global array in function scope:\n";
     var_dump($_REQUEST);
     var_dump($_COOKIE);

}

p();

Result:

$_POST in global scope:
array(1) {
  'test' =>
  string(1) "1"
}
$_POST in function scope:
array(1) {
  'test' =>
  string(1) "1"
}
Others super-global array in function scope:
array(0) {
}
array(0) {
}

Edit

Also, you can create class, and save data from HttpRequest in static field of it. In this case, you can use it from anywere.

Eugene
  • 1,651
  • 1
  • 12
  • 10