changed 4 years ago
Linked with GitHub

後端基礎 PHPMySQL

tags: Tag(後端基礎 PHP 與 MySQL!)

PHP 是什麼

參考資料 3分鐘快速認識PHP

PHP語言是伺服器端(Server)執行的網頁,PHP必須先在伺服器端執行完後,再將結果傳至使用者端(Client)的瀏覽器中檢視結果,所以必須使用網站伺服器,且伺服器要支援PHP。

前端與後端的差別

參考資料 買早餐也能了解前端 vs 後端?

參考資料 什麼是前端?什麼是後端?

連到網站,帶有畫面和動畫的這些檔案,都是從伺服器傳送來的,製作這些畫面的,都是前端。

填入帳號密碼,按下發送,內容傳到伺服器。伺服器處理各個request和response,然後會幫你做驗證,確定你可不可以登入,都是後端。

回到主畫面,右上角寫著「嗨!XXX」,這個XXX叫什麼名字,也都是後端幫忙前端填上去的,而這些動態填上去的資料,都是存放在伺服器的資料庫(database)

什麼是資料庫

參考資料 何謂資料庫系統

參考資料 資料庫系統應用 - 關聯式資料庫

資料庫可以當成是資料的檔案櫃,當需要的時候才將所需的資聊拉出來。一般來說,資料庫可以提供「新增 Create」、「查詢 Read」、「更新 Update」、「刪除 Delete」,簡稱 CRUD。

資料庫大致上可以分為兩種類型:

* 關聯式資料庫(Relational Database Management System,縮寫為RDBMS)
* 非關係型資料庫(Not Only SQL,縮寫為 NoSQL)

關聯式資料庫

使用簡單,穩定度高,常見如 MySQL、PostgreSQL、Microsoft SQL Server、SQLite。

* 資料是以一個或是多個資料表 (table) 的方式存放
 
* 資料之間有明確的關聯
  以 To-do List 舉例,以 table 資料表來存放 todo 跟 user 這兩種資料,
  並在兩個資料表之間,設定「使用者擁有 todo」這個關聯。
  
* 關聯式資料庫是以 SQL 語言操作
  SQL管理與查詢關聯式資料庫的程式語言

非關聯式資料庫

NoSQL 資料庫,常見為 mongoDB。

* 彈性高,不限定於「關聯式資料庫」的做法
  NoSQL 更關注資料所代表的人(例如使用者)與物(例如一篇分享在社交平台上的文章)的「狀態」變動,
  例如文章被分享、按讚等。

* 不講求資料同步,只求最後結果一致
  處理一篇在 Facebook 上的 po 文有多少人按讚時,這個訊息的準確性就不是非常重要。
  部分使用者可能要隔數十秒後才看到按讚數從 99 轉到 100

什麼是 Session

參考資料 Web 技術中的 Session 是什麼?

白話 Session 與 Cookie:從經營雜貨店開始

淺談 Session 與 Cookie:一起來讀 RFC

深入 Session 與 Cookie:Express、PHP 與 Rails 的實作

Session 的機制就像是你去飲料店下了單以後,得到號碼牌,然後你走開幾步,店員就忘了你是誰。

如果你想去取飲料,你就得靠這張號碼牌,去跟店員領,店員會跟據這號碼牌,認定你是顧客、是否點過餐、知道你點了什麼東西,然後可以接著給你屬於你的飲料。

點了什麼飲料,都是記錄在 Server 裡,可能是 Database、記憶體或是檔案,可以以任何一種形式儲存。然後,當你去領飲料時,店員會輸入你的號碼,用你的號碼得知你是否點過餐、點了什麼東西。

參考資料 Web 技術中的 Session 是什麼?

兩種方法讓 Client 取得號碼牌,一個是用 Cookie,另一個是直接輸出並嵌入頁面之中的方法(就是要你把號碼背起來)。

拿號碼牌去 Server 要資料,主要也分為兩種方法,Cookie 和運用標準的 Query string/POST body方法。(其實只要能把號碼傳到 Server 上,任何方法都行)

Cookie 就是存在瀏覽器裡的一些資訊。


ApachePHP 原理簡介

Server → 專門處理 request & response 的程式

資料資料庫系統 → 專門處理資料的程式

request → apache(server) → php → output(html) → apache → response 
* 接收 request
* server 轉給 php 處理
* php 處理轉成 html
* html 傳給 server
* server 回傳 response

基礎 PHP 語法

* 要用 <?php ?> 包起來
* 每一步指令完成後一定要加 ;
* 宣告變數用 $ 開頭
* 字串連接用 . 而不是 +
陣列 array
設定陣列:
$arr = array(1,2,3,4,5)
取得陣列元素:
echo $arr[i];
取得陣列長度:
echo sizeof($arr);
輸出完整陣列
var_dump : 輸出每一個內容的型態跟值: type, value

MySQL 基礎語法

新增(INSERT)

使用 INSERT INTO 指令可以新增資料:
INSERT INTO "表格名" ("欄位1", "欄位2", ...) VALUES ("值1", "值2", ...);
INSERT INTO users ("name", "email", "age", "salary") VALUES ("Mark", "mark@gmail.com", 20, 70000);

查詢(SELECT)

使用 * 查詢全部資料:
SELECT * FROM [資料表名稱];
(條件)where針對特定屬性選取:
SELECT * FROM [資料表名稱] WHERE [條件式];
排序加上 ORDER BY,設定由大到小 DESC 或由小到大 ASC
SELECT * FROM users ORDER BY age DESC;
as 改名,後面接 <new-name>
SELECT created_at as time, nickname as name FROM users
函式→數量 COUNT、加總 SUM、平均值 AVG、最大值 MAX 和最小值 MIN
COUNT計算筆數
SELECT COUNT([欄位]) FROM [資料表名稱] WHERE [條件式];
取該欄位底下最大值MAX / 最小值MIN
SELECT MAX([欄位]) FROM [資料表名稱];
SELECT MIN([欄位]) FROM [資料表名稱];
SUM欄位底下值加總
SELECT SUM([欄位]) FROM [資料表名稱];

刪除 DELETE

先用 SELECT 指令撈取要操作的資料
WHERE 在這一項非常重要,沒有加上 WHERE 則系統會對所有行進行動作,即會刪除所有資料。
DELETE FROM users WHERE id=1;

修改(UPDATE)

UPDATE "表格名" SET "欄位1"=[新值] WHERE "條件";
SET 指定要修改的列和值
WHERE 很重要,如果忘記寫上 WHERE 子句,會意外更新表中的所有行。
UPDATE users SET name=Mark WHERE id=1;

前端傳資料給後端

form 方法

* 在 form 標籤中將資料帶到後端
* form 當中要加入 method 跟 action 兩個屬性
* method: HTTP method
* action: 要帶入的檔案
// 將內容帶入 index.php 這個檔案當中
<form method="GET" action="index.php">
  id: <input type="text" name="id"/>
  name: <input type="text" name="name"/>
  age: <input type="text" name="age"/>
  <input type="submit"/>
</form>

index.php可以用$_GET把送的資料拿出來

<?php
    // 用empty檢查表單是否為空的
    if(empty($_GET['name']) || empty($_GET['age'])){
        echo '資料有缺,請再次填寫<br>';
        exit(); // 終止程序
    };
    // 接收 method 為 GET 的 From input
    echo "Hello!" . $_GET['name'] . "<br>";
    echo "Your age is" . $_GET['age'] . "<br>";

    print_r($_GET);
?>

用 GET 回傳的代號來做對應的處理

錯誤處理
<?php
  echo "wheeeeeeeeee"
?>

<form method="GET" action="data.php">
  name: <input type="text" name="name">
  age: <input type="text" name="age">
  <input type="submit">
</form>
用 query string 在導向時加上 errCode
if (empty($username) || empty($password)) {
    header('Location: login.php?errCode=1');
    die('請檢查資料');
  }
導回到 login.php 時,可用 $_GET 取得 query string 的值,以做對應的處理
if (!empty($_GET['errCode'])) {
  $code = $_GET['errCode'];
  $msg = 'Error';
  if ($code === '1') {
    $msg = '請輸入內容';            
  }
  echo '<p class="error">' . $msg . '</p>';
}

資料庫連線

conn.php

conn.php 有帳號密碼等重要資料,放在 git.ignore 不要上傳至 GitHub

  $server_name='localhost'; // server 名稱
  $user_name='ruofan'; // 帳號
  $user_password='ruofan'; // 密碼
  $db_name='ruofan'; // db 名稱

  $conn = new mysqli($server_name ,$user_name, $user_password, $db_name);
  // 一切的起源就是 mysqli 這個 class
  // 內中的伺服器名稱 / 帳號 / 密碼 / 與資料庫名的排序是固定的

  if ($conn->connect_error) { // connect_error 是內建的語法,表示連線Failed
      die('資料庫連線錯誤:' . $conn->connect_error);// die = 印出括號內文字 + 阻止底下程式執行
  }
  
 $conn->query('SET NAMES UTF8'); // 加上編碼,顯示中文才不會有問題
 $conn->query('SET time_zone = "+8:00"'); // 設定為台灣時區
讀取資料
<?php
  require_once('conn.php'); // 連線到資料庫
  // 將 SQL 撈出的資料存在 $result 這個變數中
  // select * 會撈取全部資料,意指全部的資料會放在 𝑟𝑒𝑠𝑢𝑙𝑡
  // 檢查 SQL query 是否使用成功
  $result = $conn->query("SELECT * FROM users"); 
  if (!$result) {
    die($conn->error); 
    // 中斷後面程序並顯示內容,() 內可以輸入訊息字串
  }

  while ($row = $result->fetch_assoc()) { 
  // 把 𝑟𝑒𝑠𝑢𝑙𝑡中的資料,一筆一筆抓出來給row
  // 用一個 while 迴圈,把資料一筆一筆印出
  // row 每一次只會顯示 $result 中的一筆資料
    echo "id:" . $row['id'] . '<br>';
    echo "username:" . $row['username'] . '<br>';
  }
?>
新增資料
<?php
  require_once('conn.php'); // 連線到資料庫

     // $_POST['key-name'] 取得輸入的資料
     // empty()  判斷值是否為 null
  if (empty($_POST['username'])) {
    // // 中斷後面程序並顯示內容,() 內可以輸入訊息字串
    die('請輸入 username'); 
  }
 
  $username = $_POST['username']; 
         // sprintf() 裡面可以放入替代字元
  $sql = sprintf(  
     // 插入新欄位
    "insert into users(username) values('%s')", // %s 代表字串
    $username
  );
  // 執行結果存在 $result 這個變數中
  $result = $conn->query($sql);
  if (!$result) {
    die($conn->error);
  }

  header("Location: index.php"); // 自動跳轉回 index.php
?>
刪除資料
<?php
  require_once('conn.php'); // 連線到資料庫

  if (empty($_GET['id'])) {
    die('請輸入 id');
  }

  $id = $_GET['id'];
  $sql = sprintf(
    "delete from users where id = %d",
    $id
  );
  echo $sql . '<br>';
  $result = $conn->query($sql);
  if (!$result) {
    die($conn->error);
  }

  if ($conn->affected_rows >= 1) { // 判斷影響 1 列以上資料
    echo '刪除成功';
  } else {
    echo '查無資料';
  }

  // header("Location: index.php");
?>
編輯資料
<?php
  require_once('conn.php');

  if (empty($_POST['id']) || empty($_POST['username'])) {
    die('請輸入 id 與 username');
  }

  $id = $_POST['id'];
  $username = $_POST['username'];
  $sql = sprintf(
    "update users set username='%s' where id=%d",
    $username,
    $id
  );
  echo $sql . '<br>';
  $result = $conn->query($sql);
  if (!$result) {
    die($conn->error);
  }

  header("Location: index.php");
?>

while 迴圈拿取 table 內所有 row 的資料

<?php while ($row = $result-> fetch_assoc()) { ?>
  <div class="comment">
    <div class="avatar"></div>
    <div class="text">
      <div class="info">
        <h3 class="nickname"><?php echo escape($row['nickname']) ?></h3>
        <h3 class="time"><?php echo escape($row['created_at']) ?></h3>
      </div>
      <div class="content"><?php echo htmlspecialchars_decode($row['content']) ?></div>
    </div>
  </div>          
<?php } ?>

如何使用 Session

存取 session

//要使用 Session,都要在開頭使用 session_start()
session_start();

$username = htmlspecialchars($_POST['username']);

//把資料存在 Session 對應的 key 裡面
$_SEESION['username'] = $username;

取用 session


session_start();

//如果 session 內有存過 username,
//則宣告變數 $username 為剛才存的 $_SESSION['username'] 
if(isset($_SESSION['username'])) {
    $username = $_SESSION['username'];
  }

比對資料是否存在於資料庫

num_rows 來達成

//如果有找到對應的資料,就把 username 存在 session 裡,導回 index.php
  if ($result->num_rows) {
    $_SESSION['username'] = $username;
    header("Location: index.php");
  //若是失敗,導回 index.php,顯示出錯誤
  } else {
    header('Location: login.php?errCode=2');
  }

htmlspecialchars() 防止 input 的內容被放上程式碼後跑版

建立函式
function escape($str) {
    return htmlspecialchars($str, ENT_QUOTES); //ENT_QUOTES可以轉換單雙引號
  }
使用 htmlspecialchars_decode 來把資料庫內的 unicode 解析成特殊符號
<h3 class="time"><?php echo escape($row['created_at']) ?></h3>
<div class="content"><?php echo htmlspecialchars_decode($row['content']) ?></div>

在函式內使用全域變數

使用 global
function getUserFromUsername($username) {
    global $conn;
    $sql = "SELECT * FROM nicolakacha_users WHERE username='$username'";
    $result = $conn->query($sql);
    $row = $result->fetch_assoc();
    return $row;
  }

資料庫欄位型態 VARCHARTEXT 的差別是什麼

參考資料 從基礎學習 ThinkPHP-基礎 MySQL 學習-資料表篇

參考資料 常用的資料庫資料型態

參考資料 [Mysql] 資料型態

* char : 長度為 0 ~ 255,當儲存字串不夠 255 的長度時,會用空格補齊剩餘的空間,因此讀取時必須把後面空格去除。
* varchar: 可以設定最大長度,適合用在文字量少的欄位,可以有預設值。
* text: 不可設定長度,適合用在文字量多的欄位,最大长度为 2 ^ 31 - 1 個字符,不可以有預設值。
查詢速度:
* char 最快, varchar 次之,text 最慢。
* 由于 varchar 查询速度更快,所以能用 varchar 的时候就不用 text。

使用隨機函數,讓圖片可以隨機呈現

參考資料 隨機函數

新建一個資料夾,把圖片放進去

* num則是變數名稱,而這個變數是由1~15組成的隨機數字

* rand() 函數返回隨機整數。
index.php
<div class="avatar">
     <?php $num = rand(1,15); ?>
     <img class="avatar_img" src="img/<?php echo $num ?>.png"">     
</div>
Select a repo