owned this note
owned this note
Published
Linked with GitHub
# 後端基礎 `PHP` 與 `MySQL`
###### tags: `Tag(後端基礎 PHP 與 MySQL!)`
## `PHP` 是什麼
>[參考資料](https://www.happycoding.today/posts/23) 3分鐘快速認識PHP
PHP語言是伺服器端(Server)執行的網頁,==PHP必須先在伺服器端執行完==後,再將結果傳至使用者端(Client)的瀏覽器中檢視結果,所以<font color="#c7b198">必須使用網站伺服器,且伺服器要支援PHP。</font>
## 前端與後端的差別
>[參考資料](https://noootown.com/frontend-backend-breakfast/) 買早餐也能了解前端 vs 後端?
>[參考資料](https://15days.website/posts/frontend-vs-backend) 什麼是前端?什麼是後端?
連到網站,==帶有畫面和動畫的這些檔案==,都是從伺服器傳送來的,製作這些畫面的,都是前端。
填入帳號密碼,按下發送,內容傳到伺服器。伺服器處理各個request和response,然後會==幫你做驗證,確定你可不可以登入==,都是後端。
回到主畫面,右上角寫著「嗨!XXX」,這個XXX叫什麼名字,也都是後端幫忙前端填上去的,而這些==動態填上去的資料,都是存放在伺服器的資料庫(database)==。
## 什麼是資料庫
>[參考資料](https://medium.com/pierceshih/%E7%AD%86%E8%A8%98-%E4%BD%95%E8%AC%82%E8%B3%87%E6%96%99%E5%BA%AB%E7%B3%BB%E7%B5%B1-53b59aacbfb7) 何謂資料庫系統
>[參考資料](https://ithelp.ithome.com.tw/articles/10185512) 資料庫系統應用 - 關聯式資料庫
資料庫可以當成是資料的檔案櫃,當需要的時候才將所需的資聊拉出來。一般來說,==資料庫可以提供「新增 Create」、「查詢 Read」、「更新 Update」、「刪除 Delete」,簡稱 CRUD。==
資料庫大致上可以分為兩種類型:
``` c
* 關聯式資料庫(Relational Database Management System,縮寫為RDBMS)
* 非關係型資料庫(Not Only SQL,縮寫為 NoSQL)
```
### 關聯式資料庫
==使用簡單,穩定度高==,常見如 MySQL、PostgreSQL、Microsoft SQL Server、SQLite。
``` c
* 資料是以一個或是多個資料表 (table) 的方式存放
* 資料之間有明確的關聯
以 To-do List 舉例,以 table 資料表來存放 todo 跟 user 這兩種資料,
並在兩個資料表之間,設定「使用者擁有 todo」這個關聯。
* 關聯式資料庫是以 SQL 語言操作
SQL管理與查詢關聯式資料庫的程式語言
```
### 非關聯式資料庫
NoSQL 資料庫,常見為 mongoDB。
``` c
* 彈性高,不限定於「關聯式資料庫」的做法
NoSQL 更關注資料所代表的人(例如使用者)與物(例如一篇分享在社交平台上的文章)的「狀態」變動,
例如文章被分享、按讚等。
* 不講求資料同步,只求最後結果一致
處理一篇在 Facebook 上的 po 文有多少人按讚時,這個訊息的準確性就不是非常重要。
部分使用者可能要隔數十秒後才看到按讚數從 99 轉到 100
```
## 什麼是 `Session`
>[參考資料](https://fred-zone.blogspot.com/2014/01/web-session.html) Web 技術中的 Session 是什麼?
>[白話 Session 與 Cookie:從經營雜貨店開始](https://medium.com/@hulitw/session-and-cookie-15e47ed838bc)
> [淺談 Session 與 Cookie:一起來讀 RFC](https://blog.huli.tw/2019/08/09/session-and-cookie-part2/)
> [深入 Session 與 Cookie:Express、PHP 與 Rails 的實作](https://blog.huli.tw/2019/08/09/session-and-cookie-part3/)
==Session 的機制==<font color="#ad9d9d">就像是你去飲料店下了單以後,得到號碼牌,然後你走開幾步,店員就忘了你是誰。
如果你想去取飲料,你就得靠這張號碼牌,去跟店員領,店員會跟據這號碼牌,認定你是顧客、是否點過餐、知道你點了什麼東西,然後可以接著給你屬於你的飲料。
點了什麼飲料,都是記錄在 Server 裡,可能是 Database、記憶體或是檔案,可以以任何一種形式儲存。然後,當你去領飲料時,店員會輸入你的號碼,用你的號碼得知你是否點過餐、點了什麼東西。</font>
## 什麼是 `Cookie`
>[參考資料](https://fred-zone.blogspot.com/2014/01/web-session.html) Web 技術中的 Session 是什麼?
<font color="#ad9d9d">兩種方法讓 Client 取得號碼牌,一個是用 ==Cookie==,另一個是直接輸出並嵌入頁面之中的方法(就是要你把號碼背起來)。
拿號碼牌去 Server 要資料,主要也分為兩種方法,Cookie 和運用標準的 Query string/POST body方法。(其實只要能把號碼傳到 Server 上,任何方法都行)
Cookie 就是</font>==存在瀏覽器裡的一些資訊。==
---
## `Apache` 與 `PHP` 原理簡介
>[color=#c4a244]Server → 專門處理 request & response 的程式
>[color=#c4a244]資料資料庫系統 → 專門處理資料的程式
:::warning
``` c
request → apache(server) → php → output(html) → apache → response
```
``` c
* 接收 request
* server 轉給 php 處理
* php 處理轉成 html
* html 傳給 server
* server 回傳 response
```
:::
---
## 基礎 `PHP` 語法
``` c
* 要用 <?php ?> 包起來
* 每一步指令完成後一定要加 ;
* 宣告變數用 $ 開頭
* 字串連接用 . 而不是 +
```
##### 陣列 `array`
###### 設定陣列:
```php
$arr = array(1,2,3,4,5)
```
###### 取得陣列元素:
```ph
echo $arr[i];
```
###### 取得陣列長度:
```ph
echo sizeof($arr);
```
###### 輸出完整陣列
##### `var_dump `: 輸出每一個內容的型態跟值: type, value
##### `print_r` : 比較簡潔、沒有輸出型態: value
---
## `MySQL` 基礎語法
#### <font color="#3ca59d">新增`(INSERT)`</font>
###### 使用 `INSERT INTO `指令可以新增資料:
```php
INSERT INTO "表格名" ("欄位1", "欄位2", ...) VALUES ("值1", "值2", ...);
```
```php=
INSERT INTO users ("name", "email", "age", "salary") VALUES ("Mark", "mark@gmail.com", 20, 70000);
```
#### <font color="#3ca59d">查詢`(SELECT)`</font>
###### 使用 `*` 查詢全部資料:
```ph
SELECT * FROM [資料表名稱];
```
###### (條件)`where`針對特定屬性選取:
```ph
SELECT * FROM [資料表名稱] WHERE [條件式];
```
###### ==排序加上 `ORDER BY`==,設定由大到小 `DESC` 或由小到大 `ASC`:
```ph
SELECT * FROM users ORDER BY age DESC;
```
###### ==`as` 改名==,後面接 `<new-name>`
```ph
SELECT created_at as time, nickname as name FROM users
```
###### 函式→數量 `COUNT`、加總 `SUM`、平均值 `AVG`、最大值 `MAX` 和最小值 `MIN`。
###### `COUNT`計算筆數
```ph
SELECT COUNT([欄位]) FROM [資料表名稱] WHERE [條件式];
```
###### 取該欄位底下最大值`MAX` / 最小值`MIN`
```ph
SELECT MAX([欄位]) FROM [資料表名稱];
```
```ph
SELECT MIN([欄位]) FROM [資料表名稱];
```
###### `SUM`欄位底下值加總
```ph
SELECT SUM([欄位]) FROM [資料表名稱];
```
#### <font color="#3ca59d">刪除 `DELETE`</font>
###### 先用 `SELECT` 指令撈取要操作的資料
##### <font color="#c7b198">`WHERE` 在這一項非常重要,沒有加上 `WHERE `則系統會對所有行進行動作,即會刪除所有資料。</font>
```ph
DELETE FROM users WHERE id=1;
```
#### <font color="#3ca59d">修改`(UPDATE)`</font>
```php
UPDATE "表格名" SET "欄位1"=[新值] WHERE "條件";
```
###### `SET` 指定要修改的列和值
##### <font color="#c7b198">`WHERE` 很重要,如果忘記寫上 `WHERE` 子句,會意外更新表中的所有行。</font>
```p
UPDATE users SET name=Mark WHERE id=1;
```
---
## 前端傳資料給後端
#### `form `方法
``` c
* 在 form 標籤中將資料帶到後端
* form 當中要加入 method 跟 action 兩個屬性
* method: HTTP method
* action: 要帶入的檔案
```
```c
// 將內容帶入 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`把送的資料拿出來
```c
<?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 回傳的代號來做對應的處理
##### `錯誤處理`
```c
<?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`
```c
if (empty($username) || empty($password)) {
header('Location: login.php?errCode=1');
die('請檢查資料');
}
```
###### `導回到 login.php 時,可用 $_GET 取得 query string 的值,以做對應的處理`
```c
if (!empty($_GET['errCode'])) {
$code = $_GET['errCode'];
$msg = 'Error';
if ($code === '1') {
$msg = '請輸入內容';
}
echo '<p class="error">' . $msg . '</p>';
}
```
---
## 資料庫連線
###### `conn.php`
>[color=#c4a244]conn.php 有帳號密碼等重要資料,放在 git.ignore 不要上傳至 GitHub
```c
$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"'); // 設定為台灣時區
```
##### 讀取資料
```c
<?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>';
}
?>
```
##### 新增資料
```c
<?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
?>
```
##### 刪除資料
```c
<?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");
?>
```
##### 編輯資料
```c
<?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` 的資料
```c
<?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`
```c
//要使用 Session,都要在開頭使用 session_start()
session_start();
$username = htmlspecialchars($_POST['username']);
//把資料存在 Session 對應的 key 裡面
$_SEESION['username'] = $username;
```
#### 取用 `session`
```c
session_start();
//如果 session 內有存過 username,
//則宣告變數 $username 為剛才存的 $_SESSION['username']
if(isset($_SESSION['username'])) {
$username = $_SESSION['username'];
}
```
#### 比對資料是否存在於資料庫
>[color=#db1a4a]用 `num_rows` 來達成
```c
//如果有找到對應的資料,就把 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` 的內容被放上程式碼後跑版
###### 建立函式
```c
function escape($str) {
return htmlspecialchars($str, ENT_QUOTES); //ENT_QUOTES可以轉換單雙引號
}
```
###### `使用 htmlspecialchars_decode 來把資料庫內的 unicode 解析成特殊符號`
```c
<h3 class="time"><?php echo escape($row['created_at']) ?></h3>
<div class="content"><?php echo htmlspecialchars_decode($row['content']) ?></div>
```
---
## 在函式內使用全域變數
###### `使用 global `
```c
function getUserFromUsername($username) {
global $conn;
$sql = "SELECT * FROM nicolakacha_users WHERE username='$username'";
$result = $conn->query($sql);
$row = $result->fetch_assoc();
return $row;
}
```
---
## 資料庫欄位型態 `VARCHAR` 跟 `TEXT` 的差別是什麼
>[參考資料](https://hsiangfeng.github.io/php/20190904/1799668484/) 從基礎學習 ThinkPHP-基礎 MySQL 學習-資料表篇
>[參考資料](https://ithelp.ithome.com.tw/articles/10203456?sc=iThelpR) 常用的資料庫資料型態
>[參考資料](http://n.sfs.tw/content/index/10266) [Mysql] 資料型態
``` c
* char : 長度為 0 ~ 255,當儲存字串不夠 255 的長度時,會用空格補齊剩餘的空間,因此讀取時必須把後面空格去除。
* varchar: 可以設定最大長度,適合用在文字量少的欄位,可以有預設值。
* text: 不可設定長度,適合用在文字量多的欄位,最大长度为 2 ^ 31 - 1 個字符,不可以有預設值。
```
##### 查詢速度:
```c
* char 最快, varchar 次之,text 最慢。
* 由于 varchar 查询速度更快,所以能用 varchar 的时候就不用 text。
```
---
## 使用隨機函數,讓圖片可以隨機呈現
>[參考資料](https://pjchender.blogspot.com/2015/03/php-mysql_6.html) 隨機函數
#### 新建一個資料夾,把圖片放進去
![](https://i.imgur.com/DVWxcw2.png)
```c
* num則是變數名稱,而這個變數是由1~15組成的隨機數字
* rand() 函數返回隨機整數。
```
###### `index.php`
```c
<div class="avatar">
<?php $num = rand(1,15); ?>
<img class="avatar_img" src="img/<?php echo $num ?>.png"">
</div>
```