How to make CGIHTTPRequestHandler execute my PHP scripts with POST data

257 views Asked by At

I am currently trying to do simple web stuff with the http.server module in Python. When I try to POST a form to my script, it does not receive the POST data, $_POST ist empty and file_get_contents('php://input') as well.

This is my post_test.html:

#!/usr/bin/php

<!DOCTYPE html>
<html>
<body>

<form method="post" action="post_test.html">
  Name: <input type="text" name="fname">
  <input type="submit">
</form>

<?php
if ($_SERVER["REQUEST_METHOD"] == "POST") {
    // collect value of input field
    echo "RAW POST: " . file_get_contents('php://input') . "<br>";
    $name = $_POST['fname'];
    if (empty($name)) {
        echo "Name is empty";
    } else {
        echo $name;
    }
}
?>

</body>
</html>

And this is my server script:

import urllib.parse
from http.server import CGIHTTPRequestHandler, HTTPServer

hostName = "localhost"
serverPort = 8080

handler = CGIHTTPRequestHandler
handler.cgi_directories.append('/php-cgi')


class MyServer(handler):

    def do_GET(self):
        # get path without first '/' and without anything besides path and filename
        file = self.path[1:].split("?")[0].split("#")[0]
        # if the file is in the script list, execute from php-cgi, else load from webapp
        php_handle = ["post_test.html"]
        if file in php_handle:
            self.path = "/php-cgi" + self.path
        else:
            self.path = "/webapp" + self.path
        CGIHTTPRequestHandler.do_GET(self)

    def do_POST(self):
        # get path without first '/' and without anything besides path and filename
        file = self.path[1:].split("?")[0].split("#")[0]
        # if the file is in the script list, execute from php-cgi
        php_handle = ["post_test.html"]
        if file in php_handle:
            length = int(self.headers['Content-Length'])
            post_data = urllib.parse.parse_qs(self.rfile.read(length).decode('utf-8'))
            for key, data in post_data.items():
                self.log_message(key + ": " + str.join(", ", data))

            self.path = "/php-cgi" + self.path
            CGIHTTPRequestHandler.do_POST(self)

    def do_HEAD(self):
        CGIHTTPRequestHandler.do_HEAD(self)


if __name__ == "__main__":
    webServer = HTTPServer((hostName, serverPort), MyServer)
    try:
        webServer.serve_forever()
    except KeyboardInterrupt:
        pass
    webServer.server_close()
    print("Server stopped.")

1

There are 1 answers

0
Aaron H On BEST ANSWER

Okay, I was finally able to solve the problem: #!/usr/bin/php is wrong, it should be #!/usr/bin/php-cgi.

Reason: php does NOT use the POST data, and there is no way giving it to php. php-cgi is made for the webserver purpose and can handle it.

Hwo to solve the next problem: To run php-cgi successfully you have to create a php.ini in the current directory tho, with two settings. First one to allow executing it directly, second one to set the directory where the scripts are. If you don't set it, you will be greeted with a 404 not found.

php.ini:

cgi.force_redirect = 0
doc_root = /home/username/server-directory

Where the server-directory folder is the folder containing the php.ini, and the php-cgi folder. Also the name of the folder is not related to the php-cgi binary, it's just bad naming that I did.

If you try to recreate this, it should work perfectly now.