Skip to content

Instantly share code, notes, and snippets.

@AKB428
Last active August 29, 2015 14:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AKB428/0bf590ddc33267b20ff2 to your computer and use it in GitHub Desktop.
Save AKB428/0bf590ddc33267b20ff2 to your computer and use it in GitHub Desktop.
[Mastering DMP] 01

第1章 3rd Party Cookieでピクセル トラッキングサーバーを作る

1x1ピクセルの透明Gifを返却するコントローラーを作る

app/controllers/MicroDmpCore.java

package controllers;

import play.mvc.Controller;
import play.mvc.Result;
import views.html.index;
import java.security.MessageDigest;
// Java8 lib
import java.util.Base64;

public class MicroDmpCore extends Controller {

    private static final String COOKIE_KEY = "COOKIE_ID_3RD";
    private static final int COOKIE_MAX_AFTER_AGE = 31622400 + 31622400; // 2 year

    //ref https://css-tricks.com/snippets/html/base64-encode-of-1x1px-transparent-gif/
    private static final String onePixelGifBase64 = "R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
    public static byte [] onePixcelGifBytes = Base64.getDecoder().decode(onePixelGifBase64);

    public Result index() {
        return ok(index.render("Your new application is ready."));
    }

    // pixcel tracking
    // ref https://support.google.com/dfp_premium/answer/1347585?hl=ja
    public Result pixcelTracking() {

        //generateCookieId();

        response().setContentType("image/gif");
        return ok(onePixcelGifBytes);
    }

}

conf/routes

GET        /1.gif               controllers.MicroDmpCore.pixcelTracking()

CookiID生成ロジックを加える

app/controllers/MicroDmpCore.java

package controllers;

import play.mvc.*;
import play.Logger;
import views.html.index;
// Java8 lib
import java.util.Base64;


import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class MicroDmpCore extends Controller {

    // COOKIEはドメインごとに区別されるのでここではMDMPなどフレームワークの固有名詞は不要
    private static final String COOKIE_ID_KEY = "COOKIE_ID_3RD";

    // Cookieの有効期限は1年間にしておく(対象のサービスに1年間はアクセスしなくてもオーディエンスとして扱う)
    private static final int COOKIE_MAX_AFTER_AGE = 31622400;

    //ref https://css-tricks.com/snippets/html/base64-encode-of-1x1px-transparent-gif/
    private static final String onePixelGifBase64 = "R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";

    // Base64はJava8からのメソッドなので注意
    public static byte [] onePixcelGifBytes = Base64.getDecoder().decode(onePixelGifBase64);

    public static String macAdress = getMacAddress();

    public Result index() {
        return ok(index.render("Your new application is ready."));
    }

    // pixcel tracking
    // ref https://support.google.com/dfp_premium/answer/1347585?hl=ja
    public Result pixcelTracking() {

        processingCookieId();

        response().setContentType("image/gif");
        return ok(onePixcelGifBytes);
    }


    /**
     * CookieIDの処理を行う
     * CookieIDがあれば有効期限を更新
     * CookieIDがなければCokkieIDを発行し設定
     *
     * @return false=Cookie発行済み true=Cookie新規発行
     */
    private static void processingCookieId() {

        //name() まで呼ぶとnullpoになる
        if(request().cookie(COOKIE_ID_KEY) != null) {
            Http.Cookie cookie = request().cookie(COOKIE_ID_KEY);
            Logger.debug("Cookie Exist!");
            Logger.debug(cookie.value());
            response().setCookie(COOKIE_ID_KEY, cookie.value(), COOKIE_MAX_AFTER_AGE);
            return;
        }
        // IDがなかったらID生成

        /*
        public void setCookie(String name, String value);
        public void setCookie(String name, String value, Integer maxAge);
        public void setCookie(String name, String value, Integer maxAge, String path);
        public void setCookie(String name, String value, Integer maxAge, String path, String domain);
        public void setCookie(String name, String value, Integer maxAge, String path, String domain, boolean secure, boolean httpOnly);
         */

        response().setCookie(COOKIE_ID_KEY, generateUniqueId(), COOKIE_MAX_AFTER_AGE);
        return;
    }

    /**
     * ミリセカンド、ナノセカンド、MACアドレスを使用してユニークなCookieIDを生成する
     *
     * @return CookieID(SHA256のHEX)
     */
    private static String generateUniqueId() {
        StringBuffer id = new StringBuffer();

        // 1/1000秒まで
        long now = System.currentTimeMillis();
        long nano = System.nanoTime();

        // TODO ちゃんとやるなら乱数生成などユニーク精度を高めるロジックを入れる
        String baseString = String.valueOf(now) + " " + String.valueOf(nano) + " " + macAdress;
        Logger.debug(baseString);

        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            md.update(baseString.getBytes());
            byte[] digest = md.digest();

            for (int i = 0; i < digest.length; i++) {
                id.append(String.format("%02x", digest[i]));
            }
            Logger.debug(id.toString());
        }
        catch (NoSuchAlgorithmException e) {
            //TODO
        }
        return id.toString();
    }


    /**
     * MACアドレスを取得する
     * 複数のマシンでこのAPサーバーを動かした時にCOOKIE_IDをユニークにするためサーバーのMACアドレスを使用する
     * 複数のマシン間でMACアドレスが異なることが保証されている時にこのメソッドを使用する。
     * クラウド環境や仮想ネットワークインターフェースだとMACアドレスが同じになる可能性があるので注意。
     *
     * @return 動作マシンのMACアドレスを文字列化したもの
     */
    public static String getMacAddress() {
        String macAdress = "";
        Enumeration<NetworkInterface> nic = null;
        try {
            nic = NetworkInterface.getNetworkInterfaces();

            for (; nic.hasMoreElements(); ) {
                NetworkInterface n = nic.nextElement();
                Logger.debug(n.getName());
                Logger.debug(n.getDisplayName());
                byte [] b = n.getHardwareAddress();
                if (b == null) continue;
                String singleIfAdress = "";
                for(int i=0;i<b.length;i++) {
                    singleIfAdress+=String.format("%02x", b[i]);
                }
                Logger.debug(singleIfAdress);
                macAdress+=singleIfAdress;
            }
        }
        catch (SocketException e) {
            // TODO
        }
        return macAdress;
    }

}

実際にブラウザでアクセスしてクッキーの挙動を確認してみよう。

http://localhost:9000/1.gif

1回目アクセス

[debug] - application - 1436078889266 1436078889266601000 ce49563823e3b8e856092ab6
[debug] - application - f17de9bdf0284818c99cbadbb03a2fa8e89e0c5f660a6e603a74fd4740e83540

2回目アクセス

[debug] - application - Cookie Exist!
[debug] - application - f17de9bdf0284818c99cbadbb03a2fa8e89e0c5f660a6e603a74fd4740e83540

EditCookieでクッキーを消したりして挙動を何度か確認してみよう。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment