cookie, session情報をajaxでpostする

viewから呼び込んだjsで、cookie, session情報を配列にpushして、ajaxでサーバー側にpostします。
na.js

var unix = Math.floor((new Date).getTime()/1E3);
var visit = "New User";
if(navigator.cookieEnabled){
    var all=document.cookie + ";";
    var cStart = all.indexOf("_na=",0);
    if(cStart == -1){   
        var char = "abcdefghijklmnopqrstuvwxyz123456789";
        var id = "";
        for(var i=0; i<10; i++){
            id += char[Math.floor(Math.random()*35)];
        }
        var expire = new Date();
        expire.setTime(expire.getTime() + 1000*3600*24*365*2);
        document.cookie="_na=NA1."+id+"."+unix+";expires=" + expire.toUTCString();
        a.push(['vist',visit]);
        a.push(['referrer',document.referrer]);
    } else {
        visit = "Returned User";
        a.push(['visit',visit]);
        var c = window.sessionStorage.getItem(['ScribeTransport']);
        if(c){
            d = JSON.parse(c);
            a.push(['referrer',d.path]);
            a.push(['滞在時間',(unix - d.time)]);        
        }       
    }
}
var data = '{"path":"'+location.pathname+'", "time":"'+unix+'"}';
window.sessionStorage.setItem(['ScribeTransport'],[data]);

a.push(['host',location.host]);
$(function(){
    $(document).ready(function(){
            var postData = {"userdata": a};
            $.post(
                "doubleclick.php",
                 postData,
                 function(data){
                    $(".box").html(data);
                }
            );
        });
});

doubleclick.php
$_POSTを受け取ります。

$date = date("Y-m-d H:i:s");
$data = $_POST['userdata'];
echo "アナリティクスアカウントID:" .$data[0][1]."<br><br>訪問時間:" .$date . "<br> ip:" .$data[1][1]."<br> user:" .$data[2][1]."<br> リファラー:".$data[3][1]."<br> 前のページでの滞在時間:".$data[4][1]."秒<br>";

ちゃんとsession, cookieがsetされ、配列がpostされました。

さあ、次は、postされたデータをどう処理してDBに格納するかですね。
analyticsのview(主にchart.jsを想定)も一緒につくりながらやった方が、効率良さそうな気がします。

sessionとcookieで閲覧開始・リファラー・滞在時間を取得する

1.cookieがsetされていればreturn user, setされていなければnew user
2.new userの場合、document.referrerで、リファラーを取得
3.cookieがsetされていれば、sessionのlocation.pathnameでリファラーを取得
4.cookieがsetされていれば、sessionのunixtimeの差でページ滞在時間を取得

var unix = Math.floor((new Date()).getTime()/1E3);
var data = '{"path":"'+location.pathname+'", "time":"'+unix+'"}';
var visit = "new user<br>";
if(navigator.cookieEnabled)
{
	var all=document.cookie + ";";
	var cStart = all.indexOf("_na=",0);
	if(cStart == -1){   
		var char = "abcdefghijklmnopqrstuvwxyz123456789";
		var id = "";
		for(var i=0; i<10; i++){
			id += char&#91;Math.floor(Math.random()*35)&#93;;
		}
		document.cookie="_na=NA1."+id+"."+unix+";";
		window.sessionStorage.setItem(&#91;'ScribeTransport'&#93;,&#91;data&#93;);
		document.write(visit);
		document.write("リファラー" + document.referrer + "<br>");
	} else {
		visit = "returned user<br>";
		document.write(visit);
		var a = window.sessionStorage.getItem(['ScribeTransport']);
		b = JSON.parse(a);
		var unix = Math.floor((new Date()).getTime()/1E3);
		document.write("リファラー" + b.path + "<br>");
		document.write("滞在時間" +(unix - b.time)+ "秒");
		window.sessionStorage.setItem(['ScribeTransport'],[data]);
	}
}else{
	window.sessionStorage.setItem(['ScribeTransport'],[data]);
}

あれ、待てよ、cookieがsetされていても、sessionがsetされていないパターンもあるな。
if(a)と書き換えます。cookieのexpireは1000*3600*24*365*2(730日)とします。

var unix = Math.floor((new Date).getTime()/1E3);
var visit = "new user<br>";
if(navigator.cookieEnabled){
	var all=document.cookie + ";";
	var cStart = all.indexOf("_na=",0);
	if(cStart == -1){   
		var char = "abcdefghijklmnopqrstuvwxyz123456789";
		var id = "";
		for(var i=0; i<10; i++){
			id += char&#91;Math.floor(Math.random()*35)&#93;;
		}
		var expire = new Date();
		expire.setTime(expire.getTime() + 1000*3600*24*365*2);
		document.cookie="_na=NA1."+id+"."+unix+";expires=" + expire.toUTCString();
		document.write(visit);
		document.write("リファラー" + document.referrer + "<br>");
	} else {
		visit = "returned user<br>";
		document.write(visit);
		var a = window.sessionStorage.getItem(['ScribeTransport']);
		if(a){
			b = JSON.parse(a);
			document.write("リファラー" + b.path + "<br>");
			document.write("滞在時間" +(unix - b.time)+ "秒");			
		}		
	}
}
var data = '{"path":"'+location.pathname+'", "time":"'+unix+'"}';
window.sessionStorage.setItem(['ScribeTransport'],[data]);

次は、このnew user・return user, リファラー, 滞在時間のデータを、サーバー側(ここではdoubleclick.php)に渡すところですね。

javascriptでsessionをget・setする

<script>
	window.sessionStorage.setItem(['ScribeTransport'],['WebData']);
</script>

pathとunix timeを入れます。

<script>
	var unix = Math.floor((new Date()).getTime()/1E3);
	var data = '{"path":"'+location.pathname+'", "time":"'+unix+'"}';
	window.sessionStorage.setItem(['ScribeTransport'],[data]);
</script>

ここまではOK

セットされたsessionを、JSON.parseで取り出す。

<script>
	var a = window.sessionStorage.getItem(['ScribeTransport']);
	b = JSON.parse(a);
	document.write(b.path);
	document.write(b.time);

	var unix = Math.floor((new Date()).getTime()/1E3);
	var data = '{"path":"'+location.pathname+'", "time":"'+unix+'"}';
	window.sessionStorage.setItem(['ScribeTransport'],[data]);
</script>

来た!

sessionから滞在時間とリファラーを抽出する

	var a = window.sessionStorage.getItem(['ScribeTransport']);
	b = JSON.parse(a);
	var unix = Math.floor((new Date()).getTime()/1E3);
	document.write("リファラー" + b.path + "<br>");
	document.write("滞在時間" +(unix - b.time)+ "秒");
	var data = '{"path":"'+location.pathname+'", "time":"'+unix+'"}';
	window.sessionStorage.setItem(['ScribeTransport'],[data]);

OKOKOK

twitterのsession処理 -init.ja.***.js

twitterで読み込まれるjsのうちの一つ、init.ja.***.jsの中でsessionがどのように処理されているかを見てみます。

https://abs.twimg.com/k/ja/init.ja.***.js
* Copyright(c) 2012-2014 Roman Shtylman -> CEO at Courseoff, Computer whisperer @ Cruise/GM. Formerly Coinbase, Courseoff, other stuff. SF.
* Copyright(c) 2015 Douglas Christopher Wilson ->Lead Software Engineer at Salesforce Marketing Cloud?

init.ja.***.js line.2
setSession, removeSession, getSessionしてますね。

function n(){
	this.setSessionItem=function(t,e){
		window.sessionStorage&&sessionStorage.setItem(t,e)
	},
	this.removeSessionItem=function(t){
		window.sessionStorage&&sessionStorage.removeItem(t)
	},
	this.getSessionItem=function(t){
		return window.sessionStorage&&sessionStorage.getItem(t)
	},
	this.setSessionObject=function(t,e){
		void 0===e?this.removeSessionItem(t):this.setSessionItem(t,JSON.stringify(e))
	},t
	his.getSessionObject=function(t){var e=this.getSessionItem(t);

tとeは

function(){var t=this.$element.text().trim();

e=t.extend({},t.fn[this.type].defaults,e,this.$element.data()),e.delay&&"number"==typeof e.delay&&(e.delay={
	show:e.delay,hide:100}),e},enter:function(n){var r=t(n.target);

sessionに入れる値は、scriptPathとunixtimeは入れたい。

twitterのsession情報の一部

{"product":"webclient","description":"stats:ajax:perf:partner_id_sync:tellapart","duration_ms":60,"start_time_ms":1523669400806,"metadata":"{\"url\":\"https://t.tellapart.com/twitterinitmatch\",\"browser\":{\"chrome\":true,\"version\":\"65.0.3325.181\",\"webkit\":true,\"name\":\"chrome\"}}","_category_":"perftown"}

やっぱり、ajaxで”https://analytics.twitter.com/”にトラッキングデータ送ってる。twitter、お前もか?

return t._evalUrl=function(e){return t.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,throws:!0})},t._evalUrl}.apply(e,n))&&(t.exports=r)},"0y9Y":function(t,e,i){"use strict";(function(t){function n(){this.defaultAttrs({tweetHashtagLinkSelector:".js-stream-tweet .twitter-hashtag, .permalink-tweet .twitter-hashtag",tweetLinkSelector:".js-stream-tweet ...

しかしなぜ、jsの中で処理せずに、jsonとしてsessionに値を入れているんだろう?

amazon・facebook・googleのsession strageを見てみよう

session storageとは?
>sessionStorage に保存されたデータはページのセッションが終了するときに消去されます。ページのセッションはブラウザを開いている限り、ページの再読み込みや復元を越えて持続します。新しいタブやウィンドウにページを開くと、新しいセッションが開始します。

なるほど、やりたいことに近いです。
続いて、各社のsession storageのkeyとvalueを見ていきましょう。

amazon.co.jpのsession storage:
CSM_previousURL
csmtid
rwolLastPage
rwolLastPageSet

CSM_previousURLとrwoLastPageのvalueはcurrent directoryのようです。
なにこれ?

facebookのsession storage:
sp_pi:{“pageInfo”:{“scriptPath”:”/”,”categoryToken”:”a6bebc6e”,”extraData”:{“imp_id”:”hogehoge”}},”clickPoint”:null,”time”:1523665957490}
うお、jsonだ。。。timeはunix timeっぽいですね。

google.co.jpのsession storage:
eob;;xpli p:m|l:14_[“4″,”2”]
_c;;i p:*|l:9007199254hogehoge_16
eob;;xplq p:m|l:15_[“google analytics 滞在時間”,”セッションとは”]
うおーーー前回の検索ワードがsessionに残ってる!

twitter.com/?lang=ja
ScribeTransport
{“internal_referer”:null,”client_version”:”macaw-swift”,”browser_name”:”chrome”,”duration_ms”:4231,”event_namespace”:{“client”:”web”,”page”:”home”,”section”:”home”,”component”:”full”,”element”:”ttft”,”action”:”ttft”},”triggered_on”:1523,”format_version”:2,”_categ..以下略
twitterもjsonでunixtimeが入っています。

あ~、facebook・twitterはunix time使ってるってことは、完全にトラッキングしてますね。amazonもトラッキングしてますね。googleに至ってはセッションに検索ワードが入ってる。なんかもー力抜けてきた。。
各社の設計から考えると、cookieとsessionの性質上、cookieはnewからreturnか判別、ページ遷移の挙動はsessionにunix time入れて取った方が良さそうですね。
要素が多いtwitterが一番参考になりそうです。

yahoo.co.jp
-> session storage empty
rakuten.co.jp
->phoenix, phoenix__rg, RJSCountDownTimer, RALRTID

ページ滞在時間とnew・return userを判定する

cookieのunix timeでページ滞在時間を計算します。

var unix = Math.floor((new Date()).getTime()/1E3);
var visit = "first visit!";
if(navigator.cookieEnabled)
{
	var all=document.cookie + ";";
	var cStart = all.indexOf("_na=",0);
	if(cStart == -1){   
		var char = "abcdefghijklmnopqrstuvwxyz123456789";
		var id = "";
		for(var i=0; i<10; i++){
			id += char&#91;Math.floor(Math.random()*35)&#93;;
		}
		document.cookie="_na=NA1."+id+"."+unix+";";
		document.write(visit);
	} else {
		visit = "returned user";
		var cEnd = all.indexOf(";",cStart);
		var cnt = all.substring(cStart,cEnd - 10); //_na=NA1.0000000000.
		document.cookie=cnt+unix+";";
		document.write("前回の滞在時間" + (unix - all.substring(cStart+19,cEnd)) + "秒<br>"); 
		document.write(visit);
	}
}else{
	document.write("cookieが使用できません。");
}

cookieのexpireとunix timeの差をどう考えるかですね。
exireをgoogleのように2年として

1.前回のcookie発行から10分以上差がある
unix – all.substring(cStart+19,cEnd) > 60 * 10
-> return userとみなす
2.前回のcookie発行から10分以内
unix – all.substring(cStart+19,cEnd) <= 60 * 10 -> ユーザのページ遷移とみなす
3.新規のcookie 発行
-> new visitor

何分滞在するかはページの性質によって変わってくるので、例えば1時間の動画のページでは、上記のロジックは機能しませんね。
するとセッションでしょうか。。
あれ、よくみたら、indexedDBに
https://googleads.doubleclick.netが入っていますね。

LocalStrageにもgoogleの値が入っています。
google_experiment_mod 602

これはadsenceのようです。

google_experiment_mod is used by Google AdSense for experimenting with which advertisement perform best on a website.

なんだこれは?
google_pub_config {“sraConfigs”:{“2”:{“sraTimeout”:60000},”4″:{“sraTimeout”:60000}}}

よーわからんぞ。

初めての訪問時はcookieにid・unixtimeを発行し2回目以降はunixtimeのみ更新

var cook;
var cStart,cEnd;
var cnt;

var unix = Math.floor((new Date()).getTime()/1E3);

if(navigator.cookieEnabled)
{
	cook=document.cookie + ";";
	console.log(cook);

	cStart = cook.indexOf("_na=",0);
	if(cStart == -1){   
		document.write("1回目の訪問です!");

		var char = "abcdefghijklmnopqrstuvwxyz123456789";
		var id = "";
		for(var i=0; i<10; i++){
			id += char[Math.floor(Math.random()*35)];
		}
		document.cookie="_na=NA."+id+"."+unix+";";
	} else {
		cEnd = cook.indexOf(";",cStart);
		cnt = cook.substring(cStart,cEnd - 10); // cStart + "_na="
		try {
			document.write(cnt);
			document.cookie=cnt+unix+";";
		} catch(e){
			document.write("訪問回数の取得に失敗しました。");
		}
	}
}else{
	document.write("cookieが使用できません。");
}

key:_na
value:NA.5ub8j1xn2p.1523632591

あれ、ブラウザを更新しても、GAのunixtimeが更新されない。。。何故だ????

javascriptでunixtimeを取得

ga.jsだと、new Date()は9か所で書かれてます。大体、new Date()と.getTime()が続けて書かれています。

+(new Date((new Date).getTime()+f)).toGMTString()+"; ")

a=Math.min(a,1E3*Be+a-(new Date).getTime());

this.set(ab,Math.round((new Date).getTime()/1E3));
this.set(y,Math.round((new Date).getTime()/1E3));
if("event"===a.get(sc)){var b=(new Date).getTime(),c=a.b(dc,0),d=a.b(Zb,0);

1E3 とは、10^3 つまり1000のようです。

ga.jsの真似をして1E3で書いてみます。

var date = Math.floor((new Date()).getTime()/1E3);
document.write(date);

おお、少しプログラミングが上達した錯覚を起こしますね。んな訳ない、桑原桑原。

javascriptでランダムな英数字10桁と数字10桁

console.time('timer1');
var char = "abcdefghijklmnopqrstuvwxyz123456789"
var id = "";
for(var i=0; i<10; i++){
	id += char[Math.floor(Math.random()*35)];
}
document.write(id);
console.timeEnd('timer1');

0.24609375ms
timer1: 0.411865234375ms ※2回目
timer1: 0.324951171875ms ※3回目

min:1000000000 ~ max 9999999999 の10桁の数字の場合

var id = Math.floor(Math.random() * 9000000000)+ 1000000000;
document.write(id);

timer1: 0.329833984375ms
timer1: 0.248779296875ms ※2回目
timer1: 0.24462890625ms ※3回目

感覚的に、1回の演算処理に較べて10回のforループを回す場合、レジストリの演算処理が10倍に増えるので、処理時間も約10倍位になるかと思いきや、計算してみるとforループでも処理時間はほとんど変わらない(2倍以下)ですね。multiplyとplusのCPUの処理はそんなに時間がかからない、ということなんでしょうか。よくわかりませんね。

cookieから何回目の訪問か判定する

<script>
var cook;
var cStart,cEnd;
var cnt;

if(navigator.cookieEnabled)
{
	cook=document.cookie + ";";
	console.log(cook);

	cStart = cook.indexOf("counts=",0);

	if(cStart == -1){   //indexOfで存在しない時は-1を返す
		document.write("1回目の訪問です!");
		document.cookie="counts=1;";
	} else {
		cEnd = cook.indexOf(";",cStart);
		cnt = cook.substring(cStart+7,cEnd); // cStart + "counts="
		try {
			cnt = parseInt(cnt)+1;
			document.write(cnt+"回目の訪問です!");

			document.cookie="counts="+cnt+";";
		} catch(e){
			document.write("訪問回数の取得に失敗しました。");
		}
	}
}else{
	document.write("cookieが使用できません。");
}

</script>

ga.jsのcookieの処理 18箇所出てきます。
出てくるのは、
_setCookiePath、_setVisitorCookieTimeout、_setSessionCookieTimeout、_setCampaignCookieTimeout、_cookiePathCopy、_setCookieTimeout、_setCookiePersistence
後半の、J.cookieは、J=documentなので、普通にdocument.cookieです。

b=n.cookie.split(";");

var Mc=N(),Nc=N(),Yb=N(),Jc=N(),Kc=N(),Lc=Va("utmtCookieName"),Cd=Va("displayFeatures"),Oc=N(),of=Va("gtmid"),Oe=Va("uaName"),Pe=Va("uaDomain"),Qe=Va("uaPath"),pf=Va("linkid"),w=N(),x=N(),y=N(),z=N();

V("_setCookiePath",P,9,0);

V("_setVisitorCookieTimeout",cb,28,1);V("_setSessionCookieTimeout",db,26,1);V("_setCampaignCookieTimeout",eb,29,1);

a("_cookiePathCopy",U.prototype.ha,30);

V("_setCookieTimeout",eb,25,3);V("_setCookiePersistence",cb,24,1);

pd=function(a){
	var b=[],c=J.cookie.split(";");
	a=new RegExp("^\\s*"+a+"=\\s*(.*?)\\s*$");
	for(var d=0;d

cookieのvalueは、"GA1.1.200404109.1517112693"とした場合、Timeoutの処理はUNIX timeで処理していそうですね。
あ、J.domain は、document.domainなので、refererのdomainが一緒だった場合は、UNIX Timeを引けば、滞在時間を求められますね。 なるほど、そういうことか。めちゃくちゃ頭いいな~、Paul Muret。閲覧開始数、直帰率は、リファラを見れば、判別できますね。
あれ、でも、同じドメインに遷移の場合はunix timeもsubstructすれば滞在時間が取得できますが、他のドメインに行ったり、ブラウザを閉じた場合、どうやってページ滞在時間を取得しているんでしょうか? 
なに~、わからん

あれ、こんな記載が。。。
>最後に訪問したページの滞在時間はGoogleアナリティクスが測定できないという注意点があるので気を付けましょう。
なるほど、やっぱりそうか!なぜ、cookieにunixtime入れてるのか完全に理解した!

ユーザー固有の ID:200404109 は何でしょうか?
あれ、もしかして、このユーザー(ID:200404109)が1回のセッションでどういうページ遷移をしたかを判別しているために発行しているのでは?
おお、少し仕組みが判ってきた~