[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。
<?php echo "こんにちは" ?>
<?= "こんにちは" ?>
html いつも同じ出力をする
php 状況で異なる出力をする部分に使う
別のphpファイルを読み込んで反映:
<?php require"header.php"; ?>
php文の最後には;を忘れずに。特にhtmlに短く挟むときに忘れがちだ。
複数のところで使いまわす時にはrequireを用いるとよい。
htmlspecialchars
<?php htmlspecialchars($_POST["hoge"]);
文字列のなかのタグなどを無効にする。
>検索のサーチワードは「このパラメータに従った結果が欲しい」という検索結果を受け取ることが目的なので、GETを利用するべきです。
POSTは掲示板への書き込みだとか、Twitterへの投稿だとか…Webサーバーに格納されている情報そのものを書き換える事を目的として行います。
>RESTの考え方的にGETとPOSTのパラメータが混ざる事がそもそも問題ありなので、
$_REQUESTは基本的に忘れて構いません。
>これは私がRESTを知らない時の失敗談になるのですが、掲示板の投稿内容の削除ボタンをGETのリンクで実装したために、グーグルのクローラーが巡回してきてパスワードが設定されていない全ての記事が全滅したことがありました。
POST後はリダイレクトを使って進む戻るボタンで何度も書き込みされないようにする事が可能です。
確認しておいた方がいい点がすっごくある。ノートを取ったりエラーで頭が固まってるあいだに説明があったんだろうが、構造がわかってないところが多すぎる。
あと何と馬鹿にされようとコードにコメントは付けるように。その時わかっても後でわからないんじゃ意味がない。
index.php
<?php
session_start();
$msg="";
//初めて開く場合と認証しようと思って開く場合と2種
if(!empty($_POST["u_id"]) && !empty($_POST["pass"])){ //postされたu_idもpassもemptyでない
if(!empty($_POST["ticket"]) && $_POST["ticket"]==$_SESSION["ticket"]){ //このページ内でhiddenで発行されたticketを持っている、かつpostされたticketとsession変数のticketが一致する
//認証開始
$user="root";
$dbpass="";
$host="localhost";
$dbname="auth";
$dsn="mysql:host={$host};dbname={$dbname};charset=utf8";
$pdo=new PDO($dsn, $user, $dbpass);
$sql = "SELECT * FROM users WHERE u_id=:u_id"; //dbのu_idと、"あるもの"が一致するものをひっぱってほしい。あるものについては追って連絡するから。
$stmt = $pdo->prepare($sql);
$stmt->bindValue(":u_id",$_POST["u_id"],PDO::PARAM_STR); //"あるもの"とはユーザーが入力しpostされた$_POST["u_id"]である。
//$stmt->bindValue(":pass",$_POST["pass"],PDO::PARAM_STR);
$stmt->execute();
$row=$stmt->fetch(PDO::FETCH_ASSOC);
if(password_verify($_POST["pass"],$row["pass"])){
//ログイン成功
//$name=$row["nickname"];
$_SESSION["login"]=true;
$_SESSION["name"]=$row["nickname"];
header("Location: mypage.php");
exit();
}else{
//ログイン失敗
$msg="ログインできませんよ";
$_SESSION["login"]=false;
}
}
}
$ran=rand(100,999);
$salt="tekitounamoji";
$ticket=md5($salt . $ran);
$_SESSION["ticket"] = $ticket;
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>ログイン認証</title>
<link rel="stylesheet" href="auth.css">
</head>
<body>
<div id="container">
<form method="post" action=""> //このpost先はこのページ本体でよいのか?
<table>
<tr>
<th><label for="u_id">ユーザー名</th>
<td><input type="text" name="u_id" id="u_id"></td>
</tr>
<tr>
<th><label for="pass">パスワード</label></th>
<td><input type="password" name="pass" id="pass"></td>
</tr>
</table>
<p><button type="submit">認証</button></p>
<input type="hidden" name="ticket" value="<?php echo $ticket; ?>">
</form>
<p><?php echo $msg; ?></p>
</div>
</body>
</html>
mypage.php
<?php
session_start();
if(empty($_SESSION["login"])){
header("Location:index.php"); //ログイン画面に強制移動
exit();
}
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>マイページ</title>
<link rel="stylesheet" href="auth.css">
</head>
<body>
<div id="container">
<h1 class="hoge"><p>ようこそ<?php echo $_SESSION["name"]; ?>さん!</p></h1>
<p>会員じゃないとみられないクエの絵</p>
<p>あぶらぼうず</p>
<p>たこ</p>
</div>
</body>
</html>
auth.css
body{
background:#eff;
background-image:url("../img/fish_kue2.png");
background-repeat:no-repeat;
background-position: right;
}
#container{
width: 80%;
margin: auto;
}
table{
border: solid 1px #333;
border collapse: collapse;
background:#fff;
}
th,td{
padding: 0.2rem 0.5rem;
text-align: left;
border: solid 1px #333;
}
th{
background:#cff;
}
.hoge{
background-color:#fff;
}
test03.php
<?php
echo str_replace("java","PHP","Hello, java world");
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>PHPエラーコード変換</title>
<link rel="stylesheet" href="test1.css">
</head>
<body>
<h1>phpのエラーメッセージを入力してね</h1>
<form action="mytest01.php" method="get">
<p><input type="textarea" name="hoge" value=""></p>
<button type="submit">send</button>
</form>
</body>
</html>
mytest01.php
<?php
$msg = $_GET["hoge"];
//print_r($msg);
//指定した文字列が一致したら置き換える
$foo=htmlspecialchars($msg,ENT_QUOTES);
$replace = str_replace('Parse error: syntax error', 'あるべき文字が抜けているようだ!', $foo);
$replace = str_replace('Undefined variable', 'ごめんよこの変数見つからないや→', $foo);
//$replace = str_replace('on line', '行数はここだ→', $foo);
//受け取った文字列に,があると認識されなくなる。どうしたらいいかな?
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>PHPエラーコード変換</title>
<link rel="stylesheet" href="test1.css">
</head>
<body>
<h1>エラーコードを変換しました!</h1>
<div class="proto">
<h2><?php echo ("原文"); ?></h2>
<p class="foo"><?php echo $msg; ?></p>
</div>
<div class="arrow"><p>↓</p></div>
<div class="trans">
<h2><?php echo ("変換後"); ?></h2>
<p class="foo"><?php echo $replace; ?></p>
</div>
</body>
</html>
test1.css
body{
width:90%;
margin: 0 auto;
}
input{
width:90%;
margin:auto 0;
height:3rem;
}
.proto p{
color:#ccc;
}
h1{
font-size:1.5rem;
}
.proto h2{
font-size:1rem;
background: #eff;
}
.trans h2{
font-size:1rem;
background: #fee;
}
.proto{
padding: 0;
}
.trans{
padding: 0;
}
.foo{
border:solid 1px #ccc;
border-radius: 3rem;
padding:1.5rem;
}
.arrow{
text-align:center;
font-size: 1.2rem;
color:#ccc;
font-weight:bold;
}
同一ページで書き出して同一ページで処理をするということになっている
if(!empty($_POST["u_id"]) && !empty($_POST["pass"])){
if(!empty($_POST["ticket"]) && $_POST["ticket"]==$_SESSION["ticket"]){
上のif
初めて訪れたのか、認証のためにこのページを訪れたのかで挙動が変わる
下のif
$_POSTデータをもってきて「通りたい」といってきたら、
「チェットみせて」という。
これはアタックを防ぐためにある
if(password_verify($_POST["pass"],$row["pass"])){
プレーンなパスワードと、ハッシュドのパスワードを比較する
この部分がきも。
なお完全にランダムな数はこんぴゅーたーは出力できない
なので、
$ran=rand(100,999);
$salt="tekitounamoji";
$ticket=md5($salt . $ran);
$_SESSION["ticket"] = $ticket;
というふうに
ソルトを使うといい
ブルートアタックに対抗する:
ページを開くたびにランダムな数を生成しチケットを確認する。
input type="hidden"でもたせる。
ブラウザを通してこのページに来た人は、ランダムの値のチケットをゲット
→OK
外部からのアタックはチケットを取れない
またぞろエラーを出した
とりあえずここまで
--->index.php
<?php
session_start();
$msg="";
//初めて開く場合と認証しようと思って開く場合と2種
if(!empty($_POST["u_id"]) && !empty($_POST["pass"])){
if(!empty($_POST["ticket"]) && $_POST["ticket"]==$_SESSION["ticket"]){
//認証開始
$user="root";
$dbpass="";
$host="localhost";
$dbname="auth";
$dsn="mysql:host={$host};dbname={$dbname};charset=utf8";
$pdo=new PDO($dsn, $user, $dbpass);
$sql = "SELECT * FROM users WHERE u_id=:u_id";
$stmt = $pdo->prepare($sql);
$stmt->bindValue(":u_id",$_POST["u_id"],PDO::PARAM_STR);
//$stmt->bindValue(":pass",$_POST["pass"],PDO::PARAM_STR);
$stmt->execute();
$row=$stmt->fetch(PDO::FETCH_ASSOC);
if(password_verify($_POST["pass"],$row["pass"])){
//ログイン成功
//$name=$row["nickname"];
$_SESSION["login"]=true;
$_SESSION["name"]=$row["nickname"];
header("Location: mypage.php");
exit();
}else{
//ログイン失敗
$msg="ログインできませんよ";
$_SESSION["login"]=false;
}
}
}
$ran=rand(100,999);
$salt="tekitounamoji";
$ticket=md5($salt . $ran);
$_SESSION["ticket"] = $ticket;
//print_r($_SESSION["ticket"]);
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>ログイン認証</title>
<link rel="stylesheet" href="auth.css">
</head>
<body>
<div id="container">
<form method="post" action="">
<table>
<tr>
<th><label for="u_id">ユーザー名</th>
<td><input type="text" name="u_id" id="u_id"></td>
</tr>
<tr>
<th><label for="pass">パスワード</label></th>
<td><input type="password" name="pass" id="pass"></td>
</tr>
</table>
<p><button type="submit">認証</button></p>
<input type="hidden" name="ticket" value="<?php echo $ticket; ?>">
</form>
<p><?php echo $msg; ?></p>
</div>
</body>
</html>
--->mypage.php
<?php
session_start();
if(empty($_SESSION["login"])){
header("Location:index.php");
exit();
}
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>マイページ</title>
<link rel="stylesheet" href="auth.css">
</head>
<body>
<div id="container">
<h1 class="hoge"><p>ようこそ<?php echo $_SESSION["name"]; ?>さん!</p></h1>
<p>会員じゃないとみられないクエの絵</p>
<p>あぶらぼうず</p>
<p>たこ</p>
</div>
</body>
</html>
**08
ここのechoが抜けていたので何を押しても知らんふり(エラー)になっていた。echoを忘れるとhiddenで付けられるvalueに値が入らない。ここで「発行」しているので。
<p><button type="submit">認証</button></p>
<input type="hidden" name="ticket" value="<?php echo $ticket; ?>">
</form>
CTRL+Hでキャッシュ削除
まちがってたところはセレクト文:
$sql = "SELECT * FROM users WHERE u_id=:u_id";
この*がちがってた。
1.userテーブルの全部を選択してひっぱってくる
2.dbにあるu_idと、ユーザーが入力しpostされてくる$_POST["u_id"]が一致すればいいんだが、$_POST["u_id"]は「人間が入力してくる」ものだからそのままでは触れない。よってプレースホルダにしておき、あとで中身を説明する。
WHERE句:
>SELECT構文を使って特定のレコードを検索するには、WHERE句を使います。WHEREの後に条件式を指定することにより、その条件にマッチしたレコードだけを選択することができます。
>SELECT * FROM customer WHERE id_c = 1;
全レコードの中からid_cが1のものをひっぱってこいは分かる。
u_idが:u_id"のものをひっぱってこいとはどういう意味だ? :u_idを定義してるのはどこなんだ。
次の授業までにかみ砕けないなら先生にちゃんと聞いて理解するほうがいいと思う。
→
根本的に理解できてなかった。ユーザーの入れて来る文字列はタグがあったり何があるか分からないから、いわば「:保留するぜいぇーい」という記述。:u_idとは。
だからこの時点で定義もへったくれもない。
変数名が同じだと大変混乱するといういつもの癖が出た。「:保留するぜいぇーい」を後解説してるのがbindValue。(のはずだ)
プレースホルダについて
https://webukatu.com/wordpress/blog/1638
sqlインジェクションについて
https://lets.postgresql.jp/documents/tutorial/with_php/against_sql_injection/placeholder/pg_xxxx/1
読んでも全然分からない。
そういうものだ、とりあえずそー記述すりゃいいらしい、とファジーに捉えようと思ったが、phpにしろjavaにしろ「いつか理解できるだろう」とほったらかしのファジーが増えすぎている気がする
さてログイン出来たらマイページに飛ばすよ
しかしページ遷移すると$nameが残らないですね?
①postする。めんどい
②sessionする かしこい
よって、ログイン出来たとき:
//$name=$row["nickname"];
$_SESSION["name"]=$row["nickname"];
先頭にも
<?php
session_start();
$name="";
を記述
ログインしてからはどのページもセッションをつけましょう
というわけで、index.phpにはつけてmypage.phpでsession_start();を付け忘れた例:
**06
出来た例
**07
しかしこれだとログインしてなくてもURLを直打ちしたら見れてしまう。
セッションデータがあるかないかで振り分ける必要がある。
indexの方に追加
//ログイン成功
//$name=$row["nickname"];
$_SESSION["login"]=true;//これを追加!
$_SESSION["name"]=$row["nickname"];
header("Location: mypage.php");
exit();
mypageの方
<?php
session_start();
if(empty($_SESSION["login"])){ //値がないかfalseのとき
//ログインページに戻す
header("Location:index.php");
exit();
}
?>
セッションを消すにはブラウザ終了
クッキーを消してもだめ
戻る進むをおすとまれにセッションが切れることもある
同じ人の同一アクセスが続いているかどうかがセッション情報
森本さんにネットの修復を頼む
だめなら自分の4Gをこのパソコンにつなぐ方法を聞く
ログイン認証を作る
パスワード入力のinputは***になるようにしたい
→<input type="password">
database
users/3カラム
u_id
pass
nickname
はてな?u_idをAIにしてu_nameは別に持つと思ったがそうはしないのか
・パスワード文字数は時代とともに増える性質があるからintの長さは多めにとる
・パスワードはハッシュするのでその意味でも長くしておく理由がある
ハッシュをしなくちゃいけない
ハッシュ専用のphpの関数がある
むかしはmd5(関数名)というのが使われた
md('hoge');
とか。
<?php echo md5("hoge"); ?>
→出力結果
ea703e7aa1efda0064eaa507d9e8ab7e
しかしこれは総当たり的な解析をされて使えなくなった
クリプトというアルゴリズムが考え出された
技術用語でソルトという。ハッシュ+ソルトでハッシュする
自分が好きなキーワードを仕込んで置き、それを組み合わせてハッシュするのでわかりにくくなる
いまはこのソルトを入れるのが常識。
ソルト自身をランダムに作り、しかもハッシュして、それを純粋にパスワードをハッシュしたものに内在させるという最新の手法がうまれた
同じ文字列をハッシュするたびに毎回違う値が出る
password_hash();
<?php echo password_hash("hoge",PASSWORD_DEFAULT); ?>
全部大文字は定数。バージョンがかわってもよろしく動く
第3引数をなしにするとランダムにソルトが生成
出力結果
$2y$10$S5H/GyQ72m8JdxWwMy3Gq.ulJwuaAEDtMVVZlhuw5ThtZqbE8uYba
$2y$10$YrpJTQZFk0zD9s7b.WNAmuSaSLkmYSuiUsfS.eJ1Wr6Un.nRPrGdq
$2y$10$.NTFtovLqwrqWTkKqXM7BOIifMZkww5EoIpBIYxgvTHkBz15wF/d.
みなさんpassをhogehogeで統一するよ
①でてきたものをこぴる
$2y$10$PQbARvt2wZI229dF1vAN9Ob1Tgia2xTkJvZbhq4YglLy0a.lwx8GS
②myadminの「挿入」でそれを入れる
password_hash();
第一 ハッシュする文字列
第二 PASSWORD_DEFAULT(固定)
第三 書かない
検証する関数
password_verify();
引数1 送信された値(平文)
引数2 ハッシュ済み値(DBに登録されているハッシュされたやつ)