今回は、PHPでブログを作りたいと思います。
2.はブログに直接関係しないとか言わないように。今回テキストはhatenaで書きました。文字サイズを最小にするとIEで印刷できるようになります(はみでない)。ので、じろじろ見ないように。
1.開発環境の準備
開発環境というか実験環境の準備。おすすめはOXTS.NET。インストール不要で、PHPとMYSQLが両方動く。phpmyadminも動くのでお得。これを、各自のマシン上で立ち上げて下さい。すると、マイコンピュータに「w:」なるものができていると思うので、「w:\www\」下にものを置くと、「http://localhost/」でログインできるようになります。便利便利。
2.PHPの基礎のおさらい
PHPは直感的な言語です。普段プログラミングしてれば、以下の事に気をつければいいと思います。
- コンパイル不要
- 命令の最後には;を付ける。
- プログラムは <?php と ?> の間に書く。
- 変数は$valueと$を付ける。初期化は要らない。仮想配列とか、じゃんじゃん使える。
- 関数定義は、function 関数名(引数){ } みたいな感じ。
- 文字列は . で繋げる事ができる。文字列は""か''で囲ったもの。
例を上げるので打ってみよう。HelloWorldだ。ファイル名は「index.php」だ(index.html同様URLにファイル名不要)。
index.php <html> <head> <title>HelloWorld</title> </head> <body> <?php // ここからPHPソース function helloworld($num){ for($i=0;$i<$num;$i++){ echo("<p>HelloWorld!".($i+1)."回目</p>"); } } $num=10; helloworld($num); // ここまでPHPソース ?> </body> </html>
簡単に解説すると、PHPはHTML中に書かれちゃったりして、helloworld関数がまず最初に定義されて、その引数にfor文の上限回数が入っている。echoは出力する関数、なので、HTMLを出力してしまえばHTMLにしか見えない。文字列を簡単につなぐ事が可能。今回は"<p>HelloWorld!"と、回数を表示するため($i+1)と、それっぽく見せるための"回目</p>"をつないで、ひとつの文字列にしてから、echoという関数に渡している感じ。本当に、直感で色々書けます。
3.PHPでセッション管理。ログイン画面を作ろう。
セッションとは
まずセッションとは何か。Webプログラミングにおいては、ひとつのWebページに複数の人が同時アクセスしてくる。そのユーザを見分ける必要がある。そのために、ブラウザクッキーに必要な情報を残しておいて、その人が再度アクセスした時にブラウザクッキーの内容を見て表示する内容を変える。
今回はセッションにユーザ名と暗号化したパスワードを保存しちゃいます。
まず、管理システム「control.php」で、セッションスタート
では、早速「index.php」を、と言いたいところだが、複数のPHPにそういう情報を書き込むのも難儀なので、ひとつの「control.php」というファイルを作って他のphpコードはそれを呼び出す事にしようと思います。ここにめんどくさいので管理者パスワードも載っけてしまいます。
control.php <?php //管理者パスワード define('ADMIN_PASS','himitsu'); ?>
こんな感じ。defineは、良いよね、見て分かるよね。
で、セッションを実装します。次の3つの命令が必要です。
- session_name( 文字列 ); セッションの名前を設定
- session_cache_expire( 自然数 ); セッションの有効時間の設定(単位:分)
- session_start(); 設定したセッションの開始
そのあとセッションを利用するには「$_SESSION["変数名"]」という変数として扱える。超便利。
で、追加します。
control.php <?php //管理者パスワード define('ADMIN_PASS','himitsu'); define('PHPSESSION_NAME','MYBROG_SESSION'); define('PHPSESSION_TIME',60); //セッション session_name( PHPSESSION_NAME ); //セッションの名前 session_cache_expire( PHPSESSION_TIME );//セッションの有効時間(単位:分) session_start(); //セッションスタート!! //管理者かどうか? if($_SESSION['is_admin']== TRUE ){ $Brog_admin=TRUE; }else{ $Brog_admin=FALSE; } ?>
管理者かどうかを判断し、$_SESSION['is_admin']にTRUEが入っていれば、管理者認定、なければゲスト認定します。その結果は$Brog_admin変数に代入してますが、今後呼び出した時にコレを利用して正しい管理者かどうかを判断したいわけです。ゆえに、ログインしたか確かめ用に、index.phpも作成しちゃいます。
index.php <?php require_once("./control.php"); ?> <html> <head> <title>マイブログ</title> </head> <body> <?php if($Brog_admin==TRUE){ $user_name="マスター"; }else{ $user_name="ゲストさん"; } ?> <p align="right">こんにちは<?php echo($user_name); ?>。</p> </body> </html>
今、「http://localhost/」にアクセスすると、「こんにちはゲストさん」とだけ表示されたと思います。上の「require_once("./control.php");」は、あの場所でcontrol.phpを一度実行してると思って下さい。
ログインしちゃおうぜ
じゃあ、次はセッションをに値を入れたいと思います。そのために、ログイン用のページを作っちゃいます。先ほど作成した$Brog_adminを利用して、ログイン済みの場合はきちんとその事を優しく教えてあげよう。
login.php <?php require_once('./control.php'); //既にログインしている時は切腹する。 if( $Brog_admin==TRUE ){ echo("マスターは既にログインなさっています。焦らなくとも、私がついておりますから。"); die; } //セッションを書き換えてログイン $_SESSION['is_admin']=TRUE; echo("こんにちは、マスター。ログインが完了いたしました。"); ?>
以後、全てのページで「control.php」を呼び出す予定なのでよろしく。これで、ログインできるようになったはず。「http://localhost/login.php」にアクセスして、その後「http://localhost/」にアクセスしてみよう。すると、「こんにちはマスター」と優しく迎えられるはずだ。再びログインしようとすると、優しくログイン済みだって事を教えてくれる。
ログインしたままと言うのも怖いので、ログアウトも同様に作ることにする。同様に、まだログインしていないならそのことを教えてあげよう。
logout.php <?php require_once("./control.php"); //ログイン済みなら消去 if( $Brog_admin==TRUE ){ $_SESSION['is_admin']=FALSE; echo("ログアウトします。マスター、今日もお疲れ様でした。"); }else{ echo("その、私のようなものが差し出がましいと思うのですが、)"; echo("マスター、ログインしていないようです。"); } ?>
これで、「http://localhost/logout.php」にアクセスすれば、ログアウトされてゲスト扱いになるはずだ。いちいち「login.php」と入力するのもうざいので、「index.php」を少し書き換えてそのようなリンクを作る。
index.php追記 <?php if($Brog_admin==TRUE){ $user="マスター"; }else{ $user="ゲストさん"; } ?> <p align="right">こんにちは<?php echo($user); ?>。 <?php if($Brog_admin==TRUE){ echo('<a href="./logout.php">ログアウト</a>'); }else{ echo('<a href="./login.php">ログイン</a>'); } ?> </p>
これで、「http://localhost/」にアクセスするだけでいろいろできるようになったはずだ!
パスワードの入力
しかし、今は当然ながら「login.php」にアクセスするだけで、ログインできるというセキュリティもへったくれもない仕様だ。これをパスワードを照会させることにする。
まず、よくみかけるログインフォームを作る。では、「login.php」の最下部に以下のHTMLを書こう。
login.php追記 <html> <head> <title>ログイン</title> </head> <body> <p>ログインパスワード <form method="post" action="./login.php"> <input type="text" name="pass" /> <input type="submit" name="ログイン" /> </form> </body> </html>
ログイン画面に進むとログインフォームが表示されたはずだ。しかし、ログインを押してもなにも変化がない。しかし、「<form method="post" action="./login.php">」と書いてあるとおり、「POST」というメソッドで「login.php」に情報を送っている。POSTで送られた情報はは、セッション同様「$_POST」という変数格納されている。では、どんな情報が送られているか「var_dump($_POST);」という命令をどこかに書いて見てみる。この命令は、この変数を型情報も含めて前表示させる命令だ。で、表示結果例がこちら。
array(2) { ["pass"]=> string(7) "himitsu" ["ログイン"]=> string(10) "クエリ送信"
array(2)というのは、2個の配列である事を示す。この中の"pass"配列に"himitsu"という文字列が入っている事を示す。と言う事で、$_POSTの中の"pass"という配列を見ればよい事が分かる。これを読み取りセッションをに書き込むように変える。
login.php改変 <?php //パスワードを照会する if( isset( $_POST['pass'] ) ){ //パスワードのチェック if( $_POST['pass'] !== ADMIN_PASS ){ echo("てめぇはあたしのマスターじゃねぇな。どこのどいつだ!<br />\n"); die; } //セッションを書き換えてログイン $_SESSION['is_admin']=TRUE; echo("こんにちは、マスター。ログインが完了いたしました。"); die; }
これで、パスワードがチェックできた。「isset(変数)」というのは、その変数が宣言されているかを調べる。もし、フォームから送られた内容がなければ、ここはスルーされるというわけだ。
パスワード情報の暗号化
php上にパスワードを残すのも嫌な人は、暗号化されたものだけを残しておこうとか考え出すはずだ。http://fictionlife.com/tools/md5/で、「himitsu」をMD5にかけると、「f1a0e73e5d7fc293952d380e32fda73c」になることがわかる。このことから、以下の改変ができる。
- control.phpに「f1a0e73e5d7fc293952d380e32fda73c」を書き込む&それを認証する
index.php改変 <?php //管理者パスワード define('ADMIN_PASS','f1a0e73e5d7fc293952d380e32fda73c');
- login.phpを書き換える。
login.php <?php //パスワードのチェック if( md5( $_POST['pass'] ) !== ADMIN_PASS ){
と言った具合。でも、パスワード忘れたらどうしょうもなくなるので注意。
4.PHPでDBプログラミング。ブログ記事をDBで扱おう。
DBの作成
と言う事で、やっとブログです。今回はDBとしてMYSQLを使います。MYSQLに関して細かいところはやりたくないので、phpmyadminというツールを使ってDBを作成したいと思います。
まず、DBの設計から。と言っても、今回は、以下のフィールドを持たせる事にします
- id 一意のid
- date 日付というかUNIX時間
- title タイトル
- discription 本文
OXTS.NETを使っていれば、すぐに利用できます。「タスクトレイアイコン→管理→myphpadmin」で使えます。以下の手順で
DBとテーブルを作ってしまって下さい。
- 新規データベースを作成する→「brog」照合順序「utf8_general_ci」→作成
- データベース brogs に新しいテーブルを作成する→名前「diary」フィールド数「4」→実行する
- 以下の表の通り、フィールド、種別、長さ/値、照合順序、属性、ヌル(NULL)を入力する→実行する
フィールド | 種別 | 長さ/値 | 照合順序 | 属性 | ヌル(NULL) |
id | INT | 8 | UNSIGNED | not null | |
date | INT | 10 | not null | ||
title | VARCHAR | 255 | utf8_general_ci | null | |
discription | MEDIUMTEXT | utf8_general_ci | null |
ためしに、記事を二つほど入力しよう。id以外は適当で構わない。
- テーブル「diary」中で、「挿入」ボタン
- id:1、date:1000、title:テスト、discription:テスト本文→実行する
- 「挿入」ボタン
- id:2、date:10000、title:テストにテストを重ねたテスト、discription:テストにテストを重ねたテストの本文→実行する
これで、DBを作成できた。
DBを接続しよう。
では、DBとの接続について解説する。以下の手順でDBでクエリを実行できる。
- mysql_connect(ホスト名,ユーザ名,パスワード) MYSQLに接続する
- mysql_select_db(データベース名) データベースを選ぶ
- mysql_query("SET CHARACTER SET SJIS"); 文字コードのおまじないをする
- $result = mysql_query(SQL文); クエリーを実行する
- for($i=0;$row=mysql_fetch_array($result);$i++){ 結果を一行ずつ取得する
では、今回は折角この前後輩S君がクラスについて解説してくれたので、クラスを利用しよう。PHPでは、よくわからないが、「クラス名.class.php」というソースにするのが一般的である。
BrogDB.class.php <?php class BrogDB { //コンストラクタでDBに接続する public function __construct($server,$user,$pass,$databasename){ //MYSQLに接続する if(!( mysql_connect($server,$user,$pass) )){ echo("ごめんなさいマスター。ぐすっ。MYSQLにせつぞくできませぇん。"); die; } //DBを選択 if(!( mysql_select_db($databasename) )){ echo("マスター、ごめん、なさい。".$databesename."なんてDB、ないみたいなんです。"); die; } //文字コードのおまじない mysql_query("SET CHARACTER SET SJIS;"); } } ?>
内容は、作られる時(コンストラクタ)に引数で、サーバ名、ユーザ名、パスワード、データベース名を受け取り、先ほどの1〜3まで一気にやってしまう。正直、確保する変数が特にないので、クラス化しなくても良かった気がする。
これを、index.phpに貼り付ける前に、「BrogDB.class.php」はよく使いそうなので、「control.php」で呼び出させる。かつ、mysqlの設定内容も、ここにdefineで書いてしまおう。
ONTS.NETでのMYSQLは、ホスト名は「localhost」、ユーザ名は「root」、パスワードは「」(なし)でOK。
control.php <?php //クラスの呼び出し require_once("./BrogDB.class.php"); //設定 MYSQL define('MYSQL_HOST','localhost'); define('MYSQL_USER','root'); define('MYSQL_PASS',''); define('MYSQL_DATABASE','brog');
では、「index.php」で、DBに接続させよう。DBクラスの実体を作るだけでよい。
<h1>お手軽簡単マイブログ!!</h1> <?php //DBクラスを作成 $db=new BrogDB(MYSQL_HOST,MYSQL_USER,MYSQL_PASS,MYSQL_DATABASE); ?>
「index.php」を読み込んでエラーがでなければ、接続成功である。
最新ブログを表示させよう。
では、クエリーを実行できる関数を、クラスに追加する。
BrogDB.class.php <?php //最近5件の日記を新しい順に配列に入れて返す public function read_newdiary(){ //クエリー作成 $query=("SELECT * FROM diary ORDER BY date DESC LIMIT 0 , 5"); //クエリー実行 if(!( $result = mysql_query($query) )){ echo("ぐすん、クエリーが、間違ってるみたいなの。教えて下さい、マスター。"); } //結果を1行ずつ取得して配列に入れる。 for($i=0;$row=mysql_fetch_array($result);$i++){ $data[$i]=$row; } return $data; }
read_newdiary()という関数が呼ばれると、日付を見て最新(ORDER BY date DESCでdateを見て降順に並べる)5件(LIMIT 0 , 5で0行目から開始して5つの行に限定する)の日記(SELECT *なので全てのフィールドが返る)を出力する。それを、mysql_fetch_array($result)で、1行取り出し、$dataに配列として入れていく。どこからに、var_dump($row);とか、var_dump($data);とかして、是非是非どういう出力がされているか確かめてみて欲しい。
では、「index.php」に、最新ブログを表示させよう。
index.php改変 <h1>お手軽簡単マイブログ!!</h1> <?php //まずDBクラスを作成 $db=new BrogDB(MYSQL_HOST,MYSQL_USER,MYSQL_PASS,MYSQL_DATABASE); //最近の記事を読み出す。 $diary=$db->read_newdiary(); for($i=0;isset($diary[$i]);$i++){ ?> <h2><?php echo($diary[$i]["title"]); ?></h2> <p><?php echo($diary[$i]["discription"]); ?></p> <p>No.<?php echo($diary[$i]["id"]." ".date("Y/m/d H:i:s",$diary[$i]["date"])); ?></p> <?php } ?>
結構えぐい事をしているが、PHPではよくある光景かもしれない。for文の中で配列が無くなるまで読み出し続ける。を外したり囲ったりする。{ }中で、?>が在ってもOKというPHPの直感力。なお、dateという関数が使われているが、
- $str=date(フォーマット,UNIX時間);
という用に使う。フォーマットについてはhttp://www.scollabo.com/banban/php/ref/ref_date.html参照。色々書けます。
記事1つだけを表示させよう
折角記事にidを付けたので、記事一つだけを読み出せるようにしよう。
先ほどログインの時に、POSTというメソッドを使ってユーザの入力を得たが、URLからユーザの入力を得る手段がある。GETというメソッドであり、これは、URLの最後に「index.php?no=3」などと、「index.php?変数名1=値&変数名2=値」という用に書くと、$_POSTと同様に$_GETに格納される。これを利用する。
まず、記事一つだけを表示させる関数をクラスに作成する。
BrogDB.class.php追記 <?php //指定した日記を読む public function read_onediary($no){ //クエリー作成 $query="SELECT * FROM diary WHERE id = ".$no; //クエリー実行 if(!( $result = mysql_query($query) )){ echo("うえぇぇん、ますたぁ、クエリーが、クエリーが、とおらないんです。".$query."の"); echo("なにがだめなんでしょう。マスター、見捨てないでぇ。"); } //結果を1行ずつ取得して配列に入れる。 for($i=0;$row=mysql_fetch_array($result);$i++){ $data[$i]=$row; } return $data; }
このように、クエリーに引数$noを忍ばせる事で実現できる。WHEREは、行を指定する命令である。
そして、再びindex.phpを書き換える。
index.php改変 if(isset($_GET["no"])){ //指定した番号の日記を読む $diary=$db->read_onediary($_GET["no"]); }else{ //最近の記事を読み出す。 $diary=$db->read_newdiary(); }
issetでGETメソッドにnoという変数が宣言されているかを確かめる。されていればそれを入力に用いる。という感じ。
これで、「http://localhost/?no=1」とかすると、no.1の記事だけ表示される。
日記を書く
最後に、日記を書くページを作りたいと思う。
と言う事で、DBクラスに日記をINSERTする命令を作る。
BrogDB.class.php追記 <?php //新しい日記を書く public function write_newdiary($title,$discription){ //まず、今idいくつなのか、調べる $query="SELECT MAX(id) max_no FROM diary"; //クエリー実行 if(!( $result = mysql_query($query) )){ echo("ぐすん、クエリーが、間違ってるみたいなの。教えて下さい、マスター。"); } //結果を配列に入れる $data=mysql_fetch_array($result); //空いてる番号げと $no=$data["max_no"]+1; //クエリー作成 $query="INSERT INTO `".MYSQL_DATABASE."`.`diary`(`id`,`date`,`title`,`discription`)"; $query=$query."VALUES('".$no."','".time()."','".$title."','".$discription."');"; //クエリー実行 if(!( mysql_query($query) )){ echo("うえぇぇん、ますたぁ、クエリーが、クエリーが、とおらないんです。".$query."の"); echo("なにがだめなんでしょう。マスター、見捨てないでぇ。"); } }
INSERT文では、idも事前に取得しなければならないので、別のクエリーを実行して取得する必要がある。それが「SELECT MAX(id) max_no FROM diary」にあたる。テーブル中からMAX(id)でidの最高値を取得し「max_no」というフィールド名に置換している。これは、仮想配列名に()が付いては少々困る気がしたからである。これから、新しい行を作成するクエリーを生み出している。なお、time();は現在のUNIX時間を返す関数である。PHPでは文字列を「.」を使って繋げる事ができるので、こういう時非常に見やすく便利である。
では、書き込み専用ページを作る。
writediary.php <?php require_once("./control.php"); if($Brog_admin!=TRUE){ echo("マスター以外がはいっちゃらめぇぇぇぇ。"); dir; } //DBに書き込み if(isset($_POST["send"])){ var_dump($_POST); //まずDBクラスを作成 $db=new BrogDB(MYSQL_HOST,MYSQL_USER,MYSQL_PASS,MYSQL_DATABASE); //記事を入れる。 $db->write_newdiary($_POST["title"],$_POST["discription"]); echo("マスターの日記は、正常に投稿しておきました。えへへぇ。"); }else{ ?> <html> <head> <title>日記を書く</title> </head> <body> <form method="POST" action="./writediary.php"> <p>TITLE<input type="text" name="title"/></p> <p><textarea name="discription"></textarea></p> <p><input type="submit" name="send" value="送信"></p> </form> </body> </html> <?php } ?>
まず、「control.php」を呼び出すのをお忘れなく。管理者が以外が入ったら除去する仕組みも。内容の受け渡しにはPOSTを使う。その辺りはログインの時と変わっていない。これで記事がDBに書き込まれる。
最後に、「index.php」から「writediary.php」に飛べる仕組みを追加する。
index.php追記 <?php if($Brog_admin==TRUE){ echo('<h5 align="right"><a href="./writediary.php">日記を書く</a></h5>'); }
これで、簡易ブログの完成である。ログインし、投稿したりして遊んでみよう。他、HTMLを書き換えるだけでも、だいぶ変わった感じになります。これだけの技術があれば、コメント欄の作成も可能だし色々できると思います。けど、今日はこれにておしまい。