Script 1 below is bash, and is at https://example.com/cgi-bin/test
. It produces the output 'Under construction' when fetched. It echos Status
and Content-type
headers, and some HTML. If I instead try to echo an entire HTML doc Apache just complains about an invalid header.
Script 2 below is php, and is at https://example.com/cgi-bin/test2.php
. Unlike the bash script, this one returns an HTML document.
How is it that script 2 can send an entire HTML doc, but script 1 can't?
Script 1
#!/bin/bash
cat <<'EOF'
Status: 200 OK
Content-type: text/html
<p>Under construction.</p>
EOF
Script 2
<?php
print <<<EOF
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
...etc
</head>
<body>
...etc
</body>
</html>
EOF;
?>
EDIT
php
comes in 2 flavours: the CLI and CGI versions. If you just run Script 2 from the command line as php test2.php
then the only output produced by php
is exactly what you see: the HTML doc. php-cgi
is the CGI version (install on Ubuntu/Deb as apt install php-cgi
). Apache (effectively) runs the CGI version (in real life, it does this slightly differently, but with the same results):
$ php-cgi test2.php
Content-type: text/html; charset=UTF-8
<!DOCTYPE html>
...rest of doc
CGI scripts have to return at least Content-type
to Apache (but can return more headers, including Status
). So the answer is that both scripts work because Script 1 explicitly returns Content-type
, while the under-the-hood CGI version of php
does the same.
The bash script can return the entire HTML document, as long as it also returns the Content-type
.
답변1
In CGI you need to send the Content-Type. PHP generate it for you. (check the output via a browser, you will see it even if you dont see it in your code.
I have a CGI that I did in C, and you realy need the content-type;
In my case for exemple;
printf("Content-Type: text/html;charset=us-ascii\n\n");
If you need to change the header in php you have to call header at the start of your script.
ie;
header('Content-Type: application/json');
답변2
PHP and CGI is two different things in this context.
CGI is a interface between a program - in this case a bash script - and the web server. This interface specifies communication between the web server and the program.
This standard requires that the program returns all headers, including status headers, before the actual content. In HTTP, headers and body is separated by a single line - thus the format where you have
Header
Header
Content
After the headers, you're free to include a full HTML document - or any other kind of data matching the headers you send.
PHP makes a few assumptions for you, and unless you override it, it sets content type, status code and so forth automatically.
답변3
You need to include a valid CGI header response, not an HTTP response, if calling a script via CGI through Apache. I think in essence (detail below) you need to remove "Status: 200 OK" from your file, and it might work.
There is a good article by Apache themselves (https://httpd.apache.org/docs/2.2/howto/cgi.html) which shows you the minimum to achive a valid response.
An example header received by the client might be as follows:
HTTP/1.x 200 OK
Transfer-Encoding: chunked
Date: Tue, 06 Dec 2021 19:58:00 GMT
Server: My_Bash_Script
Connection: close
X-Powered-By: My_Bash_Script
Pragma: public
Expires: Tue, 06 Dec 2021 20:58:00 GMT
Cache-Control: max-age=3600, public
Last-Modified: Tue, 06 Dec 2021 20:58:00 GMT
Content-Encoding: gzip
Vary: Accept-Encoding, Cookie, User-Agent
Content-Type: text/html; charset=UTF-8
<!DOCTYPE html>
<head><title>Under construction</title>
<body><p>Under construction.</p></body>
</html>
But your CGI, only needs to send from "Content-Type: text/html; charset=UTF-8" down.
A rather good article can be found here explaining the headers: https://code.tutsplus.com/tutorials/http-headers-for-dummies--net-8039
With regards to a served PHP file via Apache, there are several layers of communication:
- A request is made of Apache on a TCP port. This includes a request header if via HTTP.
- Apache runs any rules (e.g. mod_rewrite) and handles any SSL connections / handshakes required.
- Apache then detects the file extension as PHP and calls the PHP script through the PHP interpreter.
- The PHP code is interpreted, and turned into a static string (hopefully :-) which is returned to Apache and contains the HTML code.
- Apache then adds the header information to the HTML page, along with any other outbound processing.
- This is serialised and piped back over the TCP connection to the client.
Another good way to explore the headers is to use Firefox / Chrome Developer Tools (pressing F12 in Firefox opens them). Goto the Network Tab once Developer Tools are open and reload the page (Ctrl + R on Windows/Linux). There is a "Raw" option where you can see the exact data that was send and received.
Finally, if you find a website, or even that your CGI is being served over http rather than https, you can install Wireshark (https://www.wireshark.org) and easily monitor the traffic conversations to learn the differential between what you are sending that is being misunderstood and what a normal static html page conversatin looks like served by Apache.
P.S. (In 2022,) If you are indeed running Apache 2.2:
- You maybe missing out on other features in Apache2.4 which may help you get to where you want to be a bit quicker: https://httpd.apache.org/docs/2.4/new_features_2_4.html
- And please note that Apache 2.2 is EOL (since 2017), and contains a number of vulnerabilities: https://httpd.apache.org/security/vulnerabilities_22.html