リファラーからページごとの滞在時間を計算して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));

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

tracking code取得画面を作成する

初期画面

<?php if($_GET&#91;"tracking"&#93; == 'tracking-code'): ?>
  hoge
<?php else: ?>
<?php endif; ?>

クリックするとコピーする機能を付けたい。
onclick=”this.select(0,this.value.length)”と書くと、クリックで全選択できる。

<?php if($_GET&#91;"tracking"&#93; == 'tracking-code'): ?>
  <b>サイトタグ(デモ)</b><br>
  これは、サイトのユニバーサルアナリティクストラッキングコードです。このプロパティ(アナリティクストラッキングコード)を最大限に活用できるよう、このコードをコピーして、トラッキングする全てのページのbodyタグの前に貼り付けてください。<br>
  ntag.jsは、サイト測定、コンバージョン トラッキング、リマーケティング サービス用のウェブのタグ付けライブラリです。ntag.jsを使用すると、タグの管理や実装が容易になり、公開される最新の動的な機能や統合のメリットをすぐに活用することができます。<br><br>
  <textarea name="tracking-code" rows="13" cols="75" onclick="this.select(0,this.value.length)">
  <script type="text/javascript">
    var a = [['acount','007'],["ip","<?php echo $_SERVER&#91;'REMOTE_ADDR'&#93;; ?>"]];
    var b =['https://ajax.googleapis.com/ajax/libs/jquery/3.0.0/jquery.min.js', 'na.js'];
    var i = 0;
    (function appendScript(){
        var script = document.createElement('script');
        script.src = b[i];
        document.body.appendChild(script);
        if(i++ < 2){
            script.onload = appendScript;
        }
    })();
</script>
</textarea><br><br>
The Site Tag provides streamlined tagging across site measurement, conversion tracking, and remarketing products – giving you better control while making implementation easier. By using ntag.js, you will be able to benefit from the latest dynamic features and integrations as they become available.

よく見たら、echo $_SERVER[‘REMOTE_ADDR’];が上手くいってない。

htmlspecialcharでエスケープします。

<?php 
$hoge = '<?php echo $_SERVER&#91;\'REMOTE_ADDR\'&#93;; ?>';
?>
<?php echo htmlspecialchars($hoge);?>

修正しました。

問題はこっからどうするかだな。。
GAでよく見るのはページごとのavg timeと、リファラーがOrganic・social・directか、あたりの指標なので、そこをチャレンジしたい。

ipアドレスに対応するホスト名を取得する

google.comのhost名をgethostbyaddrを使うと、

$url = "www.google.com";
$ip = "172.217.161.196";
$host = gethostbyaddr($ip);
echo $host;

きたー、ラリー・ページの10^100
なんか知らんが嬉しいね

www.nttdocomo.co.jp
ip:163.49.61.185
gethostbyaddr:185.61.49.163.static.iijgio.jp
え、iij使ってるの?

www.fsa.go.jp
ip:151.101.101.14
gethostbyaddr:151.101.101.14
金融庁、財務省、などはgethostbyaddrでipしか表示されない。

rakuten->deploy.static.akamaitechnologies.com
nttdata(184.27.113.234)->a184-27-113-234.deploy.static.akamaitechnologies.com
ん?どういうこと、これ?akamaitechnologiesってそんなにいいの?

gaだと、service providerは細かく表示されているので、恐らくプロバイダーのデータベースを持ってると思うんだが、、

あれ?
GeoIP ISP Edition
https://www.maxmind.com/ja/geoip2-isp-database
やっぱり。。しかしip周りの領域は、なにかとmaxmindと被るな。

service providerは、DBないとかなりキツイな~、というか関数自作は無理がある。。
ので、

$ip = "192.168.33.1";
$host = gethostbyaddr($ip);
if($host == $ip){
    $gethost = "(not set)";
} else {
    $gethost = $host;
}
echo $gethost;

よしよしよし

次は画面サイズ(screen resolution)
これはjsでいけると思います。

ユーザーのosを取得する

<script src="platformjs/platform.js"></script>
<script type="text/javascript">
    document.write(platform.name + "<br>");
    document.write(platform.version + "<br>");
    document.write(platform.os + "<br>");
</script>

うーん、gaだと、windowsまでだが、osのバージョンまで出てしまう。。。

consoleでみると、jsonのfamilyで入っているので、

<script src="platformjs/platform.js"></script>
<script type="text/javascript">
    // document.write(platform.name + "<br>");
    // document.write(platform.version + "<br>");
    document.write(platform.os['family'] + "<br>");
</script>

芸が細かいな。。

$.getScript("../platformjs/platform.js", function(){
  a.push(['browser',platform.name]);
  a.push(['os',platform.os['family']]);
});

ほい!

最後は謎の”service provider”
geoip_isp_by_nameは動かない。。

プロバイダ:インターネットへの接続サービスを提供する事業者。
->ゲートウェイ?

どうやらgethostbyaddr($ip);っぽいですな。

jqueryでjsの中でplatform.jsを読み込む

na.jsはjqueryを読み込んでいるので、GETリクエストでplatform.jsを読み込みコールバック関数で実行

$.getScript("../platformjs/platform.js", function(){
  a.push(['browser',platform.name]);
});

chromeを取得できてますね。

ieだと、ブラウザ情報がIEになってます。

mongoDBにも、”browser” : “IE”で入ってます! OKOK!

{ "_id" : ObjectId("5ae48224e13823435337fd94"), "date" : "2018-04-28 23:16:04", "ip" : "192.168.33.1", "cookie" : "y28mw6ppl3", "visit" : "New User", "referrer" : "", "session" : "y28mw6ppl3", "page" : "/wwwroot/view.php", "browser" : "IE", "continent" : "Asia", "contry" : "Japan", "city" : "Komagatani" }

そのままの勢いでviewも作ります。
良し!Nice!

次はOS

platform.jsでbrowser情報を取得する

platform.js
https://github.com/bestiejs/platform.js

作った方
John-David Dalton
JavaScript tinkerer, bug fixer, & benchmark runner • Creator of Lodash • Former Chakra Perf PM • Current Web Platform DX PM @Microsoft

出たー、@Microsoft!
またかよ、このパターン。。。

それはさておき、git cloneします。

[vagrant@localhost cookie]$ git clone https://github.com/bestiejs/platform.js.git
Cloning into 'platform.js'...
remote: Counting objects: 2138, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 2138 (delta 2), reused 1 (delta 1), pack-reused 2135
Receiving objects: 100% (2138/2138), 3.69 MiB | 880.00 KiB/s, done.
Resolving deltas: 100% (1276/1276), done.
Checking connectivity... done.

入りました。

早速使ってみます。

<script src="platformjs/platform.js"></script>
<script type="text/javascript">
    document.write(platform.name + "<br>");
    document.write(platform.version + "<br>");
</script>

これこれ、求めてたの!

IEで見てみると、

素晴らしい!

ついでに、platform.jsの中身もざっと見てみます。このへんで、labelingしてます。

/* Detectable browser names (order is important). */
    var name = getName([
      'Adobe AIR',
      'Arora',
      'Avant Browser',
      'Breach',
      'Camino',
      'Electron',
      'Epiphany',
      'Fennec',
      'Flock',
      'Galeon',
      'GreenBrowser',
      'iCab',
      'Iceweasel',
      'K-Meleon',
      'Konqueror',
      'Lunascape',
      'Maxthon',
      { 'label': 'Microsoft Edge', 'pattern': 'Edge' },
      'Midori',
      'Nook Browser',
      'PaleMoon',
      'PhantomJS',
      'Raven',
      'Rekonq',
      'RockMelt',
      { 'label': 'Samsung Internet', 'pattern': 'SamsungBrowser' },
      'SeaMonkey',
      { 'label': 'Silk', 'pattern': '(?:Cloud9|Silk-Accelerated)' },
      'Sleipnir',
      'SlimBrowser',
      { 'label': 'SRWare Iron', 'pattern': 'Iron' },
      'Sunrise',
      'Swiftfox',
      'Waterfox',
      'WebPositive',
      'Opera Mini',
      { 'label': 'Opera Mini', 'pattern': 'OPiOS' },
      'Opera',
      { 'label': 'Opera', 'pattern': 'OPR' },
      'Chrome',
      { 'label': 'Chrome Mobile', 'pattern': '(?:CriOS|CrMo)' },
      { 'label': 'Firefox', 'pattern': '(?:Firefox|Minefield)' },
      { 'label': 'Firefox for iOS', 'pattern': 'FxiOS' },
      { 'label': 'IE', 'pattern': 'IEMobile' },
      { 'label': 'IE', 'pattern': 'MSIE' },
      'Safari'
    ]);

line79-81に以下のように書かれています。
// Platform tokens are defined at:
// http://msdn.microsoft.com/en-us/library/ms537503(VS.85).aspx
// http://web.archive.org/web/20081122053950/http://msdn.microsoft.com/en-us/library/ms537503(VS.85).aspx

これまた凄いな、ホントに。
http://msdn.microsoft.com/en-us/library/ms537503(VS.85).aspx

jsでbrowser情報を取得する

<script type="text/javascript">
    document.write(navigator.appCodeName + "<br>");
    document.write(navigator.appName + "<br>");
    document.write(navigator.appVersion + "<br>");
    document.write(navigator.platform + "<br>");
    document.write(navigator.userAgent + "<br>");
</script>

chromeで見てるから、chromeと出力させたいんだが、何故mozilla、Netscapeなんだ????
仕組みが分からん。

ipの地域をtableで表示する

getパラメーターの値で表示を切り替えます。

<table>
      <?php if($_GET&#91;"selectedDimension"&#93; == 'continent'): ?>
      <th>Continent</th><th>Users</th>
      <?php
        $i = 0;
        foreach($c1 as $key => $value){
          if($i < 10){
            echo "<tr>";
            echo "<td>".$key."</td><td>".$value."</td>";
            echo "</tr>";
          }
          $i++;    
        }
      ?>
      </table>
      <?php elseif($_GET&#91;"selectedDimension"&#93; == 'country'): ?>
      <th>Country</th><th>Users</th>
      <?php
        $i = 0;
        foreach($c2 as $key => $value){
          if($i < 10){
            echo "<tr>";
            echo "<td>".$key."</td><td>".$value."</td>";
            echo "</tr>";
          }
          $i++;    
        }
      ?>
      </table>
      <?php elseif($_GET&#91;"selectedDimension"&#93; == 'city'): ?>
      <th>City</th><th>Users</th>
      <?php
        $i = 0;
        foreach($c3 as $key => $value){
          if($i < 10){
            echo "<tr>";
            echo "<td>".$key."</td><td>".$value."</td>";
            echo "</tr>";
          }
          $i++;    
        }
      ?>
      </table>
      <?php else: ?>
      <th>Page</th><th>PageView</th>
      <?php
        $i = 0;
        foreach($data as $key => $value){
          if($i < 10){
            echo "<tr>";
            echo "<td>".$key."</td><td>".$value."</td>";
            echo "</tr>";
          }
          $i++;    
        }
      ?>
      </table>
      <?php endif; ?>

continent

country

city

一人デバックしてるなー
というか、これ、ページビュー単位ではなくて、cookie単位しないと駄目だ
うおおおおおおお、結構複雑だ

cookieに重複がない場合だけ、ipの地域を取得するに変更
foreachの前で$cookie=array();と宣言します。

$cookie = array();
foreach ($cursor as $document) {
  $pv[] = $document->date;
  if(!in_array($document->cookie, $cookie)){
    if(!is_null($document->continent)){
    $c1[] = $document->continent;
    }
    if(!is_null($document->contry)){
    $c2[] = $document->contry;
    }
    if(!is_null($document->city)){
    $c3[] = $document->city;
    }
  }
  $cookie[] = $document->cookie;
  $session[] = $document->session;
  if(!is_null($document->referrer)){
  $avgtime[] = $document->avgtime;
  }
  if(!is_null($document->referrer)){
  $referrer[] = $document->referrer;
  }
  $visit[] = $document->visit;
  $access[] = substr($document->date, 11, 2);
  $page[] = $document->page;    
}

continent, country, cityがuniqueになりました。
よっしゃ、ip周りはOKそう。

次は、browser, os, service provider
これ、js、phpでとれるんか?
取れなければ、スキップとしたい。が、GAでは必ず見る項目ではある。。