• ベストアンサー

PHP掲示板で新着順に表示させたい【ソーティング】

PHPで簡単な掲示板を作っているのですが、 新着順になるように、投稿したら一番上に来るようにしたいのですがそれができません。 $record .= date("Y年m月d日 H時i分s秒",time())."\n"; と投稿した日付を取得しています。 これを使って新着順にすることはできないでしょうか? 新着順にしてくれる簡単なやり方はないんでしょうか・・。調べましたがぜんぜんのってません(泣)

質問者が選んだベストアンサー

  • ベストアンサー
  • togino
  • ベストアンサー率75% (97/129)
回答No.7

(注意:インデントの為、行の先頭には【全角スペース】が入っています。コピーするのではなく、手で入力しなおしてください) 関数 Get_Record はそのままです。 $count = 0; $fp = @fopen("1.log","r"); if($fp) {  while(1) {   $line = Get_Record($fp);   if($line == "") break;   // $record_all[] 配列にすべての Record を読み込む   $record_all[$count] = $line;   // $line より、その Record の書き込み日時を取得する   list($name,$year,$month,$day,$timeman,$minuteman,$timeman2004,$minuteman2004,$message) = split("\t",$line);   $record_time[$count] = $year.$month.$day; // ←★ ちゃんと、書き込み日時をあらわすものにしなければならない! ★   $count++;  }  $fclose($fp); } else {  $error = "データファイルを閲覧できませんでした。"; } // 書き込み日時で並び替えを行う arsort($record_time); // 並び替えられた順序を表す配列を取得する $record_sorted = array_keys($record_time); // 以下は、$offset の決定 // 従来のままでよい $MAX_REC = 20; if(!$offset) $offset = 0; ・・・略・・・  if($offset >= $count) $offset -= $MAX_REC; } // $offset から $MAX_REC 件表示する for($i = 0; $i < $MAX_REC; $i++){  // 全件数より大きい(後ろ)のであれば、表示を終了  if($offset + $i >= $count) break;  // 表示する書き込みの $line を得る  $line = $record_all[$record_sorted[$offset + $i]];  // 以下 $line の内容を表示  // 従来のままでよい  list($name,$year,$month,$day,$timeman,$minuteman,$timeman2004,$minuteman2004,$message) = split("\t",$line);  if($name == "") $name = " "; ・・・略・・・  if($message == "") $message= " ";  echo '<table>・・・ながなが・・・<br><p>'; } --------------- さて難しいのは $record_time 配列と $record_sorted 配列の部分で、最後に  // 表示する書き込みの $line を得る  $line = $record_all[$record_sorted[$offset + $i]]; としている所ではないでしょうか? まず、$record_all 配列は $record_all[0] = "1件目の内容"; $record_all[1] = "2件目の内容"; $record_all[2] = "3件目の内容"; となっています。そして、$record_time は $record_time[0] = "20040813(1件目の日時"; $record_time[1] = "20030813(2件目の日時"; $record_time[2] = "20040814(3件目の日時"; となります。 // 書き込み日時で並び替えを行う arsort($record_time); の結果 $record_time[2] = "20040814(3件目の日時"; $record_time[0] = "20040813(1件目の日時"; $record_time[1] = "20030813(2件目の日時"; のように、日時で並び替えを行います。 その結果の配列の順番を array_keys で取得すると // 並び替えられた順序を表す配列を取得する $record_sorted = array_keys($record_time); の結果 $record_sorted[0] = "2"; // 最新は 2 つまり 3件目が最新 $record_sorted[1] = "0"; $record_sorted[2] = "1"; のように、並び替えられた順番を表す配列が得られます。 以上より for($i = 0; $i < $count; $i ++){  $line = $record_all[$record_sorted[$i]]; } にて、最新の順に書き込み内容が得られるということです。 いかがでしょうか?

ankoman2
質問者

お礼

お礼が遅くなりまして申し訳ございませんでした。 勉強にすごく時間がかかりました(^^;) 私でも理解できるようにご説明いただきましたまことに有り難うございます!!!! 本当にわかりやすかったです。ペコリ

その他の回答 (7)

  • togino
  • ベストアンサー率75% (97/129)
回答No.8

あと最後になりますが、moon_night さんが回答されている 多次元ソートを使って $record_all 配列を直接並び替えるということも可能です。 比較関数なるものを定義し、その中で $line の解析と日時の取り出しを行えば、もっとシンプルにプログラムは書けると思います。 なお、log の中身が日付順になっているのであれば、もっとシンプルに if($fp) {  while(1) {   $line = Get_Record($fp);   if($line == "") break;   // $record_all[] 配列にすべての Record を読み込む   array_unshift($record_all, $line)   $count++;  }  $fclose($fp); } するだけで、新着順になっています。 がんばってください。

ankoman2
質問者

お礼

ist($name,$year,$month,$day,$timeman,$minuteman,$timeman2004,$minuteman2004,$message) = split("\t",$line); if($name == "") $name = " "; if($year == "") $month = " "; if($month == "") $month = " "; if($day == "") $day = " "; if($timeman == "") $timeman = " "; if($minuteman == "") $minuteman = " "; if($timeman2004 == "") $timeman2004 = " "; if($minuteman2004 == "") $minuteman2004 = " "; if($message == "") $message= " "; timemanというのが「開始時間」 minutemanというのが「開始分」 timeman2004というのが「終了時間」 minuteman2004というのが「終了分」 でした。汗。 本当に申し訳ございません。

  • togino
  • ベストアンサー率75% (97/129)
回答No.6

では、お望みのようにプログラムを改造します。 ついて来てくださいね。わからない部分があったら質問してください。折角ですので、どう改造したのか理解してほしいですし・・・。コピーして「よく分からんが動いた」なんていうのは嫌ですから。 まず、現状のプログラムの流れをまとめます。 ■ log ファイルを開き、全部で何件(record)あるか数える ■ 表示を開始する位置(offset)を決定する ■ 表示を開始する位置まで、読み飛ばす ■ 最大表示件数分(または最後まで)、順に読んで表示する ですよね。 ここで、日付順に並び変えたいということになりますと いったんすべての record をメモリに読み込んでから 並び替えを行い、表示するという流れに変わります。 つまり ■ log ファイルを開き、全書き込みを読み込む ■ 日付で並び替えを行う ■ 表示を開始する位置(offset)を決定する ■ 並び替えを終えた方に対して、offset から順に最大表示件数分、表示を行う。 という風に改造します。 さて、具体的にプログラムの書き換えを始めますが 一点全く意味が分からない部分があります(汗) > list($name,$year,$month,$day,$timeman,$minuteman,$timeman2004,$minuteman2004,$message) = split("\t",$line); の $timeman,$minuteman,$timeman2004,$minuteman2004 4つ変数はなんですか??? 「タイムマン」「ミニッツマン」「タイムマン2004」??? も~っちょと意味ある名前にしてもらいたいところですが・・・ えっと、ここで重要なのは、書き込みされた日時がどのような形式で保存されているのかという点です。 推測するに $year が 2004, $month が 08, $day が 13 みたいなので年月日までは分かります。時間と分はどうなっているのでしょうか? とりあえず、年月日時分秒 なる文字列を log から取り出さないといけません。ここでは list($name,$year,$month,$day,$timeman,$minuteman,$timeman2004,$minuteman2004,$message) = split("\t",$line); $message_datetime = $year . $month . $day; にて $message_datetime の中身を、この書き込みの日時としますが、正しいものを教えてください。 では、次の回答で具体的なプログラムを掲載します。

ankoman2
質問者

お礼

帰省しておりましてお返事が大変遅くなり申し訳ございませんでした! 今からじっくりと、べんきょうさせていただきます!またご報告に参ります!

  • togino
  • ベストアンサー率75% (97/129)
回答No.5

> logに保存した内容を取り出しているだけです 2つの大きな方針があります。どちらで行きますか? ■ そもそも新着順になるよう log に書き込む ■ log を読み込む時、解析しながら順番を変えて表示する。 --- ■ そもそも新着順になるよう log に書き込む 通常掲示板でしたら、log は時間順になっているはずです。 (古いのが先頭、新しいのが最後) でも新しい投稿を、log ファイルの先頭に書き込むようにすれば、新着順になります。 【長所】処理がシンプル 【短所】log の形式が変わる。ファイルアクセスの効率が悪い。投稿が必ず時間順であると仮定している。 ■ log を読み込む時、解析しながら順番を変えて表示する log の中身(形式)に依存します。 投稿された書き込み内容と日付の他に、投稿した人のアカウント名とか、なにやらとありませんか? またそれらを区別するためにタグをつけたり、ヘッダをつけたりしていないでしょうか? 具体的な並び替えの方法を知りたいのであれば log の中身(形式)や、今の段階で出来ているあなたのプログラムを提示してください。

ankoman2
質問者

お礼

全角1000文字までですので、わけて投稿させていただきますね。 <? Function Get_Record($fp) { if(!$fp) return $record; while(!feof($fp)) { $buff = fgets($fp,255); $record .= $buff; if(ereg("\x0A",$buff)) break; } return $record; } $count = 0; $fp = @fopen("1.log","r"); if($fp) { while(1) { $line = Get_Record($fp); if($line == "") break; $count++; } rewind($fp); } else { $error = "データファイルを閲覧できませんでした。"; } $MAX_REC = 20; if(!$offset) $offset = 0; if($back) { $offset -= $MAX_REC; if($offset < 0) $offset = 0; } if($next) { $offset += $MAX_REC; if($offset >= $count) $offset -= $MAX_REC; } for($loop = 0;$loop < $offset;$loop++) { $line = Get_Record($fp); } ?>

ankoman2
質問者

補足

<? for($loop = 0;$loop < $MAX_REC;$loop++) { $line = Get_Record($fp); if($line == "") break; list($namae,$year,$month,$dadada,$aiueo,$note,$date) = split("\t",$line); if($name == "") $name = " "; if($year == "") $month = " "; if($aiueo == "") $year = " "; if($note == "") $note = " "; echo ' <TABLE cellspacing="2" bgcolor="#666666" width="500" cellpadding="5"> <TR> <TD ALIGN="left" BGCOLOR="#cccccc" WIDTH="1%" NOWRAP> <FONT COLOR="#000000">申請者名</FONT> </TD> <TD BGCOLOR="#ffffff" WIDTH="49%" NOWRAP>',$name,'</TD> <TD ALIGN="left" BGCOLOR="#cccccc" WIDTH="1%" NOWRAP> <FONT COLOR="#000000">日  程</FONT> </TD> <TD BGCOLOR="#ffffff" WIDTH="49%" NOWRAP>',$year,'</TD> </TR> <TR> <TD ALIGN="left" BGCOLOR="#cccccc" WIDTH="1%" NOWRAP> <FONT COLOR="#000000">開始時間</FONT> </TD> <TD BGCOLOR="#ffffff" WIDTH="49%" NOWRAP>',$name,'</TD> <TD ALIGN="left" BGCOLOR="#cccccc" WIDTH="1%" NOWRAP> <FONT COLOR="#000000">終了時間</FONT> </TD> <TD BGCOLOR="#ffffff" WIDTH="49%" NOWRAP>',$year,'</TD> </TR> <TR> <TD ALIGN="left" BGCOLOR="#cccccc" WIDTH="1%" height="50" NOWRAP> <FONT COLOR="#000000">申請理由</FONT> </TD> <TD COLSPAN="3" BGCOLOR="#ffffff">',$month,$dadada,'</TD> </TR> </TABLE> <br> <br> <br> <P> '; } if($fp) fclose($fp); ?> <FONT COLOR="#FF0000"><? echo $error; ?></FONT><BR> <FORM ACTION="p.php" METHOD="post"> <INPUT TYPE="hidden" NAME="offset" VALUE="<? echo $offset; ?>"> <INPUT TYPE="submit" NAME="back" VALUE="前へ">  <INPUT TYPE="submit" NAME="next" VALUE="次へ"> </FORM>

  • togino
  • ベストアンサー率75% (97/129)
回答No.4

>> 8月を08月のように、頭に0がついて2桁にしているのであれば、 >> 日付は文字列のアルファベット順で並び替えれば日付順になります。 > ということですが、これはどうしたらいいんでしょうか・・。 どうもこうも、すでにあなたはそうしてると思いますが??? $record .= date("Y年m月d日 H時i分s秒",time())."\n"; で、ちゃんと08月って2桁ででてるでしょ > 上記のは投稿番号をつけてなかったのでわかりませんでした んじゃ、どうやって投稿文を管理しているんですか?

ankoman2
質問者

お礼

logに保存した内容を取り出しているだけです(^^;) すいません、初心者で困らせてしまってますね・・。 申し訳ございません。

ankoman2
質問者

補足

すいません(^^: 上の記述はミスがありますね。途中なんでおかしくなってます・・。 list($name,$year,$month,$day,$timeman,$minuteman,$timeman2004,$minuteman2004,$message) = split("\t",$line); if($name == "") $name = " "; if($year == "") $month = " "; if($month == "") $month = " "; if($day == "") $day = " "; if($timeman == "") $timeman = " "; if($minuteman == "") $minuteman = " "; if($timeman2004 == "") $timeman2004 = " "; if($minuteman2004 == "") $minuteman2004 = " "; if($message == "") $message= " "; これが正しいです。 2回補足してしまったためにここに書き込みになり申し訳ございません。

  • moon_night
  • ベストアンサー率32% (598/1831)
回答No.3

単に新着順に並べるのであれば array_unshift で追加してやれば、 読み込むときに読み込んだ順に表示させれば新着順に並ぶかと思います。 ソートをしてやりたい場合は time()をそのままとるか、数字のみのデータ(例:20040812)で保存したほうがやりやすいです(文字列ソートになってしまうので) データさえあれば # 多次元配列ソート usort($Array , "cmp"); function cmp($a , $b){    return strcmp($a[0] ,$b[0] );  <--- ここのaとbの入れ替えで昇順、降順を決められる } で。

参考URL:
http://search.net-newbie.com/php/function.usort.html
ankoman2
質問者

お礼

有り難うございます。 参考にさせていただきました!

  • togino
  • ベストアンサー率75% (97/129)
回答No.2

掲示板に投稿されたものを、どのように形で格納したり処理したりしているのかが、まったく分からないので、あくまで適当に想像して回答させて頂きます。 // "0","1","2" は、投稿番号 $message["0"] = "2004年08月12日 09時59分10秒"; $message["1"] = "2003年08月12日 09時59分10秒"; $message["2"] = "2004年08月12日 09時59分11秒"; arsort($message); while(list($message_id, $message_date) = each($message)){  print "Message ID: ".$message_id." ";  print "Message Date: ".$message_date." <br>\n"; } (注:インデントに全角スペースを使っています) 8月を08月のように、頭に0がついて2桁にしているのであれば、日付は文字列のアルファベット順で並び替えれば日付順になります。

ankoman2
質問者

お礼

お忙しい中、回答有難うございます! 8月を08月のように、頭に0がついて2桁にしているのであれば、日付は文字列のアルファベット順で並び替えれば日付順になります。 ということですが、これはどうしたらいいんでしょうか・・。 上記のは投稿番号をつけてなかったのでわかりませんでした(泣)

noname#8825
noname#8825
回答No.1

time()やmktime() で拾ったタイムスタンプで、ソートすれば良いのでは、ないでしょうか。 で、表示するときに、date() でフォーマットすれば、表示も大丈夫。 データベースに掲示板のデータを格納しているのならば、日付を Date型とか、timestamp型 で、定義していれば、もっと簡単にソートできますよね。

ankoman2
質問者

お礼

すいません、そのやり方がわからないです・・(泣) 初心者すぎて。。すいません

関連するQ&A