DB連携ダイアリー

 通常のファイルベースの日記帳スクリプトだと、記事を日付順に表示するとかが結構難しいので、ここではより便利になるようにデータベース連携版にする事にしました。データベース連携版だと記事の更新も非常に簡単ですし、ファイルベースのものとは一味違うスクリプトになるはずです。

テーブル構造

 今回から文字列データに文字数制限を加えました。

[テーブル作成文]

create table db_diary (code int4, year int2, month int2, day int2,subject varchar(50), msg varchar(500),img_name varchar(30), primary key (code));

インデックス番号

列名

データ型

0 code int4
1 year int2
2 month int2
3 day int2
4 subject varchar(50)
5 msg varchar(500)
6 img_name varchar(30)

プログラム内容

<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html;CHARSET=x-sjis">
<TITLE>KOMOダイアリー(DB連携版)</TITLE>

<STYLE TYPE="text/css">
<!--
:link {
Color : blue ;
Text-Decoration : None
}
:active {
Color : blue ;
Text-Decoration : None
}
:visited {
Color : blue ;
Text-Decoration : None
}
A:hover {
Color : blue ;
Text-Decoration : Underline
}
-->
</STYLE>

</HEAD>
<BODY BGCOLOR="#FFFBF0">
<CENTER>
<P><IMG SRC="title.gif" WIDTH="415" HEIGHT="82" ALIGN="BOTTOM" BORDER="0"></P>
<P><FONT COLOR="#990066"><B>データベース連携の日記帳スクリプトです。記事は日付順(降順)に表示されます。</B></FONT><BR>
パスワードは「777」に設定しています。お試しあれ!(^o^)丿</P>
HTMLの最初の部分です。別に難しい所はありませんね。
<?php
//====================初期設定======================
$db_user = "psql"; //データベースのユーザー名(自分の環境に合わせて変更の事)
$db_name = "database"; //データベース名(自分の環境に合わせて変更の事)
$passwd = '777'; //管理者用パスワード
$data_max = 200; //データ最大記録数
$page_view = 5; //1ページの記事表示件数
$this_year = date("Y"); //アクセス時の年
$this_month = date("n"); //アクセス時の月
$this_day = date("d"); //アクセス時の日
$up_dir = '/img/'; //画像保存用ディレクトリ
$w_max = 200; //画像の横幅の最大値(ピクセル)
$h_max = 200; //画像の縦幅の最大値(ピクセル)
$w_limit = 600; //画像の横幅の制限値(ピクセル)
$h_limit = 400; //画像の縦幅の制限値(ピクセル)
//==================================================
PHPの開始。

初期設定部分です。データベース接続時のユーザー名とデータベース名は、適当に自分の環境に合わせて変えて下さい。
$php_v = PHP_VERSION; //PHPバージョンの取得
if($php_v > "4.1.0"){ //スーパーグローバル変数対応なら
 $path = dirname($_SERVER["PATH_TRANSLATED"]).$up_dir;
 $PHP_SELF = $_SERVER["PHP_SELF"];
 //フォームデータの取得
 $action = $_POST['action'];
 $code = $_POST['code'];
 $year = $_POST['year'];
 $month = $_POST['month'];
 $day = $_POST['day'];
 $subject = $_POST['subject'];
 $msg = $_POST['msg'];
 $img_name = $_POST['img_name'];
 $img_del = $_POST['img_del'];
 $button = $_POST['button'];
 $password = $_POST['password'];
 $e_code = $_POST['e_code'];
 $upfile = $_FILES['upfile']['tmp_name'];
 $upfile_name = $_FILES['upfile']['name'];
 $pline = $_POST['pline'];
}else{
 $path = dirname($PATH_TRANSLATED).$up_dir;
}
スーパーグローバル変数対策です。最近のサーバではほとんどこの処理が必要です。気をつけましょう(^.^)
//===============インライン関数===================
function inline_link($link){
 $link = ereg_replace("(https?|ftp|news)(://[[:alnum:]\+\$\;\?\.%,!#~*/:@&=_-]+)","<a href=\"\\1\\2\" target=\"_blank\">\\1\\2</a>",$link);
 return $link;
}
//================================================
コメント内にリンク記述部分があれば、自動でリンク表示を施します。
if(!$d_base = pg_connect("user=psql dbname=database")){ //データベースに接続
 $err_msg = "データベースへの接続に失敗しました。";
}
データベースに接続します。接続できなかったときのエラー処理を施しています。
if($action == "regist"){
 //処理の分岐
 if($button == "修正/更新"){
  //インラインリンクを実現(URLのみ)
  $msg = inline_link($msg);
  if(strlen($msg) < 500){
   //画像を削除
   if($img_del){
    unlink(".".$up_dir.$img_name);
   }
   if($upfile){
    $source = $upfile;
    $source_name = $upfile_name;
    $source_name = ereg_replace("^(.:.*\\\\)?(.*)", "\\2", $source_name);
    if(($source != "none")&&($source != "")){
     $dest = $path.$source_name;
     $imagesize = getimagesize($source);
     if(($imagesize[0] > $w_limit) || ($imagesize[1] > $h_limit)){ //大きな画像のアップを制限
      $err_msg = "画像のサイズが大き過ぎて登録できませんでした。";
     }else{
      if(copy($source,$dest)){
       $imagesize = getimagesize($dest);
       switch($imagesize[2]){
        case 0:
        unlink($dest);
        break;
        case 1:
        $out = $code.".gif";
        rename($dest,$path.$out);
        break;
        case 2:
        $out = $code.".jpg";
        rename($dest,$path.$out);
        break;
        case 3:
        $out = $code.".png";
        rename($dest,$path.$out);
        break;
       }
      }
      $img_name = $out;
     }
    }
   }
   //アップデート
   pg_exec($d_base, "update db_diary set code = " . $code . ",year = " . $year . ",month = " . $month . ",day = " . $day . ",subject = '" . $subject . "',msg = '" . $msg . "',img_name = '" . $img_name . "' where code = " . $code);
   //再読み込み
   echo "<META HTTP-EQUIV=refresh content=0;URL=$PHP_SELF>";
   exit;
  }else{
   $err_msg = "コメントの文字数が多すぎます。";
  }
 }
書き込み処理部分です。

変数$buttonの値によって処理を分けています。ここは修正更新処理部分です。

メッセージの文字数制限を設けていますので、注意が必要です。

画像削除の為の変数$img_delがセットされていれば、
unlink関数を使って画像を削除します。

★int unlink( string filename )関数…引数filename で指定されたファイルを削除します。成功すると0を返し、エラーの場合はfalseを返します。

次は、画像の修正アップロード処理部分です。アップロードしようとしている画像のサイズに制限を設けています。

データベースのアップデートには「
update」SQL文を使います。画像表示を更新する為、リフレッシュしている点に注意して下さい。
 if($button == "削除"){
  if($code){
   //画像の削除処理
   $result = pg_exec($d_base, "select * from db_diary where code = " . $code);
   $arr = pg_fetch_row($result, 0); //検索結果の一行分を配列に格納
   $img_name = $arr[6];
   unlink(".".$up_dir.$img_name);
   //該当データを削除
   pg_exec($d_base, "delete from db_diary where code = " . $code);
  }
 }
削除処理部分です。

まず、送られてきたコード$codeの値から、格納されている画像ファイル名を取得し、unlink()関数を使って画像を削除します。

次に「
delete」SQL文を使って、該当データを削除しています。
 if($button == "送信/更新"){
  if($msg){
   $code = time(); //アクセス時の秒数
   //インラインリンクを実現(URLのみ)
   $msg = inline_link($msg);
   if(strlen($msg) < 500){
    if($upfile){
     $source = $upfile;
     $source_name = $upfile_name;
     $source_name = ereg_replace("^(.:.*\\\\)?(.*)", "\\2", $source_name);
     if(($source != "none")&&($source != "")){
      $dest = $path.$source_name;
      $imagesize = getimagesize($source);
      if(($imagesize[0] > $w_limit) || ($imagesize[1] > $h_limit)){ //大きな画像のアップを制限
       $err_msg = "画像のサイズが大き過ぎて登録できませんでした。";
      }else{
       if(copy($source,$dest)){
        $imagesize = getimagesize($dest);
        switch($imagesize[2]){
         case 0:
         unlink($dest);
         break;
         case 1:
         $out = $code.".gif";
         rename($dest,$path.$out);
         break;
         case 2:
         $out = $code.".jpg";
         rename($dest,$path.$out);
         break;
         case 3:
         $out = $code.".png";
         rename($dest,$path.$out);
         break;
        }
       }
       $img_name = $out;
      }
     }
    }else{
     $img_name = '';
    }
    pg_exec($d_base, "insert into db_diary values ($code,$year,$month,$day,'$subject','$msg','$img_name')");
    //データ最大記録数を調整
    if($result = pg_exec($d_base, "select * from db_diary order by code DESC")){
     $row = pg_numrows($result); //検索結果の行数を取得
     if($row > ($data_max * 1.2)){
      $arr = pg_fetch_row($result, $data_max);
      $max_arr = $arr[0];
      pg_exec($d_base, "delete from db_diary where code <= $max_arr");
     }
    }
   }else{
    $err_msg = "コメントの文字数が多すぎます。";
   }
  }else{
   $err_msg = "コメントが書き込まれていません。";
  }
 }
新規登録処理部分です。

time()関数を使って、アクセス時の秒数を取得し、それを変数$codeの値に使っています。

メッセージの文字数制限を設けていますので、注意が必要です。

後はいつもの画像のアップロード処理です。

最初の書き込み処理ですから、データベースへの登録は「
insert」SQL文を使います。

データベースへの新規登録処理が終わった後、記事の最大記録数の調整を行ないます。

まずデータをコードの値を元に降順に取得します。次に取得したデータの行数(記事数)を取得します。これを初期設定の「データ最大記録数」と比較して、1.2倍を超えていれば削除処理に移ります。1.2倍に設定したのは、記事数が「データ最大記録数」を超えた場合に、いちいち削除処理を行っていたのでは、パフォーマンスが下がるからです。

削除処理は以下のような順序で行なわれています。まず、
pg_fetch_row()関数を使って、初期設定の「データ最大記録数」部分に当たるデータ1行分を取得します。次にそのコードの値を取得し、データベースからコードの値がその取得したコードの値以下のものを削除します。

★array pg_fetch_row( int result, int row )関数…数字をインデックスとする配列として行を取得します。行がもうない場合にfalseを返します。

コードの値は、古い記事ほど値が小さいことに注意しましょう。
}elseif(($action == "edit") && ($password == $passwd)){
 $kanri_flag = 1; //管理マドの表示制御用フラグ
 echo "<form action=$PHP_SELF method=POST ENCTYPE=multipart/form-data>\n";
 echo "<input type=hidden name=action value=regist>\n";
 if($e_code) {
  if($result = pg_exec($d_base, "select * from db_diary where code = " . $e_code)){
   $arr = pg_fetch_row($result, 0); //検索結果の一行分の各値を配列に格納
   $e_code = $arr[0];
   $e_year = $arr[1];
   $e_month = $arr[2];
   $e_day = $arr[3];
   $e_subject = $arr[4];
   $e_msg = $arr[5];
   $img_name = $arr[6];
  }
  echo "<input type=hidden name=code value=\"$e_code\">\n";
  echo "<input type=hidden name=img_name value=\"$img_name\">\n";
  echo "<table border=0>\n";
  echo "<tr><td align=right><B>日付:</B></td><td><SELECT NAME=year>";
  for($i=$this_year-1; $i<$this_year+5; $i++){
   echo "<OPTION" . (($e_year == $i) ? ' SELECTED' : '') . ">$i</OPTION>";
  }
  echo "</SELECT>年<SELECT NAME=month>";
  for($i=1; $i<13; $i++){
   echo "<OPTION" . (($e_month == $i) ? ' SELECTED' : '') . ">$i</OPTION>";
  }
  echo "</SELECT>月<SELECT NAME=day>";
  for($i=1; $i<32; $i++){
   echo "<OPTION" . (($e_day == $i) ? ' SELECTED' : '') . ">$i</OPTION>";
  }
  echo "</SELECT>日</td></tr>\n";
  echo "<tr><td align=right><B>題名:</B></td><td><input type=text size=35 name=subject value=\"$e_subject\"></td></tr>\n";
  echo "<tr><td align=right><B>コメント:</B></td><td><textarea name=msg rows=6 cols=50>$e_msg</textarea></td></tr>\n";
  echo "<tr><td align=right><B>添付画像:</B></td><td>上書<INPUT TYPE=file NAME=upfile SIZE=35> 削除<INPUT TYPE=CHECKBOX NAME=img_del VALUE=1></td></tr>\n";
  echo "</table>\n";
  echo "<input type=submit name=button value=修正/更新> <input type=submit name=button value=削除>\n";
管理編集処理部分です。

管理マドから送られたパスワードの値が合っていれば、管理編集処理に移ります。

変数
$e_codeの値の有無によって、「新規登録モード」か「修正モード」かの判断を行なっています。

ここは、変数
$e_codeの値がある場合ですから、「修正モード」になります。

まずデータベースから、該当のコードに当たる記事の値を
pg_fetch_row()関数を使ってそれぞれ取得します。取得したそれぞれの値は、投稿フォームのそれぞれの値に読み込んでいます。
 }else{
  echo "<table border=0>\n";
  echo "<tr><td align=right><B>日付:</B></td><td><SELECT NAME=year>";
  for($i=$this_year-1; $i<$this_year+5; $i++){
   echo "<OPTION" . (($this_year == $i) ? ' SELECTED' : '') . ">$i</OPTION>";
  }
  echo "</SELECT>年<SELECT NAME=month>";
  for($i=1; $i<13; $i++){
   echo "<OPTION" . (($this_month == $i) ? ' SELECTED' : '') . ">$i</OPTION>";
  }
  echo "</SELECT>月<SELECT NAME=day>";
  for($i=1; $i<32; $i++){
   echo "<OPTION" . (($this_day == $i) ? ' SELECTED' : '') . ">$i</OPTION>";
  }
  echo "</SELECT>日</td></tr>\n";
  echo "<tr><td align=right><B>題名:</B></td><td><input type=text size=35 name=subject></td></tr>\n";
  echo "<tr><td align=right><B>コメント:</B></td><td><textarea name=msg rows=6 cols=50></textarea></td></tr>\n";
  echo "<tr><td align=right><B>添付画像:</B></td><td><INPUT TYPE=file NAME=upfile SIZE=35></td></tr>\n";
  echo "</table>\n";
  echo "<input type=submit name=button value=送信/更新> <input type=reset value=リセット>\n";
 }
 echo "</form>\n";
}
管理編集処理部分です。

ここは変数
$e_codeの値がありませんので、新規登録処理になります。投稿フォームを表示して、新規に投稿データを書き込み、アップロードします。
//エラー処理
if($err_msg){
 echo "<FONT COLOR='red'>" . $err_msg . "</FONT>";
 echo "<BR><BR><A HREF=$PHP_SELF onMouseOver=this.style.color='red' onMouseOut=this.style.color='blue'><やり直す></A>\n";
 exit;
}
ここは、今までの処理中でエラーが発生した場合の、エラー告知(表示)処理部分です。

exit;」でこれ以降の処理を抜けます。
echo "<form action=$PHP_SELF method=POST>\n";
echo "<input type=hidden name=mode value=sort>\n";
echo "<input type=hidden name=action value=\"$action\">\n";
echo "<input type=hidden name=password value=\"$password\">\n";
echo "<input type=hidden name=pline value=\"$pline\">\n";
echo "<B>文字列検索:</B><FONT SIZE=2>題名又はコメントに文字列</FONT><input type=text size=20 name=search_str><FONT SIZE=2>を含む</FONT> <input type=submit name=submit value=送信> <input type=reset value=リセット></FORM>\n";
記事中に文字列検索をかける為のフォームを表示します。
if($mode == 'sort'){
 if($search_str){
  $SQLstr = "select * from db_diary where subject like '%" . $search_str . "%' or msg like '%" . $search_str . "%' order by year DESC, month DESC, day DESC";
 }else{
  $SQLstr = "select * from db_diary order by year DESC, month DESC, day DESC";
 }
}else{
 $SQLstr = "select * from db_diary order by year DESC, month DESC, day DESC";
}
文字列検索がかけられた場合と通常の場合とで、記事表示の為のデータ取得用SQL文を書き分けます。
if($result = pg_exec($d_base, $SQLstr)){
 $row = pg_numrows($result); //検索結果の行数を取得
 if($row > 0){
  if($pline == ""){
   $p_line = 0;
  }else{
   $p_line = $pline;
  }
  $end_data = $row - 1;
  $page_end = $p_line + ($page_view - 1);
  if($page_end >= $end_data)
   $page_end = $end_data;
  for($i=$p_line; $i<=$page_end; $i++){
   $arr = pg_fetch_row($result, $i); //検索結果の一行分を配列に格納
   //曜日を生成
   $date_str = $arr[1] . "/" . $arr[2] . "/" . $arr[3];
   $date_timestamp = strtotime($date_str);
   $week_day = strftime("%a", $date_timestamp);
   if($week_day == 'Sun'){
    $font1 = "<FONT COLOR='red'>";
    $font2 = "</FONT>";
   }elseif($week_day == 'Sat'){
    $font1 = "<FONT COLOR='blue'>";
    $font2 = "</FONT>";
   }else{
    $font1 = "";
    $font2 = "";
   }
   echo "<form action=$PHP_SELF method=POST>\n";
   echo "<input type=hidden name=action value=edit>\n";
   echo "<input type=hidden name=e_code value=\"$arr[0]\">\n";
   echo "<input type=hidden name=pline value=$pline>\n";
   echo "<table border=1 width=90% bordercolor=#555555>\n";
   echo "<tr><td>■<b>" . $arr[1] . "/" . $arr[2] . "/" . $arr[3] . "(" . $font1 . $week_day . $font2 . ")</B>\n";
   echo " <font color='green' size=4><b>" . $arr[4] . "</b></font>\n";
   if (($action == "edit") && ($password == $passwd)) {
    echo "<input type=hidden name=password value=$passwd> <input type=submit value=訂正>\n";
   }
   echo "</td></tr><tr><td><blockquote>\n";
   if($arr[6]){
    $img_name = $arr[6];
    if(file_exists("$path$img_name")){
     $size = getimagesize("$path$img_name");
     $img_w=$size[0];
     $img_h=$size[1];
     if($img_w > $w_max || $img_h > $h_max){
      $w_ritu = $w_max / $img_w;
      $h_ritu = $h_max / $img_h;
      ($w_ritu < $h_ritu) ? $key = $w_ritu : $key = $h_ritu;
      $width = (int) $img_w * $key;
      $height = (int) $img_h * $key;
      echo "<A HREF=.$up_dir$img_name TARGET=_blank><img src=.$up_dir$img_name WIDTH=" . $width . " HEIGHT=" . $height . " ALIGN=LEFT></A>";
     }else{
      echo "<img src=.$up_dir$img_name ALIGN=LEFT>";
     }
    }
   }
   $msg = nl2br($arr[5]);
   echo $msg . "</blockquote></td></tr></table></form>\n";
  }
 }else{
  echo "<FONT COLOR='red'>登録されている記事がありません。</FONT>";
 }
}
?>
記事表示部分です。

データベースから記事データを取得し、
pg_numrows()関数を使って記事の行数(記事の件数)を取得します。

★int pg_numrows( int result_id )関数…引数result_id で指定されたPostgreSQLの結果IDにおける行数を返します。引数は、pg_Exec()で返された有効な結果IDです。この関数は、エラーの際に-1を返します。

pg_fetch_row()関数を使って、記事の各行のデータを取得します。各行のデータを配列変数$arrに格納し、それぞれの場所に該当の値を表示します。

画像の表示部分の処理内容は、通常の画像掲示板と同様です。
<P>
<TABLE BORDER="0" WIDTH="600">
 <TR>
  <TD WIDTH="50%">
HTML部分
<?php
if($page_end >= $page_view){
 $page_count = floor($page_end / $page_view);
 $prev_line = ($page_count - 1) * $page_view;
 echo "<form method=Post action=$PHP_SELF>\n";
 if (($action == 'edit') && ($password == $passwd)){
  echo "<input type=hidden name=action value=edit>\n";
  echo "<input type=hidden name=password value=$passwd>\n";
 }
 echo "<input type=hidden name=pline value=$prev_line>\n";
 echo "<input type=hidden name=sort_flag value=$sort_flag>\n";
 echo "<input type=submit value=前のページ>\n";
 echo "</form>\n";
}else{
 echo "&nbsp;\n";
}
?>
「前のページ」への移動用ボタンを表示します。処理内容は通常の掲示板スクリプトと同じです。
  </TD>
  <TD WIDTH="50%"><P ALIGN="RIGHT">
HTML部分
<?php
$next_line = $page_end + 1;
if($page_end != $end_data){
 echo "<form method=Post action=$PHP_SELF>\n";
 if (($action == 'edit') && ($password == $passwd)){
  echo "<input type=hidden name=action value=edit>\n";
  echo "<input type=hidden name=password value=$passwd>\n";
 }
 echo "<input type=hidden name=pline value=$next_line>\n";
 echo "<input type=submit value=次のページ>\n";
 echo "</form>\n";
}else{
 echo "&nbsp;\n";
}
?>
「次のページ」への移動用ボタンを表示します。処理内容は通常の掲示板スクリプトと同じです。
  </TD>
 </TR>
</TABLE>
HTML部分
<?php
if($kanri_flag < 1){
 echo "<div align=left>\n";
 echo "<form action=$PHP_SELF method=POST>\n";
 echo "<input type=hidden name=action value=edit>\n";
 echo "<input type=password size=10 name=password>\n";
 echo "<input type=hidden name=pline value=$pline>\n";
 echo " <input type=submit value=管理><br>\n";
 echo "</form></div>\n";
}
?>
管理用ページに移るためのフォームを表示します。変数$kanri_flagの値によって、表示の有無をコントロールします。
</BODY>
</HTML>
HTML部分の終わり

<サンプルだよ!>

*上の内容をこのまま複写しても動きません。何故なら、表示を見やすくする為コード中に全角スペースが入っているからです。実際にお使いになる時は、この点を修正してからサーバにアップして下さい。

DB連携掲示板スペシャル 前へ

HOME

次へ DB連携Accessアナライザー