「お知らせ」が「更新情報」に派生した(2)
前回の続き。今回は登録した記事の一覧と削除機能を追加したい。平日のうちにユーザー定義関数とヒアドキュメントの予習をちゃんとしておいたのでそれ使う。身に付くまで練習しまくる。
ファイル構成を変更した
前回まではindex.htmlとnews.phpを用意してたんだけど、ファイル構成を変更。というか増やした。全部で5つになったよ。
- config.inc・・・最初に指定する変数とかまとめたもの
- function.php・・・ユーザー定義関数とかまとめたもの
- news.php・・・新規投稿・一覧・削除
- view.php・・・表示用ページ
- news.css・・・ほんの少しだけ見た目をいじるために用意
前回まではindex.htmlに新規登録用の入力フォームを置いてたんだけど、一覧リストと合体させようと思ったのでnews.phpと一体化しました。
config.inc
config.incは後から変更するかもなぁと思う変数を入れました。拡張子を.incにした理由は特にないです。こういう設定項目の入ってるファイルをインクルードしてる場合よく.incを見かけるなぁ、なんかそういうもんなんかなと思っただけ・・・安易かな。中身はこんな感じ。これを後でnews.phpにインクルードする。
function.php
次にfunction.php。さっそくユーザー定義関数とヒアドキュメントを乱れ撃ちする。
「これ、いらんやろ?」っていうのもあるけど練習だからいいのいいの。正直何かを出力することしか練習できてないけど気にしない!冒頭の$news_listとかの変数群はview.phpの方でも必要なのでnews.phpにいれずにこっちのファイルに入れてあげた。
HTML_header($title)
ここではソースの冒頭に入る部分を出力。HTML_header($title)の$titleのところにはconfig.incで入れた$title_なんたらの変数を入れて使いまわす。「//==============」を入れてある間に挟まれてるのがヒアドキュメントの部分。なんとなく入れたほうが後から分かりやすいかなと思ったけど、逆にごじゃごじゃした気がせんでもない。
で、「global」のところでつまづいた!
今日のための予習は完璧と思ってたのに、これが漏れてた・・・。関数の中で関数の外にある変数を使おうとするとエラーが。これが変数のスコープってやつかーと実感。その変数の適応される範囲みたいなの苦手意識持っててまだ勉強してなかった。で、こちらのページを熟読。意味理解。
PHPスクリプト講座:変数のスコープ -- そふぃのphp入門
PHPスクリプト講座:スコープ違いの変数 -- そふぃのphp入門
関数の外で設定した変数を関数の中で使いたい時は「外の変数を使いますよ!」っていうのをちゃんと言ってあげないとPHPさんは理解してくれないという仕組みらしい。こういう局面にぶち当たってない時はいまいち理解できなかったのに、今なら分かる。globalを使えばいいんだね!複数global宣言したい時はカンマ区切り、と。
HTML_footer()・HTML_form()
HTML_footer()は単にページの最後の方のソースを入れるだけ。
HTML_form()の部分は入力フォームの部分。actionにはconfig.incで指定した$list_fileを。globalの使い方ももうバッチリ。
HTML_data_list()
ヒアドキュメントの中で関数は使えないということで、HTML_data_list()ではヒアドキュメントを2箇所に分けてみた。ここでは今回追加する一覧リストの部分をtableを使って表示するようにした。ログ用ファイルから中身を読み込んでexplodeを使ってタブ区切りで分割したものをlistでそれぞれの変数へ代入。テーブルセル左から記事No、タイトル、削除ボタン。それらを$news_numの数だけ繰り返して表示させる。
記事番号はforでループしてる$iをそのまま利用。「echo "<th>" .($i + 1). "</th>\n";」の部分、番号として表示されるのに「0番」は違和感があるので、「$i + 1」の形にして1番から始まるようにしてみた。そして内容のセルには$subjectの値を入れる。リンクがある時はaに$urlの値を入れて囲む。削除ボタンについて考えた事は後で書く。なんかここややこしかった。
HTML_done($h_title)
HTML_done($h_title)は新規投稿、削除が完了した後の画面表示。$h_titleのところにconfig.incで設定した$title_doneや$title_delが入る。あとは元のページへ戻るリンクと表示画面(view.php)を別窓で確認するリンクをつけた。
HTML_view()
HTML_view()はview.phpでULリストの形で今回の更新情報を出力するためのもの。config.incの最大表示件数に指定した数だけリストを繰り返し。
news.php
news.phpは新規投稿・一覧リスト・削除担当の忙しい人。
最初にrequire_onceでconfig.incとfunction.phpをインクルード。受け取ったデータを変数に入れてる部分は前回までとまったく一緒。その後の流れはこんな感じで考えた。
新規投稿フォームと一覧リストを表示させる
まずnews.phpにアクセスした際に表示したいのは新規投稿フォームと一覧リスト+削除ボタン。なので新規投稿用フォームのsubmit(ボタン)、削除用フォームのdelete(ボタン)の値が空だったら新規投稿用のフォーム、一覧リストを表示するようにすればいいって思った。
それがif(!@$_POST["submit"] && !@$_POST["delete"])以下の部分。
function.phpで用意してた関数を呼び出して新規投稿フォームと一覧リストを表示してる。
新規投稿の処理
elseif(@$_POST["submit"])の部分。上で用意した新規投稿フォームのボタンが押されてたら受け取った値をそれぞれエラーチェック。チェック内容は前回までの処理と同様。エラーがあればfunction.phpで用意したHTML_header関数、$errorの内容を使ってエラー画面を表示。エラーがなければ前回の通り、ファイルへデータを書込し、HTML_header関数、HTML_done関数を使って完了画面を表示。
また続けて新規投稿を行えるようにHTML_form関数を使ってフォームを同画面に表示させる。そこで続けて投稿してエラーがあったらまたエラー画面、エラーがなかったら投稿完了を繰り返す。
一覧から削除
何もボタンが押されてない状態で表示した一覧リストの中の削除ボタンが押されたら・・・の処理。これがelseif(@$_POST["delete"])の部分。
上でチラっと触れた削除ボタンですが、これは削除したい記事があれば、ボタン横のラジオボタンにチェックを入れてから削除ボタンを押すと該当記事が1件削除される、チェックが入ってなかったらエラー、というやり方で考えた。
ホントはチェックボックスを使って複数記事を一括で削除できた方がカッコいい気がしたんだけど、単にやり方が勉強不足でわからなかったのと、ここの一覧リストに表示する件数の最大数を指定もしてないし、記事が大量の時に消したいものをチェックしてからページの上だか下だかに1つだけある削除ボタンまでスクロールすんのもめんどいなーとか思ったりした。あ。10件ずつ表示とかできればいいのか。普通こういうのってそうなってるよなぁ。今度調べてみる。
記事Noの表示部分同様、値を($i + 1)にしたのは、チェックが入ってるかどうかの確認をする時に値が0だとNULLと同じになっちゃってどうしていいのか分からなかったから。値が0の時に$error = "";にしたら値が0でも削除はできるけど、どこかにチェックが入ってなくても値が0の項目が削除されてしまう。なんかうまく条件が分岐できそうでできなかった。というか思いつかなかった。なので自分にできる方法を考えたら($i + 1)で値を1プラスの形で入れておいて、削除する時に値から1引いたものを削除しようっていう考えに至った。
array_splice関数
削除に使おうと思ったのがarray_splice関数。array_splice関数は配列の一部を削除し、他の要素で置換する
、というもの。
array_splice ( 配列 , どの位置から , 個数 , 置き換える値 ) っていう書き方。3番目のパラメータは省略可。 2番目のパラメータに負の数を指定すると最後の要素から何番目か、を指定できる。 3番目のパラメータを省略すると2番目で指定した位置以降全部の値が対象になる。 4番目の置き換える値を省略すると削除だけができるとのこと(by マイ参考書)
ということで、削除エラーがなかったらログ用ファイルを開いて、最新のものが一番上に来るように逆順に並び替える。その配列からarray_splice関数でフォームのラジオボタンから受け取った値の部分を1つ削除。そのままファイルに上書きしたら順番がおかしくなっちゃうから、もう一度逆順に並び替えて上書き書き込み。
あとはHTML_header関数、HTML_done関数を使って、削除完了画面を表示。
view.php・news.css
最後にview.php。これはconfig.incとfunction.phpを読み込んで、HTML_view();を呼び出してるだけ。出力されるのはULリストでマークアップされたソース。これを使いたい場所にインクルードするか、もしくはどうせ入ってる行数下記5行だけだし、このファイルをそのまま使ってもいっか。
CSSは特にここに書く必要もないと思うけど一応・・・。もうすでにページが異様に長くなりすぎてるからハイライト表示にはしない。
@charset "utf-8";
*{
margin:0;
padding:0;
}
.error{
color:#f00;
font-weight:bold;
}
h1{
font-size:1.2em;
text-align:center;
color:#090;
margin:20px auto;
}
form{
width:70%;
margin:15px auto 20px;
}
form dt{
line-height:1.6;
border-left:5px solid #9c0;
padding:0 0 0 6px;
}
form dd{
margin:10px auto;
}
input[type="text"]{
width:100%;
}
input[type="password"]{
margin:0 0 0 5px;
}
input[type="text"]:focus,
input[type="password"]:focus{
background:#ffc;
}
table{
width:100%;
border-collapse:collapse;
border:1px solid #999;
margin:0 auto 20px;
}
th,td{
border:1px solid #999;
padding:3px;
}
p{
text-align:center;
margin:15px auto;
}
今日の疑問点
削除部分、ファイルの中から該当1件分(一行)を削除するっていう方法についてなんだけど、今回は一旦ファイルを全部読み込んで削除する部分の行の内容を消してまたファイルに書き込むっていう手順を考えたんだけど、コレってほんとにこんな回りくどい事をしなきゃならないのかなって思った。なーんかもっとスーっとうまくいく方法ないのか疑問。
反省点
- なんかおかしい。なんで新規投稿にパスワードいるのに削除にはいらないんだろう。
- ていうか、こういうのって最初にログインしてから・・・なんじゃないの。
- 一覧リストんとこに日付入れるの忘れてるし。
- 自力でやってみようなんて思わずに何か完成したものをお手本にしながら勉強すればよかった。手戻りが多い><
<< PHP ヒアドキュメント | SimpleXML関数使ってフィード読み込みたい >>
トラックバック
このエントリーのトラックバックURL:
http://redline.hippy.jp/cgi/mt/mt-tb.cgi/221