JUGEMテーマ:
ホームページ作成
1. ypmod.phpの機能
まず、データベース修正スクリプトを作成するにあたり、どれだけの機能を実現する必要があるのかを整理してみましょう。
大きくは次の4つになります。
(1)新規登録ボタンからのリンクで、新規登録フォームの表示
(2)一覧表からのリンクで、データベース内容修正フォームの表示
(3)新規登録フォームからの呼び出しで、新規データの登録
(4)修正フォームからの呼び出しで、データベース内容の修正
このうち(3)と(4)には、入力されたデータをチェックして、エラーがある場合は修正を促すというサブ機能も必要です。
これらの4つの機能を、要求元を見分けて、それぞれに機能を実現してやる必要があります。
まず、(1)、(2)と(3)、(4)の大きく2つに分類します。これは、前者がリンクからの呼び出しで、後者がフォームからの呼び出しになっているところに注目します。
何らかのデータをスクリプトに送るには2つの方法があります。GETとPOSTです。
GETは送りたいデータをパラメータとしてURLにくっつけて送ります。
<a href="http://papercraft.techikun.com/ypmod.php?id=1>GETによる呼び出し</a>
とこんな感じです。情報量は少ないですが、特別な仕組み無しに簡単にデータを送りつけることができます。
一方POSTは、内部変数を使ってデータを送りますので、より複雑なデータも送ることができます。入力フォームから送る場合は主にこちらを使います。つまりPOSTで送られているかどうかで(1)、(2)と(3)、(4)を見分けることができるのです。
具体的には、POSTで送られた場合は、$_SERVER["REQUEST_METHOD"] という変数に "POST"が入れられますので、ここで見分けます。
次に(3)と(4)、これは登録済みの場合、データベースで一貫番号のindexを与えていますが、新規登録の場合はこれがありません。従ってindex番号を持っている場合はこれをフォームから隠しパラメータ"hidden"で送ってやり、受け側でこの値がセットされているかどうかをチェックすることで見分けてやります。
送る方はこちら、
<input type="hidden" name="id" value='.$row["index"].'>
受け側は、
if($_POST["id"]){・・・
としてやれば見分けることができます。
次に(1)と(2)の見分け方ですが、最初はGETかただのリンクかで見極めようと思ったのですが、やってみるとただのリンクも$_SERVER["REQUEST_METHOD"] に"GET"と入ってくるようでした。なので方針変更し、こちらもid有無で見分けることにしました。
2. ypmod.phpの論理構成
ということで、先ほど決めた見分け方に従い、データベース修正スクリプトypmod.php全体の論理構成を考えてみました。
// ヘッダー、タイトル、メニュー、サブタイトル等を表示
// データベースに接続
if($_SERVER["REQUEST_METHOD"] == "POST"){ // POSTの場合
if($_POST["id"]){ // id付きの場合=データベースの修正
// エラーチェック
// 画像処理
// 修正登録
}else{ // id無しの場合=新規登録処理
// エラーチェック
// 画像処理
// 新規登録
}
// 共通処理=入力項目にエラーがあった時の、修正フォーム
}elseif(($_SERVER["REQUEST_METHOD"] == "GET")and(isset($_GET["id"]))){ // GETでid付きの場合
// データベースの内容を記入済みの修正フォーム表示
}else{
// 新規登録フォームを表示
}
// データベース接続解除
こんなところでしょうか。
3. ypmod.phpの作成
ではいよいよスクリプトを書いていきます。
まず、ヘッダー類は省略させていただいて、データベースに接続するところから。
<?php
$pdo = new PDO(
'mysql:dbname=LA********-mysql5;host=********.phy.lolipop.lan;charset=utf8',
'LA********',
'password',
array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true
)
);
これは前回やった通りですね。では次に、データベース修正処理。まずはエラーチェックから。
if($_SERVER["REQUEST_METHOD"] == "POST"){ // 登録または修正操作後、修正モード
if($_POST["id"]){
// データ不備チェック→DB修正
$errorflg=0;$errorflg1=0;$errorflg2=0;$errorflg3=0;$errorflg4=0;
if(!$_POST["name"]){$errorflg=1; $errorflg1=1;}
if(!$_POST["affiliation"]){$errorflg=1; $errorflg3=1;}
if(!$_POST["password"]){$errorflg=1; $errorflg4=1;}
// パスワードチェック
$stmt1 = $pdo->prepare('SELECT * FROM テーブル名 WHERE `index` = :index');
$stmt1->bindValue(':index', (int)$_POST["id"], PDO::PARAM_INT);
$stmt1->execute();
$row1 = $stmt1->fetch();
if($_POST["password"]<>$row1["password"]){$errorflg=1; $errorflg4=1;}
考え方は、ラジオボタンで強制的に何か一つ選ばされるのではないテキスト入力のアイテムについて、入力が空だったらエラーとしています。その後にパスワードの照合をしています。
次は画像処理。
// 写真変更の場合の処理
if($_FILES["photourl"]["name"]){
// エラー処理
if($_FILES["photourl"]["error"]){
$errorflg=1; $errorflg2=1;
//exit;
}
$path = $_FILES["photourl"]["tmp_name"];
$imginfo = getimagesize($path);
switch ($imginfo[2]){
case 1: $im = imagecreatefromgif($path); break;
case 2: $im = imagecreatefromjpeg($path); break;
case 3: $im = imagecreatefrompng($path); break;
default: // エラー処理
$errlrflg=1; $errlrflg2=2; break;
}
$wratio = $imginfo[0]/120;
$hratio = $imginfo[1]/80;
if($wratio>=$hratio){
$new_width=120;
$new_height=round($imginfo[1]/$wratio);
}else{
$new_width=round($imginfo[0]/$hratio);
$new_height=80;
}
$new_image = imagecreatetruecolor($new_width, $new_height);
imagecopyresampled($new_image, $im, 0, 0, 0, 0, $new_width, $new_height, $imginfo[0], $imginfo[1]);
imagejpeg($new_image,$_FILES["photourl"]["tmp_name"],100);
$photodata = file_get_contents($path);
}else{
$stmt4 = $pdo->prepare('SELECT `photo` FROM テーブル名 WHERE `index`=:index');
$stmt4->bindValue(':index', (int)$_POST["id"], PDO::PARAM_INT);
$stmt4->execute();
$row = $stmt4->fetch();
$photodata = $row["photo"];
}
これも画像処理の回に説明した通りですね。imagecreatefrom****()で読み込んが画像を、imagecopyresampled()を使い、imagecreatetruecolor()で作った縮小ファイルに落としてやり、一旦保存してからfile_get_contents()で文字列に読み込んでいます。最後のelseブロックは、新しい写真が指定されなかったら、前回の写真を読み出して再度登録に回そう、というブロックになります。そして修正登録はこちら。
if(!$errorflg){
$query2 = 'UPDATE テーブル名 SET `photo`=:photo, `name`=:name, `category`=:category, `area`=:area, `affiliation`=:affiliation, ';
$query2 = $query2.'`url`=:url, `avail`=:avail, `note`=:note, `lastupdate`=cast(now() as datetime) WHERE `index`=:index';
$stmt2 = $pdo->prepare($query2);
$stmt2->bindValue(':photo',$photodata, PDO::PARAM_LOB);
$stmt2->bindValue(':name',$_POST["name"]);
if($_POST["category"]=="town"){
$stmt2->bindValue(':category','ご当地');
}else{
$stmt2->bindValue(':category','企業・団体');
}
$stmt2->bindValue(':area',$_POST["area"]);
$stmt2->bindValue(':affiliation',$_POST["affiliation"]);
$stmt2->bindValue(':url',$_POST["url"]);
if($_POST["avail"]=="dl"){$stmt2->bindValue(':avail','DL');}
elseif($_POST["avail"]=="sell"){$stmt2->bindValue(':avail','販売');}
elseif($_POST["avail"]=="haifu"){$stmt2->bindValue(':avail','配布');}
elseif($_POST["avail"]=="nodl"){$stmt2->bindValue(':avail','DL終了');}
elseif($_POST["avail"]=="nosell"){$stmt2->bindValue(':avail','販売終了');}
elseif($_POST["avail"]=="nohaifu"){$stmt2->bindValue(':avail','配布終了');}
else{$stmt2->bindValue(':avail','非公開');}
$stmt2->bindValue(':note',$_POST["note"]);
$stmt2->bindValue(':index', (int)$_POST["id"], PDO::PARAM_INT);
$stmt2->execute();
}
データベースの更新にはUPDATEというクエリを発行します。文法は2〜3行目の通りです。SELECTの時と同様に4行目でprepareしてやり、5行目行こうでプレースホルダに値を順次入れていっています。特記としては、最終更新日付をhow()関数を使って取得し、datetimeにキャストしていること、それとパスワードが無い事(パスワードだけは変更できない仕様です)くらいでしょうか。
新規登録の場合もこれと似ています。
エラーチェックは、パスワードチェックが無い点以外は修正登録時と同じです。
画像処理も修正登録時とほとんど同じですが、elseブロックの中身が変わっています。
if($_FILES["photourl"]["name"]){
//
//中略//
//
}else{
$photodata = file_get_contents("./images/ypindex/no-image_ypindex.jpg");
}
これは、写真が指定されなかったときは、「NO IMAGE」とかかれたjpegファイルを自動的に取り込むようにしたものです。
そして登録処理。
if(!$errorflg){
$query3 = 'INSERT INTO `yuruchara` (`name`, `photo`, `category`, `area`, `affiliation`, `url`, `avail`, `note`, `password`, `checked`, `lastupdate`) ';
$query3 = $query3.'VALUES(:name, :photo, :category, :area, :affiliation, :url, :avail, :note, :password, 0, cast(now() as datetime))';
$stmt3 = $pdo->prepare($query3);
//
// 中略
//
$new_id = $pdo->lastInsertId();
}
今度はUPDATE文ではなくINSERT文で、データベースに新たな行を追加しています。それから、indexは自動採番なので、登録が終わった後にlastInsertId()メソッドで番号を取り出しています。
そしてこの後に共通処理、入力ミス・漏れがあった時の訂正フォームです。
$checked01="";$checked02="";
if($_POST["category"]=="town"){$checked01="checked";}
else{$checked02="checked";}
$checked11="";$checked12="";$checked13="";$checked14="";$checked15="";$checked16="";$checked17="";
if($_POST["avail"]=="dl"){$checked11="checked";}
elseif($_POST["avail"]=="sell" ){$checked12="checked";}
elseif($_POST["avail"]=="haifu" ){$checked13="checked";}
elseif($_POST["avail"]=="nodl" ){$checked14="checked";}
elseif($_POST["avail"]=="nosell" ){$checked15="checked";}
elseif($_POST["avail"]=="nohaifu"){$checked16="checked";}
else{$checked17="checked";}
if($errorflg){
echo'<p>【不足データがあります】</p>';
}
echo'
<form action="ypmod.php" method="post" enctype="multipart/form-data">
<p>名前:<input type="text" name="name" value="'.$_POST["name"].'" size="20" /></p>';
if($errorflg1==1){
echo'<p class="errorcomment">*キャラクター名を入れてください。</p>';
}
if($_POST["id"]){
echo'<p>写真: <img class=ypphoto src=./ypimg.php?id='.$_POST["id"].'> <input type="file" name="photourl" /></p>';
}elseif($new_id){
echo'<p>写真: <img class=ypphoto src=./ypimg.php?id='.$new_id.'> <input type="file" name="photourl" /></p>';
}else{
echo'<p>写真:<input type="file" name="photourl" /></p>';
}
if($errorflg2){
echo'<p class="errorcomment">*jpeg,png,gifファイルを指定してください</p>';
}
echo'
<p>分類:
<input type="radio" name="category" value="town" '.$checked01.' />ご当地
<input type="radio" name="category" value="company" '.$checked02.' />企業・団体ゆるキャラ
</p>
<p>所属:<input type="text" name="affiliation" value="'.$_POST["affiliation"].'" size="20" /></p>';
if($errorflg3==1){
echo'<p class="errorcomment">*所属団体を入力してください。</p>';
}
echo'
<p>地域:<input type="text" name="area" value="'.$_POST["area"].'" size="20" /></p>';
if($errorflg5==1){
echo'<p class="errorcomment">*所在地域を入力してください。</p>';
}
echo'
<p>入手方法:<br/>
<input type="radio" name="avail" value="dl" '.$checked11.' />無料ダウンロード
<input type="radio" name="avail" value="sell" '.$checked12.' />販売
<input type="radio" name="avail" value="haifu" '.$checked13.' />配布
<br/>
<input type="radio" name="avail" value="nodl" '.$checked14.' />ダウンロード終了
<input type="radio" name="avail" value="nosell" '.$checked15.' />販売終了
<input type="radio" name="avail" value="nohaifu" '.$checked16.' />配布終了
<br/>
<input type="radio" name="avail" value="nothing" '.$checked17.' />非公開
</p>
<p>url:<input type="text" name="url" value="'.$_POST["url"].'" size="40" /></p>
<p>コメント:<br/><textarea name="note" rows="4" cols="40" >'.$_POST["note"].'</textarea></p>
<p>修正用パスワード:<input type="password" name="password" value="" size="20" /></p>';
if($errorflg4==1){
echo'<p class="errorcomment">*修正用パスワードを入力してください。</p>';
}elseif($errorflg4==2){
echo'<p class="errorcomment">*正しいパスワードを入力してください。</p>';
}
if($errorflg==1 and !$_POST["id"]){
echo'<p><input type="submit" name="submit" value="登録"/></p>';
}else{
echo'<p><input type="submit" name="submit" value="修正"/></p>';
}
if($_POST["id"]){
echo'<input type="hidden" name="id" value='.$_POST["id"].'>';
}else{
echo'<input type="hidden" name="id" value='.$new_id.'>';
}
echo'</form>';
if($_POST["id"] or $new_id){
echo'<form action="ypdelete.php" method="post">';
if($_POST["id"]){
echo'<input type="hidden" name="id" value='.$_POST["id"].'>';
}else{
echo'<input type="hidden" name="id" value='.$new_id.'>';
}
echo'<p><input type="submit" name="submit" value="削除"/></p></form>';
}
if(!$errorflg){
echo'<p><a class="clear_and_new" href="ypmod.php">フォームクリア&新規登録<a></p>';
}
まず1から11行目までのブロックは、ラジオボタンにチェックを入れるための”checked"の設定をしているところです。
13〜15行目は、入力漏れがあった時に表示させるコメントです。
17行目からが訂正フォームを表示させる部分ですが、例えば20〜22行目のようにところどころに、エラーコードに応じてコメントを挿入するような文が入っています。class="errorcomment"とし、CSSで赤く色を付けています。
67〜71行目で、idがPOSTで来ているかどうかを見て初度登録か修正登録かを判別し、フォームの送信ボタンの文字を入れ替えています。
その後、72〜77行目で、index番号をhiddenで埋め込んでいます。
79行目から87行目は、見た目は「削除」ボタンしかありませんが、index番号を埋め込んで削除スクリプトypdelete.phpを呼び出すボタンになっています。
最後の3行は、無事エラーなしに登録完了した場合に表示される、フォームクリア&新規登録ボタンです。何のオプションも無しにypmod.phpを呼び出しています。
この後は、修正フォームと新規登録フォームの表示です。細かい説明は省略しようと思います。まずは修正フォーム。
}elseif(($_SERVER["REQUEST_METHOD"] == "GET")and(isset($_GET["id"]))){
// DBから読み出し後、修正フォームを表示
$stmt1 = $pdo->prepare('SELECT * FROM yuruchara WHERE `index` = :index');
$stmt1->bindValue(':index', (int)$_GET["id"], PDO::PARAM_INT);
$stmt1->execute();
$row = $stmt1->fetch();
$checked01="";$checked02="";
if($row["category"]=="ご当地"){$checked01="checked";}
else{$checked02="checked";}
$checked11="";$checked12="";$checked13="";$checked14="";$checked15="";$checked16="";$checked17="";
if($row["avail"]=="DL"){$checked11="checked";}
elseif($row["avail"]=="販売" ){$checked12="checked";}
elseif($row["avail"]=="配布" ){$checked13="checked";}
elseif($row["avail"]=="DL終了" ){$checked14="checked";}
elseif($row["avail"]=="販売終了" ){$checked15="checked";}
elseif($row["avail"]=="配布終了"){$checked16="checked";}
else{$checked17="checked";}
echo '<p>【データ修正】</p>
<form action="ypmod.php" method="post" enctype="multipart/form-data">
<p>名前:<input type="text" name="name" value="'.$row["name"].'" size="20" /> ゆるキャラの名前</p>';
echo'<p>写真: <img class=ypphoto src=./ypimg.php?id='.$row['index'].'> <input type="file" name="photourl" /><br/>
(写真は自動的に120×80ピクセルに縮小されます。)</p>';
echo'
<p>分類:
<input type="radio" name="category" value="town" '.$checked01.' />ご当地
<input type="radio" name="category" value="company" '.$checked02.' />企業・団体ゆるキャラ
</p>
<p>所属:<input type="text" name="affiliation" value="'.$row["affiliation"].'" size="20" /> 所属する市町村・企業・団体名</p>
<p>地域:<input type="text" name="area" value="'.$row["area"].'" size="20" /> 都道府県、または全国</p>';
echo'
<p>入手方法:<br/>
<input type="radio" name="avail" value="dl" '.$checked11.' />無料ダウンロード
<input type="radio" name="avail" value="sell" '.$checked12.' />販売
<input type="radio" name="avail" value="haifu" '.$checked13.' />配布
<br/>
<input type="radio" name="avail" value="nodl" '.$checked14.' />ダウンロード終了
<input type="radio" name="avail" value="nosell" '.$checked15.' />販売終了
<input type="radio" name="avail" value="nohaifu" '.$checked16.' />配布終了
<br/>
<input type="radio" name="avail" value="nothing" '.$checked17.' />非公開
</p>
<p>url:<input type="text" name="url" value="'.$row["url"].'" size="60" /></p>
<p>コメント:<br/><textarea name="note" rows="4" cols="40" >'.$row["note"].'</textarea></p>
<p>修正用パスワード:<input type="password" name="password" value="" size="20" /></p>';
echo'<input type="hidden" name="id" value='.$row["index"].'>';
echo'<p><input type="submit" name="submit" value="修正"/></p>';
echo'</form>';
echo'<form action="ypdelete.php" method="post">
<input type="hidden" name="id" value='.$row["index"].'>
<p><input type="submit" name="submit" value="削除"/></p>
</form>';
データベース内の登録情報があらかじめフォームに記入されるようにしています。
そして新規登録フォームです。
}else{
// 新規登録フォームを表示
echo '<p>【新規追加】</p>
<form action="ypmod.php" method="post" enctype="multipart/form-data">
<p>名前:<input type="text" name="name" size="20" /> ゆるキャラの名前</p>
<p>写真:<input type="file" name="photourl" /><br/>
(写真は自動的に120×80ピクセルに縮小されます。)</p>
<p>分類:
<input type="radio" name="category" value="town" checked="checked" />ご当地
<input type="radio" name="category" value="company" />企業・団体ゆるキャラ
</p>
<p>所属:<input type="text" name="affiliation" size="20" /> 所属する市町村・企業・団体名</p>
<p>地域:<input type="text" name="area" size="20" /> 都道府県、または全国</p>
<p>入手方法:<br/>
<input type="radio" name="avail" value="dl" checked="checked" />無料ダウンロード
<input type="radio" name="avail" value="sell" />販売
<input type="radio" name="avail" value="haifu" />配布
<br/>
<input type="radio" name="avail" value="nodl" />ダウンロード終了
<input type="radio" name="avail" value="nosell" />販売終了
<input type="radio" name="avail" value="nohaifu" />配布終了
<br/>
<input type="radio" name="avail" value="nothing" />非公開
</p>
<p>url:<input type="text" name="url" size="60" /></p>
<p>コメント:<br/><textarea name="note" rows="4" cols="40"></textarea></p>
<p>修正用パスワード:<input type="password" name="password" value="" size="20"/></p>
<p><input type="submit" name="submit" value="登録"/></p>
</form>';
}
何も書かれていない、まっさらのフォームです。
最後に告知をして、接続を切って終了です。
echo '<p>本インデックスへのご意見・ご要望・データ削除依頼などは→<a href="http://6243.teacup.com/papercraft/bbs" target="_blank">【掲示板】</a>へどうぞ。</p>';
$pdo = null;
以上、長くなりましたがデータベース修正スクリプトの説明でした。
次回は最終回、データベース内容削除スクリプトのypdelete.phpの解説です。