teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

2

追記

2016/09/12 10:26

投稿

退会済みユーザー
answer CHANGED
@@ -125,4 +125,87 @@
125
125
  <a href = "staff_list.php">戻る</a>
126
126
  </body>
127
127
  </html>
128
- ```
128
+ ```
129
+
130
+ ---
131
+
132
+ > > グローバル変数に直接アクセスしない
133
+ >
134
+ > ご指摘ありがとございます。
135
+ > このページでは{}内なのでローカル変数かと思っておりましたが、
136
+ > 確かに上位ページではグローバルの領域にこの変数を定義しておりま
137
+ > すので、それでグローバル変数に該当するという事なのですね。
138
+ >
139
+ > ちなみにグローバル変数に直接アクセスしないのは、プログラミング
140
+ > においては当たり前のルールなのでしょうか。
141
+ > 始めたばかりの初心者で申し訳ございません。
142
+
143
+ ここでグローバル変数と言っているのは、`$_POST['xxxx']`の事です。
144
+ $_POST, だけではなく、$_SERVER や $_GET も然り。マニュアルでは「[スーパーグローバル](http://php.net/manual/ja/language.variables.superglobals.php)」と表現されています。
145
+ $GLOBALS もそうですが、この変数は「どこからでもアクセスできる」と同時に「どこからでも書き換えできる」性質があります。「どこからでもアクセスできる」ことはそれほど問題ないのですが、「どこからでも書き換えできる」ということが、意図せず発生した場合、バグの特定が困難になり、コードの保守性・安全性を損なう結果になってしまうので、出来る限り、ソースコードに $_POST や $_GET が登場しないように書きましょうといういわば、作法です。
146
+
147
+ > また、filter_input()
148
+ > 関数を使って間接的に取得することで、グローバル変数に影響を与えなく出来るという事なのですね。
149
+
150
+ そうですね。同時に、
151
+
152
+ `$val = (isset($_POST['key'])) ? $_POST['key'] : null;`
153
+
154
+ という冗長な書き方をせずに済みます。
155
+
156
+ > > SQLに渡す変数を htmlspecialchars 使うのは論外
157
+ > こちらは脆弱性対策のためのサニタイジングとして入れていたのですが、
158
+ > SQLに渡す変数では使ってはいけないのですね。
159
+ > 理由としては、変数に何らかの影響が出てしまうという事なのでしょうか。
160
+ > 例えば以下のようなことなのでしょうか。
161
+ > http://php-archive.net/php/htmlspecialchars/
162
+
163
+ いいえ。これは全く無関係です。
164
+ 単純に、SQLインジェクション対策のための関数ではないので、ここで使ってはいけないということです。
165
+ SQLインジェクション対策のために必要なことは、PDO においては、プリペアドステートメントを利用します。
166
+
167
+ とある、PHPの初心者向けの書籍のせいで、誤用が広まっている…
168
+
169
+ そもそも、これがSQLインジェクションに有用な関数なのであれば、PHPの開発チームは `htmlspecialchars` って関数名はつけないでしょう。おかしいと思いません?(→ 某書籍の作者さん、どうですか?)
170
+
171
+ > > 文字コードは「$dsn」で「$dbh->query('SET NAMES utf8');」
172
+ > DBを指定するときに文字コードを指定すべきなのですね。
173
+
174
+ 今のバージョンでは、そうすべきです。古いバージョンのPHPでは、SET NAMES utf8 を使うことは許容されます。(それ以外に方法がないから)
175
+
176
+ > > いらない「$dbh=null;」
177
+ > こちらはSQLへの接続を閉じるために必要かと思っておりましたが不要なのでしょうか。
178
+
179
+ こちらは、接続が切れたら勝手に NULL になります。あえて書く必要はありません。
180
+
181
+ > > ここで exit すると、htmlが崩れる
182
+ > これはexitの後が表示されなくなってしまうという事なのでしょうか。
183
+
184
+ exit; で処理が止まるので、<html> 以下は表示されるが、</body></html> の部分は出力されなくなりますね。
185
+
186
+ ```html
187
+ <html>
188
+ <body>
189
+ ...
190
+
191
+ ```
192
+
193
+ となって、</body> や </html> がないって、気持ち悪いですよね…
194
+ html 的には、</body> や </html>は省略可能ですが…
195
+
196
+ > > 欲を言えばこうしたい
197
+ > こちらのソースでは、PHP処理をHTML内より抜き取り、HTMLには別のコードを追加して
198
+ > おりますが、そこではエラーの場合に(
199
+ > INPUT_POST)という場所から変数を持ってきて更新するという処理が書かれているのでしょうか。
200
+
201
+ ```php
202
+ if (null != filter_input_array(INPUT_POST)) {
203
+ ...
204
+ }
205
+ ```
206
+
207
+ の部分ですね。
208
+ この if 文がないと、`$sql = 'UPDATE mst_staff SET name=?,password=? WHERE code=?';`
209
+
210
+ 以下の部分も実行され、`UPDATE mst_staff SET name='',password='' WHERE code=''` というSQLが実行されてしまいます。
211
+ POSTされたデータが存在しないなら、あえてSQLを実行する意味はありません。

1

追記

2016/09/12 10:26

投稿

退会済みユーザー
answer CHANGED
@@ -1,3 +1,5 @@
1
+ 場当たりな対処を施したコード
2
+
1
3
  ```php
2
4
  <!DOCTYPE html>
3
5
  <html>
@@ -74,4 +76,53 @@
74
76
 
75
77
  </body>
76
78
  </html>
79
+ ```
80
+
81
+ ---
82
+
83
+ 欲を言えばこうしたい
84
+
85
+ ```php
86
+ <?php
87
+ try {
88
+ if (null != filter_input_array(INPUT_POST)) {
89
+ $staff_code = filter_input(INPUT_POST, 'code');
90
+ $staff_name = filter_input(INPUT_POST, 'name');
91
+ $staff_pass = filter_input(INPUT_POST, 'pass');
92
+
93
+ $options = array(
94
+ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
95
+ );
96
+
97
+ $dsn = 'mysql:dbname=shop;host=localhost;charset=utf8;';
98
+ $user = 'root';
99
+ $password = '';
100
+ $dbh = new PDO($dsn, $user, $password, $options);
101
+
102
+ $sql = 'UPDATE mst_staff SET name=?,password=? WHERE code=?';
103
+ $stmt = $dbh->prepare($sql);
104
+ $data[] = $staff_name;
105
+ $data[] = $staff_pass;
106
+ $data[] = $staff_code;
107
+ $stmt->execute($data);
108
+ }
109
+ } catch (Exception $e) {
110
+ $err = 'ただいま障害により大変ご迷惑をおかけしております。';
111
+ }
112
+ ?>
113
+ <!DOCTYPE html>
114
+ <html>
115
+ <head>
116
+ <meta charset = "UTF-8">
117
+ <title>タイトル</title>
118
+ </head>
119
+ <body>
120
+ <?php if (isset($err)) : ?>
121
+ <p><?= $err; ?></p>
122
+ <?php elseif (null != filter_input_array(INPUT_POST)) : ?>
123
+ <p>更新しました。</p>
124
+ <?php endif; ?>
125
+ <a href = "staff_list.php">戻る</a>
126
+ </body>
127
+ </html>
77
128
  ```