標籤彙整:PHP

PHP 會員留言板系統

延續前篇:PHP 會員登入系統

結構

  • MySQL留言資料庫(message)
  • 留言板頁面(msg.php)
  • 留言新增功能(msg-add.php)
  • 留言刪除功能(msg-del.php)

MySQL留言資料庫(message)

編碼:utf8_unicode_ci

名稱 型態 備註
id int AI
guest_id int
content text
date date

留言板頁面(msg.php)

  • 結合 message 的 guest_id 與 member 的 id
    在 message 的提取迴圈裡面,寫下指令 mysql_query( 讀取 member 資料表,WHERE條件設定 id=’$row[guest_id]’ )
<?php
mysql_connect("localhost", "root", "");
mysql_select_db("hahow");
mysql_query("SET NAMES UTF8");

//如果沒有登入的SESSION,就轉址
if (isset($_SESSION["email"])==FALSE) {
 header('Location: login.php');
}
?>
<!DOCTYPE html>
<html>
<head>
 <title>Message Board</title>
 <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
 <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
</head>
<body>
<br><br><br><br>
<div class="container">
 <h3 class="text-center">會員留言板</h3>
 <hr>

<?php
$re=mysql_query("SELECT * FROM message");
//檢査有沒有留言數( message 資料表的資料筆數是否大於0):參考
if(mysql_num_rows($re)>0){
 //如果有留言,一筆一筆印出留言
 //使用 while 迴圈從 message 資料表一筆一筆讀取留言的方法:參考
 while($row=mysql_fetch_array($re))
 {
 //mysql_query() 括弧裡面的指令,使用變數時,要用單引號包起來,參考
 $memberRe=mysql_query("SELECT * FROM member WHERE id='$row[guest_id]'");
 $memberRow=mysql_fetch_array($memberRe);

 echo "<div class=\"panel panel-default\">
 <div class=\"panel-heading\">$memberRow[name] 
 <span class=\"pull-right\">$row[date]
 //以更改網址的方式強制讀取GET表單資料
 //正常的流程:使用者在GET表單輸入資料→送出轉址→新網址裡面有使用者輸入的資料
 //轉址到有特定 GET 表單 id 的 msg-del.php
 <a href=\"msg-del.php?id=$row[id]\" class=\"btn btn-danger btn-xs\">
 DELETE
 </a>
 </span>
 </div>
 <div class=\"panel-body\"> $row[content]
 </div>
 </div>";
 }
}

else{
 //沒有留言的話
 echo "<p class=\"text-center\">沒有任何訊息!</p>";
}
?>
 <hr>
 <p class="pull-right">以 <?php echo $_SESSION["name"]; ?> 的身份留言</p>
 <h4>新增留言</h4>
 <form action="msg-add.php" method="post">
 <textarea name="msg" class="form-control"></textarea>
 <br>
 <input type="submit" name="submit" value="送出" class="btn btn-primary btn-sm pull-right">
 </form>
</div>
</body>
</html>

留言新增功能(msg-add.php)

<?php
require("msg.php");

//設定日期格式
$date=date("Y-m-d");

$SaveNewMsg=mysql_query("INSERT INTO message(guest_id, content, date) 
//對應 msg.php 新增留言區的 POST表單
VALUES('$_SESSION[id]','$_POST[msg]','$date')");

//檢査
if(!$SaveNewMsg){
 echo "留言失敗";
}else{
 echo "留言成功";
}

//新增完畢轉回留言板
header('Location: msg.php');
?>

留言刪除功能(msg-del.php)

<?php
require("msg.php");

//抓取 msg.php 布好的GET表單的刪除ID
mysql_query("DELETE FROM message WHERE id='$_GET[id]'");

//刪除完畢轉回留言板
header('Location: msg.php');
?>

範例:會員登入網站

測試用帳號:123@123
測試用密碼:123

結語

  • 善用 Sublime + SFTP,存檔即上傳主機可以節省時間
  • bug 可能出現在各種地方,資料庫連線,上一份檔案的 session 沒有寫好,都可能有錯,必須小心

PHP 隱藏錯誤訊息

@:用在函數前,使不顯示錯誤訊息

範例

//檢査註冊表單輸入之email有沒有重複註冊到
$result=mysql_query("SELECT * FROM member WHERE email=$_GET[email]");

 //@ 用在函數前,使不顯示錯誤訊息
 $row=@mysql_fetch_array($result);

error_reporting(0):關閉提示

//關閉提示(非錯誤訊息)
error_reporting(0);

PHP + MySQL 中文字亂碼問題

解説

建立PHP網頁讀取MySQL資料庫時,如果資料庫裡面有中文,讀取出來放到網頁上會變成問號

解決方法

MySQL資料庫編碼設定

點選資料庫右邊的小水庫圖案,在編碼與排序設定【utf8_unicode_ci】

php中的head設定

在php的html部分裡面的,之中插入這行程式碼

<head>
mysql_query("SET NAMES 'UTF8'");
</head>

讀取資料庫設定

php讀取資料前,設定這一行

mysql_query("SET NAMES 'UTF8'");

PHP結合MySQL

資料庫連線

<?php

//網址:localhost 因為網頁跟資料庫的伺服器在電腦上面
//登入帳號:root(預設)
//密碼:留空
mysql_connect("localhost", "root", "");

?>

檢査資料庫連線是否成功

<?php

$Connect=mysql_connect("localhost", "root", "");

if (!$Connect) {
 die("連線失敗,錯誤訊息:".mysql_error());
}
echo "連線成功";
mysql_close($Link);

?>

選擇資料庫

<?php

//DB:DataBase
//member是要操作的資料庫名稱
mysql_select_db("hahow");

?>

資料庫長得像這樣
左邊這排外排的就是資料庫 (hahow, information_schema, mysql, performance_schema, phpmyadmin, test)
内縮的是資料表 (mem, member)

phpmyadmin

SQL査詢指令

<?php

//SELECT後面接欄位,*代表所有欄位
//FROM後面接資料表,從member這個資料表裡面讀取
//mysql_query()裡面的東西用""包起來
//査詢member這個資料表裡面所有内容
//將mysql_query()的回傳値存在$re裡面
$re=mysql_query("SELECT * FROM member");

?>

回傳資料處理  mysql_fetch_array()

<?php

$re=mysql_query("SELECT * FROM member");
//在回傳値$re中擷取其中一筆資料出來
$row=mysql_fetch_array($re);
//提取第一筆name資料
//如果要提取很多資料,必須寫成迴圈

echo $row["name"];
//資料會存成陣列

/************寫成迴圈版本**************/

$re=mysql_query("SELECT * FROM member");
while($row=mysql_fetch_array($re)){
 echo $row["name"];
 //只要條件符合,就會一筆一筆地把資料處裡過去
}

?>

MySQL指令使用變數

<?php

//mysql_query()裡面的MySQL指令中的變數
//要用單引號'包起來
//並且變數裡面不能有雙引號"
$re=mysql_query("SELECT * FROM member" WHERE email='$_GET[email]'");

?>

抓取資料總筆數 mysql_num_rows()

<?php

$re=mysql_query("SELECT * FROM member");

//mysql_num_rows()裡面放存mysql_fetch_array()的變數
$dataNum=mysql_num_rows($re);

echo $dataNum;
//會顯示總共有幾筆資料

?>

SQL Injection 資料庫隱碼注入攻擊

<?php

//沒有防護措施的原始php
//"$_GET["email"]"是要産生MySQL指令的片段
SELECT * FROM member WHERE id="$_GET["email"]"

//正常的情況下:使用者填入正常的email
SELECT * FROM member WHERE id="MingWang@gmail.com"
//SQL query査詢功能會回傳符合id="MingWang@gmail.com"的資料

//受到攻擊:有人輸入" OR "1"="1
SELECT * FROM member WHERE id="" OR "1"="1"
//id不一定等於空値,但是1永遠等於1,所以true
//所有資料都符合id="" OR "1"="1",所以會回傳所有資料

//結果:不論帳號密碼是對或錯,都可以直接登入

?>

防止SQL Injection:mysql_escape_string()

<?php

//$q=使用者輸入的資料
//使用SQL query査詢指令之前先過濾
$q=mysql_escape_string($q);

//然後開始査詢
SELECT * FROM member WHERE id="$q"

?>

 

 

PHP 基本知識

基本語法

<?php
//單行註解

/*
多行註解
*/

//echo 顯示文字
//;代表結束
echo "Hello world";
?>

變數

<?php

/*$宣告變數*/
$x=3;
$y=5;

/*修改變數*/
$x=4;
//x就變成4了

/*輸出變數*/
echo $x;

/*同時輸出字串與變數*/
$name="Ian";
//中間用.連接兩者
echo "Hello".$name;
//output: Hello Ian

/*同時輸出法2*/
$name="Ian";
echo "Hello $name";
//output: Hello Ian
//echo 使用"包起來,會自動識別裡面的$變數

/*同時輸出法注意*/
$name="Ian";
echo 'Hello $name';
//output: Hello $name
//echo 使用'包起來,不會識別裡面的$變數,全部都會變成字串


?>

運算

1+2
1:運算元
+:運算子
2:運算元

基本運算子

運算子符號
+ 相加
相減
* 相乘
/ 相除
% 模除(取餘數)
++ 連加1
連減1

關係運算子

關係運算子
> 大於
< 小於
>= 大於等於
<= 小於等於
== 等於
!= 不等於
運算成立:true,echo顯示為1
運算不成立:false,echo 顯示為無

邏輯運算子:針對布林運算

邏輯運算子
&&
||
! 非(反轉現在ture/false的狀態)

選擇性敘述:if-else

<?php

// 獲得今天的日期,並將 Monday/Tuesday/.../Sunday 存放於 wday 變數中
date_default_timezone_set("Asia/Taipei");
$today = getdate();
$wday = $today['weekday'];

// 依照不同的星期顯示繞口令
if($wday == 'Monday'){
    echo "星期一,猴子穿新衣";
}
elseif($wday == 'Tuesday'){
    echo "星期二,猴子肚子餓";
}
elseif($wday == 'Wednesday'){
    echo "星期三,猴子去爬山";
}
elseif($wday == 'Thursday'){
    echo "星期四,猴子看電視";
}
elseif($wday == 'Friday'){
    echo "星期五,猴子去跳舞";
}
elseif($wday == 'Saturday'){
    echo "星期六,猴子去斗六";
}
else{
    echo "星期日,猴子過生日";
}

?>

選擇性敘述:switch case

//放晴:$sunny==2
//陰天:$sunny==1
//非晴非陰→雨天:default

switch($sunny){
  //$sunny==2
  case 2:
    //放晴出去玩
    play();
    //沒有break的話即便$sunny==2,程式碼也會繼續往下執行default的lol();
    break;

  //$sunny==1
  case 1:
    //陰天散步
    walk();
    break;

  //既非晴天亦非陰天
  default:
    //在家打lol
    lol();
}

while迴圈

<?php

while($sunny==false){
  //如果天還沒亮,繼續睡覺
  sleep();
}

?>

陣列

<?php

// 建立陣列
$fruits = array("蘋果","香蕉","梨子","芭樂");
//輸出索引値key為 0 的元素
echo $fruits[0];
echo "<br>";

// 建立陣列(自訂索引値)
$fruits_eng = ["a"=>"蘋果","b"=>"香蕉","p"=>"梨子","g"=>"芭樂"];
// 輸出索引値為 p 的元素
echo $fruits_eng["p"];

?>

函數

參數→函式本體→回傳値

<?php

//square為函式的名字
//$x為參數
function square($x){

 $y=$x*$x;
 return $y;
 //return回傳値

}
echo square(2);

?>

HTTP Method

client向server要資料的溝通方式

  • GET 向server索取資料
  • POST 給予server資料

GET:html送出資料後跳出的php網址列會顯示使用者鍵入的資料

<!-- 送出的對象13-1.php -->
<!-- 送出的方式HTTP Method GET -->
<form action="13-1.php" method="get">
 <input type="text" name="firstname">
 <input type="submit" name="submit" value="送出">
</form>
<?php

//$_GET超級全域變數
//只要PHP存在,有對應的GET資料傳進來時,這個變數就會永遠存在
$name = $_GET['firstname'];

echo "Hi $name!";

?>

POST:html送出資料後跳出的php網址列不會顯示使用者鍵入的資料

<!-- 送出的對象13-1.php -->
<!-- 送出的方式HTTP Method POST -->
<form action="13-2.php" method="post">
 <input type="text" name="firstname">
 <input type="submit" name="submit" value="送出">
</form>
<?php

//$_POST超級全域變數
//只要PHP存在,有對應的POST資料傳進來時,這個變數就會永遠存在
$name = $_POST['firstname'];
echo "Hi $name!";

?>

isset()檢査變數是否存在

<?php

$a=0;

isset($a);//$a已經宣告過,所以値等於true
isset($b);//$b已經宣告過,所以値等於false

?>

empty()檢査變數是否為空

<?php

$a="";
$b="Hi";

empty($a);//$a為空値,所以値等於ture
empty($b);//$b不為空値,所以値等於false
?>

htmlspecialchars() 防止XSS

網頁漏洞XSS:Cross Site Scripting

透過別的網站,或站外的方式,修改HTML的内容,使網頁做出他原本不應該做的動作

//html(内崁沒有防護措施的php)

<form action="<?php echo $_SERVER["PHP_SELF"];?>">

//表單送出時會送回這個檔案本身
//如果使用者瀏覽ex.com/test.php
//HTML就會變成<form action="test.php">
//但如果使用者瀏覽ex.com/一行JS程式碼
//HTML就會執行那段JS程式碼了QQ

htmlspecialchars() 讓輸入的程式碼變成純文字的編碼,使文字失去程式碼的執行能力

<form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>">

//htmlspecialchars()裡面的程式碼變成純文字,失去執行程式的能力

htmlspecialchars()的使用時機:
使用php産生網頁内容,需要使用者輸入資料時,
利用此function過濾使用者輸入的内容

Cookie

網頁存在使用者電腦裡面的一些資料

<?php

//建立
setcookie("user", "Ian", time()+3600);
//建立一個名為user的cookie
//其値為Ian
//失效時間為此程式執行後3600秒
//time()為程式執行當下的時間

//刪除他
setcookie("user", "Ian", time()-3600);

//讀取:超級全域變數
echo $_COOKIE["user"];
?>

Session:存放在伺服器的Cookie

比Cookie安全,比較不容易被竄改(可以用在登入狀態的資料等)

<?php

//開始Session
session_start();

//寫入
//email是這個session的名字
//ianchen0419@gmail.com是這個session的値
$_SESSION["email"]="ianchen0419@gmail.com";

//或是也可以不輸入値直接使用他
$_SESSION["email"];

//印出ianchen0419@gmail.com
echo $_SESSION["email"];

//刪除
unset($_SESSION["email"]);
//刪除email這筆SESSION

//刪除這台電腦所有的session
session_destroy();
?>