PHP+SQLite:情報を追加する

(1/1)
データベースに情報を追加する。
SQL の INSERT 文を書くことで、レコードを 1 つ追加する。

サンプル・プログラム:昇順に並べ替える

このプログラムは、冒頭行にデータを入力し、登録 ボタンをクリックすることで、情報を追加するものである。

サンプル・プログラム:実行例

PHP+SQLite:情報を追加する

解説:バリデーション

ブラウザからの入力は、正しいデータが入るとは限らない。入力者のミスもあるし、悪意の持った第三者がシステムを攻撃する場合もある。
そこで、データベースに不正なデータを登録しないために、事前にバリデーションチェックを行う。

0030: //バリデーション用
0031: define('YEAR_MIN', -9999);       //生年・没年の最小値
0032: define('YEAR_MAX', +9999);       //生年・没年の最大値
0033: define('NAME_MIN', 1);          //名前の最小長
0034: define('NAME_MAX', 20);     //名前の最大長
0035: define('COMMENT_MIN', 1);      //業績の最小長
0036: define('COMMENT_MAX', 200);    //業績の最大長

0138: /**
0139:  * 数値のバリデーション
0140:  * @param mixed  $data チェックする数値
0141:  * @param string $type int:整数 float:浮動小数
0142:  * @param mixed  $min, $max 最小値、最大値
0143:  * @param string $errmsg エラーメッセージを格納する
0144:  * @return bool TRUE:成功/FALSE:失敗
0145: */
0146: function validNumber($data$type$min$max, &$errmsg) {
0147:     $res = TRUE;
0148:     $errsg = '';
0149: 
0150:     //整数かどうか
0151:     if (preg_match("/int/i", $type) != 0) {
0152:         $flag_int = TRUE;
0153:         $format = "%d";
0154:     } else {
0155:         $flag_int = FALSE;
0156:         $format = "%f";
0157:     }
0158: 
0159:     //引数チェック
0160:     if ($min > $max) {
0161:         $errmsg = sprintf("最小値({$format})が最大値({$format})より大きい.", $min$max);
0162:         $res = FALSE;
0163: 
0164:     //値の取り出し
0165:     } else {
0166:         if ($data == '' || $data == NULL) {
0167:             $errmsg = '値がない.';
0168:             $res = FALSE;
0169:         } else if (! is_numeric($data)) {
0170:             $errmsg = '数値ではない.';
0171:             $res = FALSE;
0172:         } else {
0173:             if ($flag_int)  $data = round($data);        //整数に丸める
0174:             //最大値・最小値チェック
0175:             if ($data > $max) {
0176:                 $errmsg = sprintf("最大値({$format})より大きい.", $max);
0177:                 $res = FALSE;
0178:             } else if ($data < $min) {
0179:                 $errmsg = sprintf("最小値({$format})より小さい.", $min);
0180:                 $res = FALSE;
0181:             }
0182:         }
0183:     }
0184:     return $res;
0185: }
0186: 
0187: /**
0188:  * 文字列のバリデーション
0189:  * @param mixed  $data チェックする文字列
0190:  * @param int    $min, $max 文字列長の最短/最長
0191:  * @param array  $pattern 排除するパターンマッチ配列
0192:  * @param string $errmsg エラーメッセージを格納する
0193:  * @return bool TRUE:成功/FALSE:失敗
0194: */
0195: function validString($data$min$max$patterns, &$errmsg) {
0196:     $res = TRUE;
0197:     $errsg = '';
0198:     $data = trim($data); //行頭・行末のホワイトスペースを除く
0199: 
0200:     //引数チェック
0201:     if ($min > $max) {
0202:         $errmsg = sprintf("最小値({$format})が最大値({$format})より大きい.", $min$max);
0203:         $res = FALSE;
0204: 
0205:     //値の取り出し
0206:     } else {
0207:         if ($data == '' || $data == NULL) {
0208:             $errmsg = '値がない.';
0209:             $res = FALSE;
0210:         } else if (mb_strlen($data) < $min) {
0211:             $errmsg = sprintf("最小長(%d)より短い.", $min);
0212:             $res = FALSE;
0213:         } else if (mb_strlen($data) > $max) {
0214:             $errmsg = sprintf("最大長(%d)より長い.", $max);
0215:             $res = FALSE;
0216:         } else {
0217:             foreach ($patterns as $pat) {
0218:                 if (preg_match($pat$data) > 0) {
0219:                     $errmsg = '異常な文字が含まれている.';
0220:                     $res = FALSE;
0221:                     break;
0222:                 }
0223:             }
0224:         }
0225:     }
0226:     return $res;
0227: }
0228: 
0229: /**
0230:  * SELECT実行
0231:  * @param object $pdo PDO
0232:  * @param string $sql SQL文
0233:  * @param array  $items  INSERTするデータ
0234:  * @return string 表示用文字列(HTML)
0235: */
0236: function selectItems($pdo$sql$items) {
0237:     $myself = MYSELF;
0238: 
0239: $html =<<< EOT
0240: <form name="myform" method="post" action="{$myself}" enctype="multipart/form-data">
0241: <table class="stripe_table_1">
0242: <tr class="index">
0243: <th>名前</th>
0244: <th>生年</th>
0245: <th>没年</th>
0246: <th>業 績</th>
0247: <th>&nbsp;</th>
0248: </tr>
0249: <tr>
0250: <td><input type="text" id="name"  name="name"  size="8" value="{$items['name']}" /></td>
0251: <td><input type="text" id="birth" name="birth" size="3" value="{$items['birth']}" /></td>
0252: <td><input type="text" id="death" name="death" size="3" value="{$items['death']}" /></td>
0253: <td><textarea id="comment" name="comment" cols="36" rows="4">{$items['comment']}</textarea></td>
0254: <td><input type="submit" id="exec" name="exec" value="登録" /></td>
0255: </tr>
0256: 
0257: EOT;
0258:     foreach ($pdo->query($sqlas $row) {
0259: $html .=<<< EOT
0260: <tr>
0261: <td class="index">{$row['name']}</td>            <!-- カラム name -->
0262: <td class="year">{$row['birth']}</td>            <!-- カラム birth -->
0263: <td class="year">{$row['death']}</td>            <!-- カラム death -->
0264: <td class="comment">{$row['comment']}</td>        <!-- カラム comment -->
0265: <td class="btn">&nbsp</td>                        <!-- カラム comment -->
0266: </tr>
0267: 
0268: EOT;
0269:     }
0270:     $html .= "</table>\n</form>\n";
0271: 
0272:     return $html;
0273: }
0274: 
0275: /**
0276:  * INSERT実行
0277:  * @param object $pdo    PDO
0278:  * @param array  $items  INSERTするデータ

生年、没年といった数値データに対しては、ユーザー関数 validNumber を使ってバリデーションを行う。データの存在可否、整数かどうか、最大値、最小値をチェックする。
validNumber の仕組みは「PHP セキュリティ対策:正規化した数値を取り出す」で紹介した getValidNumber とほぼ同じである。

名前、業績といった文字列データに対しては、ユーザー関数 validString を使ってバリデーションを行う。データの存在可否、最大長、最小長、異常文字を含んでいるかどうかチェックする。
validString の仕組みは「PHP セキュリティ対策:正規化した文字列を取り出す」で紹介した validString とほぼ同じである。

解説:INSERT文

INSERT 文は次のように書く。

INSERT テーブル名 (カラムの並び) VALUE (登録データの並び)

0025: //実行するSQL
0026: define('PRE_INSERT', 'INSERT INTO chronologic (name, birth, death, comment) VALUES (:name, :birth, :death, :comment)');
0027: define('PRE_COUNT',  'SELECT count(*) FROM chronologic WHERE name=:name');
0028: define('SQL_SELECT', 'SELECT * FROM chronologic WHERE 1 ORDER BY birth');

データベースに不正なデータを登録しないために、ここでは PDO の プリペアドステートメントを用いている。

解説:INSERT文の実行

0275: /**
0276:  * INSERT実行
0277:  * @param object $pdo    PDO
0278:  * @param array  $items  INSERTするデータ
0279:  * @param sring  $errmsg エラーメッセージを格納
0280:  * @return string bool TRUE:成功/FALSE:失敗(重複データあり)
0281: */
0282: function insertItems($pdo$items, &$errmsg) {
0283:     $msg = '';
0284:     $res = TRUE;
0285:     $patterns = array("/\p{Cc}/u");  //制御文字を除く
0286: 
0287:     //バリデーション
0288:     if (validString($items['name'], NAME_MIN, NAME_MAX, $patterns$msg) == FALSE) {
0289:         $errmsg['name'] = '名前が' . $msg;
0290:         $res = FALSE;
0291:     }
0292:     if (validNumber($items['birth'], 'int', YEAR_MIN, YEAR_MAX, $msg) == FALSE) {
0293:         $errmsg['birth'] = '生年が' . $msg;
0294:         $res = FALSE;
0295:     }
0296:     if (validNumber($items['death'], 'int', YEAR_MIN, YEAR_MAX, $msg) == FALSE) {
0297:         $errmsg['death'] = '没年が' . $msg;
0298:         $res = FALSE;
0299:     }
0300:     if (validString($items['comment'], COMMENT_MIN, COMMENT_MAX, $patterns$msg) == FALSE) {
0301:         $errmsg['comment'] = '業績が' . $msg;
0302:         $res = FALSE;
0303:     }
0304:     if ($res == FALSE)      return $res;
0305: 
0306:     //重複チェック
0307:     $stmt = $pdo->prepare(PRE_COUNT);
0308:     $stmt->bindValue(':name', $items['name'], PDO::PARAM_STR);
0309:     $stmt->execute();
0310:     $res = $stmt->fetch();
0311:     if ($res[0] > 0) {
0312:         $errmsg['duplicate'] = '登録済みデータです.';
0313:         return FALSE;
0314:     }
0315: 
0316:     //INSERT実行
0317:     $stmt = $pdo->prepare(PRE_INSERT);
0318:     $stmt->bindValue(':name',    $items['name'],    PDO::PARAM_STR);
0319:     $stmt->bindValue(':birth',   $items['birth'],   PDO::PARAM_INT);
0320:     $stmt->bindValue(':death',   $items['death'],   PDO::PARAM_INT);
0321:     $stmt->bindValue(':comment', $items['comment'], PDO::PARAM_STR);
0322: 
0323:     return $stmt->execute();
0324: }

INSERT 文を実行するのは、ユーザー関数 insertItems である。
前述のバリデーション関数を用いてデータのチェックをした後、すでに登録されたデータでないかどうか(重複する名前がないかどうか)を SELECT 文を使って調べる。

すべてがクリアできたら、INSERT 文を実行する。

参考サイト

(この項おわり)
header