iT邦幫忙

2

php登入系統

各位大大您好:

我試寫一個登入頁面,若輸入正確帳號密碼跟驗證碼,會顯示'已成功',但是只要有輸入錯誤,並不會跳到else 顯示'失敗',會是在'資料庫已成功開啟'畫面,想請問要怎麼修改呢? 謝謝
以下是登入頁面html

<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>鑰匙管理系統</title>
</head>

<body>
<center>
<p>鑰匙管理系統</p>
<form name="form1" action="key_login.php" method="post">
姓名:<input type="text" name="name"><br>
<br>
密碼:<input input type="password" name="id"> <br>
<br>
驗證碼:<input type="number" name="ans"><img src="testpic.php" width="35" height="25" alt="show image"><br>

<p><input type="submit" value="送出"><input type="reset" value="重新設定" name="reset"></p>
</form>
</center>

</body>

</html>

以下是key_login.php

<?php session_start(); ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
<title>PDO</title>
</head>


<body>

<?php

$hostdb='localhost';
$namedb='key';
$userdb='root';
$passdb='123!';

/*try { */

$conn= new PDO("mysql:host=$hostdb;dbname=$namedb",$userdb,$passdb);
echo'資料庫已成功開啟'.'<br>';
$conn->exec("SET CHARACTER SET utf8");
 

/*} 

  catch(PDOEXception $e){
  echo $e->getMessage();
	
}*/

$name=$_POST['name'];
$id=$_POST['id'];
$sql="SELECT name,pw FROM admin where name='$name'and pw='$id'";
$result = $conn->query($sql);
foreach ($result->fetchALL() as $row)

{
	
if ($name!=null && $id=!null && $row['name']==$name && $row['pw']==$id && $_POST['ans']==$_SESSION['test'])


echo '已成功';

else 

echo '失敗';

}
$conn=null;
?>

</body>
</html>
看更多先前的討論...收起先前的討論...
在檢查點上加入 MSGBOX 回報變數值,逐步確認卡在哪裡,來判斷程式邏輯是否有錯誤
php.ini的display_errors是不是設定成off了?
是的話請改on然後重啟伺服器。
mayyola iT邦新手 3 級 ‧ 2018-01-09 10:18:38 檢舉
有開啟了 但還是一樣..
mayyola iT邦新手 3 級 ‧ 2018-01-09 10:26:30 檢舉
好像是只要$sql="SELECT name,pw FROM admin where name='$name'and pw='$id'"; 不等於就不會執行下面的式子..
mayyola iT邦新手 3 級 ‧ 2018-01-09 11:17:29 檢舉
想請問
$connection->prepare($sql)跟$connection->query($sql) 差在哪邊
mayyola iT邦新手 3 級 ‧ 2018-01-09 11:22:06 檢舉
剛剛查網頁有修改了,但不知道原本到底錯在哪 冏
try {

$conn= new PDO("mysql:host=$hostdb;dbname=$namedb",$userdb,$passdb);
echo'資料庫已成功開啟'.'<br>';
$conn->exec("SET CHARACTER SET utf8");
$name=$_POST['name'];
$id=$_POST['id'];

$sql="SELECT name,pw FROM admin where name=? and pw=?";
$result = $conn->prepare($sql);
$result->execute(array($name,$id));
$result1=$result->fetch(PDO::FETCH_OBJ);
if ($result1&&$_POST['ans']==$_SESSION['test'])

echo 'OK';

else

echo 'not OK';


}

catch(PDOEXception $e){
echo $e->getMessage();

}

1 個回答

1
weiclin
iT邦高手 4 級 ‧ 2018-01-09 13:53:44
最佳解答

登入不是這樣判斷的,如果 $result 沒有查到資料,foreach 就不會執行

$result = $conn->query($sql);
foreach ($result->fetchALL() as $row)
{
    if ($name!=null && $id=!null && $row['name']==$name && $row['pw']==$id && $_POST['ans']==$_SESSION['test'])
        echo '已成功';
    else
        echo '失敗';
}

先不管你程式裡的漏洞,要修正也很簡單,改成這樣

if(!empty($result->fetchALL())
        echo '已成功';
    else
        echo '失敗';

還有其他問題:

  • $name!=null && $id=!null 應該在你去資料庫查詢前就檢查
  • 這個打錯了:$id=!null
  • prepare 可以將 SQL 語法與參數分開處理來避免攻擊,但你用法錯了
  • 這個不保證完全支援 utf8:"SET CHARACTER SET utf8",建議用 "SET NAMES 'UTF8'",原因:https://stackoverflow.com/a/1566908
  • 你可以一行就搞定編碼問題 "mysql:host=$host;dbname=$db;charset=utf8"

最後
在你搞懂與修正 SQL Injection 之前,不要讓你寫的網站上線運作
在你搞懂與修正 SQL Injection 之前,不要讓你寫的網站上線運作
在你搞懂與修正 SQL Injection 之前,不要讓你寫的網站上線運作

看更多先前的回應...收起先前的回應...
mayyola iT邦新手 3 級 ‧ 2018-01-09 15:08:42 檢舉

w大您好:
我大概有修正如下變數前加addslashes跟SQL變數改問號,這樣是否不會產生SQL Injection 謝謝

$name=addslashes($_POST['name']);
$id=addslashes($_POST['id']);


$sql="SELECT name,pw FROM admin where name= ? and pw= ?";
$result = $conn->prepare($sql);
$result->execute(array($name,$id));
$result1=$result->fetch(PDO::FETCH_OBJ);
if ($result1&&$_POST['ans']==$_SESSION['test'])


weiclin iT邦高手 4 級 ‧ 2018-01-09 16:17:11 檢舉

現在沒人那樣做了, 去把 prepare 搞懂吧, 學一次可以用很久, 不要再花時間去學過時的東西

weiclin iT邦高手 4 級 ‧ 2018-01-09 16:31:22 檢舉

隨手改一改給你參考, 但不保證能跑:

$name = filter_input(INPUT_POST, 'name');
$id = filter_input(INPUT_POST, 'id');


$sql="SELECT name,pw FROM admin WHERE name=:name AND pw=:pw";
$sth = $conn->prepare($sql);
$sth->execute([':name' => $name, ':pw' => $id]);
if ($sth->rowCount() > 0) {
    $result=$sth->fetch(PDO::FETCH_OBJ);
    if ($result && $_POST['ans'] === $_SESSION['test'])
mayyola iT邦新手 3 級 ‧ 2018-01-09 16:38:53 檢舉

w大您好:
看到您改的了~謝謝~
要怎麼google呢?(我自己google都是以前的做法,買書也沒特別寫到這塊)因為我也不是本科出生..只是有興趣寫看看 謝謝

weiclin iT邦高手 4 級 ‧ 2018-01-09 16:53:13 檢舉

這本是必讀: http://www.books.com.tw/products/0010688181
剩下的就只能多關注新消息, 參加社群或是各個研討會
有些可以線上看的, 例如 https://www.youtube.com/user/PHPSrbijaVideo/videos
去社群裡找個家教或許是最快的方式

mayyola iT邦新手 3 級 ‧ 2018-01-09 18:30:13 檢舉

w大我再請教一個問題
:pw(這是甚麼意思)跟$pw(知道是變數)是差在哪呢,:pw綁定參數嗎?可是為什麼不直接寫$pw謝謝~

weiclin iT邦高手 4 級 ‧ 2018-01-09 19:21:53 檢舉

你原本的 prepare 是用 ? 來標示參數的位置,然後再按照陣列的順序去填,所以你參數一多就連帶要常常確認順序對不對。

$sth->execute(['參數1', '參數2', '參數3']);

:name 是另一種用法,等於是給參數標上名稱,這樣就會以名稱來帶入參數

$sth->execute([':name' => '參數1', ':phone' => '參數3', ':email' => '參數2']);

通常用名稱來標示會更好讀一些,但這是 pdo 才有的功能。如果你有機會用到 mysqli_ 系列的函式,他只支援 ? 這種形式綁定參數。

我要發表回答

立即登入回答