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を想定)も一緒につくりながらやった方が、効率良さそうな気がします。

計測タグを発行して、そのページのアクセス情報をajaxでpostする

Google Analyticsの挙動と比較しやすいように、view.php, na.js, doubleclick.php の3つのファイルを用意します。view.php はタグを埋め込むhtmlファイル、na.jsはview.phpの情報を読み込んで処理しdoubleclick.phpに情報を渡す、doubleclick.phpはna.jsから送られた情報を受け取るサーバー側の処理。

まず、view.php
var objにアカウントidを入れて、ajaxとna.jsを読み込みます。
ここでは仮で id = 007 とします。

<style>
.box{
    width:400px;
    height: 400px;
    background-color:#ddd;
}
</style>
<body>
    <div class="box"></div>
</body>
<script type="text/javascript">
    var obj = obj || [];
    obj.push(['id','007']);
    var scripts =['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 = scripts[i];
        document.body.appendChild(script);
        if(i++ < 2){
            script.onload = appendScript;
        }
    })();
</script>

na.js
var objに、ユーザー情報を追加して、doubleclick.phpにdataをpostします。

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

doulbeclick.php
na.jsから送られてきた配列を$_POSTで受け取ります。

 
$data = $_POST['userdata'];
var_dump($data);

うお!やばい

少し加工すると、タグを埋め込んだページに

ああ、そうか、setCookieをして、ユーザーが最初の訪問か、return userかを判別しているんですね。なるほど♪

google analyticsをつくろう

まず、tableをつくります。

create table cookie.analytics(
	host varchar(255),
	host_name varchar(255),
	port varchar(255),
	request varchar(255),
	code varchar(255),
	browser varchar(255),
	version varchar(255),
	platform varchar(255),
	useragent varchar(255),
	referer varchar(255),
	domain varchar(255),
	screen_w varchar(255),
	screen_h varchar(255),
	ip varchar(255),
	access datetime
);

次に、ajaxで、アクセスがあったらデータをpostします。

<style>
.box{
    width:200px;
    height: 200px;
    background-color:#ddd;
}
</style>
<body>
    <div class="box"></div>
    <button id="ajax-button">送信</button>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script>
</body>
<script>
$(function(){
    $(document).ready(function(){
            var postData = {"HOST": location.host,
                "HOST_NAME":location.hostname,
                "PORT": location.port,
                "REQUEST":location.pathname,
                "CODE": navigator.appCodeName,
                "BROWSER":navigator.appName,
                "VERSION": navigator.appVersion,
                "PLATFORM":navigator.platform,
                "USERAGENT": navigator.userAgent,
                "REFERER": document.referrer,
                "DOMAIN": document.domain,
                "SCREENW":screen.width,
                "SCREENH": screen.height,
                "IP":"<?php echo $_SERVER&#91;'REMOTE_ADDR'&#93;; ?>"};
            $.post(
                "test1.php",
                 postData,
            );
        });
});
</script>

ajaxで送られてきたデータをdbに格納します。

$date = date("Y-m-d H:i:s");
$host = $_POST['HOST'];
$host_name = $_POST['HOST_NAME']; 
$port = $_POST['PORT']; 
$request = $_POST['REQUEST']; 
$code = $_POST['CODE']; 
$browser = $_POST['BROWSER']; 
$version = $_POST['VERSION']; 
$platform = $_POST['PLATFORM']; 
$useragent = $_POST['USERAGENT']; 
$referer = $_POST['REFERER']; 
$domain = $_POST['DOMAIN']; 
$screen_w = $_POST['SCREENW']; 
$screen_h = $_POST['SCREENH']; 
$ip = $_POST['IP']; 


$dsn = "mysql:dbname=cookie;host=localhost";
$user = "hoge";
$password = "hogehoge";	 
try {
    $dbh = new PDO($dsn, $user, $password);
} catch (PDOException $e){
    print('connection failed:'.$e->getMessage());
} 

$stmt = $dbh -> prepare("INSERT INTO analytics (host, host_name, port, request, code, browser, version, platform, useragent, referer, domain, screen_w, screen_h, ip, access) VALUES(:host, :host_name, :port, :request, :code, :browser, :version, :platform, :useragent, :referer, :domain, :screen_w, :screen_h, :ip, :access)");
$stmt->bindParam(':host', $host, PDO::PARAM_STR);
$stmt->bindParam(':host_name', $host_name, PDO::PARAM_STR);
$stmt->bindParam(':port', $port, PDO::PARAM_STR);
$stmt->bindParam(':request', $request, PDO::PARAM_STR);
$stmt->bindParam(':code', $code, PDO::PARAM_STR);
$stmt->bindParam(':browser', $browser, PDO::PARAM_STR);
$stmt->bindParam(':version', $version, PDO::PARAM_STR);
$stmt->bindParam(':platform', $platform, PDO::PARAM_STR);
$stmt->bindParam(':useragent', $useragent, PDO::PARAM_STR);
$stmt->bindParam(':referer', $referer, PDO::PARAM_STR);
$stmt->bindParam(':domain', $domain, PDO::PARAM_STR);
$stmt->bindParam(':screen_w', $screen_w, PDO::PARAM_STR);
$stmt->bindParam(':screen_h', $screen_h, PDO::PARAM_STR);
$stmt->bindParam(':ip', $ip, PDO::PARAM_STR);
$stmt->bindParam(':access', $date, PDO::PARAM_STR);
$stmt->execute();

ユーザーのアクセス開始のデータがdbに格納されました。

1.cookieの使い方が良くわからない。
2.サイトにscriptタグを埋め込んで、jsにidの配列を送るとした場合、js側はajaxの処理ができるのか?
3.ユーザーが訪問ページを離れた時に、ajax・jsでは、どのように書いたらいいのか?

なんだかんだ難しいな。。

Ajaxでpostして、DBに格納する

まず、mysql側でhostというtableをつくります。

mysql> use cookie
Database changed
mysql> create table cookie.host(
    -> host varchar(41),
    -> hostname varchar(41)
    -> );
Query OK, 0 rows affected (0.33 sec)

受信側で、pdoのinsertを書きます。
test1.php

$Host = $_POST['HOST'];
$HostName = $_POST['HOST_NAME']; 


$dsn = "mysql:dbname=cookie;host=localhost";
$user = "hoge";
$password = "hogehoge";	 
try {
    $dbh = new PDO($dsn, $user, $password);
} catch (PDOException $e){
    print('connection failed:'.$e->getMessage());
} 

$stmt = $dbh -> prepare("INSERT INTO host (host, hostname) VALUES(:host, :hostname)");
$stmt->bindParam(':host', $Host, PDO::PARAM_STR);
$stmt->bindParam(':hostname', $HostName, PDO::PARAM_STR);
$stmt->execute();

$result = 'HOST' . $Host . '<br>HostName'.$HostName;
echo $result;

送信側は、buttonが押されたら、postと書きます。
test.php

<script>
$(function(){

    $('#ajax-button').click(
        function(){
            var postData = {"HOST": location.host,"HOST_NAME":location.hostname};
            $.post(
                "test1.php",
                postData,
                function(data){
                    $(".box").html(data);
                }
            );

        });
});
</script>

ボタンを押して、mysqlをselectすると、、、、
入ってる! まじかー

“$(‘#ajax-button’).click(” のところを、$(document).ready(function(){に変えます。
test.phpをリロードすると、
あああああああああああああああああ

$(“.box”).html(data);をコメントアウトしてリロードすると

// function(data){
                //     $(".box").html(data);
                // }

あれ、ちょっと待て、混乱してきた、あれ、これ、もしかしてアナリティクスいける?

AjaxでPOST

test.php

<style>
.box{
    width:200px;
    height: 200px;
    background-color:#ddd;
}
</style>
<body>
    <div class="box"></div>
    <button id="ajax-button">送信</button>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script>
</body>
<script>
$(function(){
    $('#ajax-button').click(
        function(){
            var postData = {"HOST": location.host,"HOST_NAME":location.hostname};
            $.post(
                "test1.php",
                postData,
                function(data){
                    $(".box").html(data);
                }
            );

        });
});
</script>

test1.php

$Host = $_POST['HOST'];
$HostName = $_POST['HOST_NAME'];
$result = 'HOST' . $Host . '<br>HostName'.$HostName;
echo $result;

hoverした時だけ送信される、と書くこともできる

$(function(){
    $(".box").hover(function(){
            var postData = {"HOST": location.host,"HOST_NAME":location.hostname};
            $.post(
                "test1.php",
                postData,
                function(data){
                    $(".box").html(data);
                }
            );

        }, function(){
            $(".box").html("");
        });
});

$(document).ready(function(){ なら、読み終わった後に処理。

ajaxでボタンを押すごとに写真の表示を変える

buttonをclickするごとに、var iを++;して、表示を変えます。

<body>
    <button class="button">写真を表示</button><br>
    <img src="img/01.gif">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script>
</body>
<script>
var img = ['img/01.gif','img/02.gif','img/03.gif','img/04.gif'];
var i = 1;
$(document).ready(function(){
    $(".button").click(function(){
        $("img").attr("src", img[i]);
        i++;
        if(i == (img.length)){
            i = 0;
        }
    });
});
</script>

ははーん、これは色々応用できそうですね。

ajax

<style>
.box{
    width:200px;
    height: 200px;
    background-color:#ddd;
}
</style>
<body>
    <div class="box"></div>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script>
</body>
<script>
$(document).ready(function(){
    $(".box").hover(function(){
        $(this).css({
            "background-color":"#ff9999",
        });
    }, function(){
        $(this).css({
            "background-color": "#dddddd",
        });
    });
});
</script>

$(document).ready(function()
HTML=DOMの読み込みが終わったらfunction()の中の処理(=なにかしらの処理)を実行

書き方を変えて試してみます。

<script>
$(document).ready(function(){
    $(".box").hover(function(){
        $(".box").html("hello");
    }, function(){
        $(".box").html("你好");
    });
});
</script>

おお、すこし馴染んできました。

クリックされた時

$(document).ready(function(){
    $(".box").click(function(){
        $(".box").html("クリックされました");
    });
});

buttonがクリックされたら、.boxの表示を変える

<body>
    <div class="box">こんにちは</div>
    <button class="button">表示</button>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script>
</body>
<script>
$(document).ready(function(){
    $(".button").click(function(){
        $(".box").html("クリックされました");
    });
});
</script>

なるほど!

少し応用して、Math.floor(Math.random * 配列の数)として、配列の乱数をつくると、おみくじも簡単にできますね♪

<body>
    <div class="box"></div>
    <button class="button">おみくじを引く</button>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script>
</body>
<script>
var kuji = ['大吉','中吉','小吉','吉','凶','大凶']
$(document).ready(function(){
    $(".button").click(function(){
        var rand = Math.floor(Math.random() * 6);
        $(".box").html(kuji[rand]);
    });
});
</script>

ga.jsからのデータ送信はAjax?

ga.jsの最後の方でW.XMLHttpRequest;と書かれており、

df=function(a,b,c,d){
		var e=W.XMLHttpRequest;
		if(!e)return!1;
		var f=new e;
		if(!("withCredentials"in f))return!1;

onreadystatechangeでhttps://stats.g.doubleclick.net/j/collect? となっているので、
Ajaxで非同期で送っているようですな。

f.setRequestHeader("Content-Type","text/plain");
	f.onreadystatechange=function(){
		if(4==f.readyState){if(d)try{var a=f.responseText;
			if(1>a.length||"1"!=a.charAt(0))Ra("xhr","ver",a),b();
			else if...

つまり、cookieなどを取得し、ga.jsで処理して、Ajaxでサーバー側に送っているということでしょうか。
すると、Ajaxからですね。

Ajaxを使ってMySQLの更新をHTML側で自動更新

$(“”).empty();で、一旦データを空にして、setTimeout、countupで自動更新します。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <title>Ajax</title>

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
    <script>
    // setTimeout関数で2秒ごとに取得
    var countup = function(){
    $("#content").empty();
    $(document).ready(function(){
      // /**
      // * Ajax通信メソッド
      // * @param type
      // * @param url
      // * @param dataType
      // ** /
      $.ajax({
      type: "POST",
      url: 'json.php',
      dataType: "json",

      success: function(data, dataType)
      {
        if(data == null) alert('データが0件でした');

        var $content = $('#content');
        for (var i = 0; i<data.length; i++)
        {
          $content.append("<li>" + data[i].name + "</li>");
        }
      },
      error: function(XMLHttpRequest, textStatus, errorThrown)
      {
        alert('Error : ' + errorThrown);
      }
    });
  });
    setTimeout(countup, 2000);
  }
  countup();
    </script>
  </head>
  <body>
    <h1>sample</h1>
    <ul id="content"></ul>
  </body>
</html>

todo app

mysqlと連携したtodoアプリです。削除に際して、チェックボックスはajaxを使っています。

reference
openssl_random_pseudo_bytes:Generate a pseudo-random string of bytes

<?php

session_start();

require_once(__DIR__ . '/config.php');
require_once(__DIR__ . '/functions.php');
require_once(__DIR__ . '/Todo.php');

// get todos
$todoApp = new \MyApp\Todo();
$todos = $todoApp->getAll();

//var_dump($todos);
//exit;

// create table todos(
//   id int not null auto_increment primary key,
//   state tinyint(1) default 0,
//   title text
// );
//
// insert into todos (state, title) values
// (0, 'todo 0'),
// (0, 'todo 1'),
// (1, 'todo 2');

?>
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <title>Todo app</title>
  <link rel="stylesheet" href="styles.css">
  <style>
  </style>
</head>
<body>
  <div id="container">
      <h1>Todos</h1>
      <form action="" id="new_todo_form">
        <input type="text" id="new_todo" placeholder="What needs to be done?">
      </form>
      <ul id="todos">
        <?php foreach ($todos as $todo) : ?>
          <li id="todo_<?= h($todo->id); ?>" data-id="<?= h($todo->id); ?>">
            <input type="checkbox" class="update_todo" <?php if ($todo->state === '1') { echo 'checked'; } ?>>
            <span class="todo_title <?php if ($todo->state === '1') { echo 'done'; } ?>"><?= h($todo->title); ?></span>
            <div class="delete_todo">x</div>
          </li>
        <?php endforeach; ?>
        <li id="todo_template" data-id="">
          <input type="checkbox" class="update_todo">
          <span class="todo_title"></span>
          <div class="delete_todo">x</div>
        </li>
      </ul>
  </div>
  <input type="hidden" id="token" value="<?= h($_SESSION&#91;'token'&#93;); ?>">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
  <script src="todo.js"></script>
</body>
</html>
$(function() {
  'use strict';

   $('#new_todo').focus();
  // update
  $('#todos').on('click', '.update_todo', function() {
    // idを取得
    var id = $(this).parents('li').data('id');
    // ajax処理
    $.post('_ajax.php', {
      id: id,
      mode: 'update',
      token: $('#token').val()
    }, function(res) {
      if (res.state === '1') {
        $('#todo_' + id).find('.todo_title').addClass('done');
      } else {
        $('#todo_' + id).find('.todo_title').removeClass('done');
      }
    })
  });

  // delete
  $('#todos').on('click', '.delete_todo', function() {
    // idを取得
    var id = $(this).parents('li').data('id');
    // ajax処理
    if (confirm('are you sure?')){
      $.post('_ajax.php', {
        id: id,
        mode: 'delete',
        token: $('#token').val()
      }, function() {
        $('#todo_' + id).fadeOut(800);
      });
    }
  });

  // create
  $('#new_todo_form').on('submit', function() {
    // titleを取得
    var title = $('#new_todo').val();
    // ajax処理
    $.post('_ajax.php', {
      title: title,
      mode: 'create',
      token: $('#token').val()
    }, function(res) {
      // liを追加
      var $li = $('#todo_template').clone();
      $li
        .attr('id', 'todo_' + res.id)
        .data('id', res.id)
        .find('.todo_title').text(title);
      $('#todos').prepend($li.fadeIn());
      $('#new_todo').val('').focus();
    });
    return false;
  });

});
<?php

session_start();

require_once(__DIR__ . '/config.php');
require_once(__DIR__ . '/functions.php');
require_once(__DIR__ . '/Todo.php');

$todoApp = new \MyApp\Todo();

if ($_SERVER&#91;'REQUEST_METHOD'&#93; === 'POST') {
  try {
    $res = $todoApp->post();
    header('Content-Type: application/json');
    echo json_encode($res);
    exit;
  } catch (Exception $e) {
    header($_SERVER['SERVER_PROTOCOL'] . ' 500 Internal Server Error', true, 500);
    echo $e->getMessage();
    exit;
  }
}
<?php




namespace MyApp;

class Todo {
  private $_db;

  public function __construct() {

    $this->_createToken();

    try {
      $this->_db = new \PDO(DSN, DB_USERNAME, DB_PASSWORD);
      $this->_db->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
    } catch (\PDOException $e) {
      echo $e->getMessage();
      exit;
    }
  }

  private function _createToken(){
    if (!isset($_SESSION['token'])){
      $_SESSION['token'] = bin2hex(openssl_random_pseudo_bytes(16));
    }
  }

  public function getAll() {
    $stmt = $this->_db->query("select * from todos order by id desc");
    return $stmt->fetchAll(\PDO::FETCH_OBJ);
  }

  public function post() {
    $this->_validateToken();
    if (!isset($_POST['mode'])) {
      throw new \Exception('mode not set!');
    }

    switch ($_POST['mode']) {
      case 'update':
        return $this->_update();
      case 'create':
        return $this->_create();
      case 'delete':
        return $this->_delete();
    }
  }

  private function _validateToken(){
    if (
      !isset($_SESSION['token']) ||
      !isset($_POST['token']) ||
      $_SESSION['token'] !== $_POST['token']
    ) {
      throw new \Exception('invalid token!');
    }
  }
  private function _update() {
    if (!isset($_POST['id'])) {
      throw new \Exception('[update] id not set!');
    }

    $this->_db->beginTransaction();

    $sql = sprintf("update todos set state = (state + 1) %% 2 where id = %d", $_POST['id']);
    $stmt = $this->_db->prepare($sql);
    $stmt->execute();

    $sql = sprintf("select state from todos where id = %d", $_POST['id']);
    $stmt = $this->_db->query($sql);
    $state = $stmt->fetchColumn();

    $this->_db->commit();

    return [
      'state' => $state
    ];

  }

  private function _create() {
    if (!isset($_POST['title']) || $_POST['title'] === '') {
      throw new \Exception('[create] title not set!');
    }

    $sql = "insert into todos (title) values (:title)";
    $stmt = $this->_db->prepare($sql);
    $stmt->execute([':title' => $_POST['title']]);

    return [
      'id' => $this->_db->lastInsertId()
    ];
  }

  private function _delete() {
    if (!isset($_POST['id'])) {
      throw new \Exception('[delete] id not set!');
    }

    $sql = sprintf("delete from todos where id = %d", $_POST['id']);
    $stmt = $this->_db->prepare($sql);
    $stmt->execute();

    return [];

  }
}