JavaScriptの覚書

img要素の画像をcanvas要素にコピー
HTMLソース
	<img id="img1" src="test.jpg" />
	<canvas id="cvs1"  ></canvas>
	


JSソース
	var cvs = $('#cvs1')[0];
	var ctx = cvs.getContext('2d');
	var img1=$("#img1")[0];

	//座標(0,0)かつ原寸サイズでコピー
	ctx.drawImage(img1, 0, 0);

	//座標(50,80)の位置にコピー
	ctx.drawImage(img1, 50, 80);

	//画像幅を変えてコピー(100px × 100px)
	ctx.drawImage(img1, 0, 0,100,100);
	
参考

画像ファイルを直接canvas要素へ書き出す
HTMLソース
	<canvas id="cvs1"  ></canvas>
	


JSソース:
	var date = new Date();
	var ms=date.getTime();

	var img1=new Image();//イメージオブジェクトを生成
	img1.src="img/temp.png?ms=" + ms;// 「?ms = ~」の役割はキャッシュから画像を表示させなくする。


	//画像読込完了後にイメージオブジェクトをcanvas要素へ描画。
	img1.onload=function(){
		ctx.drawImage(img1, 0, 0);
	}

	

ローカルストレージとセッションストレージ | localStorage,sessionStorage
sessionStorage
ウィンドウやタブが開いている間有効。
ウィンドウやタブを閉じるとデータ消去。

localStorage
ブラウザ内に永続的に保存する。
ドメイン:ポート番号の組み合わせでデータ保存。


ローカルストレージの主なメソッド

localStorage.setItem("key1","Hello world");
ローカルストレージにデータをセットする。
5MBくらいの文字列をセット。配列などはJSON文字列に変換してからセットするとよい。
store.js を使うと、JSON変換の手間が省けるようである。

var v=localStorage.getItem("key1");
ローカルストレージから文字列を取り出す。

localStorage.removeItem("key1");
ローカルストレージから指定キーに紐づく文字列を削除。

localStorage.clear();
ローカルストレージ内のデータをクリア。

localStorage.length;
ローカルストレージのデータ数。

localStorage.key(i);
インデックス(連番)を指定してキーを取得することができる。


ストレージのイベント
データセットなどを行った際にイベントを起こせるようだがIE11では不安定なので使わない方が無難。


※注意
開発の修正時、ローカルストレージに値が入っている状態だと、 キャッシュが表示されてしまい修正が反映されないことがある。
この場合、ローカルストレージをクリアすると修正が反映されるようになる。
Chromeでこの現象を確認中(2015年現在)。



現在URLを取得
	var url = location.href;

クエリを除いたURLを取得

	var url = location.href;
	var url2 = url.split(/[?#]/)[0]; // URLからクエリ部分を除去する
	

現在のURLからドメイン部分を抜き出す
	var domain=location.href.split('/')[2];
	
現在ページのURLが以下の場合、
http://localhost/sample/index.html

ドメイン部分の「localhost」が取得できる。


プルダウンメニュー
ulタグ,CSS,JQueryの組み合わせによるプルダウンメニュー。 ソースコード

	<!DOCTYPE html>
	<html lang="ja">

		<head>
			<meta charset="utf-8">

			<title>プルダウンメニュー</title>

			<script src="jquery-1.11.1.min.js"></script>

			<style>
				.menu1 li{
					list-style-type: none;

					float:left;
					width:50px;
				}

				.menu1 li ul li{
					width:100px;
					position:relative;
					left:-40px;
				}

				
				.pulldown_menu ul{
					display:none;
					position:absolute;
					width:180px;
					padding-bottom:10px;
					background-color:#484848;
					z-index:2;
				}
				

				.pulldown_menu ul a{

					color:white;
				}
			</style>
			<script>
				$( function() {

					//~読込イベント処理~
					
					//トップメニューのプルダウン
					$(".pulldown_menu").hover(function() {

					    $(this).children('ul').show();

					}, function() {

					    $(this).children('ul').hide();

					});
					
				});
			</script>
		</head>

	<body>

	<h1 >プルダウンメニュー</h1>

	<ul class="menu1">
		<li>neko</li>
		<li>yagi</li>
		<li>kani</li>
		
		<li class="pulldown_menu"><a href="#"></a>same
			<ul >
				<li><a href="">シュモクザメ</a></li>
				<li><a href="">ホホジロザメ</a></li>
				<li><a href="">アオザメ</a></li>
				<li><a href="">ネコザメ</a></li>
			</ul>
		
		</li>

	</ul>
	<div style="clear:both"></div>



	</div>


	</body>
	</html>
	
サンプル

URLのサニタイズ | url sanitize

URLのサニタイズ | url sanitize

a要素のhrefへ、自由にURLを指定できるようなシステムの場合、XSSの危険性がある。
また、aタグ以外でも、要素の属性を指定できる場合、XSSが起きる。
該当する属性は、href,srcだけでなく、すべてに注意。

URLのサニタイズの必要性については下記を参考。
PHPのURLサニタイズ

URLをサニタイズする関数

記号「;<>"'」をエンコードする。また「http:」のコロンを除く、すべてコロンをエンコードする。
	function urlSanitize(str) {


		//記号「;<>"'」をサニタイズ
		str = str.replace(/;/g, '&#059;');
	    str = str.replace(/</g, '&lt;');
	    str = str.replace(/>/g, '&gt;');
	    str = str.replace(/"/g, '&quot;');
	    str = str.replace(/'/g, '&#39;');

	    //「http:」のコロンを除く、すべてコロンをサニタイズ
	    str = str.replace('http:', 'http>');
	    str = str.replace('https:', 'https>');
	    str = str.replace(/:/g, '&#058;');
	    str = str.replace('http>', 'http:');
	    str = str.replace('https>', 'https:');

	    return str;
	}
	

使用例

	function test_run(){


		var xssList=[
		 		"https://example.com/?neko=1&yagi=2",
				"http://example.com/\"onmouseover=\"alert(1)\"",
				"http://example.com/?<script>alert('XSSテスト');</script>",
				"javascript:alert('XSS')",
				"jav	ascript:alert('XSS');",
				"color:expression(alert('XSS'));",
				"behavior:url(test.sct)",
			];

		for(var i=0;i<xssList.length;i++){
			var xss=xssList[i];
			var url=urlSanitize(xss);

			console.log(url);
		}


	}

	/**
	 * URL用のサニタイズ
	 */
	function urlSanitize(str) {


		//記号「;&<>"'」をサニタイズ
		str = str.replace(/;/g, '&#059;');
	    str = str.replace(/</g, '&lt;');
	    str = str.replace(/>/g, '&gt;');
	    str = str.replace(/"/g, '&quot;');
	    str = str.replace(/'/g, '&#39;');

	    //「http:」のコロンを除く、すべてコロンをサニタイズ
	    str = str.replace('http:', 'http>');
	    str = str.replace('https:', 'https>');
	    str = str.replace(/:/g, '&#058;');
	    str = str.replace('http>', 'http:');
	    str = str.replace('https>', 'https:');

	    return str;
	}


	/**
	 * 一般用のサニタイズ
	 */
	function sanitize_str(str) {


		//記号「;&<>",」をサニタイズ
	    str = str.replace(/&/g, '&amp;');
	    str = str.replace(/</g, '&lt;');
	    str = str.replace(/>/g, '&gt;');
	    str = str.replace(/"/g, '&quot;');
	    str = str.replace(/'/g, '&#39;');



	    return str;
	}
	


URLサニタイズの例

サニタイズ前のURLサニタイズ後のURL
https://example.com/?neko=1&yagi=2https://example.com/?neko=1&yagi=2
http://example.com/"onmouseover="alert(1)"http://example.com/&quot;onmouseover=&quot;alert(1)&quot;
http://example.com/?<;script>;alert('XSSテスト');<;/script>;http://example.com/?&lt;script&gt;alert(&#39;XSSテスト&#39;)&#059;&lt;/script&gt;
javascript:alert('XSS')javascript&#058;alert(&#39;XSS&#39;)
jav ascript:alert('XSS');jav ascript&#058;alert(&#39;XSS&#39;)&#059;
color:expression(alert('XSS'));color&#058;expression(alert(&#39;XSS&#39;))&#059;
behavior:url(test.sct)behavior&#058;url(test.sct)

連想配列(オブジェクト)から指定キーとそのデータを削除する
delete オブジェクト[キー];

連想配列objAからsakanaキーに紐づくデータを削除する。

	var objA={'neko':'猫','sakana':{'guppi':'グッピー','maguro':'マグロ'}};
	delete objA.sakana;
	

別の記述方法

	delete objA['sakana'];


ファイル名から拡張子を取得する

ソースコード:ファイル名から拡張子を取得する関数
	/**
	 * ファイル名から拡張子を取得する。
	 * @param string fn ファイル名
	 * @return string 拡張子
	 */
	function _getExtension(fn){
		if(fn==null || fn=='') return '';
		if(fn.indexOf('.') == -1) return '';

		let ary=fn.split(".");
		let ext=ary[ary.length-1];

		ext = ext.toLowerCase();//小文字化する

		return ext;
	}
	

使用例
	var fn="テスト.min.pdf";
	var ext=getExtension(fn);//→ pdf
	

Ajaxファイルアップロード | 基本

HTML


	<input id="file1" type="file" name="file1" />
	<input type="button"  value="アップロード" onclick="upload1()" />
	<div id="res"></div>
	<div id="err"></div>
	

JavaScript


	function upload1(){
		var fd = new FormData();
		fd.append( "fu_file1", $("#file1").prop("files")[0] );
	    
		$.ajax({
			type: "POST",
			url: "upload.php",
			data: fd,
			cache: false,
			dataType: "text",
			processData : false,
			contentType : false,

		})
		.done(function(str_json, type) {
			var data;
			try{
				data = JSON.parse(str_json);
				
			}catch(e){
				console.log(str_json);
				jQuery('#err').html(str_json);
				throw e;
			}
			
			console.log(data);
			$('#res').html('success');
			
		})
		.fail(function(jqXHR, statusText, errorThrown) {
			
			var err_res = jqXHR.responseText;
			console.log(err_res);
			jQuery('#err').html(err_res);
			alert(statusText);
		});
	}	
	

サーバー側(upload.php)


	<?php
	if($_SERVER['SERVER_NAME']=='localhost'){
		// 一時ファイルをコピー
		move_uploaded_file($_FILES["fu_file1"]["tmp_name"], 'xxx/'.$_FILES["fu_file1"]["name"]);
	}
	echo $_FILES["fu_file1"]["name"];
	
	?>	
	



Ajaxファイルアップロード |ファイルチェンジイベント時にアップロード

HTML


	<input id="file1" type="file" name="file1" multiple />
	

JavaScript

	//ファイルアップロードイベント
	$('#file1').change(function(e) {
		
		var files = e.target.files;
		var oFile = files[0];
		
		// IEはファイル要素にnullが入っていてもチェンジイベントが発生するため対策する。
		if(oFile==null){return;}

		var reader = new FileReader();
		reader.readAsDataURL(oFile);
	
		//ファイル読込成功イベント
		reader.onload = function(evt) {
			
		    var fd = new FormData();
		    fd.append( "upload_file", $("#file1").prop("files")[0] );
			
			$.ajax({
				type: "POST",
				url: "upload.php",
				data: fd,
				cache: false,
				dataType: "text",
				processData : false,
				contentType : false,

			})
			.done(function(str_json, type) {
				var data;
				try{
					data = JSON.parse(str_json);
					
				}catch(e){
					console.log(str_json);
					jQuery('#err').html(str_json);
					throw e;
				}
				
				console.log(data);
				$('#res').html('success');
				
			})
			.fail(function(jqXHR, statusText, errorThrown) {
				
				var err_res = jqXHR.responseText;
				console.log(err_res);
				jQuery('#err').html(err_res);
				alert(statusText);
			});

		}
	});
	

PHP(upload.php)


	<?php
	// 一時ファイルをコピー
	move_uploaded_file($_FILES["upload_file"]["tmp_name"],$_FILES["upload_file"]["name"]);
	
	echo $_FILES["upload_file"]["name"];
	?>
	



Ajaxファイルアップロード | 複数のファイル要素

HTML


	<input id="file1" type="file" name="file1" multiple />
	<input id="file2" type="file" name="file2" multiple />
	<input type="button"  value="アップロード" onclick="upload1()" />
	<div id="res"></div>
	

JavaScript


	function upload1(){
		var fd = new FormData();
	    
	    fd.append( "fu_file1", $("#file1").prop("files")[0] );
	    fd.append( "fu_file2", $("#file2").prop("files")[0] );
	    
		$.ajax({
			type: "POST",
			url: "upload.php",
			data: fd,
			cache: false,
			dataType: "text",
			processData : false,
			contentType : false,
	
		})
		.done(function(str_json, type) {
			var data;
			try{
				data = JSON.parse(str_json);
				
			}catch(e){
				console.log(str_json);
				jQuery('#err').html(str_json);
				throw e;
			}
			
			console.log(data);
			$('#res').html('success');
			
		})
		.fail(function(jqXHR, statusText, errorThrown) {
			
			var err_res = jqXHR.responseText;
			console.log(err_res);
			jQuery('#err').html(err_res);
			alert(statusText);
		});
	}	
	

サーバー側(upload.php)


	<?php
	foreach($_FILES as $key=> $fileData){
		if($_SERVER['SERVER_NAME']=='localhost'){
			move_uploaded_file($fileData["tmp_name"], 'xxx/'.$fileData["name"]);
		}
		echo $fileData["name"] .'<br>';
	}
	
	?>
	



Ajaxファイルアップロード | 複数ファイル

HTML


	<input id="file1" type="file" name="file1" multiple />
	<input type="button" value="アップロード" onclick="upload1()" />	
	

JavaScript


	function upload1(){
		
		
		var fileElm = $("#file1");
		var len = $("#file1").prop("files").length;
		if(len==0){
			return;
		}
		var fd = new FormData();
		for (var i=0 ; i<len ; i++){
			var key = 'fu_' + i;
			 fd.append( key, fileElm.prop("files")[i] );
	
		}
	
	
		$.ajax({
			type: "POST",
			url: "upload.php",
			data: fd,
			cache: false,
			dataType: "text",
			processData : false,
			contentType : false,
	
		})
		.done(function(str_json, type) {
			var data;
			try{
				data = JSON.parse(str_json);
				
			}catch(e){
				console.log(str_json);
				jQuery('#err').html(str_json);
				throw e;
			}
			
			console.log(data);
			$('#res').html('success');
			
		})
		.fail(function(jqXHR, statusText, errorThrown) {
			
			var err_res = jqXHR.responseText;
			console.log(err_res);
			jQuery('#err').html(err_res);
			alert(statusText);
		});
	}	
	

サーバー側(upload.php)


	<?php
	foreach($_FILES as $key=> $fileData){
		if($_SERVER['SERVER_NAME']=='localhost'){
			move_uploaded_file($fileData["tmp_name"], 'xxx/'.$fileData["name"]);
		}
		echo $fileData["name"] .'<br>';
	}
	
	?>	
	



Ajaxファイルアップロード | 一般的な値データも同時に送信

HTML


	<input id="file1" type="file" name="file1" multiple />
	<input type="text" id="animal_name" value="neko" />
	<input type="button" value="アップロード" onclick="upload1()" /><br>
	<div id="res"></div>	
	

JavaScript


	function upload1(){
		
		var animal_name = $('#animal_name').val();
		
		var fd = new FormData();
	    fd.append( "fu_file1", $("#file1").prop("files")[0] );
	    fd.append( "animal_name", animal_name );
	    
		$.ajax({
			type: "POST",
			url: "upload.php",
			data: fd,
			cache: false,
			dataType: "text",
			processData : false,
			contentType : false,
	
		})
		.done(function(str_json, type) {
			var data;
			try{
				data = JSON.parse(str_json);
				
			}catch(e){
				console.log(str_json);
				jQuery('#err').html(str_json);
				throw e;
			}
			
			console.log(data);
			$('#res').html('success');
			
		})
		.fail(function(jqXHR, statusText, errorThrown) {
			
			var err_res = jqXHR.responseText;
			console.log(err_res);
			jQuery('#err').html(err_res);
			alert(statusText);
		});
	}
	

サーバー側(upload.php)


	<?php
	if($_SERVER['SERVER_NAME']=='localhost'){
		move_uploaded_file($_FILES["fu_file1"]["tmp_name"], 'xxx/'.$_FILES["fu_file1"]["name"]);
	}
	echo $_FILES["fu_file1"]["name"].'<br>';
	echo htmlspecialchars($_POST['animal_name'],ENT_QUOTES).'<br>';// XSSサニタイズしてから出力
	
	?>	
	



拡張子によるバリデーションでファイル情報を入力チェック(複数ファイルアップロードに対応)
関数
	//拡張子によるファイル名バリデーション
	function validByExt(files){

		//許可拡張子マップ
		var perExtMap={'doc':1,'docx':1,'xls':1,'xlsx':1,'xlsm':1,'ppt':1,'pptx':1,'pptm':1,'mdb':1,
				'accdb':1,'txt':1,'jpg':1,'jpeg':1,'png':1,'bmp':1,'gif':1,'pdf':1,'epub':1,'book':1,
				'zbf':1,'azw':1,'acsm':1,'xml':1,'mp3':1,'mpg':1,'mpeg':1,'vls':1,'csv':1,'wav':1,
				'm4a':1,'tiff':1,'tif':1,'bpg':1,};

		var errFns=[];//エラーファイル名リスト

		for (var i = 0; i < files.length; i++) {

			var file_name=files[i].name;//ファイル名を取得する

			//ファイル名から拡張子を抜き出す。ついでに拡張子は小文字可する。
			var ext=getExtension(file_name);

			//許可拡張子マップに拡張子は存在しない場合
			if(!perExtMap[ext]){
				errFns.push(file_name);//ファイル名を不許可リストに追加する。
			}
		}

		//retの初期化
		var ret=null;

		//不許可リストの件数が1件以上である場合。
		if(errFns.length >= 1){
			//エラーメッセージを組み立てて、retにセット
			var str_fns=errFns.join('\n');
			ret="以下のファイルはアップロード禁止です。\n" + str_fns;
		}

		return ret;
	}


	//ファイル名から拡張子を取得する。
	function getExtension(fn){
		if(fn==null){
			return '';
		}

		var ary=fn.split(".");
		var ext=ary[ary.length-1];
		ext=ext.toLowerCase();//小文字化する

		return ext;
	}
	





使用例:ファイルドラッグ&ドロップの場合
	$( function() {

		$('#dad_area').bind('drop', function(e){

			// デフォルトの挙動を停止
			e.preventDefault();

			// ファイル情報を取得
			var files = e.originalEvent.dataTransfer.files;

			//拡張子によるファイル名バリデーション
			
			var err=validByExt_fudad(files);
			if(err!=null){
				alert(err);
				return;
			}
			

			//ファイルアップロード
			//uploadFiles(files);

		}).bind('dragenter', function(){
			// デフォルトの挙動を停止
			return false;
		}).bind('dragover', function(){
			// デフォルトの挙動を停止
			return false;
		});

	});
	



使用例:ファイルアップロードボタンの場合
	$( function() {

		//ファイルアップロードボタンイベント
		$('input[type="file"]').change(function(){
			var files = this.files;

			
			//拡張子によるファイル名バリデーション
			var err=validByExt_fudad(files);
			if(err!=null){
				alert(err);
				return;
			}
			

			//uploadFiles(files);//ファイルアップロード
		});

	});
	

XSSサニタイズ


	/**
	 * XSSサニタイズ
	 * 
	 * @note
	 * 「<」と「>」のみサニタイズする
	 * 
	 * @param any data サニタイズ対象データ | 値および配列を指定
	 * @returns サニタイズ後のデータ
	 */
	function _xss_sanitize(data){
		if(typeof data == 'object'){
			for(var i in data){
				data[i] = _xss_sanitize(data[i]);
			}
			return data;
		}
		
		else if(typeof data == 'string'){
			return data.replace(/</g, '&lt;').replace(/>/g, '&gt;');
		}
		
		else{
			return data;
		}
	}
	


	/**
	 * XSSサニタイズ・デコード
	 * 
	 * @note
	 * 「<」と「>」のサニタイズ化を元に戻す
	 * 
	 * @param any data サニタイズ対象データ | 値および配列を指定
	 * @returns サニタイズ後のデータ
	 */
	function _xss_sanitize_decode(data){
		if(typeof data == 'object'){
			for(var i in data){
				data[i] = _xss_sanitize_decode(data[i]);
			}
			return data;
		}
		
		else if(typeof data == 'string'){
			return data.replace(/&lt;/g, '<').replace(/&gt;/g, '>');
		}
		
		else{
			return data;
		}
	}
	


旧:2017-1-5

XSSサニタイズするには、文字列中から以下のコードをサニタイズします。
サニタイズ前サニタイズ後
<;&lt;
>;&gt;
"&quot;
'&#39;

XSSサニタイズエンコード関数と元に戻すデコード関数
		//XSSサニタイズエンコード
		function xssSanitaizeEncode(str){
			if(typeof str == 'string'){
				return str.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#39;');
			}else{
				return str;
			}
		}

		//XSSサニタイズデコード
		function xssSanitaizeDecode(str){
			return str.replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&quot;/g, '"').replace(/&#39;/g, '\'').replace(/&#039;/g, '\'');
		}
		

使い方
		//XSSインジェクションを引き起こす文字列のサンプル。マウスオーバーするだけでXSS攻撃されかねない。
		var xss="<a href=\"http://example.com/\"onmouseover=\"alert('xss attack!')\"\">XSS Attack!!</a>";
		$("#res1").html(xss);

		xss=xssSanitaizeEncode(xss);//XSSサニタイズエンコード
		$("#res2").html(xss);
		//エンコード後→&lt;a href=&quot;http://example.com/&quot;onmouseover=&quot;alert(&#39;xss attack!&#39;)&quot;&quot;&gt;XSS Attack!!&lt;/a&gt;
		console.log(xss);

		//XSSサニタイズデコードでサニタイズ解除
		xss=xssSanitaizeDecode(xss);
		$("#res3").html(xss);

		
		<div id="res1"></div>
		<div id="res2"></div>
		<div id="res3"></div>
		
参考

改行コードをBRタグに変換する

バージョン1

	// 改行をBRタグに変換
	function nl2br(str) {
	    return str.replace(/[\n\r]/g, "<br>");
	}
	

バージョン2

	function nl2brEx(v){
		v = v.replace(/[\n\r]/g, "<br>");
		v = v.replace(/\\r?\\n/g, "\n");
		v = v.replace(/\r?\n/g, "\n");
		v = v.replace(/<br>\n/g,"\n");
		v = v.replace(/\\n/g,'<br>');
		return v;
	}
	

バージョン3

	function nl2brEx(v){
		if(v == null || v == '' || v=='0'){
			return v;
		}

		v = v.replace(/\r\n|\n\r|\r|\n/g,'<br>');
		return v;
	}