[PHP] アクセスカウンター用のRESTfulAPIを作成する - その1 ファイル版

PHPの練習用にアクセスカウンター用のREST APIPHPで作成します。

最終的に以下のような画面になります。ここで再読み込みを行うと数値がどんどん加算されていきます。

※この記事は専門学校の講義用に作成した物です。

ソースコード

PHP

以下のコードをget.phpなど適当な名前で保存します。

<?php
/**
 * アクセスカウンターAPI
 * 
 * @author M.Katsube <katsubemakito@gmail.com>
 * @version 1.0.0
 */

// デバッグ時にエラーを画面に表示したい場合は以下をコメントアウトする
// ini_set('display_errors', "On");

//-----------------------------------
// 定数
//-----------------------------------
define('DATA_FILE', 'data.txt');

//-----------------------------------
// メイン処理
//-----------------------------------
// 現在の値を取得(カウントアップする)
$count = getCounter(DATA_FILE);

// 現在の値を返却する
header('Content-type: application/json');
echo json_encode([
      'status' => true
    , 'count'  => $count
]);


/**
 * カウンターの値を取得
 * 
 * @param  string $file
 * @return integer
 */
function getCounter($file){
    // データを取得する
    $fp = fopen($file, 'r+'); // ファイルを読み込み+書き込みモードで開く
    flock($fp, LOCK_EX);      // ファイルをロックする
    $buff = (int)fgets($fp);  // ファイルから1行読み込み

    // ファイルを空にする
    ftruncate($fp, 0);    // ファイルサイズをゼロにする
    fseek($fp, 0);        // ファイルポインタを先頭に戻す

    // +1した数値を書き込む
    fwrite($fp, $buff+1);

    // ファイルを閉じる
    flock($fp, LOCK_UN);  // ファイルのロックを解除
    fclose($fp);          // ファイルを閉じる

    return($buff);
}

HTML

先ほどのPHPを呼び出すかんたんなHTMLを用意します。ファイル名は何でも良いのですがindex.htmlとしておきます。

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf8">
  <title>アクセスカウンター</title>
</head>
<body>

<h1>ようこそ</h1>
<p>あなたは<span id="count"></span>人目のお客様です</p>

<form>
  <button id="btn-reload" type="button">
    再読み込み
  </button>
</form>

<!-- 外部のJavaScriptを呼び出す -->
<script src="app.js"></script>
</body>
</html>

JavaScript

HTMLから呼び出されるJavaScriptです。ここではapp.jsという名前で保存しておきます。

/**
 * ファイルの読み込みが完了したら実行
 **/
window.onload = ()=>{
  //-------------------------------------
  // get.phpと通信を行う
  //-------------------------------------
  fetch("get.php")
    // get.phpから返却された値をJavaScriptから操作できるよう加工する
    .then((res)=>{
      return( res.json() );
    })
    // 加工した値を使って処理する
    .then((json)=>{
      if( json["status"] ){
        const count = document.querySelector("#count");  // id="count"とある箇所のHTMLを取得
        count.innerHTML = json['count'];  // get.phpから取得した値をセットする
      }
      else{
        alert("APIでエラーが発生しました");
      }
    })
    // 通信中などにエラーが発生した場合は↓ここが実行される
    .catch((error)=>{
        alert("通信中にエラーが発生しました");
    });
}

/**
 * 再読み込みボタンがクリックされたら実行
 **/
document.querySelector("#btn-reload").addEventListener("click", ()=>{
  // 現在のページを再読み込みする
  location.reload();
});

実行する

準備

コードを保存

まずはWebサーバが見ることのできるディレクトリ(ドキュメントルート)の下に適当な名前のディレクトリ作成し、先ほどのソースコードを保存します。ここでは/var/www/htmlの下にcounterという名前のディレクトリを作成します。

$ mkdir /var/www/html/counter

カレントディレクトリ移動し、ファイルを保存します。

$ cd /var/www/html/counter
$ ls
app.js  get.php  index.html

データファイルを用意

次に最新のカウンターの値を保存するためのデータファイルを準備します。テキストエディタなどを開き任意の数字(1など)だけを書いたファイルを、先ほどのPHPと同じ階層に保存します。もしくは以下のコマンドを実行しても同じ結果が得られます。

$ echo -n "1" > data.txt

データファイルの実行権(パーミション)を確認すると、以下のようになっています。

$ ls -l data.txt 
-rw-rw-r-- 1 neec neec 1  67 23:12 data.txt
  • ファイルの所有者は「読み込み」と「書き込み」が可能
  • ファイルの所有者と同じグループのユーザーは「読み込み」と「書き込み」が可能
  • それ以外のユーザーは「読み込み」だけ可能

Webサーバを起動しているユーザーは「それ以外」のユーザーに当たることが多いのですが、この実行権のままだとデータを読み込むことは出来ても書き込むことができません。そこでそれ以外のユーザーも書き込みが出来るよう実行権を変更します。

$ chmod o+w data.txt

最終確認

最終的に以下のような表示にあっていれば次のステップへ進みます。

$ ls -l
合計 12
-rw-rw-r-- 1 neec neec    0  67 23:10 app.js
-rw-rw-rw- 1 neec neec    1  67 23:24 data.txt
-rw-rw-r-- 1 neec neec 1144  67 22:41 get.php
-rw-rw-r-- 1 neec neec 1373  67 22:57 index.html

Webブラウザから実行

ここまで準備が整ったらWebブラウザからアクセスしてみます。次のように表示されているでしょうか? 「再読み込み」ボタンを押すとカウントアップすることが確認できたら成功ですね。

エラーになったら?

現象にもよりますが、まずはどこでエラーになっているのか切り分けを行います。

最初に「get.php」に直接アクセスしてみてください。ここでエラーになったり何も表示されない場合はPHPに原因がある可能性が高いです。PHPを実行した際にエラーが発生した場合は/var/log/httpd/error_logへその内容が記録されます。以下のようにエラーログを表示し何か記録が残っていないか確認をしてみてください。

$ sudo tail /var/log/httpd/error_log

「get.php」が正常に動作している場合は、HTMLかJavaScriptに問題があるかもしれません。Webブラウザの「開発ツール」のConsoleを開きエラーが表示されていないか確認してみてください。

GitHubにpushする

リポジトリを作成

GitHub上にリポジトリを作成します。

GitHubにログインしたら新しくリポジトリを作成する画面へ移動します。以下は入力例です。

作成すると以下のような画面が表示されますので、この画面は閉じずにこのまま残しておきます。

画面上部のタブで「HTTPS」を選択しておいてください。

ローカルの設定をする

まず最初に先ほどのリポジトリと関連付けたいディレクトリに移動し、ここをGitのディレクトリとして初期化します。

$ cd /var/www/html/counter
$ git init

ls -laコマンドを実行し、.gitという隠しディレクトリが作成されていれば成功しています。

$ ls -la 
合計 12
drwxrwxr-x  3 neec neec   81  67 23:56 .
drwxr-xrwx. 3 root root   21  67 22:12 ..
drwxrwxr-x  7 neec neec  119  67 23:56 .git
-rw-rw-r--  1 neec neec    0  67 23:10 app.js
-rw-rw-rw-  1 neec neec    1  67 23:24 data.txt
-rw-rw-r--  1 neec neec 1144  67 22:41 get.php
-rw-rw-r--  1 neec neec 1373  67 22:57 index.html

コミットする

現在のファイルの内容をステージに登録後、コミットします。

まずは現在の状況を確認します。git statusを実行すると、Gitの管理下に無いファイル(Untracked files)として、今回作成した4つのファイルが表示されています。

$ git status
On branch master

No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be committed)

    app.js
    data.txt
    get.php
    index.html

ではステージに登録し、もう一度git statusしてみます。表示変わったのがわかりますね。なおこの場合はgit add .としても同じ結果が得られます。

$ git add app.js data.txt get.php index.html
$ git status
On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

    new file:   app.js
    new file:   data.txt
    new file:   get.php
    new file:   index.html

最後に現在のステージの内容でコミットしましょう。

$ git commit -m '1st commit'

pushする

先ほどcommitした内容はまだローカルにしかありません。パソコンが吹っ飛ぶとデータも消えてなくなってしまいますので、最終的にGitHubへ送信してやります。

最初に1回だけどこにpushすれば良いのか定義する必要があります。リポジトリ作成後に表示されたページにあった以下のようなコマンドを実行します。

$ git remote add origin https://github.com/katsube/counter.git

では最後にgit pushしましょう。最初にGitHubのユーザー名とパスワードを聞かれるので入力します。

$ git push
Username for 'https://github.com': katsube
Password for 'https://katsube@github.com': 

Counting objects: 6, done.
Delta compression using up to 3 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (6/6), 1.66 KiB | 1.66 MiB/s, done.
Total 6 (delta 0), reused 0 (delta 0)
To https://github.com/katsube/counter.git
 * [new branch]      master -> master

push後にGitHubのページを再読み込みしてみましょう。先ほどのファイルが確認できたでしょうか。

続き

blog.katsubemakito.net

参考ページ