简体   繁体   中英

PHP redirection with code 307 changes method from POST to GET

In my PHP software I have an self-update feature which sends a HTTP request with the POST method to a certain URL (to a PHP script). Now this URL has changed (I moved the script to another directory), but to stay backward compatible I want to use the script at the old URL to redirect the POST request to the new location. I tried to use the HTTP 307 status code but the second time PHP makes the request, it changes the method from POST to GET, although it must not do this (at least I though this is what the 307 code is for). I use PHP 5.4.29 on Windows 7 as Apache (2.2.27) module and I sniffed the traffic to make sure that HTTP 1.1 is used in the request and the response.

This is how I make a POST request:

<?php

$requestData = http_build_query(
    array(
        "param1" => "value1",
        // and so on...
    )
);

$requestOptions = array("http"=>
    array
    (
        "protocol_version"=>"1.1",
        "method"=>"POST",
        "header"=>array(
            "Content-type: application/x-www-form-urlencoded",
            "Connection: close",
        ),
        "content"=>$requestData,
    )
);

$requestContext = stream_context_create($requestOptions);

$serverResponse = @file_get_contents("http://localhost/old/long/path/update.php", false, $requestContext);

?>

I tried to redirect manually and automatically by PHP:

<?php

    // Redirect manually
    header("HTTP/1.1 307 Temporary Redirect");
    header("Location: http://localhost/update.php");

    // or redirect automatically
    header("Location: http://localhost/update.php", true, 307);

?>

According to the sniffed data, everything looks normal. HTTP 1.1 is used in request and response and code 307 is used. But the second time PHP sends the request (to the new location, still with HTTP 1.1, ..) it simply changes the method to GET and my POST payload is lost.

Again: This is not a user / browser redirection - I redirect PHP. I make my request myself and manually though my software and I want to redirect it to a new location. This has nothing to do with a security related topic.

It looks like file_get_contents does not repost the data, possibly for the reason highlighted by @daiscog.

Curl however will repost to the redirected url:

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, 'http://localhost/old/long/path/update.php');   
curl_setopt($ch, CURLOPT_POST, true);    
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);  
curl_setopt($ch, CURLOPT_FRESH_CONNECT, true);  
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);    
curl_setopt($ch, CURLOPT_POSTFIELDS, $requestData);

$serverResponse = curl_exec($ch);

However it would make more sense to either handle this at the server level (eg an Apache url rewrite) or to simply include the new file in the old one:

//old.php
include('path/to/new.php');

The W3C HTTP/1.1 specification for 307 states:

If the 307 status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued.

The point behind this is that it is unsafe for a server to tell a client to POST to a different URL as that may be a malicious attempt to get the client to send data somewhere the user did not intend, so POST redirections are not possible.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM