今だからこそ作る、Laravelで「アクセスカウンター」

by

Kazuya Takei

on

2019-02-16

in

Laravel JP Conference 2019

Who am I?

Kazuya Takei

../_images/icon-attakei.jpg
  • NIJIBOX Co., Ltd.

    • 昔 PHPでWebサービス系

    • 今 Pythonでインフラ寄り

  • Pythonista

    • Errbotプラグイン/Errcron

    • Ansibleロール

    • sphinx-revealjs

  • @attakei

出オチ

あなたは、このスライドの COUNTER_IMAGE 番目の閲覧者です。

アクセスカウンター

どんなものだっけ?

  • ホームページにアクセスしたときに出てくる、「何人目に訪れたか」がわかるカウンター

    • サイトの人気具合を図る「スカウター」の一種

    • たまに壊れる

    • 「キリ番」「踏み逃げ」という文化

  • アクセス解析の機能がついていたりも

ぶっちゃけ

「旧世代の風物詩」感ありますね (要出展)

ちなみに...

「忍者カウンター」サービスはいまだ現役でした

https://www.ninja.co.jp/

技術的な視点で見るアクセスカウンター

仕組みを分解してみる

リクエストに応じて、

  • 永続化されたデータストアに対して、加算を行い

  • その数値とベースの絵素材から、表示用画像を作り

  • 画像としてレスポンスを返す

仕組みを分解してみる(2)

さらにおまけで、

  • リクエストヘッダなどを元に、人を分類

    • 新規の来訪者

    • 直近の再来訪者

    • 時間経過してかららから来た人

  • 直近の再来訪者だったらカウンターの加算をせずに画像を表示

    • 場合によっては304レスポンスも?

まとめると

  • セッション情報を元にしたキャッシュ出し分けを行い

  • 多重アクセスしてもある程度正しく処理できるように、排他処理でカウンターを扱い

  • 画像を結合して、 image/xxx レスポンスを返す

  • さらに、Webサービスとして提供するのなら管理画面なども必要

...コンパクトなWebアプリってこういうことを言うのかも

Laravelで作る!

※「自分の実装」と、「探してみた歴史あるアクセスカウンタ」を元にしています

ファイル構成のBefore

※一例です


- count.php

ファイル構成のAfter

※一例です


- App/AccessCounter/
  - Counters/
    - FilesystemCounter.php
  - Http/Controllers/
    - ShowController.php
  - ImageWriters/
    - TextSVGImageWriter.php
    - GDImageWriter.php
- Tests
    - Feature/
      - AccessCounter/SessionTest.php
    - Unit/
      - AccessCounter/CounterTest.php
      - AccessCounter/WriterTest.php

データ管理のBefore

fopen , flock , fclose ,,,


// fopenでファイルを開き
$fp = fopen('count.data');
// flockで排他処理
flock($fp);

データ管理のAfter

Storage 使うのが楽。(ロックは?)


// Storageのみ
use Storage;

$data = Storage::get('count.dat');

データ管理のAfter(2)

DB も楽。( Eloquent も可)


use DB;

$data = DB::where('key', $Key)->lockForUpdate()->get();

多重カウント防止のBefore

$_SERVER['REMOTE_ADDR'] をログにとってチェックする時代もあったかな?


$logs = file('log.dat');
foreach ($logs => $log) {
    $host, $timestamp = explode(',', '$log);
    if ($host != $_SERVER['REMOTE_ADDR']) {
        continue;
    }
    if ($timestamp + 24*60*60 > time()) {
        return false;
    }
    return true;
}

多重カウント防止のAfter

session に預かってもらうのはどうでしょう?


// 略
$session = $request->session();
$count = $session->get('access_counter.count', 0);
$timestamp = $session->get('access_counter.timestamp', 0);
if ($timestamp + 24*60*60 > time()) {
    return $count;
}
$count = $couner->increment();
return $count;

カウンター表現のBefore

image関数にお任せ


// 実コード略
// 0.gif 〜 9.gif とかありましたね

カウンター表現のAfter

SVGというものがありまして。。。

ただし、デザイン力が足りないと辛い


$dom = new \DOMDocument();
$svg = $dom->createElement('svg');
// svgタグの属性足す
$text = $dom->createElement('text', $this->text);
// textタグの属性足す
$svg->appendChild($text);
$dom->appendChild($svg);
return $dom;

結論

アクセスカウンターはWebアプリ

温故知新、楽しい

以上

ご清聴ありがとうございました