CGI スクリプト: HTTP 応答ではなくドキュメントを返すことができるのはいつですか?

CGI スクリプト: HTTP 応答ではなくドキュメントを返すことができるのはいつですか?

以下のスクリプト 1 は bash で、 にありますhttps://example.com/cgi-bin/test。取得すると、「Under construction」という出力が生成されます。ヘッダーといくつかの HTML がエコーされますStatusContent-type代わりに HTML ドキュメント全体をエコーし​​ようとすると、Apache は無効なヘッダーについてエラーを出します。

以下のスクリプト 2 は php で、 にありますhttps://example.com/cgi-bin/test2.php。bash スクリプトとは異なり、これは HTML ドキュメントを返します。

スクリプト 2 は HTML ドキュメント全体を送信できるのに、スクリプト 1 はできないのはなぜでしょうか?

スクリプト 1

#!/bin/bash
cat <<'EOF'
Status: 200 OK
Content-type: text/html

<p>Under construction.</p>
EOF

スクリプト 2

<?php
print <<<EOF  
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    ...etc
  </head>

  <body>
  ...etc
  </body>
</html>
EOF;
?>

編集

php2つのバージョンがあります: CLIバージョンとCGIバージョンです。コマンドラインからスクリプト2を実行するとphp test2.phpのみによって生成される出力は、phpまさにあなたが見ているとおりです。HTML ドキュメントphp-cgiは CGI バージョンです (Ubuntu/Deb に としてインストールしますapt install php-cgi)。Apache は (事実上) CGI バージョンを実行します (実際には少し異なる方法で実行されますが、結果は同じです)。

 $ php-cgi test2.php
Content-type: text/html; charset=UTF-8

<!DOCTYPE html>
...rest of doc

CGIスクリプトは少なくともContent-typeApacheに返す必要があります(ただし、を含むより多くのヘッダーを返すことができますStatus)。したがって、答えは次のようになります。両方スクリプト 1 は を明示的に返すためContent-type、スクリプトは機能しますが、 の内部的な CGI バージョンはphp同じことを行います。

bash スクリプトは、 も返す限り、HTML ドキュメント全体を返すことができますContent-type

答え1

CGI では、Content-Type を送信する必要があります。PHP がそれを生成します。(ブラウザ経由で出力を確認すると、コード内に表示されていなくても表示されます。)

私は C で作成した CGI を持っていますが、コンテンツ タイプが本当に必要です。

たとえば私の場合、

printf("コンテンツタイプ: text/html;charset=us-ascii\n\n");

PHP でヘッダーを変更する必要がある場合は、スクリプトの先頭で header を呼び出す必要があります。

すなわち;

ヘッダー('Content-Type: application/json');

答え2

この文脈では、PHP と CGI は異なるものです。

CGI は、プログラム (この場合は bash スクリプト) と Web サーバー間のインターフェイスです。このインターフェイスは、Web サーバーとプログラム間の通信を指定します。

この標準では、プログラムが全て実際のコンテンツの前に、ステータスヘッダーを含むヘッダーが配置されます。HTTPでは、ヘッダーと本文は1行で区切られます。そのため、

Header
Header

Content

ヘッダーの後には、完全な HTML ドキュメント、または送信するヘッダーに一致するその他の種類のデータを自由に含めることができます。

PHP はいくつかの仮定を立て、それを上書きしない限り、コンテンツ タイプ、ステータス コードなどを自動的に設定します。

答え3

Apache を通じて CGI 経由でスクリプトを呼び出す場合は、HTTP 応答ではなく、有効な CGI ヘッダー応答を含める必要があります。基本的には (詳細は下記)、ファイルから「Status: 200 OK」を削除すれば、機能すると思います。

Apache自身による良い記事があります(参考:) は、有効な応答を達成するための最小限のものを示します。

クライアントが受信するヘッダーの例は次のようになります。

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>

ただし、CGI では、「Content-Type: text/html; charset=UTF-8」から下のみを送信する必要があります。

ヘッダーについて説明している非常に良い記事がここにあります: https://code.tutsplus.com/tutorials/http-headers-for-dummies--net-8039

Apache 経由で提供される PHP ファイルに関しては、通信にはいくつかの層があります。

  • リクエストは TCP ポートで Apache に対して行われます。HTTP 経由の場合は、リクエスト ヘッダーが含まれます。
  • Apache はあらゆるルール (例: mod_rewrite) を実行し、必要な SSL 接続/ハンドシェイクを処理します。
  • 次に、Apache はファイル拡張子を PHP として検出し、PHP インタープリターを介して PHP スクリプトを呼び出します。
  • PHP コードが解釈され、静的な文字列に変換され (うまくいけば :-)、Apache に返され、HTML コードが含まれます。
  • 次に、Apache は他の送信処理とともに、ヘッダー情報を HTML ページに追加します。
  • これはシリアル化され、TCP 接続を介してクライアントにパイプされます。

ヘッダーを調べるもう 1 つの良い方法は、Firefox / Chrome 開発者ツールを使用することです (Firefox で F12 キーを押すと開きます)。開発者ツールが開いたら、ネットワーク タブに移動してページを再読み込みします (Windows/Linux では Ctrl + R)。送受信された正確なデータを表示できる「Raw」オプションがあります。

最後に、ウェブサイトを見つけた場合、またはCGIがhttpsではなくhttpで提供されている場合、Wireshark(https://www.wireshark.org) を使用すると、トラフィック会話を簡単に監視して、誤解されている送信内容と、Apache によって提供される通常の静的 HTML ページ会話の違いを把握できます。

PS (2022 年) 実際に Apache 2.2 を実行している場合:

  • Apache2.4 の他の機能を見逃している可能性がありますが、この機能により、目的の場所に少し早く到達できる可能性があります。新機能
  • また、Apache 2.2 は EOL (2017 年以降) であり、いくつかの脆弱性が含まれていることに注意してください。脆弱性の修正

関連情報