CSS Editer [Eclipse plugin]のインスコ

Eclipse再インスコしてるときにいれたものメモ第二段

CSS編集用のプラグイン CSS Editer

ここからDL

解凍

でてきたフォルダをEclipseのpluginフォルダに放り込む

Eclipse再起動

終わり

No Comments
5月 29, 2010 in css

JSEclipseのインスコ手順

Eclipse上でJavaScriptをきれいに表示して編集しやすい感じにしてくれるプラグインです。
JSEclipse

昔はここにいって簡単にDLできたんですが今日いってみるとなんか提供形式がかわってたのか簡単に落とせなかったのでメモ

Eclipse>help>Install New SoftWare

Work withのテキスト入力欄に

http://download.macromedia.com/pub/labs/jseclipse/autoinstall


を記入でエンター

するとリストにAjaxがでてくるからチェックつけてひたすらNextとか同意すればおk

ちなみに僕の環境は以下のとおり
Eclipse IDE for C/C++ Developpers
OS:WondowsVista

No Comments
5月 29, 2010 in javascript

Google maps api V3 を使ってみた。

Google maps apiを最近触ってみたんですが、やり始めがV2でAPIキーが必要とかで色々めんどくさかったんです。

一年前からgoogle maps api v3の登場をちらほらと聞いてはいたのでこれを機にとおもって使ってみた。
とはいったもののあまり参考になるサイトで日本語のものがないんですね。
困ったなぁとおもいながら英語のドキュメント読もうかとおもったら非公認の日本語ドキュメント発見

Google Maps API Version3 日本語ドキュメント(非公式)

らっきー! っておもってたら各オブジェクトの関数説明のところがちらほら「不明」とある。
翻訳がまだ完璧じゃないのかなっておもったら公式の英語ドキュメントですら空欄になってた。
未実装なんだろうか・・
とりあえずgoogle maps api v3の日本語ドキュメントを読みながらがんばってみた。

つくったものはこれです。
google_maps_api_v3

作ったシステムの仕様は以下のとおり。

—動作概要—
ページに地図を表示し、地図内の任意の場所にクリックでマーカーを設置することができ、そのマーカーが位置座標を返してくれるってもの。
マーカーはドラッグで位置変更可能。 
ダブルクリックでも移動してくれる。
——————-

あまり必要性はなかったかもしれないけど今回もjQuery使ってます。
なのでこのソースそのまま使いたい場合はjQueryダウンロードしてgoogle_map_v3.jsより手前でインクルードしといてください。

gmap_v3.html

<!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" />
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript" src="jquery.js" ></script>
<script type="text/javascript" src="google_map_v3.js"></script>
<title>Google Maps V3</title>
</head>

<body>
<h1>地図上の座標取得ぷろぐらむ</h1>
任意の場所をクリックするとマーカーがあらわれます。 マーカーが位置とってくれます。<br/>
<div id="maps" style="width:500px; height:500px; border:1px solid #333;"></div>
<div id="flag">true</div>

<p>
	<h3>マーカーの座標(単位:緯度経度)</h3><br/>
	x座標 : <span id="x">地図上でクリックしてください。</span><br/>
	y座標 : <span id="y">地図上でクリックしてください。</span>
</p>
</body>
</html>

google_map_v3.js

$(function(){

	var marker;

    var mapdiv = document.getElementById('maps');
    var myOptions = {
        zoom: 5,//縮尺
        center: new google.maps.LatLng(38.680816,138.767537),
        mapTypeId: google.maps.MapTypeId.ROADMAP,
        disableDoubleClickZoom : true,
        scaleControl: true,
        scrollwheel: true
    };
    var map = new google.maps.Map(mapdiv, myOptions);

    google.maps.event.addListener(map,'click',function(event){

    	if($("#flag").text()=="true"){

			var x = event.latLng.lat();
    		var y = event.latLng.lng();

			marker = createMarker(map,x,y);

    		$("#flag").text("false");

    		echoPoint(event.latLng);
    	}
    });    

});

function createMarker(map,x,y){
	 var marker = new google.maps.Marker({
		position: new google.maps.LatLng(x,y),
    	map: map,
    	title: "マーカーのタイトル",
    	draggable: true //なんかV3での動作が超遅いきがする
	 });

    google.maps.event.addListener(marker,'mouseup',function(){
    	echoPoint(marker.position);
    });		 

    google.maps.event.addListener(map,'dblclick',function(event){
    	marker.setPosition(event.latLng);
    	echoPoint(marker.position);
    });  

	return marker;

}

function echoPoint(point){

	var y = point.lat();
	var x = point.lng();

	$("#x").text(x);

	$("#y").text(y);

}

[解説]

gmap_v3.html

05行目
Google maps api v3のインクルードです。

06行目
jQueryをインクルードしてます。

07行目
今回作ったjsファイルをインクルードしてます。

14行目
このDiv要素に地図を流し込みます。 idでmapsを割り振ってます。 どうもサイズ指定したげないとGoogleさんが怒って変な表示にするみたいなんでスタイルシートいれて指定してます。

15行目
後述しますが、マーカーの表示処理の分岐に使います。

19/20行目
ここに緯度経度が表示されます。

google_map_v3.js

01~31行目
$(function(){
//処理
});
jQueryの書き方なんですが要するにgmap_v3.htmの読み込みが終わったらここに書かれた処理をするよってことです。

14行目
var map = new google.maps.Map(mapdiv, myOptions);

これでマップがでます。
MAPクラスのインスタンス化にmapdiv,myOptionsの二つの引数つけてますが、mapdivってのがgmap_v3.htmlの14行目に指定した地図を流し込むdiv要素になります。 型はHTMLコンテナでブロック要素なら多分なんでもおkです。
05行目のvar mapdiv = document.getElementById(‘maps’);でHTMLコンテナを取得してます。

mapOptionsが地図に付加されるオプションです。
ここでは

zoom: 5,
center: new google.maps.LatLng(38.680816,138.767537),
mapTypeId: google.maps.MapTypeId.ROADMAP,
disableDoubleClickZoom : true,
scaleControl: true,
scrollwheel: true

としてます。
上から3つまでが必須項目です。

zoomは地図の初期ズーム値です。 指定する数字が若いと縮尺がでかくなります。その逆もしかり。

centerは地図の中心座標です。 指定の型はLatLngっていうGoogleさんの提供してくれてるオブジェクトでこのオブジェクトを作るときの引数が緯度経度になります。 今はとりあえず日本がみれるような座標にしてます。

mapTypeIdはどんな地図にするかってもので今回はロードマップを使いたかったのでgoogle.maps.MapTypeId.ROADMAPと指定しています。

disableDoubleClickZoom : true,
ダブルクリックでのズームはオフにしてます。 うざいよねこれ。

scaleControl: true,
地図のコントロールバーを表示してます。

scrollwheel: true
マウスのスクロールホイールで縮尺を変更できるようにしてます。

16行目
イベントリスナの登録です。
google maps上でのイベントの登録はaddListenerで行います。
引数は
1.イベントが発生するオブジェクト
2.イベントの種類
3.処理(関数)

これは地図上をクリックした時の処理について記述しているので第一引数にMapオブジェクトのはいってるmap、第二引数にclickを指定しています。
第三引数は処理関数です。
clickイベントのときはマウスイベントオブジェクトが関数の引数として指定できます。
マウスイベントオブジェクトは以下の二つのプロパティを持ってます。
latLng ….前述のとおり緯度経度を含むオブジェクトです。
pixel ….これまたGoogleさんの作ったオブジェクトでPointオブジェクトというものです。 これはイベントが発生した位置のカーソルのピクセル値を返します。

18行目if
手前のaddListnerが地図をクリックしたときにマーカーを表示するっていう目的のものなんだけど、クリックするたびにマーカーがどんどんでてきたらマーカーだらけになるので初めてのクリックだけにマーカーを出すというための条件分岐です。

gmap_v3.htmlの15行目のdivの中身がtrueだったら~という分岐です。
ちなみにマーカーが入ったと同時に25行目の$(“#flag”).text(“false”);という処理でdivの中身がfalseにかわるのでこの分岐は一度しか適応されません。

20/21行目
マウスイベントオブジェクトのプロパティであるlatLngオブジェクトのメソッドlat()で緯度をlng()で経度を取得してそれぞれを変数x,yにいれてます。

23行目
createMarker(map,x,y);でマーカーを作ってます。
このcreateMarkerは僕の定義した関数で33行目のところの関数です。

google.maps.Marker({});でマーカーをインスタンス化してます。
地図同様にオプションが指定できます。
positionがマーカーを設置する緯度、経度でLatLngオブジェクトで指定します。
mapはマーカーを設置するマップオブジェクトを指定します。
titleはマーカーのタイトル
draggableはマーカーがドラッグで移動できるかどうかをbool値で指定できます。

41/45行目
前述のaddListenerを使ってマーカーのmouseupイベント、マップにdblclickイベント時に座標を出力するようにイベント処理を登録してます。
mouseupイベントはマーカーをドラッグしてるとき、ドラッグをやめた瞬間に発生するイベントです。 
dblclickはダブルクリック時に発生します。
これは第三引数の関数に対してまた、マウスイベントオブジェクトを与えることができます。

mouseupのときとdblclickの時の両方で行ってるのがechoPoint関数でこれは引数にlatLngオブジェクトを与えることでその座標をgmap_v3.htmlの19/20行目のspan要素に流し込む関数で54行目で定義してます。

ちなみにdblclickイベントでは地図上でダブルクリックが生じたところにマーカーを移動させるというシステムの仕様のためにsetPositionメソッドを使ってマーカーの位置をイベント発生した場所に移動させてます。
これもまた引数はLatLngオブジェクトです。
マウスイベントオブジェクトのプロパティから取得しています。

なんとなく作ってみたものの感想としてはV2のがさくさく動いたって印象。
通信速度がある程度速いPCでだったらほとんどかわらず動くけどゴミスペックのPCだったら結構しんどいかもです。

誰かぼくにモンスターPCをかってください>m<

ps
今度ジオコードの使い方に関する記事もかきます~

No Comments
5月 23, 2010 in ajax, javascript

リアルタイム同期チャット

今回はリアルタイムな同期チャットを作ってみました。

考え方的にはぐーぐるさんが使ったことで有名なコメットとよく似ています。

ただPHPを使ってやりたかったのでcometは用いません。

そもそもコメットの特徴はクライアントサイドからサーバーへの要求の投げかけを一回にしてるところなのでその一回を半無限ループ使って常時接続状態にすればいいわけです。

以下がソースです。

index.html

<!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" />
<meta http-equiv="content-script-type" content="text/javascript" />

<link rel="stylesheet" href="css/main.css" charset="utf-8" type="text/css" />
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/chat.js"></script>
</head>

<body>
<div class="chat" id="chat"></div>
		<div class="commentarea" id="commentarea">
        	<textarea class="comment" id="comment"></textarea>
			<input type="button" class="submit" value="発言" onclick="remark();" />
        </div>

</div><!-- end Chat Program -->
</body>
</html>

chat.js

$(function(){
	$("#submit").click(remark);
	$.post("get_chat_log.php",{},get_message,"text");
});

function remark(){
	var txt = $("#comment").val();
	$.post("write_chat_log.php",{name:"oppai星人",message:txt});
	$("#comment").val("");
}

function get_message(text){

	var recs = eval(text);
	n = recs.length;

	for(var i = 0; i<n; i++){
		data = $("#chat").html();
		$("#chat").html(data +"<span class=\"name\">" +recs[i]["name"]+"</span> さんの発言:<br />"+"<span class=\"message\">"+recs[i]["message"]+"</span><br />\n");
	}
	$.post("get_chat_log.php",{},get_message,"text");
}

get_chat_log.php

<?php
set_time_limit(0);

$file_name = "log/chatlog.txt";

//ファイルの最終更新時間を取得
$o_time = filemtime($file_name);
$o_filesize = filesize($file_name);

while(TRUE){

	//キャッシュ削除
	clearstatcache();

	//今現在のファイルの最終更新時間を取得
	$n_time = filemtime($file_name);

	//アクセス時の最終更新時間と比較
	if($o_time!==$n_time){
		$n_filesize = filesize($file_name);
		$fp = fopen($file_name,"r+");
		$fp2 = fseek($fp,$o_filesize);

		//通常ファイルサイズ文読み込むがEOFになると終了する。
		$body = fread($fp,$n_filesize);
		fclose($fp);
		break;
	}
	//遅延
	sleep(1);
}

$new_line = explode("\n",$body);
$n = count($new_line);

$res = array();

for($i=0; $i<$n; $i++){
	$data = explode(">",$new_line[$i]);
	$account = $data[0];
	$message = trim($data[1]);

	$message = str_replace("&gt;",">",$message);
	$message = str_replace("&lt;","<",$message);

	$arr = array("name"=>$account,"message"=>$message);
	array_push($res,$arr);
}

$n = count($res);

$txt ="";
for($i=0; $i<$n-1; $i++){
	if($i==0 && ($n-1)!=1){
		$txt .= '\'[{"name":"'.$res[$i]["name"].'","message":"'.$res[$i]["message"].'"}';
	}elseif($i==0 && ($n-1)==1){
		$txt .= '[{"name":"'.$res[$i]["name"].'","message":"'.$res[$i]["message"].'"}]';
	}elseif($i==$n-2){
		$txt .= ',{"name":"'.$res[$i]["name"].'","message":"'.$res[$i]["message"].'"}]';
	}else{
		$txt .= ',{"name":"'.$res[$i]["name"].'","message":"'.$res[$i]["message"].'"}';
	}
}

echo $txt;
?>

write_chat_log.php

<?php
$name = $_POST["name"];

$msg = str_replace("\n","<br />",$_POST["message"]);
$msg = htmlspecialchars($msg,ENT_QUOTES);

$body = $name.">".$msg."\r\n";

$file_name = "log/chatlog.txt";

$fp = fopen($file_name,'a');
fwrite($fp,$body);
fclose($fp);
echo $body;
?>

以上の4ファイルです。

index.htmlのページ読み込みと同時にchat.js内でget_chat_log.phpへのajax通信が始まります。

set_time_limit関数の引数に0を代入することでphpの実行時間の制約を無限大に伸ばしてます。

そしてwhile(true)を用いて無限ループ。
sleepで引数時間に一回ずつループします。
ログファイルに更新があればbreakして差分をjsのコールバック関数にjsonフォーマットで受け渡し、js側で整形して出力します。
出力後、またget_chat_log.phpにアクセスして次の更新を待ち続けます。

次に発言時、index.htmlのonclickイベントでchat.jsのremark関数が動きwrite_chat_log.phpにajax通信し、入力情報をログに書き出しします。

これでリアルタイムなチャットが更新されます。
まぁ結構サーバーに負荷かかりますが。笑

2 Comments
5月 7, 2010 in PHP, ajax, javascript

Linux上でのPHP開発環境

ほんとんど自分用のメモです。

ちょっとCent-OS上で二週間ほど開発しなきゃならない事態が起きたので開発環境の整え方をメモ

[.PHP]

もともとPHPは入ってるんで最新版にアップします。
と、ここで問題が。
CentOS3.4ではyumでいれられるPHPが5.1x?(小数点第二位は忘れた)までなんですね。
MySQLをphpMyAdminで扱うときにphpMyAdminの最新版はphp5.2x以降じゃないとうまく動作しないんですね。
そのためにちょっといじります。

まずレッドハッドのパッケージマネージャーからRPM-GPG-KEYをインポートしてきます。

# rpm –import http://www.jasonlitka.com/media/RPM-GPG-KEY-jlitka

リポジトリの設定します。

# vi /etc/yum.repos.d/utterramblings.repo

viでファイル開くんで下をこぴぺで貼り付けして保存

[utterramblings]
name=Jason’s Utter Ramblings Repo
baseurl=http://www.jasonlitka.com/media/EL$releasever/$basearch/
enabled=1
gpgcheck=1
gpgkey=http://www.jasonlitka.com/media/RPM-GPG-KEY-jlitka

それからphpアップデートします。

# yum update php

そしてapache再起動

# service httpd restart

[MySQL]

そして次にMySQL

これもyumでインストールできます。

# yum install mysql-server

MySQL起動してログインしてさらにパスワード設定します。

# service mysqld start
# mysql

mysql> set password for root@localhost=password(‘ここにパスワード設定しよう。’);
mysqlから離脱
mysql>\q

次からMysqlにはいるときは

# mysql -u root -p

と入力します。 するとパスワード求められるので設定したものを入力してエンターすればおk

それからmysql拡張もいれときます。 これもphpMyAdminで必要になってきます。

# yum install php-mysql

そしてまたアパッチ再起動

# service httpd restart

[PhpMyAdmin]

phpmyadminを入れたいけどその前にphp-mbstringとphp-mcryptがないとエラーおきるとかいうことをどこかの賢い人がいってたのでインスコ

# yum -y install php-mbstring
# yum -y install php-mcrypt

そしてまたアパッチ再起動

# service httpd restart

ほんでPHPmyadminのダウンロード

2010/05/06現在じゃphpMyAdmin-3.3.2-all-languages.tar.gzってのが最新っぽいのでこれをダウンロード。
最新情報はここでわかります。

# wget http://jaist.dl.sourceforge.net/sourceforge/phpmyadmin/phpMyAdmin-3.3.2-all-languages.tar.gz

解凍、そしてdocs内に移動、apache様が触れるように権限変更

# tar zxvf phpMyAdmin-3.3.2-all-languages.tar.gz
# mv phpMyAdmin-3.3.2-all-languages /var/www/phpMyAdmin
# chown -R root.apache /var/www/phpMyAdmin/

設定ファイルの作成(アクセス権とエイリアスの設定)

# vi /etc/httpd/conf.d/phpMyAdmin.conf
Alias /phpMyAdmin "/var/www/phpMyAdmin"

<Directory "/var/www/phpMyAdmin">
    order deny,allow
    deny from all
    allow from 127.0.0.1
</Directory>

一応これで動くはずなのでアクセス。

http://localhost/phpmyadmin

アカウントはroot , さっきmysqlのところで自分が設定したパス

[Eclipse]

ここからEclipse IDE for Java EE Developers の中の Linux 32bit を選択してダウンロードします。

なんか周りみてると /usr/local/share/に設置してる人が多いのでmv使ってダウンロードしたtar.gzファイルを移動します。
そして解凍

# tar zxvf eclipse-jee-galileo-linux-gtk.tar.gz (ファイル名は若干異なるかも)

普通ならこれでもう動かせるんだけどCentOSにはSun純正のJava SDKが入ってないとかで動かないらしいのでここから純正をとってくる。

そしてまたmv使って /usr/local/share/ に移動させます。

そして権限変えて解凍して実行しちゃいます。 バージョンが微妙に違うとかあれば各自補間してください。(2010/05/06現在はこれでいい)

# chmod a+x jdk-6u20-linux-i586-rpm.bin
# ./jdk-6u20-linux-i586-rpm.bin

これでうまく動くはずなのでEclipseを動かします。(jdk1.6.0_20はDLしたバージョンによって違うので確認してください。)

# /usr/local/share/eclipse/eclipse -vm /usr/java/jdk1.6.0_20/bin/java &

うまく立ち上がるとワークスペース聞かれるんで /var/www/html/ らへんにしといたら楽です。

起動コマンドが長いのでエイリアスつけときます。

# alias eclipse='/usr/local/share/eclipse/eclipse -vm /usr/java/jdk1.5.0_06/bin/java &'

これで
# eclipse
とすりゃEclipse立ち上がります。 

しかしこのままではElipseはPHPファイル作れません。 この記事のタイトルPHP開発環境なのに。

そもそもEclipseいれるなら何故 Eclipse for PHP Developers いれないの?って話ですよね。
なんかまだ開発中で不安定らしく、Eclipseからプラグインで「phpeclipse」なるものを入れたほうがいいとのこと。

ちなみにphpeclipseはSourceForge.netさんのところにあります。
これをダウンロードしてきて解凍します。

# unzip PHPEclipse-1.2.3.200910091456PRD-bin.zip

すると「plugins」「features」の二つのフォルダがあります。
この中にcdコマンドで移動します。

中身をEclipseの「plugins」「features」に全部いれちゃいます。

まず(ダウンロードして解凍したほうの)pluginsフォルダに入って全部Eclipseにいれちゃいます。

# cd plugins
# mv * /usr/local/share/eclipse/plugins/

次にfeaturesも同様に移し変えます。

# cd ../features
# mv * /usr/local/share/eclipse/features/

これで
#eclipse
でphpファイル作れるようになってます。

よかったね! jsとかも追記していきます。

No Comments
5月 6, 2010 in Linux, PHP

GDライブラリを用いたサムネイル生成

どんどん先延ばしにしていましたが、ようやくまとまった時間がとれたので公開します。

投稿された画像のサイズをいじるためのプログラムです。

PHPには画像編集用のライブラリ(GDライブラリ)が存在してるのでこれを使ってサムネイルを生成します。

具体的にはこんな感じ

「参照」でサイズ変更する画像を選択し、「リサイズ」を押してください。
JPEG,PNG,GIFに対応しています。(一応透過情報も保持するようにしています。)

つくったソースは以下の二つ

  • test.php
  • class.resize.php

test.php

<?php
require_once("class.resize.php");
?>
<!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" />
<style type="text/css">
<!--
	body{color:#ffffff;}
-->
</style>
</head>
<body bgcolor="#000000">

<form action="test.php" method="post" enctype="multipart/form-data">
	<input type="file" name="userfiles" />
    <input type="submit" value="リサイズ" />
</form>

<br /><br />

<?php
if(!$_FILES['userfiles']['size'] == 0){

	$updir = "./uploads/";
	$resizedir = "./resize/";

	$filename = $_FILES['userfiles']['name'];
	$filepath = "./uploads/".$_FILES['userfiles']['name'];	

	if(!move_uploaded_file($_FILES['userfiles']['tmp_name'],$filepath)){
		die("アップロードに失敗しました。");
	}

	$size = getimagesize($filepath);

	echo "元ファイル\n<br />\n width:".$size[0]."px \n <br> \n height:".$size[1]."px \n <br />\n";
	echo "<br />\n<img src=\"{$filepath}\" />\n<br />\n";

	//サムネイルのwidthを200pxとする

	$height = $size[1] * (200 / $size[0]);

	$resize = new Resize();
	$resize->img_resize($filename,$updir,200,
                         ceil($height),$resizedir,100);
	echo "<br />リサイズ後の画像<br />\n";

	$size = getimagesize($resizedir.$filename);

	echo "width:".$size[0]."px \n<br>\n height:".$size[1]."px\n<br />\n";
	echo "<img src=\"resize/{$filename}\" />\n";
}
?>

</body>
</html>

class.resize.php

<?php
class Resize{

	public function __construct(){}

	public function __set($prop,$val){
		echo "error : 存在しないプロパティ{$prop}に、値{$val}を設定しようとしています。\n";
	}

	public function __get($prop){
		echo "error : プロパティ{$prop}は存在しません\n";
	}

	public function __call($func,$params){
		echo "error : 存在しない関数{$func}が呼び出されました。\n";
		var_dump($params);
	}

	public function img_resize($filename,$path,$thumb_width,
					$thumb_height,$savedir,$quality){
    	$img_size = getimagesize($path.$filename);

		switch($img_size['mime']){
			//それぞれ元画像のリソースIDを返す
			case "image/jpeg":
			case "image/pjpeg":
				$img = @imagecreatefromjpeg($path.$filename);
				//リサイズ後の画像のリソースIDを返す
				$cp_img = imagecreatetruecolor($thumb_width,
									$thumb_height);
				break;

			case "image/gif":
				$img = @imagecreatefromgif($path.$filename);
				$cp_img = imagecreatetruecolor($thumb_width,
									$thumb_height);
				$scal_index = imagecolortransparent($img);

				if(!$scal_index>=0)break;//透過色がなければbreak

				//第二引数は色相近似の向上のためのディザon
				imagetruecolortopalette($cp_img, true, 256);
				$trnprt_color = imagecolorsforindex( $img, $scal_index);
				imagecolorset( $cp_img, 0, $trnprt_color['red'],
				$trnprt_color['green'],$trnprt_color['blue']);
				imagefill( $cp_img, 0, 0, 0 );
				imagecolortransparent( $cp_img, 0);
				break;

			case "image/png":
				$img = @imagecreatefrompng($path.$filename);
				$color_num = imagecolorstotal($img);
				$cp_img = imagecreatetruecolor($thumb_width,
									$thumb_height);
				$scal_index = imagecolortransparent($img);
				if(!$scal_index>=0)break;
				imagetruecolortopalette($cp_img, true, $color_num);
				break;

			default:
				return FALSE;
		}

		//imagecopyresized->返り値:bool , 第1引数のIDにリサイズしてコピーする。
		$res = imagecopyresampled(
			$cp_img,
			$img,
			0,
			0,
			0,
			0,
			$thumb_width,
			$thumb_height,
			$img_size[0],
			$img_size[1]
		);

		if(!$res)return FALSE;

		switch($img_size['mime']){
			//それぞれ元画像のリソースIDを返す
			case "image/jpeg":
			case "image/pjpeg":
				imagejpeg($cp_img,$savedir.$filename,$quality);
				break;
			case "image/gif":
				imagegif($cp_img,$savedir.$filename);
				break;
			case "image/png":
				$quality = ceil($quality * 0.09);
				imagepng($cp_img,$savedir.$filename,$quality);
				break;
		}
		//メモリ開放
		imagedestroy($cp_img);
		imagedestroy($img);
    }
}

?>

とこんな感じです。

test.php解説
まず1~3行目でサムネイル生成用のクラスを呼び出しています。
16~19行目までがサムネイルの元となる画像のアップロード用のformを生成しています。

24行目の条件分岐はファイルがPOSTされている場合に動くというものです。

25~34行目がファイルのアップロードです。
ファイルアップロードを行う関数、move_uploaded_fileは第一引数に現在のファイルパス、第二引数にアップロード先のファイルパスになります。
返り値は成功、および失敗をしめすBoolean値です。
基本的にPOSTで送られてきたファイルというのはサーバー内のテンポラリーファイル内に保存されます。
$_FILES['name']['tmp_name'] でアクセスできます。
ちなみにnameはformのinput type=”file”で設定したnameに相当します。

36行目のgetimagesizeで元のファイルの横幅、縦幅を獲得します。
getimagesizeの返り値は配列になっており キーは0,1,mimeの三つです。
0が横幅 1が縦幅 mimeがMIMETYPEになります。

43行目はサムネイル後のサイズを算出しています。
今回は横幅を200pxにあわせています。
この行の数式はアスペクト比を保持した縦幅の算出を行っています。

45行目でリサイズ用のクラスをインスタンス化しています。
46行目でリサイズクラスのサムネイルを作るための関数img_resize(ユーザー定義関数)を使ってサムネイルを生成しています。
引数は1.画像の名前 2.保存されているディレクトリのパス 3.サムネイルの横幅 4.サムネイルの縦幅 5.サムネイルの保存先ディレクトリのパス 6.画質(0~100 単位:%)

class.resize.php解説

6~17行目の__set , __get , __call で存在しないプロパティ、関数を呼び出したときの処理を書いています。

19行目のimg_resize関数がサムネイルを作成する関数になります。

23行目はファイルの種類をmimeから判定して、それぞれ種類に応じて処理を行っています。

25~26行目はjpeg画像の分岐ですが26行目のpjpegというのが曲者で、IEでプログレッシブJPGをアップロードしたときにこんなMIMEタイプがでてきます。 処理は同じなのでまとめています。

27行目でimagecreatefromjpeg関数で元画像を現すIDを取得します。
29行目がリサイズ後の画像を表現するIDの取得です。
(まだ現時点では真っ白の画像)

gif,pngはこれに加えて imagecolortransparent関数を用いて画像内の透過カラーが存在するかどうかを調べ、存在すればそれを元にリサイズ後の画像で透過を保持するように処理を行っています。

65行目はimagecopyresampled関数を用いた画像のリサイズです。
よく似た処理をする関数にimagecopyresized関数というものがありますが、256色までしか表現できないというものなのでimagecopyresamped関数を用いています。

そして80~92行目がリサイズ後のファイルの書き出しです。
imagejpeg関数の第3引数は画質の%ですが0~100なのでimg_resize関数の引数をそのまま使っておkです。

pngの方も書き出しの関数imagepngで第3引数が画質の値をとるのですが、これは0~9までの値です。
img_resize関数の画質の引数は0~100なので0.09倍して整数になるように切り上げする処理をいれています。

最後の95~96行目はメモリの開放です。
やたらめったにメモリ食う処理なので必ず開放してあげましょう。

3 Comments
1月 7, 2010 in PHP

アクセスの制限

GDライブラリをいじくったサムネイル作成は透過GIF,PNG対応とか考えるともう少し時間がかかるので明日にします・w・
今日は.htaccessを用いた直リンクの制限について。

会員制のサイトとかで使われてる画像って、外部からアドレスを直打ちしても403 Forbiddenってなるケースがありますよね。

あんな感じで外部からのアクセスを制限する方法について述べます。

htmlファイルに関してはphpつかってログインページかなんかでセッション変数を発行して、その変数を保持していなければログインページへheader(‘Location:path’)でとばしてあげればいいです。

問題は画像とかテキストファイルとかです。

こういったものは基本的に .htaccess というApacheの設定ファイルでなんとかしちゃいます。

<Files ~ "\.jpg$">
SetEnvIf Referer "^http://www\.hikingoo\.net" CHECK
order deny,allow
deny from all
allow from env=CHECK
</Files>

今回はjpgファイルを例にとって説明します。

まず1行目で対象となるfileを正規表現でjpgにしぼります。

2行目で環境変数の設定です、リファラーがサーバーアドレスだったら場合はCHECKを設定します。
その他ならスルーです。

3行目のorder は禁止と許可の順序を決めてます。 denyが禁止、allowが許可なので禁止→許可の順に設定されます。

4行目ですべてのアクセスを禁止します。

5行目で環境変数がCHECKのものだけを許可します。

これによってサーバー内でのリンクでその画像を表示することができても外部からのアクセスは拒否されるようになりました。

例をあげましょう。

まず最初に

http://www.hikingoo.net/test/2010-01-05/img/nyanxhiko.jpg

このアドレスをブラウザにぶちこんで画像を表示してみてください。

403とでて正しく画像が表示されなかったはずです。
(見れちゃった人は先にこの記事下部の結果を見てしまったんだと思います。 キャッシュを見てるだけなので削除してみてください)

次に同一サーバー内のhtmlファイルからのimgタグによる表示です。
ソースはこんな感じ

<!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=euc-jp" />
<title>にゃんひこ</title>
</head>

<body>

<img src="img/nyanxhiko.jpg">
</body>
</html>

結果はこちら

どうでしょう。

みごとなラリアットですね。

同じ画像ファイルにアクセスしてるのに同一サーバー内からのリンクを辿るか辿らないかでアクセスを禁止できます。

これを利用してアクセスを禁止された状態でそのままログインページをリダイレクトするとかしてSNSにありがちなシステム構築ができそうです。

No Comments
1月 5, 2010 in apache, html

ありがちな勘違い

PHP素人(僕みたいなやつ)のありがちな勘違い

①header関数

勘違い)用途は別ページにジャンプするためのもの。 どこにいれてもいい。

<?php
 header('Location:path');
?>

よくこんな使い方でページのリダイレクトさせてますが、header関数の使い方の一つに過ぎません。

大前提はHTTP ヘッダの送信に必要な関数なので、別に第一引数にLocationとせずに

<?php
 header('Content-type: image/png');
?>

とかしちゃうとそのページがpngファイルとかになっちゃうんですね。
まぁ後続にimagepng()とかで出力せんといけませんが。

まぁそんな感じでリダイレクトってのはヘッダ送信時の副産物で本当の用途はHTTPヘッダ送信のためのものです。
ヘッダ送信ってのはすべての出力の前にないといけないものなので当然前にechoとかの何かしらな出力があるとエラーがでます。
ありがちなミスはinclude と require_once とかでファイル引っ張ってくるときに引張先でエラーがあってheader関数に怒られるとかです。

②(MySQL) char型とvarchar型の違い

php素人(僕みたいなやつ)はとかくDBを扱う機会が多いくせにあまり定義を知らなかったりします。
特にcharとvarchar何が違うんやろ? 別にvarchar使っといたらええかな とか投げやりな理解をしてしまいがちです。

二つの違いは固定長であるか可変長であるか。
char : 固定長
varchar : 可変長

といってもとっつきにくい日本語ですよね
テーブル作成時にフィールドでそれぞれ長さを指定しますがcharで5の長さとvarcharで5の長さを指定した時の違いを例にとって考えます。

前者char型で “abc” というデータを放り込むと ”abc__” というデータが格納されます。(_はスペース)
これは5の長さをめいいっぱい使うっていう固定長の特徴です。
abcは三文字なので残りの2文字分をスペースで埋めます。

それに対しvarcharの方では “abc” というデータを放り込むと “abc” というそのままのデータが入ります。
可変長とは5文字以内という定義なのです。
PHPエンジニアはchar型を使うとデータをMySQLからとってきたあとに文字列操作とか必要になるので特にきまりがないかぎりvarcharを使う機会がほとんどでしょう。

③include()とrequire()の違い

両方ともファイルの読み込みに使う関数です。
基本的には同じですが両者の違いはエラーを出したときに明確になります。

includeの方はファイルが見つからないときに「Warning」を返します。
requireの方はファイルが見つからないときに「fatal error」を返します。

つまりincludeのほうはもしファイルがみつからなくても後続の処理が動きますがrequireの方はファイルがないとエラーで止まります。

include関数

<?php
 include("aiueo.php");
 echo "include関数";
?>

require関数

<?php
 require("aiueo.php");
 echo "require関数";
?>

結果:include , require

前者のincludeは後続の処理(echo “include関数”;)が出力されてるのに対し、require側ではエラーのみで出力がありませんね。
読み込むファイルが存在することが不明確な場合はincludeを使うといった感じに使い分けましょう

ちなみに _once をつけると(include_once , require_once)そのファイルがすでに読み込まれてるかどうかを評価してくれます。
ファイルが見つからないときの評価はinclude関数とrequire関数のときの違いと同じです。

No Comments
1月 3, 2010 in MySQL, PHP

2010年新春

http://www.hikingoo.net/blog/wp-content/uploads/%E3%83%8B%E3%83%A3%E3%83%B3tora%E6%A7%98.jpg明けましておめでとうございます。

酒飲みすぎて正月三ヶ日は全くプログラミングしてないです。

まぁこんなときくらいは自由に暮らそう。zzz

明日は小学校の頃からの大親友が地元に帰ってくるのでまた遊びまくります。

でもがんばって更新もします。

次回はPHPのGDライブラリ使って画像のリサイズに挑戦しようと思います。

2 Comments
1月 3, 2010 in ニャンまげ, 未分類

開発環境のバージョンあれこれ。

本日、就職先(現状:内定)の同期からWEBのことでたたき起こされた。

内容はMySQLからPHPに値引っ張ってきたときに文字化けが生じるとのこと。

過去に数100回ほど頭を悩まされていて解決策をしっていたので紹介

SQLのSELECT文で値を引っ張る前にデータベース側のエンコードをいじる。

SET NAMES utf8

これで解決

と思ったら
「Unknown system variable ‘NAMES’」って言われたらしい

んなばかなとおもってMySQLのバージョンを聞いてみると「mysql-4.0.20c-win」を利用しているとのこと。

調べてみるとMySQL4.0以前と4.1以降ではエンコードの仕様に断絶があるらしく4.0以前はサーバー全体での文字コード定義しかできないらしい。
というわけでSET NAMESは当然使えない。

ならばPHP側でmb_convert_encoding()を使ってSQLをEUC-JPに、返された値を同様に今度はUTF8に変換すればいい。

つまり

$sql = "SELECT `field1` from `Table`";
$sql = mb_convert_encoding($sql, 'EUC-JP');
$res = mysql_query($sql);

こんな感じでSQLを発行し、

while($data = mysql_fetch_array($res,MYSQL_ASSOC)){
    $field1 = mb_convert_encoding($data['field1'], 'UTF8');

    //処理
}

という風にする。

しかし、ここまでもまた問題が。

「Fatal error: Call to undefined function: mb_convert_encoding()」

mb_convert_encoding()が未定義の関数とかほざいてくるんですね。
そんなバカなことがあるかーっておもってPHPのバージョンを聞くとPHP4.3だとか。

なんでこうも古いのばっか使ってるのかと思ったら古い参考書についてた古いCDを使って開発環境を整えてしまったのが原因らしい。

まぁよくありそうな現象やなぁと思いながらも私、堪忍袋の緒がきれてしまいました。

Apache,MySQL,PHPをアンスコしてXAMPPで開発環境整えさせました。
強引ですいません。
アンスコウィザードのあるApacheと違ってMySQLの削除が曲者なので紹介しておきます。

まずCドライブ直下にMySQLフォルダがあると過程します。
MySQLは事前に停止しておいてください。

停止方法(cmd)

# net stop mysql

削除方法(cmd)

# CD C:\mysql\bin
# mysqld –remove MySQL

これでサクシードほにゃららってのが出たら一応アンスコに成功してます。
ただ、my.iniというmysqlの設定ファイルがサーバー内に残ってる可能性があるから
スタート→検索→[my.ini]でWINDOWSファイルやSYSTEMファイル以外の場所でmy.iniが見つかったら削除しといてください。

これでアンスコ完了です。

PHPに関しては別に設置ディレクトリさえ違えば競合するものではないので適当に削除してくれていいです。

No Comments
12月 31, 2009 in MySQL, PHP