Cookie規制とは

## Cookieとは
Cookieとはサイトに訪れたユーザ情報を一時的にユーザのブラウザに保存する仕組み
サイト分析、広告配信などのトラッキング技術に利用されるほか、ID、パスワード、メールアドレス、訪問回数などユーザ情報として保存するためにも活用される

## 企業視点でのCookie利用例
– 自社サイトを訪問した人にCookieを付与し、その対象者に向けてリターゲティング広告を配信
– ユーザが最終的にコンバージョンに至るまでの過程でどのような行動履歴を取ったのかアトリビューション計測をする

### 1st party cookieと3rd party cookie
1st Party Cookie: サイトの運営者が発行しているCookie
3rd party cookie: 第三者が発行しているCookie
=> 複数のサイトを横断して閲覧した履歴を追跡していくために使われており、その情報を様々なデータと紐付けて活用されている。
=> プライバシーの観点で問題視されている
=> 日本でも改正個人情報保護法が施行され、Cookieなどの個人情報を第三者に提供し個人情報紐付けを行う場合は本人の同意が必要になった

### Apple社の対応
Safari内で3rd party cookieを利用したユーザの行動データの収集を規制、完全にブロックされている
=> リターゲティング広告が利用できない
=> コンバージョン・アトリビューション計測精度の低下(最初の訪問から数日経ってからのコンバージョンはCookie情報がなくなってしまう)

### Google社
3rd party cookieを利用したユーザの行動データの収集を2024年後半に段階的に廃止する

What is cookie?

A cookie is information stored in smartphone or PC from the website you are viewing. There are various contents such as the data and time of visiting the site, the number of visits, etc are recorded there.

So why does the website need to store information?

Cookie
Thanks to cookies to be able to see the website comfortably. For example, if you access a site once logged in by entering ID and password, such as Facebook or Twitter, after a while, you can go in without having to enter ID and password. This is thanks to the cookie where the login information is stored.

Or, while you are shopping at a shopping site, you log out with the item in the cart. After a while, if you access the same shopping site again, the items in the cart will not disappear and remain firmly. This is thanks to the cookie which stored the cart information.

In this way, cookie are extremely helpful in making the access and operation of the Web convenient, and enabling the provision of various services. Actually, if you do not enable cookies, inconvenience arises that websites are not displayed properly or you can not shop. Many of internet banking can not be used unless cookies are enabled.

Also, with cookies, websites can learn shopping history, user interests and topics, so they are also heavily used in corporate marketing analysis.

ページごとのユニークなユーザー数(cookie単位)を取得する

cookieとpageを文字列で連結して、array_uniqueでcookieとpage完全一致の重複を削除して、そこからsubstrでurlのみ切り抜いて、array_count_valuesする。
※最初、cookieとpageで連想配列をつくって、そこから、連想配列のvalueの重複削除しようとしたが、何度やってもうまくいかず、これ考えるのに、4~5時間くらいかかった。。。

foreach ($cursor as $document) {
  if(!is_null($document->referrer) and $document->referrer != ""){
  $referrer = $document->referrer;
  $avgtime = $document->avgtime;
  $data1[] = array($referrer=>$avgtime); 
  }
  $page[] = $document->page;

  $a = $document->cookie;
  $b = $document->page;
  $data2[] = $a.$b;
}

$unique = array_values(array_unique($data2));
foreach($unique as $value){
    $urls[] = substr($value, 10);
}
$urls = array_count_values($urls);
arsort($urls);
var_dump($urls);

よしよしよし

繋げると

viewに反映

次は鬼門のリファラー関係
1.document.referrer でどれだけ取れるか
2.ga.js・twitterのsessionがどうやって定義しているか参考にする
3.vagrantだけでなく、実ドメインからのリンクでテストしながらつくる
->GAのようにorganic searchの検索ワードは抽出できないので、代替案を考える

リファラーからページごとの滞在時間を計算してPVと一緒に表示する

array_merge_recursiveでPVの配列と平均滞在時間の配列同士を結合させて、tableで表示する。

<?php 

$date1 = date("Y-m-d", strtotime("-10 day"));
  $date2 = date("Y-m-d H:i:s");

$mng = new MongoDB\Driver\Manager("mongodb://localhost:27017");
$filter =  &#91;
    'date' => [ '$gte' => $date1, '$lte' => $date2]
];
$options = [
  'projection' => ['_id' => 0],
  'sort' => ['_id' => -1],
];
$query = new MongoDB\Driver\Query($filter, $options);
$cursor = $mng->executeQuery('app.na007', $query);

foreach ($cursor as $document) {
  if(!is_null($document->referrer) and $document->referrer != ""){
  $referrer = $document->referrer;
  $avgtime = $document->avgtime;
  $data[] = array($referrer=>$avgtime); 
  }
  $page[] = $document->page;   
}
// var_dump($data);

function arraySum(array $arr)
{
    $res = [];
    if (is_array($arr)) {
        foreach ($arr as $val) {
            foreach ($val as $k => $v) {
                if (isset($res[$k])) {
                    $res[$k] = (double)($res[$k] + $v)/2;
                } else {
                    $res[$k] = (double)$v;
                }
            }
        }
    }
    return $res;
}
$data = arraySum($data);
// var_dump(arraySum($data));
$page = array_count_values($page);
// var_dump($page);
$newdata = (array_merge_recursive($page, $data));
arsort($newdata);
print_r("<pre>");
var_dump($newdata);
print_r("</pre>");
function s2h($avgtime){
  $hours = floor($avgtime / 3600);
  $minutes = floor(($avgtime / 60)%60);
  $seconds = $avgtime % 60;
  $hms = sprintf("%02d:%02d:%02d", $hours, $minutes, $seconds);
  return $hms; 
}
?>
<table>
<th>Page</th><th>PageView</th><th>Avg time</th>
      <?php
        $i = 0;
        foreach($newdata as $key => $value){
          if($i < 10 and !is_null($value&#91;1&#93;)){
            echo "<tr>";
            echo "<td>".$key."</td><td>".$value[0]."</td><td>".s2h($value[1])."</td>";
            echo "</tr>";
          } else {
            echo "<tr>";
            echo "<td>".$key."</td><td>".$value."</td><td>00:00:00</td>";
            echo "</tr>";
          }
          $i++;    
        }
      ?>
</table>

あ、ページごとのユニークなユーザー数もカウントしたくなってきた(笑)

リファラーの平均滞在時間を算出する

foreachでkeyにvalueを入れる際に、すでにvalue1があれば、(value1 + value2)/2とすれば、valueの平均が算出されるので、それをforeachで回せばよい。
具体的には、$res[$k] = ($res[$k] + $v)/2; のところ。

foreach ($cursor as $document) {
  if(!is_null($document->referrer) and $document->referrer != ""){
  $referrer = $document->referrer;
  $avgtime = $document->avgtime;
  $data[] = array($referrer=>$avgtime); 
  }  
}
var_dump($data);

function arraySum(array $arr)
{
    $res = [];
    if (is_array($arr)) {
        foreach ($arr as $val) {
            foreach ($val as $k => $v) {
                if (isset($res[$k])) {
                    $res[$k] = ($res[$k] + $v)/2;
                } else {
                    $res[$k] = $v;
                }
            }
        }
    }
    return $res;
}
var_dump(arraySum($data));

リファラーがある場合の各ページの平均滞在時間

新規ユーザーとリターンユーザーを表示する

$visit = json_encode(array_count_values($visit))を配列で渡して、
chart.jsで表示する。

  var visit = JSON.parse('<?php echo $visit; ?>');
  console.log(visit);
  var ctx = document.getElementById("myChart").getContext('2d');
  var myChart = new Chart(ctx, {
  type: 'pie',
  data: {
    labels: ["New", "Returned"],
    datasets: [{
      backgroundColor: [
        "#2ecc71",
        "#3498db",
      ],
      data: [visit['New User'],visit['Returned User']]
    }]
  }
});

ここまではそんなに難しくないんだが、次が問題。
(1)時間ごと、もしくは(2)日付ごとのアクセスを棒グラフで表示する。
まず分けて考えよう。

1.時間ごとの場合
->chart.jsのラベルは24時間
->訪問時間 y:m:d h:m:s の該当するhの数をcountしてjsonにencodeする

2.日付ごとの場合
->ラベルは期間の日付
->訪問時間 y:m:d h:m:s の該当するy:m:dの数をcountしてjsonにencodeする

ややこしいので、時間から作る。

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)に渡すところですね。

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}}}

よーわからんぞ。