@blog.justoneplanet.info

日々勉強

mod_rewrite.c(リライトする)

以下のように.htaccessファイルに記述するとURL(URI)をリライトできる。

<IfModule mod_rewrite.c>
RewriteEngine on
RewriteBase /
RewriteRule !\.(js|ico|gif|jpg|png|css)$ index.php
</IfModule>

以下のように書いてしまうと、サーバにmod_rewrite.cが入ってなかったときエラー(500)となる。

RewriteEngine on
RewriteBase /
RewriteRule !\.(js|ico|gif|jpg|png|css)$ index.php

JavaScript Class Basic(クラスの基本)

JavaScriptには現時点でclassという概念がない(JavaScript2.0から使える予定)。

■メンバ

インスタンスプロパティ

インスタンス化した後のオブジェクトのプロパティ。

function Person(name){
    this.name = name;
    this.introduce = function(){
        alert('My name is ' + this.name + '.');
    };
}
var john = new Person('John');
//an instance property is john.name

インスタンスメソッド

インスタンス化した後のオブジェクトのメソッド。

function Person(name){
    this.name = name;
    this.introduce = function(){
        alert('My name is ' + this.name + '.');
    };
}
var john = new Person('John');
//an instance property is john.introduce()

但し、以下のようにprototypeによってインスタンスメソッドを定義した場合、introduce()メソッドのnameにはthisが必須となる。

var undefined;
function Person(name){
    this.name = name;
}
Person.prototype.introduce = function(){
    alert(this.name);
}
var john = new Person('John');
john.introduce();

クラスプロパティ

以下のようにすると、クラスプロパティが定義できる。インスタンス化されたオブジェクトからは当然アクセスできない。クラスプロパティは(クラス定数のように)慣例で全て大文字にする。

function Person(name){
    this.name = name;
    this.introduce = function(){
        alert('My name is ' + this.name + '.');
    };
}
Person.GENUS = 'genus Homo';
var john = new Person('John');
alert(john.GENUS);//none
alert(Person.GENUS);//genus Homo

クラスメソッド

クラスメソッドには以下のようなものがある。PHPで言い換えるならばstaticをつけてクラスメソッドを宣言したような感じだ。自身で定義したクラスにメソッドを付加することも可能である。

alert(Date.parse('2009/09/23 17:30:37'));//1253694637000

■プライベートメンバ

JavaやPHPではアクセス修飾詞を使用してコントロールする機能。但し、以下のようにプロパティに保持しないというだけであり、グローバル空間からインスタンス化したオブジェクトを介してnameを表示させることはできる。メリットはnameを外から変更できない事だ。

function Person(name){
    this.getName = function(){return name;};
}
Person.prototype.introduce = function(){
    alert(this.getName());
}
var john = new Person('John');
alert(john.getName());//John
john.introduce();//John

JavaScript Constructor and Prototype

■コンストラクタ関数

以下のようにするとコンストラクタ関数を定義できる。

function Person(name){
    this.name = name;
    this.introduce = function(){
        alert("My name is " + this.name + ".");
    }
}
var john = new Person('John');
var mike = new Person('Mike');
john.introduce();//My name is John.
mike.introduce();//My name is Mike.

慣例でコンストラクタ関数(クラス)は大文字で定義する。

■プロトタイプ

上述のコードは全てのインスタンスが同じintroduce()メソッドを保持するようになる。もし全てのインスタンスが同じintroduce()メソッドを参照すればメモリの節約につながる。そこで以下のようにprototypeを用いる。

function Person(name){
    this.name = name;
}
Person.prototype.introduce = function(){
    alert("My name is " + this.name + ".");
}
var john = new Person('John');
var mike = new Person('Mike');
john.introduce();//My name is John.
mike.introduce();//My name is Mike.

この場合、以下のように書くとメソッドが増えたときにスッキリする。

function Person(name){
    this.name = name;
}
Person.prototype = {
    introduce : function(){
        alert("My name is " + this.name + ".");
    }
}
var john = new Person('John');
var mike = new Person('Mike');
john.introduce();//My name is John.
mike.introduce();//My name is Mike.

参考

以下のようにしてArrayクラスを継承させることもできる。

var undefined;
function Stack(){
    this.T = -1;
}
Stack.prototype = Array.prototype;

■プロパティの性質

以下のようにコンストラクタ関数で記述したintroduceメソッドは、直属のプロパティ(メソッド)になる。

function Person(name){
    this.name = name;
    this.introduce = function(){
        alert("My name is " + this.name + ".");
    }
}
var john = new Person('John');
alert(john.hasOwnProperty('name'));//true
alert(john.hasOwnProperty('introduce'));//true
alert("introduce" in john);//true

一方で以下のようにprototypeを使用した場合、introduceメソッドはPersonから継承されたプロパティ(メソッド)ということになる。

function Person(name){
    this.name = name;
}
Person.prototype = {
    introduce : function(){
        alert("My name is " + this.name + ".");
    }
}
var john = new Person('John');
alert(john.hasOwnProperty('name'));//true
alert(john.hasOwnProperty('introduce'));//false
alert("introduce" in john);//true

■prototypeにおける読み込みと書き込み

読み込み

プロパティを読み込む場合、インスタンスはプロトタイプのプロパティを参照するので(継承している)、prototypeが使われる。

function Person(name){
    this.name = name;
}
Person.prototype = {
    introduce : function(){
        alert("My name is " + this.name + ".");
    }
}
var john = new Person('John');
var mike = new Person('Mike');
john.introduce();//My name is John.
mike.introduce();//My name is Mike.

インスタンスは自身にプロパティが見つからない場合、コンストラクタ関数のprototypeプロパティを参照する。コンストラクタ関数で見つからない場合は、さらにprototypeをたどる。

書き込み

プロパティを書き込む場合、JavaScriptはprototypeを使用しない。

function Person(name){
    this.name = name;
}
Person.prototype = {
    introduce : function(){
        alert("My name is " + this.name + ".");
    }
}
var john = new Person('John');
var mike = new Person('Mike');
john.introduce = function(){
    alert("I'm " + this.name + ".");
}
john.introduce();//I'm John.
mike.introduce();//My name is Mike.

■ネイティブコンストラクタ関数の拡張

通常は行ってはならないが、古いブラウザに対して標準に準拠したメソッドを付加するには便利である。

array.forEach(callback[, thisObj]);

配列の各要素を引数にして指定された関数を呼び出す。

if(!Array.prototype.forEach){
    Array.prototype.forEach = function(func/*, thisObj*/){
        var length = this.length >>> 0;
        if(typeof func !== 'function'){
            throw new TypeError();
        }
        var thisObj = arguments[1];
        for(var i = 0; i < length; i++){
            if(i in this){
                func.call(thisObj, this[i], i, this);
            }
        }
    }
}
サンプル
[1, 2, 3, 4].forEach(
	function(element, index, array){
		alert("[" + index + "] is " + element);
	}
);
/*
[0] is 1
[1] is 2
[2] is 3
[3] is 4
*/

array.map(callback[, thisObj]);

配列の各要素(を引数として)に対して関数を実行し、返された値を配列にまとめて返す。

if(!Array.prototype.map){
    Array.prototype.map = function(func/*, thisObj*/){
        var length = this.length >>> 0;
        if(typeof func !== 'function'){
            throw new TypeError();
        }
        res = new Array(length);
        var thisObj = arguments[1];
        for(var i = 0; i < length; i++){
            if(i in this){
                res[i] = func.call(thisObj, this[i], i, this);
            }
        }
        return res;
    }
}
サンプル
alert([1, 16, 81].map(Math.sqrt));//1,4,9

function.apply()

if(!Function.prototype.apply){
    Function.prototype.apply= function(object, parameters){
        var f = this;
        var o = object || window;
        var args = parameters || [];
        o._$_apply_$_ = f;
        var stringArgs = [];
        for(var i = 0; i < args.length; i++){
            stringArgs[i] = "args[" + i + "]";
        }
        var arglist = stringArgs.join(",");
        var methodcall = "o._$_apply_$_(" + arglist + ");";
        var result = eval(methodcall);
        delete o._$_apply_$_;
        return result;
    }
}

各メソッドについて

array.forEach(callback([element[, index[, array]]])[, thisObj]);
callback…各要素を引数として実行される関数。
thisObj…callbackが実行するされるときにthisとして扱われるオブジェクト。
array.map(callback[, thisObj]);
callback…各要素を引数として実行される関数。
thisObj…callbackが実行するされるときにthisとして扱われるオブジェクト。
var result = fun.apply(thisArg, [argsArray]);
thisArg…カレントオブジェクト。省略された場合はグローバルオブジェクト。
argsArray…関数に渡される引数の配列。

参考

JavaScript Array Basic(配列の基本)

配列とは値を順序づけしたもので、個々の値を要素、各要素に割り当てる番号をインデックスと呼ぶ。但し、内部的にJavaScriptにおける配列とはオブジェクトを拡張したものである。

var tmpAry = new Array();
alert(typeof tmpAry);//object

■配列の生成

配列リテラルを使用

var ary = ['John', 'Jack', 'Nick'];

Arrayコンストラクタを使用

var ary = new Array('John', 'Jack', 'Nick');

但し、以下のように1個の数字を引数に指定した場合は、引数で指定した個数の未定義値の値の要素を持つ配列が生成される。

var ary = new Array(5);

■要素へのアクセス

var ary = ['John', 'Jack', 'Nick'];
ary[3] = 'Mike';
ary['3'] = 'Emily';
alert(ary);//John,Jack,Nick,Emily

■要素の追加

以下のようにして要素を追加することができる。インデックスは連続した値である必要はなく、メモリ上に使用していないインデックスが確保される事もない。

var ary = ['John', 'Jack', 'Nick'];
ary[101] = 'Pochi';
for(var i = 0; i< ary.length; i++){
    alert(ary[i]);
}
//102 times alerts

但し、lengthは最後のインデックス+1が格納され、上述のようなコードではループが最後のインデックスまで1ずつ実行される。

■要素の削除

以下のようにdelete演算子を使うこともできるが、undefinedが入り要素自体は削除されない。

var undefined;//for browsers not implementing the type 'undefined' 
var ary = ['John', 'Jack', 'Nick'];
delete ary[1];
alert(ary);//John,,Nick
alert(ary.length);//3
for(var i = 0; i < ary.length; i++){
    if(typeof ary[i] === undefined){
        alert('undefined');
    }
    else{
        alert(ary[i]);
    }
}
/*
John,undefined,Nick
*/

■lengthプロパティ

以下のように配列の長さより小さな値を代入し配列を切り詰めることができる。

var ary = ['John', 'Jack', 'Nick'];
ary.length = 2;
alert(ary);//John,Jack

以下のように配列の長さより大きな値を代入し配列を拡張することができる。

var ary = ['John', 'Jack', 'Nick'];
ary.length = 4;
alert(ary);//John,Jack,Nick,

代入することが出来るのは基本的には数値のみである。

var ary = ['John', 'Jack', 'Nick'];
ary.length = {};
//syntax error

OpenPNEで全員マイフレンドになるPHPを書いてみよう

■ダウンロード

version 0.9.0(2009.04.08 latest release)
OpenPNE v2.12.3でテスト済み
関数を外部からインクルードしソースを簡素化
互換性を考慮し、ショートタグを使用中止
MySQLのみ対応
9行目、10行目の「//」を削除することにより、エラーメッセージを表示させられる(デバッグを考慮)
version 0.9.0tester.zip(2009.04.08 release)
OpenPNE v2.12.3でテスト済み
テスト用のプログラムです
version 0.8.0.zip(2009 release)
OpenPNE v2.12.3でテスト済み
functionsはset.php内に記述されています
version 0.7.0.zip(2009 release)
OpenPNE v2.12.3でテスト済み
set01.phpも含まれています

■インストール方法

  1. 公開ディレクトリにダウンロードしたファイルを設置
  2. テンプレート内に全てのメンバーをフレンドにするボタンを設置

テスト用のプログラムについて

通常版で不具合が発生する場合、テスターバージョンをご利用ください。その際に13~18行目を環境に応じて変更してください。

define('OPENPNE_URL', 'http://sample.com/');
define('DB_HOST', 'localhost');
define('DB_USER', 'your_db_user_name');
define('DB_PASS', 'your_db_user_password');
define('DB_NAME', 'your_db_name_for_openpne');
define('TBL_PRE', '');
localhost
MySQLサーバーの場所。Webサーバーと同じ場合は「localhost」、他のサーバ上の時はIPアドレスで指定。通常は「localhost」のままで良い
your_db_user_name
MySQLサーバーのユーザーネーム
your_db_user_password
MySQLサーバーのパスワード
your_db_name_for_openpne
データベースの名前
TBL_PRE
通常は空欄のままで問題はないかと思われる

変更が完了したら、同じく所定の位置にアップしてください。

■テンプレートの修正

PNE BIZを使ってない方

webapp/modules/pc/templates/h_home.tplを編集

<li><a href="/modules/pc/add_all_friends/set.php?c_member_id= ({$c_member.c_member_id})">みんなフレンド!</a></li>

を73行目あたりに追加してください。

PNE BIZを使ってる方

webapp_biz/modules/biz/templates/inc_biz_schedule_week.tplを編集

<li><a href="/modules/pc/add_all_friends/set.php?c_member_id=({$member_info.c_member_id})"><input type="button" class="input_submit" value="みんなフレンド!" onclick="location.href = '/modules/pc/add_all_friends/set.php?c_member_id=({$member_info.c_member_id})'" /></a></li>

を122行目あたりに追加してください。

■version 0.9.0 ソースコード

set.php

「/modules/pc/add_all_friends/set.php」(公開ディレクトリ)に設置

<?php
/**
 * Mitsuaki Ishimoto
 * justoneplanet.info
 * 2009-04-07
 * ver 0.9.0
 * set.php
/*==========================================================================================*/
//error_reporting(E_ALL);
//ini_set('display_errors', '1');
require_once('../../../config.inc.php');
require_once('inc/functions.php');
define('TBL_PRE', '');
define('MSG_BECAME', 'Everyone became your friend!!');
define('MSG_ALREADY', 'Everyone have been already your friend!!');
/*==========================================================================================*/
//main
$dbh = mysql_connect(
	$_OPENPNE_DSN_LIST['main']['dsn']['hostspec'],
	$_OPENPNE_DSN_LIST['main']['dsn']['username'],
	$_OPENPNE_DSN_LIST['main']['dsn']['password']
);
mysql_select_db(
	$_OPENPNE_DSN_LIST['main']['dsn']['database'],
	$dbh
);
$user_id_list = getAllUserList();
$combination_list = getAllCombinations();
$msg = setFriends($user_id_list, $combination_list);
mysql_close($dbh);
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Everyone is your Friends</title>
</head>
<body>
<p><?php print($msg); ?></p>
<form action="<?php print(OPENPNE_URL); ?>" method="post">
<input type="submit" value="もとのページに戻る" />
</form>
</body>
</html>

functions.php

「/modules/pc/add_all_friends/inc/functions.php」(公開ディレクトリ)に設置

<?php
/**
 * Mitsuaki Ishimoto
 * justoneplanet.info
 * 2009-04-07
 * ver 0.9.0
 * functions.php
/*==========================================================================================*/
/**
 * get all user list
 * @return (array) all users list
 */
function getAllUserList(){
	global $dbh;
	$user_id_list = array();
	$sql = "SELECT DISTINCT `c_member_id` FROM `c_member`";
	$result = mysql_query($sql, $dbh);
	while($row = mysql_fetch_array($result)){
		$user_id_list[] = $row['c_member_id'];
	}
	return $user_id_list;
}
/**
 * get all combinations
 * @return (array) all users combinations
 */
function getAllCombinations(){
	global $dbh;
	$combination_list = array();
	$sql = "SELECT `c_member_id_from`,`c_member_id_to` FROM `c_friend`";
	$result = mysql_query($sql, $dbh);
	while($row = mysql_fetch_array($result)){
		$combination_list[] = "'$row[c_member_id_from]','$row[c_member_id_to]'";
	}
	return $combination_list;
}
/**
 * set friends
 * @return (array) result status
 */
function setFriends($user_id_list, $combination_list){
	global $dbh;
	$date = date("Y-m-d H:i:s");
	$msg = MSG_BECAME;
	if(isset($_GET['c_member_id']) && in_array($_GET['c_member_id'], $user_id_list)){
		$c_member_id = mysql_real_escape_string($_GET['c_member_id']);
		$value_list = '';
		for($i=0; $i<count($user_id_list); $i++){
			if($c_member_id != $user_id_list[$i]){
				$register_list = "'$c_member_id','$user_id_list[$i]'";
				if(!in_array($register_list, $combination_list)){
					$value_list .= ",('',$register_list,'$date','','')";
				}
				$register_list = "'$user_id_list[$i]','$c_member_id'";
				if(!in_array($register_list, $combination_list)){
					$value_list .= ",('',$register_list,'$date','','')";
				}
			}
		}
		if($value_list != ''){
			$value_list = substr($value_list, 1);
			$sql = "INSERT INTO c_friend (`c_friend_id`,`c_member_id_from`,`c_member_id_to`,`r_datetime`,`intro`,`r_datetime_intro`) VALUES $value_list";
			$result = mysql_query($sql, $dbh);
		}
		else{
			$msg = MSG_ALREADY;
		}
	}
	else{
		$register_list = array();
		for($s=0; $s<count($user_id_list); $s++){
			for($t=0; $t<count($user_id_list); $t++){
				if($s != $t){
					$register_list[] = "'$user_id_list[$s]','$user_id_list[$t]'";
				}
			}
		}
		for($i=0; $i<count($register_list); $i++){
			if(!in_array($register_list[$i], $combination_list)){
				$value_list .= ",('',$register_list[$i],'$date','','')";
			}
		}
		if($value_list != ''){
			$value_list = substr($value_list, 1);
			$sql = "INSERT INTO c_friend (`c_friend_id`,`c_member_id_from`,`c_member_id_to`,`r_datetime`,`intro`,`r_datetime_intro`) VALUES $value_list";
			$result = mysql_query($sql, $dbh);
		}
		else{
			$msg = MSG_ALREADY;
		}
	}
	return $msg;
}
?>

■作者の一言

用途にもよるんですが、社内SNSなどとして運用する時に特定の人としかフレンド関係になれなかったりするのが弊害になったりしますよね。そんな時、全員がマイフレンドになれたらって思うわけです。エラーがありましたらエラー表示も教えて頂けると助かります。