Google Analyticsでip情報を取得する方法

Google Analytics -> 管理 -> プロパティ -> カスタム定義 -> カスタムディメンション をクリック
「+新しいカスタムディメンション」を押下

カスタム ディメンションを追加 で名前を追加
JavaScript(ユニバーサルアナリティクスのプロパティのみで有効)から、
ga(‘set’, ‘dimension1’, dimensionValue); をコピー

GA JSにdimension1 とphpのREMOTE_ADDRの情報を送る

<script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

  ga('create', 'UAxxxxxx-xx', 'auto');
  ga('set', 'dimension1', <?php echo $_SERVER&#91;‘REMOTE_ADDR’&#93;; ?>);
  ga('send', 'pageview');

</script>

あとは、セカンダリディメンション・カスタムディメンションで指定した名前を見れば、ipアドレスを閲覧できますね。

ga.jsでは、タグから送られてきたdimension1とipアドレスを配列に入れて、processingしてgaにレポーティングいるだけですな。
なるほど!ga.jsはまだ途上だが、仕組み自体は少しづつ分かってきた!

javascriptでユーザー情報を取得

<script type="text/javascript">
document.write("HOST : " + location.host + "<br>");
document.write("HOSTNAME : " + location.hostname + "<br>");
document.write("PORT : " + location.port + "<br>");
document.write("REQUEST : " + location.pathname + "<br>");
document.write("CODE : " + navigator.appCodeName + "<br>");
document.write("BROWSER : " + navigator.appName + "<br>");
document.write("VERSION : " + navigator.appVersion + "<br>");
document.write("LANG : " + navigator.language + "<br>");
document.write("PLATFORM : " + navigator.platform + "<br>");
document.write("USERAGENT : " + navigator.userAgent + "<br>");
document.write("REFERER : " + document.referrer + "<br>");
document.write("DOMAIN : " + document.domain + "<br>");
document.write("SCREEN.W : " + screen.width + "<br>");
document.write("SCREEN.H : " + screen.height + "<br>");
document.write("SCREEN.COL : " + screen.colorDepth + "Bit" + "<br>");
</script>

ipアドレスがありませんね。
ga.jsでipに関する記述を見てみると、
line10: Xa=Va(“anonymizeIp”)
くらいしかみつけられません。

Google analyticsのユーザー エクスプローラはipアドレスではなく、ユーザー固有の数字のようです。

予約数と予約時間を2軸でchart.jsで表示する

php側
1.DBから取得した予約データで、時間は+=,予約数は++で連想配列をつくる
2.array_multisortで時間の多い順に連想配列をソート
3.jsに値を渡す

$i = 0; 
while($result = $stmt->fetch(PDO::FETCH_ASSOC)){
	if($year == substr($result['day'], 0, 4) && $month == substr($result['day'], 7, 2)){
		$charge = $result['charge'];
		$book[$charge]['course'] += $result['course'];
		$book[$charge]['count']++;
		$total += $result['course'];
		$i++;
	} 
}

foreach($book as $key => $value){
	$time[$key]["course"] = $value["course"];
}
array_multisort($time, SORT_DESC, $book);

foreach($book as $key => $value){
	$name_list[] = $key;
	$time_list[] = $value["course"];
	$count_list[] = $value["count"];
}

chart.js
オプションで、左右の軸を指定する
tickのmaxは配列の中の最も大きい数 x N とする
Math.max.apply(null, array)*N

ただし、javascriptの IEEE 754の計算だと、誤差が生じることがある
例 Math.max.apply(null, array)*1.1 = 90.00000000000001(!?)
IEEE 754は、2進法計算だかららしい。※wikipediaを読んだが、何故二進法だと誤差が出るのかは私の頭では理解不能


そのため、 Math.floor(Math.max.apply(null, array)*N) として、小数点以下切り捨て

var name_arr = JSON.parse('<?php echo $name_l; ?>');
var time_arr = JSON.parse('<?php echo $time_l; ?>');
var count_arr = JSON.parse('<?php echo $count_l; ?>');
var ctx = document.getElementById("BarChart");
var BarChart = new Chart(ctx, {
	type: 'bar',
	data:{
		labels:name_arr,
		datasets:[{
			label:'予約時間',
			data: time_arr,
			backgroundColor: "rgba(255,136,86,0.8)",
			yAxisID: "y-axis-1",
		},{
			label:'予約数',
			data: count_arr,
			backgroundColor: "rgba(54,264,235,0.4)",
			yAxisID: "y-axis-2",
		}]
		},
		options:{
			responsive: true,
			scales:{
				yAxes:[{
					id: "y-axis-1",
					type: "linear",
					position: "left",
					ticks:{
						max: Math.floor(Math.max.apply(null, time_arr)*1.1),
						min:0,
						stepSize: 30
					}
				},{
					id: "y-axis-2",
					type: "linear",
					position: "right",
					ticks:{
						max: Math.max.apply(null, count_arr)+1,
						min:0,
						stepSize: 1
					}
				}],
				
			}
		}
		
});

結果:今月

翌月

予約日(datepicker)が今日の場合は、現在時刻以降のselectを表示

onSelectのところで、dateTextが今日を選択された場合、idと現在時刻の分を比較して、idが現在時刻より前(値が小さければ)、display noneに変更する。

onSelect: function(dateText, inst) {
                    $("#date_val").val(dateText);
                    if(today == dateText){
                    	for(var i = 0; i < timelist.length; i++){
                    		if(timelist[i] < time){
                    			document.getElementById(timelist[i]).style.display = "none";
                    		}
                    	}
                    	
                    } else{
                    	for(var i = 0; i < timelist.length; i++){
                    			document.getElementById(timelist[i]).style.display = "";
                    	}
                    }              
        }

デフォルト

今日の日付が選択された場合
->現在時刻以降しか選択できない

きた!

if(timelist[i] < time + 60) とすれば、現在時刻から、1時間後以降しか選べなくなりますね♪♪♪

JavaScriptでphpの変数が使えない?

以下のように書いたら、全くgoogle map apiが表示されず、

{
                    'address': <?php echo $address; ?>,
                    'region': 'jp'
                },

jsonにエンコードしたら表示されるようになりました。

{
                    'address': <?php echo json_encode($address); ?>,
                    'region': 'jp'
},

たったこれだけに1時間以上嵌ってしまいました。。

選択ファイルのjavascript側の表示数をsliceで制御

適当に数時間試していたら上手くいきました。
変数のlengthをcountして条件分岐で欲しい数だけsliceしてます。

<script>
  function handleFileSelect(evt){
    var files = evt.target.files;
    if(files.length > 2){
      files = files.slice(0, 2);
    }    

    for (var i = 0, f; f = files[i]; i++) {
    // for (var i = 0, f; f = files[i]; i++) {

      if (!f.type.match('image.*')) {
            continue;
          }

      var reader = new FileReader();

      reader.onload = (function(theFile){
        return function(e){
              var span = document.createElement('span');
              span.innerHTML = ['<img class="thumb" src="', e.target.result,
                                '" title="', escape(theFile.name), '"/>'].join('');
              document.getElementById('list').insertBefore(span, null);
            };
          })(f);

      reader.readAsDataURL(f);
    }

    var output = [];
    for (var i = 0, f; f = files[i]; i++) {
    // for (var i = 0, f; f = files[i]; i++) {

      output.push('<li><strong>', escape(f.name), '</strong> (', f.type || 'n/a', ') - ',
                  f.size, ' bytes, last modified: ',
                  f.lastModifiedDate.toLocaleDateString(), '</li>');
    }
    document.getElementById('list').innerHTML = '<ul>' + output.join('') + '</ul>';
  }

  document.getElementById('files').addEventListener('change', handleFileSelect, false);
</script>

OK! Nice!

さて、問題は、送信ファイルをどうやって保存するかですね。
gmailやhotmailなどは、ファイル名は変わらずに送られてくるので、拡張子にバリデーションをかけて、ファイル名はそのままにしたいと思います。

ファイルアップロードの進捗(%)をjavascriptで表示

コードでは一番下に来ていますが、addEventListenerで、getElementById(‘files’).addEventListener(‘change’, handleFileSelect, false)として、handleFileSelectの関数を実行します。
handleFileSelectでは、new FileReader();とした後、errorHandlerとupdateProgressを実行します。
%は、Math.round((evt.loaded / evt.total) * 100);

<style>
#progress_bar {
	margin: 10px 0;
	padding: 3px;
	border: 1px solid #000;
	font-size: 14px;
	clear: both;
	opacity: 0;
	-moz-transition: opacity ls linear;
	-o-transition: opacity ls linear;
	-webkit-transition: opacity ls linear;
}
#progress_bar.loading {
	opacity: 1.0;
}
#progress_bar .percent {
	background-color: #99ccff;
	height: auto;
	width: 0;
}
</style>

<input type="file" id="files" name="file" />
<button onclick="abortRead();">Cancel read</button>
<div id="progress_bar"><div class="percent">0%</div></div>

<script>
	var reader;
	var progress = document.querySelector('.percent');

	function abortRead(){
		reader.abort();
	}

	function errorHandler(evt){
		switch(evt.target.error.code){
			case evt.target.error.NOT_FOUND_ERR:
				alert('File Not Found!');
				break;
			case evt.target.error.NOT_READABLE_ERR:
				alert('File is not readable');
				break;
			case evt.target.error.ABORT_ERR:
				break;
			default:
				alert('An error occurred reading this file.');
		};
	}

	function updateProgress(evt) {
    if (evt.lengthComputable) {
      var percentLoaded = Math.round((evt.loaded / evt.total) * 100);
      if (percentLoaded < 100) {
        progress.style.width = percentLoaded + '%';
        progress.textContent = percentLoaded + '%';
      }
    }
  }


		function handleFileSelect(evt) {
	    progress.style.width = '0%';
	    progress.textContent = '0%';

	    reader = new FileReader();
	    reader.onerror = errorHandler;
	    reader.onprogress = updateProgress;
	    reader.onabort = function(e) {
	      alert('File read cancelled');
	    };
	    reader.onloadstart = function(e) {
	      document.getElementById('progress_bar').className = 'loading';
	    };
	    reader.onload = function(e) {
	      progress.style.width = '100%';
	      progress.textContent = '100%';
	      setTimeout("document.getElementById('progress_bar').className='';", 2000);
	    }

		reader.readAsBinaryString(evt.target.files&#91;0&#93;);
	}
	document.getElementById('files').addEventListener('change', handleFileSelect, false);
</script>

容量が小さいと、直ぐに100%となるので、最近downloadして重かったJavaの”spring-tool-suite-3.9.2.RELEASE-e4.7.2-win32-x86_64.zip”で試してみます。

いや、参りました。って感じですかね。参ってばっかりですが。。

FileReader()

FileReader クラスは、HTML5 世代の機能

File APIで出来ること
-ローカルにある画像をアップロードする前にプレビューを表示する
-ローカルにある画像をブラウザで加工してダウンロードする
-テキストファイルをブラウザで解析する
-データをJSONファイルとしてエクスポートして、インポートする
-大きなファイルを分割してサーバーに送信する

特に、「ローカルにある画像をアップロードする前にプレビューを表示する」ですね。

readAsDataURL メソッドは、指定された Blob ないし File オブジェクトを読み込むために使用
reader.readAsDataURL(file);
escape():16 進数エスケープシーケンスに置換
insertBefore:指定のノードを現在のノードの子ノードとして参照要素の前に挿入

inputで選択した複数画像をブラウザ上で表示させる

<style>
.thumb {
	height: 100px;
	width: 100px;
	border: 1px solid #000;
	margin: 10px 5px 0 0;
}
</style>

<input type="file" id="files" name="files&#91;&#93;" multiple /><br>
<output id="list"></output>
<script>
	function handleFileSelect(evt){
		var files = evt.target.files;

		for (var i = 0, f; f = files[i]; i++) {

			if (!f.type.match('image.*')) {
		        continue;
		      }

			var reader = new FileReader();

			reader.onload = (function(theFile){
				return function(e){
							var span = document.createElement('span');
		          span.innerHTML = ['<img class="thumb" src="', e.target.result,
		                            '" title="', escape(theFile.name), '"/>'].join('');
		          document.getElementById('list').insertBefore(span, null);
		        };
		      })(f);

			reader.readAsDataURL(f);
		}
	}

	document.getElementById('files').addEventListener('change', handleFileSelect, false);
</script>

初期

画像を選択

選択後
なんだこりゃーー!!すげー

では繋げてみましょう。

<?php
	  for ($i=0; $i<count($_FILES&#91;'files'&#93;&#91;'name'&#93;); $i++) {
    $file_ext = pathinfo($_FILES&#91;"files"&#93;&#91;"name"&#93;&#91;$i&#93;, PATHINFO_EXTENSION);
    if (/*FileExtensionGetAllowUpload($file_ext) && */ is_uploaded_file($_FILES&#91;"files"&#93;&#91;"tmp_name"&#93;&#91;$i&#93;)) {
      if(move_uploaded_file($_FILES&#91;"files"&#93;&#91;"tmp_name"&#93;&#91;$i&#93;, "upload/img/".$_FILES&#91;"files"&#93;&#91;"name"&#93;&#91;$i&#93;)) {
          echo $_FILES&#91;"files"&#93;&#91;"name"&#93;&#91;$i&#93; . "をアップロードしました。<br>";
      } else {
        echo "ファイルをアップロードできません。<br>";
      }
    } else {
      echo "ファイルが選択されていません。<br>";
    }
  }
  //アップロードできるファイルに拡張子の制限をかけたい時
  function FileExtensionGetAllowUpload($ext){
    $allow_ext = array("gif","jpg","jpeg","png","eps");
    foreach($allow_ext as $v){
      if ($v === $ext){
        return 1;
      }
    }
    return 0;
  }

?>
<style>
.thumb {
  height: 100px;
  width: 100px;
  border: 1px solid #000;
  margin: 10px 5px 0 0;
}
</style>
<form action="#" method="post" enctype="multipart/form-data">
<input type="file" id="files" name="files&#91;&#93;" multiple />
<input type="submit" value="Send">
</form>
<output id="list"></output>
<script>
  function handleFileSelect(evt){
    var files = evt.target.files;

    for (var i = 0, f; f = files[i]; i++) {

      if (!f.type.match('image.*')) {
            continue;
          }

      var reader = new FileReader();

      reader.onload = (function(theFile){
        return function(e){
              var span = document.createElement('span');
              span.innerHTML = ['<img class="thumb" src="', e.target.result,
                                '" title="', escape(theFile.name), '"/>'].join('');
              document.getElementById('list').insertBefore(span, null);
            };
          })(f);

      reader.readAsDataURL(f);
    }

    var output = [];
    for (var i = 0, f; f = files[i]; i++) {
      output.push('<li><strong>', escape(f.name), '</strong>(', f.type || 'n/a', ') -',
        f.size, ' bytes, last modified: ',
        f.lastModifiedDate.toLocaleDateString(), '</li>');
    }
    document.getElementById('list').innerHTML = '<ul>' + output.join('') + '</ul>';
  }

  document.getElementById('files').addEventListener('change', handleFileSelect, false);
</script>

ほお

php側にもちゃんと渡されています。