RZ-Huang
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Note Insights Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    # 後端基礎 - PHP、SQL、Database ###### tags: `back-end`、`SQL`、`php`、`databasse` ## 前言 本篇記錄關於後端的一些基本知識。 ## 後端是什麼? 後端實際上包含下列的三大項 1. 要有一個伺服器來處理 request 與 response 常用的伺服器是 Apache。 2. 寫程式來處理商業邏輯 常用的程式語言是 PHP,PHP 容易學習、方便使用,而且業界常用,因此對於初學者來說,後端學習 php 是優先考量的選擇。 3. 資料庫儲存資料 常用的資料庫為 MySQL。專門設計用來快速儲存資料的資料庫。 --- # UwAmp 一個結合 Apache、PHP、MySQL 的簡易程式: https://www.uwamp.com/en/ ![擷取](https://user-images.githubusercontent.com/49014468/59174127-aca4c680-8b82-11e9-82db-ac6104d344da.JPG) 它的介面如上圖。 * `Browser www` 的部份就是顯示 php 檔案內容的地方。 * `Folder www` 按下去會跳出一個資料夾,資料夾裡新增一個資料夾,在新增的資料夾裡加上 php 的檔案,在 php 檔案裡寫上 html 標籤就可以從 `Browser www` 按鈕的頁面看到 html 的內容。然後 html 和 php 語法可以同時寫在 php 檔案裡。 * php 的語法不會顯示在頁面上(除了一些顯示語法,如 `echo`),php 的語法處理完之後,傳到 Server,會經過 Server 的機制,Server 處理完之後,顯現最後的頁面結果。像是下面這段程式碼: ``` <h1> <?php echo 'yo'; ?> </h1> ``` 結果會是 `yo` 字樣為 h1 標籤大小的內容。也就是和 `<h1>yo</h1>` 是一樣的。 P.S. 記得 PHP Version 選擇最新版本的。 --- # php、server、database、request、response 的關係 Server 端接收到 request 的訊息之後,把這個訊息傳到 php 裡,根據 request 的要求執行 php 程式碼裡相對應的功能,並且把結果傳回到 Server 端,接著 Server 端做 response 的傳送。而 php 在執行時有必要會與 database 請求資料、提取資料。如下示意圖。 ![未命名](https://user-images.githubusercontent.com/49014468/59175734-30fa4800-8b89-11e9-9831-f85ca3d2e7f8.png) --- # PHP 基礎語法 * 在 `.php` 檔案裡,輸入任何單純的文字都會顯示出來,包括字串,還有 html 的語法也可以,除了用 `<?php ?>` 包住的內容才不會顯示在頁面上。 * 在 php 語法的段落最前面一定要加上 `<?php`,尤其是 `php` 字樣最好一併打上,若沒打上可能功能會不完整;而內容的結尾則是用 `?>` 包住。 * php 語法的每一行都要加分號。 ### echo 使用 echo 語法可以顯示內容,像是: ``` <?php echo "<h1>123</h1>"; ?> ``` 會顯示 h1 標籤大小的 123 字串內容。 ### 陣列 ``` <?php $arr = array(1, 'google', 3, 4, 5); echo $arr[sizeof($arr) - 1]; var_dump($arr); print_r($arr); ?> ``` * `$arr = array(1, 'google', 3, 4, 5);` 為建立一個新陣列。 * ` echo $arr[sizeof($arr) - 1];` 這之中的 `sizeof()` 回傳陣列長度。 * `var_dump()` 回傳陣列的詳細資料,包括每個陣列的值的索引值、值的型態、值的內容。 * `print_r()` 就是簡易版的 `var_dump()`,只會回傳陣列的值的索引值和值的內容。 ### 函式 ``` <?php function add($a, $b) { return $a + $b; } echo add(1, 2); ?> ``` 跟 Javascript 語法差不多。 ### 範例 顯示一個 0~9 數字的列表: ``` <ul> <?php for($i=0; $i<10; $i++) { echo '<li>' . $i . '</li>'; } ?> </ul> ``` * 在 php 裡不用先替變數宣告,但是要在每個變數的前面加上「$」字號。 * 在 php 裡的 + 號是用「.」來代替。 * for-loop 其它部分和 Javascript 一樣。 <br> GET: ``` <?php $username =''; if (isset($_GET['username'])) { $username = $_GET['username']; } echo 'username' . $username . '<br>'; if ($username === 'admin') { echo 'hello admin!'; } else { echo 'fail'; } ?> ``` * `_GET` 是 PHP 內建的變數,就是串接 API 取得資料的那個 `GET` 。 * `_GET['username']` 意思是要從資料裡面拿取所有有關 `username` 物件的資料。 * `isset()` 用來判定變數是否有被設置。在這個例子是在判定有沒有拿到 GET 回來的資料。 <br> POST: ``` <?php $username =''; if (isset($_POST['username']) && isset($_POST['password'])) { $username = $_POST['username']; $password = $_POST['password']; if ($username === 'admin' && $password === 'admin') { echo '登入成功'; } } ?> <form action='/RZ/index.php' method='POST'> username: <input name='username' /> password: <input name='password' /> <input type='submit' /> </form> ``` * 程式碼下方設定一個 form 表單,使用的方法是 POST,表單內資料的值填好按送出後,會傳送到 `'/RZ/index.php'` 的頁面。 * `<input name='username' />` 裡面的 `name` 屬性為 POST 上去後的 object,因此若要取得這個 input 的值,必須使用 object 提取方式,如 `$_POST['username']` 的方式。 * 程式碼上方則是判定值(username 和 password)有沒有被設置(存在),也就是表單的值的資料有沒有被 POST 上去,若有被設置的話,就會把表單 POST 的值賦予給 `$username` 和 `$password` 兩個變數。 <br> 可以在 php 程式碼中間斷開,並且在中間放上 html 的標籤: ``` <?php $username =''; if (isset($_POST['username']) && isset($_POST['password'])) { $username = $_POST['username']; $password = $_POST['password']; if ($username === 'admin' && $password === 'admin') { ?> <h1>登入成功</h1> <?php } else { ?> <h1>登入失敗</h1> <?php } } ?> ``` 上面 POST 表單的例子,可以說是前端與後端的結合,它的順序是這樣: index.php => 表單 => POST login.php => 顯示資料 我們把上方的程式碼拆開來分成 `index.php` 和 `login.php` 兩個檔案。 `index.php` 檔案裡面放 html 表單的結構: ``` <form action='/RZ/login.php' method='POST'> username: <input name='username' /> password: <input name='password' /> <input type='submit' /> </form> ``` 在 `index.php` 檔案裡,我們把表單的傳送位置設定到 `login.php` 的位址。 <br> `login.php` 檔案裡面放入 php 的程式碼作為登入是否成功的判定: ``` <?php $username =''; if (isset($_POST['username']) && isset($_POST['password'])) { $username = $_POST['username']; $password = $_POST['password']; if ($username === 'admin' && $password === 'admin') { ?> <h1>登入成功</h1> <?php } else { header('Location: index.php'); } } ?> ``` 在程式碼當中, `header('Location: index.php');` 這一行指的是,當登入沒有成功的時候,會把頁面轉址回去到 `index.php`,也就是登入畫面。 --- # 資料庫 ### 為什麼需要資料庫? 雖然我們可以自己寫程式碼來管理檔案的新增、修改、上傳、刪除,但是資料庫已經有現成的 CRUD 的語法可以使用,且較方便管理。 ### 關聯式資料庫、非關聯式資料庫(NoSQL) 常用的關聯式資料庫系統:MySQL、PostgreSQL 常用的非關聯式資料庫系統:NoSQL NoSQL 指的是資料結構沒有一定,資料的型態不一定要是字串或是數字,也可以是 object、array 等,然後新增新的資料類別也比較方便與彈性。 操控資料庫的語法叫做 SQL(Structural Query Language),每個資料庫系統都有定義的 SQL 語法,大致上每個系統的語法都差不多,只是有些不通用。 以下 CRUD 語法的粗體字都是 SQL 的關鍵字(keywords),不可取代與竄改。 #### 查詢 **select** phone **from** users **where** name=peter 整個句子的意思是:「從 users 裡面找到 name 是 peter 的那列(row),並且把 phone 這個欄位(column)的值取出來。」 **select** * **from** users 意思是:「從 users 裡面找到所有列,並且把**所有欄位**的值取出來。」 #### 刪除 **delete from** users **where** name=peter 意思是:「刪除 users 裡面,name 是 peter 的那列。」 #### 更新 **update** users **set** phone=123 **where** name=peter 意思是:「更新 users 裡面,name 是 peter 的那列,把 phone 設為 123。」 #### 新增 **insert into** users(name, phone) **values** (peter, 1234) 意思是:「新增一筆記錄。name 是 peter;phone 是 1234。」 #### or 和 and **select** phone **from** users **where** name=peter or name=mandy 意思是:「name 是 peter 的那列或者是 name 是 mandy 的那列都會被選到。」 ### phpMyAdmin 一個資料庫的圖形介面,方便管理資料庫的資料,並且有現成的指令,下指令也方便。 在 phpMyAdmin 裡面建立新資料庫時,注意編碼與排序請選擇「utf8_unicode_ci」。 --- # 用 PHP 來操作 MySQL ``` <?php $servername = "localhost"; $username = "root"; $password = "root"; $dbname = "mentor"; $conn = new mysqli($servername, $username, $password, $dbname); if ($conn->connect_error) { die("Connection failed: " . $conn->connect_error); } $sql = "SELECT * from users"; $result = $conn->query($sql); if ($result->num_rows > 0) { while($row = $result->fetch_assoc()) { echo "id:" . $row["id"] . ', username:' . $row['username'] . '<br>'; } } else { echo "0 results"; } ?> ``` * $servername = "localhost"; $username = "123"; $password = "123"; $dbname = "mentor"; 這四行是用來作為 MySQL 登入的需求的變數值。 `$servernmae` 就是 MySQL 的伺服器名稱;`$username` 是 MySQL 使用的帳號;`$password` 是 MySQL 使用的密碼;`$dbname` 則是資料庫名稱。 * `$conn = new mysqli($servername, $username, $password, $dbname);` 使用 php 的 `mysqli` 方法把登入的資訊(變數)放到 `$conn` 物件裡。 * if ($conn->connect_error) { die("Connection failed: " . $conn->connect_error); } 用來判定如果連線失敗,會使用 `die` 這個方法取消 php 傳遞,並且把失敗的訊息給印出來。 * `$sql = "SELECT * from users";` 建立一個 MySQL 操作資料的字串,放到 `$sql` 變數中。 * `$result = $conn->query($sql);` 針對 `$conn` ,也就是伺服器裡的 `$dbname` 這個資料庫做 `$sql` 這個操作資料的方式的請求,並且把操作後的內容放到 `$result` 這個變數。 * `if ($result->num_rows > 0)` , `num_rows` 是 `$result` 的資料的筆數,也就是說此行在判定是否至少有一筆資料。 * `$row = $result->fetch_assoc())` ,對 `$result` 使用 `fetch_assoc()` 方法,這個方法功用是把 `$result`的每一筆資料一一照順序取出來。然後傳到 `$row` 變數裡 ,然後下面的 `echo` 就會印出每一個 `$row` 的資料內容。 新增列數: ``` $sql = "INSERT INTO users (username) VALUE ('huli')"; if ($conn->query($sql)) { echo "New record created suceessfully"; } else { echo "Error:" . $sql . "<br>" . $conn->error; } ``` * `$sql = "INSERT INTO users (username) VALUE ('huli')";` 是 MySQL 的新增資料語法。 * `if ($conn->query($sql)) `,把 `$sql` 新增的資料請求到 `$conn`,假如有請求成功則為 `true`。 * `else {echo "Error:" . $sql . "<br>" . $conn->error;}` 判定當新增的資料沒有成功時,發生錯誤的時候就把 `$conn` 的錯誤訊息(error) echo 出來。 ## Require、Require_once 因為 MySQL 登入資訊幾乎會很常用到,因此我們可以把這些資訊放到另一個 php 檔案。 ``` $servername = "localhost"; $username = "root"; $password = "root"; $dbname = "mentor"; ``` 然後在要引用登入資訊的 php 檔案中輸入 ` require('登入資訊的 php 檔名')`,這個語法的意思有點像是 node.js 模組的請求,差別只在說這個 require 的意思像是「從那邊複製資料貼上到這個 php 檔名」的感覺。 不過實務上通常會採用 `require_once('檔名)` 的寫法,這個寫法意思就是裡面的檔案內容只會在 require 的檔案中被引用一次而已,這樣可以避免重複的內容被貼上來。 以下為範例: ``` <?php require_once('conn.php'); if ($conn->connect_error) { die("Connection failed: " . $conn->connect_error); } $sql = "SELECT * from users"; $result = $conn->query($sql); if ($result->num_rows > 0) { while($row = $result->fetch_assoc()) { echo "id:" . $row["id"] . ', username:' . $row['username'] . '<br>'; } } else { echo "0 results"; } ``` `conn.php `的檔案內容則是: ``` <?php $servername = "localhost"; $username = "root"; $password = "root"; $dbname = "mentor"; $conn = new mysqli($servername, $username, $password, $dbname); ?> ``` --- # 簡單實作登入與註冊 登入與註冊功能的檔案分成四個:index.php、login.php、register.php、conn.php `conn.php` 裡面放登入 MySQL 資料庫的資料: ``` <?php $servername = "localhost"; $username = "root"; $password = "root"; $dbname = "mentor"; $conn = new mysqli($servername, $username, $password, $dbname); ?> ``` `index.php` 則是放登入與註冊的表格的 index 結構: ``` <h1>登入</h1> <form action='/RZ/login.php' method='POST'> username: <input name='username' /> password: <input name='password' type="password" /> <input type='submit' /> </form> <h1>註冊</h1> <form action='/RZ/register.php' method='POST'> username: <input name='username' /> password: <input name='password' type="password"/> <input type='submit' /> </form> ``` `login.php` 是放登入功能的檔案: ``` <?php require_once('conn.php'); $username = $_POST['username']; $password = $_POST['password']; $sql = "SELECT * from users where username='" . $username . "' and password='" . $password ."'"; $result = $conn->query($sql); if ($result->num_rows > 0) { echo '登入成功'; } else { header('Location: index.php'); } ?> ``` `register.php` 是放註冊功能的檔案: ``` <!-- 重複帳號的部分還沒解決 --> <?php require_once('conn.php'); $username = $_POST['username']; $password = $_POST['password']; $sqlSelect = "SELECT * FROM users where username='" . $username . "'" ; if ($username && $password ) { $sqlInsert = "INSERT INTO users(username,password) VALUES('$username','$password')"; $result = $conn->query($sqlInsert); if ($result) { echo 'Register success'; } else { echo 'Register failed'; } } else { echo '請輸入正確的格式' ; ?> <br> <a href="index.php">Back to register</a> <?php } ?> ``` --- # SQL 的一些語法 ### 正常化 Normalization 把資料庫中的表格分成很多表格,這樣在修改的時候才會比較好修改,而每個表格之間需要建立彼此的關聯,因此採用這這種方式的資料顧叫做「關聯式資料庫」。 ### index 幫欄位增加索引,方便資料庫搜尋欄位。可以同時把兩個欄位設定相同的索引。 ### Primary index 在 phpMyAdmin 叫做「主鍵」,被設定為主鍵的欄位是表格當中最重要的欄位,一個表格只會有一個主鍵的欄位。 ## 內建函式 ### COUNT 數選定欄位的個數。 `SELECT COUNT(id) FROM users` ### SUM 針對選定的欄位,把每個 row 的數值做加總。 `SELECT SUM(id) FROM users` ### AVG 針對選定的欄位,把每個 row 的數值加總後做平均計算。 `SELECT AVG(id) FROM users` ### CONCAT 可以顯示兩個欄位合併的結果。 `SELECT CONCAT(id,username) FROM user` ## 非函式的查詢 ### between 用在數字的查詢,以一個範圍搜尋。 `SELECT * FROM `users` WHERE `id ` BETWEEN 0 AND 10;` 就會顯示 id 欄位是在 0~10 的所有列。 ### in 列出和 in 裡面所有相符的值的結果的列。 `SELECT * FROM `users` WHERE id in(1,57)` 就會顯示在 id 欄位中有 1 或是 57 的列。 ### NOT in 列出和 in 裡面所有不相符的值的結果的列。 `SELECT * FROM `users` where id NOT in(2)` 就會顯示在 id 欄位中不包括有 2 的列。 ### like 用在字串的查詢。 `SELECT * FROM `users` where username like '%a%'` 會顯示在 username 的欄位中有「a」字元的列。 `SELECT * FROM `users` where username like 'a%'` 會顯示在 username 的欄位中以「a」字元為開頭的列。 ## Join 把兩個表格做連結,交集、聯集那些。 ### Inner Join 交集 列出所選的兩個表格的欄位有相同資料的列。 `SELECT comments.id,comments.content, users.nickname FROM comments JOIN users ON comments.user_id = users.id` 針對 comments 和 users 的表格,以 comments 表格的 user_id 欄位等於 users 表格的 id 欄位為主,列出兩個表格所選的對應欄位(comments 的 id, comments 的 content, users 的 nickname)。 可以這麼寫,只是不容易看出是使用 Inner Join: `SELECT comments.id,comments.content, users.nickname FROM comments, users WHERE comments.user_id = users.id` ### LEFT (outer) Join 保留左邊的表格的所有資料。 `SELECT comments.id,comments.content, users.nickname FROM comments LEFT JOIN users ON comments.user_id = users.id` ### RIGHT (outer) Join 保留右邊的表格的所有資料。 `SELECT comments.id,comments.content, users.nickname FROM comments RIGHT JOIN users ON comments.user_id = users.id` ## Sort 排序 ### 升冪排列 `SELECT * FROM users ORDER BY id ASC` ### 降冪排列 `SELECT * FROM users ORDER BY id DESC` ## 分頁 回傳前 30 筆資料 `SELECT * FROM users LIMIT 30` 回傳 61~90 筆資料 `SELECT * FROM users LIMIT 30 OFFSET 60` 意思是跳過 60 筆資料,從第 61 筆開始回傳 30 筆的資料。 `SELECT * FROM users LIMIT 60, 30` ## 改名 把 users 表格裡面,欄位 created_at 改名為 time;nickname 改名為 name `SELECT created_at as time, nickname as name FROM users` 也可以用在 JOIN 的改名 `SELECT c.id, c.content, u.nickname as name FROM comments as c, users as u WHERE c.user_id = u.id` ## VIEW 建立一張虛擬的 Table 表格,可以檢視各種 Table Join 後的表格,並把它存在資料庫當中儲存。通常用作需要經常使用這個表格來審閱,或者是你只想開放特定的資料給資料庫觀看權限的人看。 `CREATE VIEW view表格的名稱 AS SQL語法` 如果是使用 Myadmin 的資料庫介面,在 table 的部份會多出一項「檢視表」的分類,而這個檢視表可以做進一步的排列表格的選取動作,但是不能更改 table 的結構、刪除、更新等等動作。 再加上這些檢視表有個缺點,如果下一個人來接手的話,可能會不曉得這個檢視表合併了哪些 table 組合而成的,因此必須加以審慎做註解或是 table 的管理。 ## Stored Procedure 像是 SQL 的 function,和內建 function 不同的地方在於它可以取代整個 sql 的語法。 假如 `SELECT * FROM order where user_id = ?` 這個語法很常使用到,我們除了可以在 php 檔案裡寫 function 外,還可以使用 Stored Procedure: ``` DELIMITER // CREATE PROCEDURE GetOrders(id INT) BEGIN SELECT * FROM orders WHERE user_id = id; END // DELIMITER ; ``` * `DELIMITER` 意思是把分段符號改成 //(預設是 ;),因為 sql query 那段有個分號的關係會導致原本的預設會讓最後的 END 被分行,有點像是我們的字串是用雙引號包住的話,如果中間要再加上其他字串的引號那就要使用單引號的概念。記得最後要再改回「;」的預設。 * 大寫字串都是定義好的預設字。 * `GetOrders(id INT)`,`GetOrders` 是這個 Stored Procedure 之後若被呼叫所使用的名稱。INT 則是 id 的變數型態。 呼叫這個 Stored Procedure 則是使用:`CALL GetOrders(1)` 然而 Stored Procedure 和 VIEW 一樣會被存放在資料庫當中,如果是使用 Myadmin 的資料庫介面,先點選 database 的名稱,會有個「預存程序」,點下去就會看到所有的 Stored Procedure 都被放在那邊。 它的缺點就是如果要更改或是 debug 會很不方便,因為同時要看程式碼又要看資料庫裡面的 Stored Procedure,等於兩邊跑。因此建議 Stored Procedure 和 VIEW 都不要亂用,除非團隊有人在管理後端的資料庫。 ## Triggers 事件前/後要做的事,方便記錄一些 log,知道更改前後的差別,或是不小心改到參數忘記原本的參數時,還可以有個 log 去觀看。 ``` DELIMITER // CREATE TRIGGER trigger名稱 BEFORE(AFTER) UPDATE ON products FOR EACH ROW BEGIN INSERT INTO products_audit(product_id, name, price, action) VALUES(OLD.id, OLD.name, OLD.price, 'UPDATE'); END // DELIMITER ; ``` * `BEFORE UPDATE ON products` 這行指的是,在 `products` 這個 table update 以前,要做什麼動作;另外還有 AFTER,意思和 BEFORE 相反,在執行後要做什麼動作。 * `FOR EACH ROW` 指的是,針對 `products` 這個 table 的所有 row 進行下列動作。 * `BEGIN` 和 `END` 中間要放的就是事件前/後要做的事。其中 OLD 指的是事件變更資料以前的資料,我要拿這個舊資料放到現在要做的動作上;另外還有 NEW,意思和 OLD 相反,要拿事件變更資料後的資料。 ## 疑難雜症區 ### 顯示的中文變成 ???,可以加入這行: `mysqli_set_charset($conn, "utf8")` 或是: ` $conn->query('SET NAMES UTF8');` ### 用「.」的字串拼接太麻煩,可以這麼做: `$sql = "select from users where name='$name'"` 或者是使用 sprintf ### 時區有問題可以加入: `$conn->query("SET time_zone = '+08:00'");`

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully