プログラミング

ブラウザがウェブサーバーに送っている情報を表示するウェブページを作ってみよう(HTML/CSS/JavaScript/PHP)

投稿日:2016年11月8日 更新日:

目次

1. はじめに

これは、Webアプリケーション開発のための入門記事です。

日頃 私たちが使っている Webブラウザ(以下「ブラウザ」と書きます)は、Webサーバーにアクセスして、目的の Webページ(以下「ページ」と書きます)を取得しているわけですが、この際にいろいろな情報を送っています。本記事ではこの情報を表示する Webページを作ることを題材にして、ブラウザとWebサーバーのやりとりを順番に説明していきます。この Webページは、1つのファイルでできており、HTML/CSS/JavaScript/PHP を使って書いています。

ブラウザが Webサーバーに送っている情報を表示するという内容ですので、「インターネットでウェブサイトを見るだけで個人が特定されるのだろうか?」といった疑問を持っている方へのヒントにもなると思います。

Web Programming

アクセス元のグローバルIPアドレスが表示されるだけのWebページを作る (Content-Type を変えた2種類)(PHP利用)

2019.01.10

2. この記事の対象とする人

  • HTML/CSS/JavaScript/PHPなどの基礎は分かるが、実際どう使ったら良いのか分からない人。
  • ブラウザがどうやってページを取得して表示しているのか知りたい人。

3. 今回の題材となるWebページとファイル

3-1. 作成するページ

完成したページはこちらになります。

2016-15_you-info-page

3-2. 今回の題材となるファイル

今回題材とするファイルは、以下のサイトに置いてあります。

ファイルのダウンロード

実際に使うのは index.php という1ファイルのみです。以下のリンクをクリックすると、ファイルをダウンロードすることができます。

index.php をダウンロードする

ファイルを閲覧する

完成したファイルは以下のリンクから見ることができます。

ファイルの中身を以下に表示します

ファイルの中身もここに載せておきます。

(注意: 上手く表示されない時があるようです。その場合は、上のリンクを開いて見て下さい。)

index.php

4. 利用する技術・登場する用語

それぞれの用語に対して「ここまで理解してれば大丈夫そうだ」という確信が持てる状態まで調査・学習することが大切です。とはいえ、たくさんありますので、一旦先に進んで必要に応じてここに戻ってくるとよいと思います。

TCP/IP

  • ネットワークでつながっているコンピュータ同士が相互に通信するためのプロトコルです。
  • 現在のインターネットでは、このプロトコルが使用されています。
  • インターネットに接続されたコンピュータに一意のIPアドレスが割り振られることで相互に通信することができます。
  • あくまでコンピュータ間での通信を成り立たせるための基盤となるプロトコルであり、ブラウザが WebサーバーにHTMLデータを要求するような部分は、この上の別レイヤで別プロトコルを使って行います。
  • 参考

IPアドレス

  • ネットワーク上の機器を識別するために、個々のコンピュータに割り当てられる番号
  • インターネットに接続しているコンピュータにも IPアドレスが割り当てられます。
  • 参考

DNS

  • Domain Name System
  • インターネットに接続されたコンピュータの名前を管理するデータベースシステムです。それぞれの名前に対応するIPアドレスも管理することができ、要求された名前に対応するIPアドレスを返すことができます。この名前は階層構造になっており、コンピュータに一意な名前を付けやすくなっています。
  • TCP/IPにおいてコンピュータ同士が通信するには、相手のIPアドレスが必要となります。しかし、どこかのサーバーにアクセスする度にIPアドレスを入力するのは非常に面倒です。IPアドレスはただの数字なので、人間はいくつも覚えていられません。ですので、例えば ブラウザでは、IPアドレスの代わりに www.example.com のような名前を指定すれば、内部で対応するIPアドレスを自動的に取得してそこにアクセスしてくれる仕組みになっています。
  • 参考

ドメイン名

  • インターネットに接続された膨大な数のコンピュータをIPアドレスではなく名前で識別したい場合、一意に識別できる名前をそれぞれのコンピュータに付ける必要があります。この名前の仕組みの1つが「ドメイン名」です。例えば、http://www.example.com というURLの場合、http:// を取り除いた www.example.com の部分を FQDN(Fully Qualified Domain Name) と呼び、この文字列が特定のコンピュータを指すことになります。この文字列はピリオドによって階層が分かれており、右端が一番上位で、左にいくほど階層が下がっていきます。この例の場合、一番右の com をトップレベルドメインといいます。次の example が第2レベルドメインで、最後の www がホスト名です。通常は、「example.com というドメインの中の www というホスト名を持ったコンピュータ」と表現することが多いです。
  • 参考

ホスト名

  • 通常、コンピュータに付ける名前をホスト名といいます(そのコンピュータをインターネット上に公開する/しないに関わらず)。
  • インターネットにおいては、本来のホスト名(www) とドメイン名(example.com)をピリオドでつなげた名前(FQDN)によって一意にコンピュータを特定することができますが、このFQDNのことをホスト名ということもあります。
  • 本やインターネット上の情報を読んでいると、時々ドメイン名とホスト名が紛らわしい記述があったりするのですが、「ドメイン名のうち、IPアドレスが割り当てられ通信可能なもの(ホストとして機能するもの)はホスト名である。」という考え方もあり、この考えで問題ないと思います。(引用元:下のウィキペディアのページ)
  • 参考

TLD

FQDN

  • Fully Qualified Domain Name
  • 完全修飾ドメイン名
  • 「TLD(Top Level Domain)まで含めたホスト名のことです。
  • 例えば、misc.laboradian.com は FQDNです。この名前により、インターネットに接続されたコンピュータを一意に特定することができます。
  • 参考

URL

  • Uniform Resource Locator
  • ウィキペディアの言葉を借りると、「インターネット上のリソース(資源)を特定するための形式的な記号の並び」ということになります。
  • ブラウザのアドレスバーに表示されている文字列です。Webの場合は通常、特定のページを表します。
  • 上位概念として URI (Uniform Resource Identifier) があります。Webを扱う範囲内では、URIとURLは同じものと考えて問題ありません。本記事では、「URL」を使います。
  • URLは、scheme://host:port/path?query#fragment といった形式になっています。
    • schemeには、リソースにどのようにアクセスするかを指定します。Webページにアクセスする場合は、http もしくは https を指定します。(暗号化された通信の場合は、https を指定します)
    • hostには、Webサーバのホスト名を指定します。IPアドレスでも指定することができます。
    • portには,Webサーバのポート番号を指定します。「:port」を省略した場合は 80番が指定されたことになります。(通常、Webサーバは 80番を使います)
    • pathには、パスを指定します。パスというのは、host で指定した Webサーバにおいて、目的のリソースが存在する位置を示す文字列で、スラッシュで区切られた階層構造となっています。
    • queryでは、パラメータを渡すことができます。「パラメータ名=値」という形式で指定し、「&」でつなげることによって、複数のパラメータを指定することができます。
    • fragmentには、目的のWebページ内の目的の部分を示す文字列を指定します。

    例えば、http://www.example.com/foo?param1=value1&param2=value2#bar というURLの場合、scheme が「http」、host が「www.example.com」、port が 「80」、path が「foo」、query が「param1=value1&param2=value2」、fragment が「bar」となります。

  • 参考

HTTP

World Wide Web (WWW, Web)

  • インターネット上で HTML文書をやりとりするためのシステムです。
  • URI, HTTP, HTML を土台に成り立っています。
  • Webはクライアントサーバモデルを採用しています。クライアントである「ブラウザ」が、サーバーである「Webサーバー」に、リソース(メインのリソースは HTMLデータです)を要求するというモデルです。そのリソースの場所を表すために、URLを使用します。
  • 参考

リソース

  • Webにおける「リソース」とは、URLを指定することによって取得することができるモノを指します。具体的には、HTMLファイル・CSSファイル・JavaScriptファイル・画像などです。
  • 参考

メディアタイプ

  • MIMEタイプ(Multipurpose Internet Mail Extensions)とも呼ばれます。
  • リソースの種類のことです。
  • タイプ/サブタイプ」という形式で表現されます。
  • HTML文書(text/html)、PDF(application/pdf)、PNG画像(image/png) などいろいろなメディアタイプが存在します。
  • 参考

Webサーバー

  • ブラウザなどのクライアントからHTTPリクエストメッセージを受け取り、そこで要求された内容に応じたHTTPレスポンスメッセージを返すプログラムです。または、そのようなプログラムが稼働しているサーバーコンピュータのことを指します。紛らわしい場合は、前者のことを Webサーバーソフトウェアと呼びます。
  • 有名は Webサーバーソフトウェアとしては、Apache HTTP Servernginx などがあります。
  • 参考

HTML

CSS

  • Cascading Style Sheets
  • HTMLの要素をどのように装飾(表示)するかを指示するための仕様
  • CSSの形式で記述したテキストファイルをHTMLに読み込ませることで、そのHTMLのデザインを変更することができます。
  • HTMLファイルの中に記述することもできます。
  • CSSのホームページ
  • 参考

JavaScript

  • HTMLの要素を操作することのできるプログラミング言語
  • JavaScriptを記述したテキストファイルをHTMLに読み込ませることで、そのHTMLファイルの内容を操作することができます。
  • HTMLファイルの中に記述することもできます。
  • ブラウザが WebサーバーからHTMLファイル/CSSファイル/JavaScriptファイルなどを取得した後、ブラウザ側でJavaScriptの処理が実行されます。
  • 参考

PHP

  • PHP: Hypertext Preprocessor
  • Webサーバー側で動作するプログラミング言語
  • PHPで記述された処理は、ブラウザが Webサーバーにアクセスした際に実行され、ブラウザに返すHTMLファイルの内容をその場で生成することができます。
  • ブラウザから送信された情報を元にユーザーを特定することによって、そのユーザ固有の情報をデータベースから取得して HTMLを生成することもできます。ブラウザはそのHTMLを受け取ってユーザーに表示することになります。
  • 参考

5. Webサーバーの準備

Webサーバーを持っていない・借りていない方は、無料のレンタルサーバーを利用するとよいでしょう。

以下のサービスをオススメします。

(1) スターサーバーフリー

  • PHPが利用可能
  • .htaccess利用可能(一部制限あり)
  • FTP接続(FTP over SSL対応)
    • サーバーにファイルをアップロードする際、データが暗号化されて送信されます。
  • MySQL (データベース)が利用可能
  • ディスク容量 2GB
  • 以前あった「ウェブクロウ」というレンタルサーバーサービスは、こちらに統合されました。

(2) XFREE(エックスフリー)

  • PHPが利用可能
  • .htaccess利用可能(一部制限あり)
  • FTP/FTP over SSL
    • サーバーにファイルをアップロードする際、データが暗号化されて送信されます。
  • ディスク容量 1GB
有料のレンタルサーバーを使う場合、より高機能になりますが、それなりの知識が必要となりますので、詳しくなってから利用すればよいと思います。

6. ファイルを Webサーバーにアップロードする

先程の index.php を自分の管理している Webサーバーにアップロードします。本記事を一通り読んだ後で、このコードを写経してみたり、一部を変えてみて再度アップロードし、どう変わるかを見てみると勉強になります。

作成したファイルを Webサーバーにアップロードする方法はいろいろありますが、「Webサーバーの準備」で紹介したレンタルサーバーを使っている場合は、FTPというプロトコルを使います。

FTPを使ってファイルをアップロードするには、専用のアプリケーションを使うのが一般的です。ここでは例として FileZilla というアプリケーションを使用する方法を簡単に説明します(無料で使用できます)。

  1. ブラウザで、FileZilla にアクセスします。
  2. [Download FileZilla Client] というボタンをクリックします。
    2016-15_23_32-filezilla-download-icon
  3. 次のページに遷移しますので、Windows 64bit版 を使っている場合は、[Windows (64bit)] にある [Download FileZilla Client] ボタンのをクリックします。
    2016-15_23_32-filezilla-download-icon-win64
  4. 64bit の Windows 以外の方は、その下にあるアイコンからご自分のプラットフォーム(OS)を選んでクリックします。次のページで表示されるダウンロードボタンをクリックするとダウンロードが開始されます。
  5. ダウンロードが終わりましたら、ご使用のプラットフォーム(OS)のやり方でインストールします。Windows 64bit版の場合は exeファイルがダウンロードされますので、ダブルクリックすればインストールが始まります。
  6. FileZilla を起動し、[ファイル] – [サイトマネージャー]を選択します。
    2016-15_41_19-filezilla
  7. サイトマネージャーに、FTP接続情報を設定します。今回は XFREEを利用している場合の設定を説明します。
    • 以下は、XFREEのサーバー管理画面です。
    • 以下は、サイトマネージャーの画面です。
    • number_01 [新しいサイト]ボタンをクリックします。
    • number_02 画面左に新しいエントリが表示されますので、適当な名前を付けてEnterを押します。
    • number_03 [一般]タブをクリックします。ここからは、XFREEの管理サイトにある「FTPアカウント設定」に表示されている情報を入力していきます。
    • number_04 [プロトコル] には、[FTP – ファイル転送プロトコル] を選択します。
    • number_05 [ホスト] には、[FTPホスト]に記載されたホスト名を入力します。
    • number_06 [暗号化] には、[使用可能なら明示的な FTP over TLS を使用] を選択します。
    • number_07 [ログオンの種類] には [アカウント] を選択します。
    • number_08 [ユーザ] には [FTPユーザー]に指定されたユーザー名を入力します。
    • number_09 [パスワード] には [FTPパスワード]に指定されたパスワードを入力します。
    • number_10 [アカウント] には [FTPユーザー]に指定されたユーザー名を入力します。
    • number_11 [接続]ボタンを押して、FTPサーバーに接続します。
  8. 以下は、FTPサーバーに接続した状態の画像です。number_01 がローカルのファイルを表示するエリアで、number_02 がFTPサーバー上のファイルを表示するエリアです。この手のレンタルサーバーのFTPサーバーというのは、Webサーバーも兼ねており、FTPで接続すると Webに公開されるディレクトリにつながります。なので、number_01 の中に表示されたファイルを number_02 のエリアにドラッグ・アンド・ドロップすれば、そのファイルは Webブラウザからアクセスできるようになります。ここではまず、number_02 のエリア内で右クリックして number_03 のように [ディレクトリを作成]を選択します(サーバーにアクセスした階層は一番上の階層になっているはずなので、そこに新たにディレクトリを作成します。)。
  9. すると、作成するディレクトリの名前を聞かれますので、適当な名前を入力します。今回は「your-info-page」と入力します。
    2016-16_25_03-filezilla-webcrow-make-dir
  10. すると サーバー側のエリアにディレクトリが生成されますので、ダブルクリックしてその中に移動します。
  11. ローカル側のエリアに、作成したファイルを表示しておき、それをサーバー側のエリアにドラッグ・アンド・ドロップします。これで、ローカル側のファイルがサーバー側にアップロードされます。今回は index.php というファイルをアップロードします。
  12. Webブラウザで、レンタルサーバーのホスト名 + “/作成したディレクトリ名” にアクセスすれば、アップロードしたファイルにアクセスできます。(ディレクトリ名までを指定すれば、index.php ファイルにアクセスしてくれるように、Webサーバー側で設定されています。PHPが使えるようになっているWebサーバーでは、これは一般的な設定です)
    2016-17_09_03-browser-url-input
  13. ページが表示されたでしょうか?

7. ブラウザと Webサーバーのやり取りの概略

PHPを使用した場合の、ブラウザと Webサーバーとの一般的なやり取りについて簡単に説明します。詳細は次の章で説明します。

7-1. ブラウザがWebサーバーへにアクセスする

web001b

number_01 ユーザーがブラウザのアドレスバーにURLを入力して Enterキーを押します。

number_02 ブラウザが HTTPリクエストメッセージを、Webサーバーの80番ポートに送信します。この図では foo.php というファイルを要求しています。

7-2. Webサーバーがブラウザに HTTPレスポンスメッセージを返す

web002b

number_03 foo.php はPHPのファイルですので、ファイルに記述されたPHPコードが実行されます。最終的には、HTTPレスポンスメッセージが生成されます。この中には HTMLのデータも入っています。

number_04 HTTPレスポンスメッセージがブラウザに送信されます。

number_05 HTTPレスポンスメッセージを受け取ったブラウザは、そこに含まれているHTMLを画面に描画しようとします。

7-3. ブラウザが HTMLを画面に描画する

web003b

number_06 CSSファイルを読み込むタグが記述されている場合は、そのファイルを Webサーバーにアクセスして取得し、その内容に沿って画面を装飾します。

number_07 画像を読み込むタグが記述されている場合は、そのファイルを Webサーバーにアクセスして取得し、画面に表示します。

number_08 JavaScriptファイルを読み込むタグが記述されている場合は、そのファイルを Webサーバーにアクセスして取得し、記述されているコードを実行します。

おおよそ、以上の動作になります。

8. ブラウザが Webページを表示するまで

ブラウザで Webページを見る際に起きている処理を順番に解説していきます。ソースコードも合わせて解説します。

8-1. ブラウザの起動

まずはブラウザを起動します。今回は Chrome を使います。

ブラウザと Webサーバーとのやりとりを見るため、Chromeを起動したら「デベロッパーツール」を表示しておきます。

手順

  1. Chromeの右上にあるアイコンを押し、[その他のツール] – [デベロッパーツール] を選択します。
    2016-09_58_47-chrome-open-dev-tool
  2. これで Chromeのウィンドウ内に、デベロッパーツールが表示がされるのですが、右側に表示されて見辛い場合は、デベロッパーツールの右上にあるアイコンをクリックし、[Dock side] にある真ん中のアイコンをクリックすると、ウィンドウの下側に表示されるようになります。
    2016-09_58_47-chrome-dev-tool-dock-to-bottom
  3. デベロッパーツールはいろいろな機能があるのですが、ここでは通信の内容が見たいので、以下のように [Network] – [All] をクリックしておきます。
    2016-09_58_47-chrome-dev-tool

8-2. URLを指定してアクセスする

ブラウザのアドレスバーに、閲覧したい Webページの URLを入力して Enterキーを押します。

以下のURLにアクセスします。

https://misc.laboradian.com/your-info-page/

2016-chrome-address-bar

これで、ブラウザにページが表示されるはずですが、この時何が起きているのでしょうか?

1. DNS によりホスト名からIPアドレスが取得される

まず ブラウザは、指定された URLの中の misc.laboradian.com を Webサーバーの名前(ホスト名)とみなし、この Webサーバーにアクセスしようとします。インターネットでは、TCP/IP というプロトコルを使って通信するのですが、この TCP/IP はホスト名ではなく IPアドレス を使って目的のサーバーに接続する仕組みであるため、目的のホスト名に対応する Webサーバーの IPアドレスを取得する必要があります(ブラウザのアドレスバーに、ホスト名の代わりにIPアドレスを指定してもアクセスできます)。IPアドレスとは 203.0.113.1 のような数字の並びで、インターネットに接続されているコンピュータに割り振られる番号です(人間が分かりやすいように4つのかたまりがピリオドで区切られていますが、実際は1つの数値です)。このように、ホスト名に対応する IPアドレスを取得することを 名前を解決する といい、この仕組を DNS といいます。この辺りのやりとりは低階層で行われるため、Webサイトの制作者であっても通常意識する必要はありません。ブラウザで URLを指定すれば、その中のホスト名を元に、内部で自動的に IPアドレスを取得して、そのIPアドレスに接続してくれると考えておけばよいでしょう。

DNSについてもう少し補足すると、例えば misc.laboradian.com というホスト名(FQDN)の場合は、laboradian.com というドメインが管理する misc というコンピュータのIPアドレスを探すことになります。 laboradian.com は、comの部分がトップレベルドメインで、laboradian が第二レベルドメインになりますが、実際はその上にルートドメインというのがあります。上位のドメインが下位のドメインを管理しているため、最上位のドメインのDNSサーバーから順番に、下位のドメインのDNSサーバーの所在を尋ねていきます。

  1. ルートドメインDNSサーバーに、comドメインを管理しているDNSサーバー(IPアドレス)を教えてもらう。
  2. comドメインを管理するDNSサーバーにアクセスし、laboradianドメインを管理するDNSサーバー(IPアドレス)を教えてもらう。
  3. laboradianドメインを管理するDNSサーバーにアクセスし、ホスト misc のIPアドレスを教えてもらう。

2. Webサーバーの 80番ポートに対してHTTPリクエストメッセージを送信する

DNSを使うことで目的の WebサーバーのIPアドレスは分かりましたが、「特定の Webページを取得したい」ことをブラウザはWebサーバーに対してどのように伝えるのでしょうか? この時、TCP/IP というプロトコルで通信自体は行われるのですが、ブラウザとWebサーバーのやりとりにはHTTPというプロトコルが利用され、TCP/IPの上のレイヤで行われます。「上のレイヤ」といっても、実際には TCP/IPのデータの中に、HTTPのデータが包み込まれた形で通信が行われます。 ここで、コンピュータの通信の機構について少し説明すると、コンピュータには他のコンピュータとやりとりするための「ポート」という窓口がいくつも用意されており、それぞれ番号がついています。HTTPプロトコルは通常 80番を使用します。ですので、「ブラウザは DNSで得たIPアドレスの80番ポートに対して HTTPプロトコルに従った形式のリクエストメッセージ(HTTPリクエストメッセージといいます)を送る」ということになります。

ブラウザが、HTTPプロトコルで送ったリクエストメッセージの内容を確認してみよう

HTTPプロトコルでやりとりされるデータを、Chromeのデベロッパーツールで見てみましょう。デベロッパーツールを開いた状態で URLにアクセスすれば、ここにいろいろな情報が表示されているはずです。何も表示されない場合は、F5キーを押して再読込みして下さい。

以下の順に操作して下さい。

2016-12-chrome-dev-tool

number_01 [Network] タブをクリックします。

number_02 [All] タブをクリックします。

number_03 一番上にある your-info-page/ をクリックします。これは、Webサーバー側で your-info-page/index.php と解釈されています。

number_04 [Headers]タブをクリックします。

number_05 順番が前後しますが、ここに Webサーバーからブラウザに返された HTTPレスポンスメッセージのヘッダ部が表示されています。見やすいように元の内容に対して多少加工されています。[Response]タブで、HTTPレスポンスメッセージのボディ部を見ることができますが、このボディ部が HTML文書の内容になっています。

number_06 ここにブラウザが Webサーバーに送った HTTPリクエストメッセージのヘッダ内容が表示されます。見やすいように元の内容に対して多少加工されています。の場合、HTTPリクエストメッセージのボディ部はありません。

number_07 ここをクリックすると、表示用に整形していない元のHTTPレスポンスヘッダ部の表示に切り替わります。

number_08 ここをクリックすると、表示用に整形していない元のHTTPリクエストヘッダ部の表示に切り替わります。

number_07number_08view source をクリックして、HTTPリクエストメッセージとHTTPレスポンスメッセージの元の内容に切り替えた画面は以下です。

2016-12-chrome-dev-tool2

HTTPリクエストメッセージ

ブラウザが Webサーバーに送ったリクエストメッセージを抜き出したものが以下です。

GET /your-info-page/ HTTP/1.1
Host: misc.laboradian.com
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2929.3 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate, sdch
Accept-Language: ja,en-US;q=0.8,en;q=0.6
Cookie: _ga=GA1.2.3203882.1479780093

HTTPレスポンスメッセージもそうなのですが、HTTP/1.1では人間が読めるテキスト形式でやりとりが行われますので、各項目の意味さえ分かれば、比較的簡単に何が行われているのかを知ることができます。

HTTPのリクエストメッセージは、以下の形式になっています。

http_request_message

1行目は リクエストラインといって、

メソッド URI HTTPのバージョン

という形式になっており、今回の場合、メソッドは「GET」、URIは「/your-info-page/」、HTTPのバージョンは「1.1」となります。HTTPリクエストメッセージでは、その内容の意味合いを「メソッド」として表すのですが、Webページを閲覧するという場合は「GET」を指定します。ECサイトで注文を行うような、Webサーバー側にあるデータを更新する必要があるリクエストの場合だと「POST」を指定します(参照: HTTPメソッド)。

2行目から空行までは メッセージヘッダといい、1行ごとに、

フィールド名: 内容

という形式になっています。詳細は省きますが、ここで、「使用しているブラウザの情報」、「受け付けられるドキュメントの形式」、「使用できる言語」などを指定しています。Webサーバーはこの情報を受け取ることで、ブラウザにより適切なレスポンスを返すことができます。

GETメソッドで送るメッセージの場合、「ボディ」はありません。

メッセージボディの部分は、また後で確認します。

参考

8-3. Webサーバーが HTTPリクエストメッセージを受け取る

Webサーバーは、ブラウザからの HTTPリクエストメッセージを受け取り、それに対して、HTTPレスポンスメッセージを返します。HTTPレスポンスメッセージには、いろいろな情報が含まれており、その中には HTMLデータも含まれています。ブラウザではそのHTMLデータを表示しているわけです。

URLで指定されたファイルの特定

Webサーバーには、ドキュメントルート という設定値があります。これは、Webサーバーが稼働しているコンピュータ上のあるディレクトリパスがセットされており、このディレクトリを基点にして、ブラウザから要求されたファイルを探すことになります。

少し上でリクエストメッセージの内容を見た通り、要求されていた URLは /your-info-page/ でした。これではファイルが指定されていないじゃないかと思われるかもしれませんが、末尾がスラッシュになっている場合は、index.htmlindex.php が要求されていると解釈されます(このあたりは Webサーバーの設定次第ですが、PHPを使う場合このような設定になっています)。

例えば、ドキュメントルートが以下のように設定されているとします(OSはLinuxを想定しています)。

/var/www

するとWebサーバーは、/var/www/your-info-page/index.html もしくは /var/www/your-info-page/index.php を探すことになるわけです。今回は index.php ファイルを設置しているのでこちらが要求されたファイルであると解釈されます。

もちろん Webサーバーが PHPと連携するためには、あらかじめ そのように設定しておく必要があります。
例えば、Apache と PHPを連携させるための設定方法は以下のページで説明されています。

PHP: Apache 2.x (Unixシステム用) – Manual

コンテントネゴシエーション

今回はブラウザから要求されたのがPHPのファイルでしたが、もし、これがHTMLファイルであったり PDFファイルであったりした場合は、コンテントネゴシエーションという処理がなされます。これは、ブラウザから送られてきたリクエストのメッセージヘッダで指定されたメディアタイプ、 言語、エンコーディングなどに基づいて、 最適な形でレスポンスを返そうとする Webサーバー側の処理です。例えば、「ブラウザが日本語を望んでいるから、できるだけ日本語の情報を返そう」ということを Webサーバーがやってくれるのです。優先順位も伝えることができます。

主に以下のメッセージヘッダが利用されます。

Acceptヘッダ (RFC7231の該当箇所 )

  • 希望するメディアタイプを指定します。
  • 主要なメディアタイプには、text/html(HTML文書)、application/xhtml+xml(XHTML文書)、application/xml(XML文書) などがあります。

Accept-Languageヘッダ (RFC7231の該当箇所 )

  • 希望する言語を指定します。

Accept-Encoding (RFC7231の該当箇所 )

  • gzip (GNU zipという圧縮された形式), deflate (こちらも圧縮の形式です) などが指定できます。

参考

8-4. PHPの処理が実行される

ということで、Webサーバーは index.php を読み込もうとするのですが、ファイルの拡張子が php ですので、これは PHPの実行エンジンが処理すべきファイルであると判断して、PHP実行エンジンに処理を任せます。PHP実行エンジンは、index.php を受け取って中身を解釈し、その結果を Webサーバーに返して、Webサーバーはそれをブラウザに返すのです。

ブラウザから要求されたファイルにPHPコードが含まれている場合(厳密にはHTTPサーバーの設定によりますが)は、サーバー側でそのコードが実行され、それによってレスポンスメッセージの一部分を生成したり・変更したりします(レスポンスに対しては何もしないPHPコードというのもありますが)。

では、PHP実行エンジンが index.php を受け取って処理する内容を見ていきます。

PHPコードの開始

ファイルの先頭に、PHPのコードが記述されています。

<?php

PHPというプログラミング言語は、HTMLファイルの中に手軽に埋め込むことができます。 PHPのコードを <?php?> で囲むだけです。よって、ここから PHPのコードが始まることがわかります。

タイムゾーンの設定

// set time zone
date_default_timezone_set("Asia/Tokyo");

PHPで使用されるタイムゾーンを「東京」に設定しています。 PHPの設定ファイルである php.ini の中でも指定できますが、今回は念のため関数を使って設定しておきます。タイムゾーンを設定する関数は、date_default_timezone_set() です。

エンコーディングの設定

// set default encoding
if (extension_loaded('mbstring')) {
  mb_internal_encoding('UTF-8');
}

mb_internal_encoding()関数を使って、PHPが使用する文字エンコーディングを設定しています。文字エンコーディングというのは、コンピュータにおける文字の表現方法です。いろいろな種類があるのですが、現在では UTF-8 を指定するのが一般的です。UTF-8 では、日本語のような英語以外の文字をまとめて使用することができます。一昔前まで日本語を表現する場合は、SHIFT_JISEUC-JP が使われていました。mb_internal_encoding()関数というのは、PHPでマルチバイトを扱う mbstringという拡張モジュールが持っている関数ですので、ここでは念のため extension_loaded()関数を使って、この拡張モジュールがインストールされているかチェックしてから実行しています。日本語の文字は、1文字を表すのに2バイト以上使用しますので、マルチバイトです。

関数の定義

//----------
// 関数定義
//----------

ここから、この後で使用する関数を定義していきます。同じ処理を何回も記述するような場合は、その処理を関数として一度だけ定義しておき、いろいろなところからこの関数を呼び出すことで、コードが重複しないようにします(処理を変更する場合も一箇所で済みます)。

PHPで関数を定義するには、以下のように記述します。

<?php
// 2つの引数をとる関数の例です。
function 関数名($引数1, $引数2)
{
    // ここに処理を書きます。
    return $引数1 + $引数2;  // 呼び出し元に値を返します。
}
?>

参考

では、順番に見ていきます。

HTMLエスケープを行う関数
// HTMLエスケープ
function e($html) {
  return htmlspecialchars($html, ENT_QUOTES);
}

Webサイトの画面は HTMLフォーマットで記述されたテキストが表示されるわけですが、記述の仕方によって JavaScriptコードを実行させることができます。万が一、開発者が意図しないJavaScriptコードが PHPによって生成されてしまった場合、それを画面にそのまま表示すると実行されてしまい危険です。ですので、通常 PHPによって生成した文字列を Webサイトに表示する場合は、危険な文字列を無害化するエスケープ処理というのを行ってから画面に出力します。

今回 エスケープ処理を行うには、htmlspecialchars()という関数に第二パラメータ ENT_QUOTESを与えて使っているのですが、これを毎回記述するのは大変なので、e() という単純な名前の関数を定義して、エスケープ処理を行う場合はこちらを使用するようにします。

そして、なるべくWebサイトの安全性を高めるために、「PHPで画面に文字列を出力する項目は一律に e()関数に渡して出力する」という方針を取ります。e()関数を通して何か問題がある場合(HTML形式の文字列出力したい場合など)は例外であると考え、その時だけ慎重に別の対応をとります。

nonce属性値を生成する関数
// nonce生成
function createNonce() {
  return md5(uniqid(rand(), true));
}

先程、意図しない JavaScriptコードを実行させると危険であると書きましたが、これと同様に意図しないCSS や 画像等が Webサイトに挿入された場合もセキュリティ上の問題になることがあります。その対策の1つとして Content Security Policy(CSP) という仕組みがあります。このCSPというのはなかなか強力なのですが、導入するのが少し面倒であるためか、あまり普及していないようです。しかし、なるべく早い段階でセキュリティに対する意識を持ってもらうために、今回のコードでは様々なセキュリティ対策の方法を取り入れています。取り入れてはいるのですが、この段階で詳細は説明しても難しいと思いますので、本記事では詳細な説明は省きます。興味を持った方は インターネットで検索して調べてみて下さい。

上の関数では、CSPを利用するための一意な文字列を生成しています。

クッキーを表示用に整形する関数
// cookieの中身を表示用の文字列に変換して返す
function showCookies($hash) {
  $html = '';
  foreach($hash as $key => $val) {
    if ($html != '') $html .= ', ';
    $html .= $key . '=' . $val;
  }
  return $html;
}

これは、画面上の「クッキー」の行に表示する文字列を生成する関数です。クッキー(または HTTPクッキー) というのは、ブラウザ上に保存される小さなデータで、特定の URLとセットで保持されます。

クッキー

クッキーの一般的な動作は以下になります。

  1. ブラウザが、初めて http://www.example.com にアクセスします。
    • 初めてアクセスするURLなので、送るクッキーはありません。
  2. www.example.com の Webサーバーが HTMLデータをブラウザに返す際、一緒にクッキーも送ります。クッキーの情報は、HTTPレスポンスメッセージのヘッダ部にセットされてブラウザに送信されます。

    Set-Cookie:クッキー名=値; expires=Sun, 29-Nov-2015 00:41:01 GMT; path=/; domain=.laboradian.com
    
  3. ブラウザは、www.example.com というドメイン名とセットにして、送られてきたクッキーを保存します。
  4. ブラウザが再度、http://www.example.com にアクセスする際は、このURLとセットで保存しているクッキーを、HTTPリクエストメッセージ内にセットして Webサーバーに送信します。クッキーの情報は、HTTPリクエストメッセージのヘッダ部にセットされて Webサーバーに送信されます。

    Cookie:クッキー名1=値1; クッキー名2=値2
    
  5. www.example.com の Webサーバーは、クッキーを受け取ります。どう使うかは、Webサーバーの自由です。

例えば、もし 2 のところで Webサーバーがランダムで一意な文字列をブラウザに返却するとともに、サーバー側でもその文字列を保存しておけば、5でどのユーザーか判別することができます。ログインするような Webサイトでは、このようにして 特定のユーザーのログイン状態を管理しています(セッションといいます)。

参考

PHPでのクッキーの扱い

PHPでは、ブラウザから送られてきたクッキーの情報が $_COOKIE という連想配列にセットされます。連想配列というのは、キーとなる名前とその値のペアを複数持つことのできる変数のことを言います。

PHPでの連想配列の処理

例えば、名前(name)が ‘foo’で、趣味(hobby)がギター(‘guitar’) という情報は以下のような連想配列で表すことができます。

$array = array(
    "name" => "foo",
    "hobby" => "guitar",
);

// PHP 5.4 以降ではこのようにも書けます
$array = [
    "name" => "foo",
    "hobby" => "guitar",
];

この連想配列内の各要素に対して、順番に何か処理を行いたい場合は、以下のように foreach を使うとラクです。

foreach ($array as $key => $value) {
    // キー名 $key と 値 $value を使って何か処理を行う。;
}
showCookies($hash) のやっていること

showCookies($hash)関数では、$_COOKIEを引数として受け取って、その中の各キー名と値を文字列として連結し、その結果を返すという処理を行っています。キー名と値の間には = を入れ、ペア同士の区切りとして , を挿入しています。

例えば、上で例を上げた $array の中身であれば、以下の文字列が生成されます。

name=foo, hobby=guitar

画面上の「クッキー」の行には、ブラウザから Webサーバーに送信されたクッキーの情報をこの形式で表示します。

OSの判定処理を行う関数
function getOS($user_agent) { 
  $os_platform = "Unknown OS Platform";
  $os_array = array(
    '/windows nt 10/i'     =>  'Windows 10',
    '/windows nt 6.3/i'     =>  'Windows 8.1',
    '/windows nt 6.2/i'     =>  'Windows 8',
    '/windows nt 6.1/i'     =>  'Windows 7',
    '/windows nt 6.0/i'     =>  'Windows Vista',
    '/windows nt 5.2/i'     =>  'Windows Server 2003/XP x64',
    '/windows nt 5.1/i'     =>  'Windows XP',
    '/windows xp/i'         =>  'Windows XP',
    '/windows nt 5.0/i'     =>  'Windows 2000',
    '/windows me/i'         =>  'Windows ME',
    '/win98/i'              =>  'Windows 98',
    '/win95/i'              =>  'Windows 95',
    '/win16/i'              =>  'Windows 3.11',
    '/macintosh|mac os x/i' =>  'Mac OS X',
    '/mac_powerpc/i'        =>  'Mac OS 9',
    '/linux/i'              =>  'Linux',
    '/ubuntu/i'             =>  'Ubuntu',
    '/iphone/i'             =>  'iPhone',
    '/ipod/i'               =>  'iPod',
    '/ipad/i'               =>  'iPad',
    '/android/i'            =>  'Android',
    '/blackberry/i'         =>  'BlackBerry',
    '/webos/i'              =>  'Mobile'
  );
  foreach ($os_array as $regex => $value) { 
    if (preg_match($regex, $user_agent)) {
      $os_platform    =   $value;
    }
  }   
  return $os_platform;
}

ここで、クライアントのOSを判定しています。
どうやって判定するか?といいますと、ブラウザが Webサーバーに送信する HTTPリクエストメッセージのヘッダ内にある User-Agent というフィールドを見て判定します。User-Agent というのは使用しているブラウザそのものについての情報がセットされます。 Webサーバーはここの文字列を見ることで、スマートフォンがアクセスしてきたのか、もしくはパソコンからアクセスしてきたのか?や、どいうったスマートフォンなのか?、パソコンであればどのOSなのか?を判断し、それぞれに合ったコンテンツを返すことができるのです。

User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2931.0 Safari/537.36

この中でいうと、Windows NT 10.0; Win64; x64 の部分が、OS の情報になります。この場合、Windows 10 64bit版であるということが分かります。

PHPでは、ブラウザから送信されるHTTPリクエストメッセージのヘッダにセットされるこの手の情報は、$_SERVER という連想配列にセットされます。User-Agent の文字列であれば、キー名が HTTP_USER_AGENT となっているので、$_SERVER['HTTP_USER_AGENT'] という形で取得することができます。
getOS($user_agnet) という関数では、引数として $_SERVER['HTTP_USER_AGENT'] の値が渡されることを想定しています。ここでは予め 各OSの User-Agent における文字列と、そのOS名を連想配列で用意しておき、引数に対して 1つ1つ preg_match()関数をを使って比較し、一致したOSの名前を返しています。

ブラウザを判定する関数
function getBrowser($user_agent) {
  $browser = "Unknown Browser";
  $browser_array  =   array(
    '/msie/i'       =>  'Internet Explorer',
    '/firefox/i'    =>  'Firefox',
    '/safari/i'     =>  'Safari',
    '/chrome/i'     =>  'Chrome',
    '/edge/i'       =>  'Edge',
    '/opera/i'      =>  'Opera',
    '/netscape/i'   =>  'Netscape',
    '/maxthon/i'    =>  'Maxthon',
    '/konqueror/i'  =>  'Konqueror',
    '/mobile/i'     =>  'Handheld Browser'
  );
  foreach ($browser_array as $regex => $value) { 
    if (preg_match($regex, $user_agent)) {
      $browser    =   $value;
    }
  }
  return $browser;
}

ここでは、先程の getOS($user_agnet)関数と同じやり方で ブラウザを判定しています。一致したブラウザ名を返します。

セキュリティを考慮したHTTPヘッダ情報をPHPで出力する

// CSP
// nonceの値はアクセス毎に違う値を生成するのがよい。
$nonce1 = createNonce();
$nonce2 = createNonce();
header("Content-Security-Policy: default-src 'self';"
 . " script-src 'nonce-${nonce1}' code.jquery.com maxcdn.bootstrapcdn.com use.fontawesome.com;"
 . " style-src 'nonce-${nonce2}' maxcdn.bootstrapcdn.com use.fontawesome.com;"
 . " font-src maxcdn.bootstrapcdn.com use.fontawesome.com;");
// XSS攻撃を検知させる(検知したら実行させない)。
header("X-XSS-Protection: 1; mode=block");
// IEにコンテンツの内容を解析させない(ファイルの内容からファイルの種類を決定させない)。
header("X-Content-Type-Options: nosniff");
// このページを iframe に埋め込ませない
header("X-Frame-Options: DENY");

ここでは、この Webページのセキュリティを向上させるための HTTPレスポンスヘッダフィールドをセットしています。PHPの header()関数に渡した文字列は、HTTPレスポンスメッセージのヘッダに出力されてブラウザに送られます。ブラウザはこの情報を受け取り、そこに指示されている動作を行います。詳細は省略しますが、ここで指定している内容は全てセキュリティに関するものです。これらの処理は必須ということではありませんが、Webサイトというのは基本的に全世界に向けての発信となりますので、少しでも安全な措置は取るよう心がけましょう。

<style type="text/css" nonce='<?php echo e($nonce2); ?>'>
  :
<script type="text/javascript" nonce='<?php echo e($nonce1); ?>'>

上側が CSSを記述する style要素タグで、そこから実際はかなり間を隔てていますが、下側が JavaScriptを記述する <script> 要素タグです。ここでは CSPのための nonce属性値を PHPの echo()で出力してセットしています。これにより、ブラウザはこれらを安全なタグであるとみなして正常に実行してくれます。

画面に出力する各項目

<th>あなたからのリクエストを取得した時間</th>
<td><?php echo e(date("Y年m月d日 H時i分s秒", $_SERVER['REQUEST_TIME'])); ?></td>

ここでは、Webサーバーが 受け取ったHTTPリクエストメッセージに対する処理を開始した時刻を出力しています。この値は、$_SERVER[‘REQUEST_TIME’]で取得できるのですが、形式が UNIXタイムスタンプ(1970年1月1日 午前0時0分0秒からの経過秒数)になっていますので、date() 関数を使って「Y年m月d日 H時i分s秒」という形式に変換し、更に HTMLエスケープを行う e()関数を通して出力しています。date()関数の結果に危険な文字列(JavaScriptコードなど)が混入することはほぼ考えられませんが、「PHPで画面に文字列を出力する項目は一律に e()関数に渡して出力する」という方針を取りますので、ここでも e() を使っています。

<th>このWebサーバーのホスト名</th>
<td><?php echo e($_SERVER['SERVER_NAME']); ?></td>

ここでは、Webサーバー自身のホスト名を画面に出力しています。この文字列は、$_SERVER[‘SERVER_NAME’] によって取得することができます。こちらも e() でHTMLエスケープした結果を、echo()関数で画面に出力します。

<th>あなた側のコンピュータのIPアドレス</th>
<td>
  <span class="em1"><?php echo e($_SERVER['REMOTE_ADDR']); ?></span><br>
  <p>(通常、あなたのコンピュータがデフォルトゲートウェイに設定しているデバイスのIPアドレスになります(ルータであることが多いです))。</p>
</td>

ここでは、Webサーバーにアクセスした側、つまりあなた側のコンピュータのIPアドレスを出力しています。通常はあなたのコンピュータがデフォルトゲートウェイに設定しているデバイスに対して、プロバイダが割り当てたIPアドレスになります。デフォルトゲートウェイとしてルータを指定している場合は、そのルータにそのIPアドレスが割り当てられています。PHPからは、$_SERVERという連想配列の REMOTE_ADDRというキーによって取得することができます( $_SERVER[‘REMOTE_ADDR’])。

この値も、どこでどう改ざんされるか分かりませんので、e()関数に渡してHTMLエスケープした上で、echo()関数で画面に出力しています。

<th>あなた側のコンピュータのホスト名<br></th>
<td>
  <span class="em2"><?php echo e(gethostbyaddr($_SERVER['REMOTE_ADDR'])); ?></span><br>
  <p>(上のIPアドレスに対応するホスト名です)</p>
</td>

gethostbyaddrという関数で、上の項目に出力しているIPアドレスをホスト名に変換した文字列を出力しています。 このIPアドレスはプロバイダから割り当てられているだけですので、これを変換すると、プロバイダが本来そのIPアドレスに割り当てているデバイスのホスト名になります。

<th class="success"><a href="https://tools.ietf.org/html/rfc7231#section-4">Method</a></th>
<td><?php echo e($_SERVER['REQUEST_METHOD']); ?><br>
  (メソッド名)
</td>

HTTPリクエストメッセージのリクエストラインにセットされた HTTPメソッドの種類を出力しています。$_SERVER連想配列の REQUEST_METHODキーから取得できます。

<th><a href="https://tools.ietf.org/html/rfc7230#section-3.1.1">Request-URI</a></th>
<td>
  <?php echo e($_SERVER['REQUEST_URI']); ?><br>
 (要求されたURI)
</td>

HTTPリクエストメッセージのリクエストラインにセットされていた URI を出力しています。

<th><a href="https://tools.ietf.org/html/rfc7230#section-3.1.1">HTTP-Version</a></th>
<td>
  <?php echo e($_SERVER['SERVER_PROTOCOL']); ?><br>
  (ページがリクエストされた際のHTTPバージョン)
</td>

HTTPリクエストメッセージのリクエストラインにセットされていた HTTPのバージョンを出力しています。

<th><a href="https://tools.ietf.org/html/rfc7230#section-5.4">Host</a></th>
<td>
  <?php echo e($_SERVER['HTTP_HOST']); ?><br>
  (要求されたホスト名)
</td>

HTTPリクエストメッセージの HOSTヘッダにセットされていたホスト名を出力しています。

<th><a href="https://tools.ietf.org/html/rfc7231#section-5.5.3">User-Agent</a></th>
<td>
  <?php echo e($_SERVER['HTTP_USER_AGENT']); ?><br>
  (あなたのブラウザ情報)
</td>

ここでは、HTTPリクエストメッセージの User-Agentヘッダにセットされていた文字列を出力しています。

<th>あなたのOS<br>(User-Agentから取得)</th>
<td>
  <span><?php echo e(getOS($_SERVER['HTTP_USER_AGENT'])); ?></span><br>
  解像度: <span id="resolution"></span>
  <span>(この値はクライアント側で取得している)</span>
</td>

まず、HTTPリクエストメッセージの User-Agentヘッダを $_SERVER[‘HTTP_USER_AGENT’] により取得し、自作した getOS()関数にその文字列を渡すことで、OSの名前を取得して出力しています。その次に、ユーザーの使用しているディスプレイの解像度を出力しているのですが、これは Webサーバー側からは取得できない値なので、ブラウザ側のJavaScriptで取得して表示します。JavaScriptコードに関しては、もう少し後で説明しますが、<span id="resolution">...</span> というタグの中に解像度を出力しています。

<th><a href="https://tools.ietf.org/html/rfc7231#section-5.3.5">Accept-Language</a></th>
<td>
  <?php echo e($_SERVER['HTTP_ACCEPT_LANGUAGE']); ?><br>
  (ブラウザの希望する言語)
</td>

ここでは、HTTPリクエストメッセージの Accept-Languageヘッダにセットされていた文字列を、$_SERVER[‘HTTP_ACCEPT_LANGUAGE’]で取得して出力しています。

<th><a href="https://tools.ietf.org/html/rfc7231#section-5.5.2">Referer</a></th>
<td>
  <?php echo e($_SERVER['HTTP_REFERER']); ?><br>
  (どこのURLからこのページに来たのか)
</td>

ここでは、HTTPリクエストメッセージの Refererヘッダにセットされていた文字列を $_SERVER[‘HTTP_REFERER’]で取得して出力しています。

<th><a href="https://tools.ietf.org/html/rfc7231#section-5.3.2">Accept</a></th>
<td>
  <?php echo e($_SERVER['HTTP_ACCEPT']); ?><br>
  (ブラウザが希望するメディアタイプ)
</td>

ここでは、HTTPリクエストメッセージの Acceptヘッダにセットされていた文字列を $_SERVER[‘HTTP_ACCEPT’]で取得して出力しています。

<th><a href="https://tools.ietf.org/html/rfc7231#section-5.3.4">Accept-Encoding</a></th>
<td>
  <?php echo e($_SERVER['HTTP_ACCEPT_ENCODING']); ?><br>
  (ブラウザが受け入れるエンコーディング)
</td>

ここでは、HTTPリクエストメッセージの Accept-Encodingヘッダにセットされていた文字列を $_SERVER[‘HTTP_ACCEPT_ENCODING’]で取得して出力しています。

<th><a href="https://tools.ietf.org/html/rfc6265#section-4.2">Cookie<a></th>
<td><?php echo e(showCookies($_COOKIE)); ?></td>

HTTPリクエストメッセージ内の Cookieヘッダにセットされていたクッキーの情報は、$_COOKIE という変数で取得できます。この変数を、自作の関数である showCookies()に渡し、見やすい形にした上で表示しています。

以上、元々記述されていた HTMLの中に、PHPコードによって出力された文字列が埋め込まれ、ブラウザに返す HTMLができあがります。

8-5. Webサーバーが HTTPレスポンスメッセージを返す

ブラウザから要求された index.php ファイルが PHP実行エンジンにより処理され、その結果が、HTTPプロトコルのレスポンスメッセージとなって、ブラウザに返されます。

HTTPレスポンスメッセージ

Chromeのデベロッパーツール内に表示された中から、Webサーバーからブラウザに返されたレスポンスメッセージの部分をあらためて以下に記載します。

HTTP/1.1 200 OK
Date: Thu, 30 Nov 2016 00:00:00 GMT
Server: Apache
Content-Security-Policy: default-src 'self'; script-src 'nonce-4c86f68423bd7bc8148c54092a85bb7b' code.jquery.com maxcdn.bootstrapcdn.com use.fontawesome.com; style-src 'nonce-5c57340f0aae756a143408f8e23f087a' maxcdn.bootstrapcdn.com use.fontawesome.com; font-src maxcdn.bootstrapcdn.com use.fontawesome.com;
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Content-Length: 6014
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=UTF-8

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
(省略)

HTTPのレスポンスメッセージは、以下の形式になっています。

http_response_message

1行目をステータスラインといい、

HTTPバージョン ステータスコード メッセージ

という形式になっています。上記の場合、「HTTPバージョン」は「1.1」、「ステータスコード」は「200」、「メッセージ」が「OK」となります。HTTPプロトコルでは、リクエストに対して Webサーバー側でちゃんと処理できたのかどうか?について、番号で教えてくれるのですが、その番号のことを「ステータスコード」と呼びます。 ステータスコードを見ても分かる通り、200というのは、正常に処理できたことを意味します。「メッセージ」というのはステータスコードの意味を表します。

2行目以降から空行までをメッセージヘッダといい、先程のHTTPリクエストメッセージと同じで、

フィールド名内容

という形式でいろいろな情報が送られてきます。ブラウザはここの情報を利用することで、Webサーバー側の意図した動作を行うことができます。

空行が終わると、続いてメッセージボディになります。通常はここがHTML文書のデータとなっており、ブラウザに描画されることになります。もしこのHTMLの中で、別ファイルとなっているCSSファイルやJavaScriptファイル、画像ファイル等があれば、ブラウザはそれらのファイルもWebサーバーに要求して取得します。CSSであればそこで指定された装飾を画面上の要素に施すことになりますし、JavaScriptコードであればそこに記述された処理を実行します。

以下が、[Response]タブに表示された HTMLです。ブラウザはこのHTMLを画面に描画することになります。

2016-12-chrome-dev-tool3

8-6. 取得したHTMLを描画する

今回 Webサーバーから返ってくる HTMLデータは、index.phpファイルの <!DOCTYPE html>という行以降の部分になります。ところどころ <?php ... ?> というPHPコードがありますが、そこは Webサーバー側で処理されて、それぞれ文字列が生成されて出力されることは既に説明しました。ここではブラウザで処理の対応となる部分を説明します。

まず、<!DOCTYPE html>以下は以下の構造になっています。

<!DOCTYPE html>
<html lang="ja">
<head>
  <!-- この Webページに関するヘッダ情報 -->
  <style type="text/css">
    /* CSS の内容 */
  </style>
</head>
<body>
  <!-- 画面に表示する内容 -->
  <script type="text/javascript">
    // JavaScriptのコード
  </script>
</body>
</html>
  1. <!DOCTYPE html> から末尾までが HTML の記述です。今回は CSS と JavaScript もこの中に記述しています。
  2. <head></head> の間には、このHTMLファイルについての情報を記述します。CSSについての記述もここで行います。
  3. <body></body> の間には、メインの内容(表示したい内容)を記述します。ここも HTMLのフォーマットで書きます。
  4. <style type="text/css"></script> に囲まれた部分に、CSS の記述を行います。 <link rel="stylesheet" src="..." ...> の部分では、外部のCSSファイルを読み込んでいます。
  5. <script type="text/javascript"></script> で囲まれた部分に、JavaScript の記述を行います。 <script src="..."></script> の部分では、外部の JavaScriptファイルを読み込んでいます。

HTML & CSS & JavaScript

まず、HTMLの部分から解説します。

HTMLにもいくつかのバージョンがありますが、現在の主流は HTML5です。最新の仕様は HTML 5.1 で読めます。 この HTML5 でシンプルな HTML文書を書くなら、以下のような内容になります。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>文書のタイトルです</title>
</head>

<body>
文書の本文です…
</body>

</html>

基本的には、ここに必要な記述を追加していけば間違いありません。今回のHTMLもこの記述になっています。

<!DOCTYPE html>

DOCTYPE とは文字通り「文書の種類」という意味なのですが、この記述を行うことで、このファイルが HTML5の書式であることを ブラウザに伝えることができます。 Webブラウザの画面描画処理は HTMLのバージョンによって異なりますので、この記述は重要です。

例えば、HTML 4.01 の場合であると以下のように長い文字列になります(4.01の場合、実際には書き方が何種類かあります)。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

参考:

では、元のファイルに戻って続きを見ていきます。

<html lang="ja">

この文書のデフォルトの言語を指定します。

参考:

<head>

head要素の中には、この文書全体の属性を指定していきます。

参考:

  <meta charset="UTF-8">

この文書に適用される文字エンコーディングの種類を指定しています。通常は UTF-8 です。

参考:

  <meta http-equiv="X-UA-Compatible" content="IE=edge">

IE (Internet Explorer )に対して、最新の描画エンジンを使用するように伝えます。meta要素はこのようにいろいろな目的で使うことができます。

参考:

  <meta name="viewport" content="width=device-width, initial-scale=1">

meta要素の name属性に viewport を指定することによって、表示領域の大きさを指定することができます。上記の記述の場合、表示領域をデバイスの幅に合わせ、拡大率100%で表示するよう指示しています。

参考:

  <title>あなたのウェブブラウザが送信する情報</title>

title要素で、この文書のタイトルを指定します。

参考:

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" ...>

link要素の rel属性に stylesheet を指定することによって、外部の CSSファイルを読み込んでいます。 href属性に、読むこむCSSファイルの URL を指定します。
ここでは、Bootstrap という CSSフレームワークの CSSファイルをここで読み込ませています。

Bootstrap について

Bootstrap の Webサイトには、

Bootstrap is the most popular HTML, CSS, and JS framework for developing responsive, mobile first projects on the web.

と記載されています。日本語にすると、

Bootstrap は、Webにおけるレスポンシブでモバイルファーストなプロジェクトを開発するための 最も人気のある HTML, CSS, JS フレームワークです。

となります。簡単に言うと、それなりに見た目のよい Webサイトを手軽に作るためのライブラリです。
Bootstrap側でいろいろな CSSを記述してくれていますので、ファイルを読み込むだけで見た目が良くなります(画面サイズに合わせてレイアウトを変えてくれます)。更に、便利なCSSのクラスもたくさん定義されていますので、自分で記述する HTML要素の class属性にそのクラス名を指定すれば、いろいろと見た目を変えることができます。
また、JavaScript も使われており、ちょっとした動きを付けることもできます。そのため、JavaScriptのファイルも読み込ませておかないといけないのですが、それは後で出てきます。

Bootstrapのファイルを自分のサーバーにアップロードして使うのではなく、Bootstrap側が用意した Webサーバーに用意されたファイルを直接読み込んで使うこともでき、そのための説明は、Bootstrap CDN – Getting started に記載されています。この方法で使う場合、Webサイトを読み込む際に少し時間が掛かるかもしれませんが、今回作るような小さな Webページであれば手軽でよいと思います。

Bootstrap を使いこなすためには、公式サイトのドキュメントを十分に読み込む必要がありますが、今回は深くは使いませんので、使用している箇所で簡単に説明します。

参考:

次の記述の説明に戻ります。

  <style type="text/css" nonce='<?php echo e($nonce2); ?>'>
  body {
    margin: 30px;
  }
  (省略)
  </style>

ここでは、style要素に、src属性を指定せず、開始タグ <style> と 終了タグ </style> の間に、CSSコードを記述しています。 この文書独自に見た目を変えたい部分もありますので、ここに記述します。本当は別ファイルにした方がよいのですが、小さなWebページですのでここに書きました。nonce属性は CSPを使うために記述しています。

いくつかピックアップして説明します。

CSS の記述その1

.em1 {
  font-size:200%;
  color: blue;
}  

ここでは、em1 というクラスを定義しています(”em” というのは、”emphasis” (強調)という英単語からとりました)。 CSSでは、. + クラス名 { 属性名1: 属性値1; 属性名2: 属性値2; ... } と書くと、クラスを定義することができます。こうしておけば、例えば <span class="em1">強調されます!</span> とHTMLを書けば、”強調されます!” の部分に、font-size:200%;color: blue が適用され、「フォントサイズは2倍」、「色は青」で表示することができます。

CSS の記述その2

.kakunin tbody tr th {
  min-width: 200px;
  background-color: #d9edf7;
}

順番が前後しますが、上記では「((((kakunin というクラスが指定された要素) の中の tbody要素) の中の tr要素) の中の th 要素)」に対して、{ ... } 内に記述した属性設定が適用されます。例えば、以下の (A)の部分に適用されます。

<table class="kakunin">
  <tbody>
    <tr>
      <th>タイトル1</th> <!-- (A) -->
      <td>内容1</td>
    </tr>
  </tbody>
</table>

ようやく次からが、このブラウザの画面上に表示される部分になります。

<body>

body要素から始まります。

  <h1>あなたのウェブブラウザが送信する情報</h1>

h1要素でこのページのタイトルを記述しました。

  <p>あなたのウェブブラウザがこのウェブサーバーに送ってきた情報を表示しています。</p>
  <p class="text-danger">* このウェブページはあくまで実験的なものです。定期的にこのようなウェブページが必要な方は、<a href="http://www.ugtop.com/spill.shtml">確認くん</a> などをご利用下さい。</p>

p要素でこのページについての説明文を記述しています。2つ目のp要素(2行目)には、class="text-danger が指定されていますが、このtext-danger は、Bootstrap 側で定義されているクラスです。CSS · Bootstrap で説明されていますが、デフォルトでは 赤系統の色になります。以下のように定義されているようです。

.text-danger {
    color: #a94442;
}

ここからは、table要素を使って 表を記述しています。

<div class="table-responsive">
  <table class="kakunin table table-striped table-bordered table-hover">
    ...
  </table>
</div>

Bootstrap 側で table要素を装飾する CSSクラスがいろいろ定義されていますので、Tables · CSS · Bootstrap を読んで、欲しい機能を探し、そのために必要なクラスを class属性に指定してあります。レスポンシブルな表にしたかったので、Responsive tables のところに書いてある通り、table要素を <div class="table-responsive"> で囲んであります。

表に表示している各項目については、PHPコードの解説で合わせて書きますので、ここでは飛ばします。

 <footer class="kakunin-footer">
    <p><i class="fa fa-copyright"></i> 2016 laboradian.com</p>
  </footer>

フッター部です。このページに関するメタ情報など書いておきましょう。
もう少し先で触れますが、<i class="fa fa-copyright"></i> というのは、Font Awesome というアイコンをフォントとして使えるようにしたもので、このようなタグを書くだけで、アイコンが表示されます。ちなみにここでは、著作権のマークを表示しています。

  <!-- Latest compiled and minified JavaScript -->
  <script type="text/javascript"
    src="https://code.jquery.com/jquery-3.1.1.slim.js"
    integrity="sha256-5i/mQ300M779N2OVDrl16lbohwXNUdzL/R2aVUXyXWA="
    crossorigin="anonymous"></script>

script要素の src属性にURLを指定することで、外部の JavaScriptファイルを読みませています。ここでは jQeury を読み込んでいます。Bootstrapを使うには jQuery が必須なのです。外部のサーバーにおいてあるライブラリのようなファイルのURLを直接指定して読み込ませてくれるサービスを CDN といいますが、jQeury のCDN は、例えば、jQuery CDN に載っています。最近ですと、jQeuryの全てが入ったファイルだけでなく、一部の機能のみを提供してくれるファイルも用意されているようです。今回は後者(slim)を選びました。

  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>

こちらは、Bootstrap の JavaScriptファイルを読み込ませています。

  <script src="https://use.fontawesome.com/c215ece6c6.js"></script>

こちらは、Font Awesome の JavaScriptファイルを読み込ませています。Font Awesome というのは、いろいろな形をしたアイコンがフォントとして用意されているものです。いろいろなアイコンが手軽に使えて便利です。

  <script type="text/javascript" nonce='<?php echo e($nonce1); ?>'>
$(function(){
  $('#resolution').text(screen.width + ' x ' + screen.height + ' pixel');
});
  </script>

ここでの script要素では、src は指定せず、直接JavaScriptコードを書くために使用しています。jQeuryというJavaScriptをより便利に書けるライブラリを使って書いています。

$(function(){
  // (A)
});

このように書くと、ブラウザが HTMLを全て読み込んだ後で、(A)に記述したコードを実行してくれます。画面上の特定の HTML要素を操作するようなコードが書きたい場合は、こうしないと「処理対象となる要素が見つからない」というエラーが発生してしまいます。

$('#resolution').text(screen.width + ' x ' + screen.height + ' pixel');

$('#resolution') では ‘resolution’ という idが指定されたHTML要素を取得して jQueryオブジェクトとして取得してくれます。具体的にいうと、<span id="resolution">...</span> という部分を指しており、span要素が取得されます。.text( ... ) というのは、そのオブジェクトが持っている text というメソッドを呼び出しており、引数で渡した文字列が、span要素の <span ...></span> の間に出力されます。screen.width と書くとディスプレイの横幅(単位はピクセル)が取得できます。同様に screen.height は高さが取得できます。ここでの + というのは数学でいう「足す」ではなく、文字列を連結する意味になりますので、.textメソッドに渡す文字列は、例えば “1366 x 768 pixel” となります。

</body>
</html>

これで、body要素も終わり html要素も終了です。

9. まとめ

以上、ブラウザがURLを指定してからページが表示されるまでを説明してきました。盛りだくさんの内容だったと思います。「ブラウザがどんな値を Webサーバーに送っていて、それをブラウザに返して表示させるには、どうすればよいのか」理解できましたでしょうか? 自分でWebサイトを作ることはなくても、ブログサービスを利用するような場合は、今回説明した知識があると随分と使いやすくなると思います。

また、HTML, CSSの基礎と CSSフレームワーク(Bootstrap)、アイコンフォント(Fontawesome) を知っているだけでも、それなりの見た目の Webページが作成できて便利です。

10. まだやっていないこと

  • form 要素と POSTメソッドを使ったリクエスト送信
  • HTTP 認証
  • セッション管理
  • Ajax の利用
  • node.js 及び npmを使ったフロントエンドの開発
  • サーバーサイドで使用しているプログラミング言語のフレームワーク利用
  • データベース管理システムの利用
  • SSL/TLS の利用
  • etc.

11. 参考



📂-プログラミング
-

執筆者:labo


comment

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

関連記事

JavaScript

JavaScriptで画面上の文字列をクリップボードにコピーする方法

目次1. はじめに2. Clipboard API and events を使う方法3. Selection API を使う方法(1) 基礎知識(2) プログラムの書き方(3) サンプルページ4. お …

Web Programming

IntersectionObserver API を使ったテストページを作成しました

IntersectionObserver API を使ったテストページを作成しました。 IntersectionObserver API は、ウェブページ上のある要素が見える範囲 (viewport) …

Web Programming

サーバーからブラウザを通じてデスクトップ通知する方法(Push API を利用)

Push API を使ってサーバーからブラウザにメッセージを送る方法について説明しています。

web development

Resource Timing API を使って、リソースの読み込みに掛かった時間を計測する

目次1. Resource Timing API について2. サンプルコード3. PerformanceResourceTiming インターフェイス4. デモページ5. 参考仕様MDNブラウザの対 …

QRコードの画像ファイルから内容を読み取るWebページを作りました

目次1. はじめに2. スクリーンショット3. URL4. 操作と内容5. ソースコード6. 参考情報 1. はじめに QRコードの画像ファイルから内容を読み取る を作りました。 2. スクリーンショ …