# 【上課】Jquery,Medoo,PHP
> 已完成的內容:[連結點我](https://meng.finf.idv.tw/teach/class110/)
## 建立上課首頁
### 建立bootstrap5與navbar
在官網上看到的navbar樣式
![image](https://hackmd.io/_uploads/BJTEZ5mMA.png)
比較常看到的navbar樣式,按鈕們會靠右手邊,如圖所示:
![image](https://hackmd.io/_uploads/HJM3-9XMA.png)
基本上就是加上 <b>justify-content-end</b>就好
`<div class="collapse navbar-collapse justify-content-end" id="navbarNav">`
可參考下方的程式:
```html=
<!DOCTYPE html>
<html lang="zh-tw">
<head>
<title>class110上課練習</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<link href="./assets/css/global.css" rel="stylesheet">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light p-2 shadow">
<div class="container-fluid">
<a class="navbar-brand" href="./"><b>Learn</b></a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse justify-content-end" id="navbarNav">
<ul class="navbar-nav">
<!--教學文件可以不需要增加-->
<li class="nav-item">
<a class="nav-link" href="#">教學文件</a>
</li>
</ul>
</div>
</div>
</nav>
</body>
</html>
```
### 加入google fonts
[google fonts 連結](https://fonts.google.com/noto/specimen/Noto+Sans+TC)
1. 在google fonts找Noto Sans Traditional Chinese(如下圖),並點選get font
![image](https://hackmd.io/_uploads/HyQ_K5mfC.png)
2. 選擇Get embed code
![image](https://hackmd.io/_uploads/BySTtqmM0.png)
3. 加入樣式
- html header
```html=
<head>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+TC:wght@100..900&display=swap" rel="stylesheet">
</head>
```
- CSS
```css=
/*custom css*/
body{
font-family: "Noto Sans TC", sans-serif;
font-optical-sizing: auto;
font-style: normal;
}
```
目前font-weight呈現,結果如下圖:
![image](https://hackmd.io/_uploads/Byw166aGR.png)
4. 加入文字的font-weight
當需要不同文字樣式的時候,只要加入對應的class即可。
```css=
.font-w200{
font-weight: 200;
}
.font-w300{
font-weight: 300;
}
.font-w400{
font-weight: 400;
}
.font-w500{
font-weight: 500;
}
```
### 其他樣式
#### banner
```html=
<div class="container-fluid p-5 mb-5 bg-light text-dark text-center font-w300">
<h1 class="mt-3">準備好進入學習的世界了嗎</h1>
<p class="mb-3">再下方選擇你要進入的頁面</p>
</div>
```
#### 按鈕選項
在header上要加入 bootstra-icons [官網連結](https://icons.getbootstrap.com/)
` <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons/font/bootstrap-icons.css" rel="stylesheet">`
```html=
<div class="container text-center mt-5">
<div class="row">
<div class="col">
<button class="btn stats-button blue">
<i class="bi bi-code-slash"></i>
<div class="pt-2" style="font-size: 1rem;"><b>First</b></div>
<div>JS練習</div>
</button>
</div>
<div class="col">
<button class="btn stats-button red">
<i class="bi bi-journal-plus"></i>
<div class="pt-2" style="font-size: 1rem;"><b>Second</b></div>
<div>新增練習</div>
</button>
</div>
<div class="col">
<button class="btn stats-button blue">
<i class="bi bi-person-plus"></i>
<div class="pt-2" style="font-size: 1rem;"><b>Third</b></div>
<div>註冊練習</div>
</button>
</div>
<div class="col">
<button class="btn stats-button red">
<i class="bi bi bi-door-open"></i>
<div class="pt-2" style="font-size: 1rem;"><b>Fourth</b></div>
<div>登入練習</div>
</button>
</div>
</div>
</div>
```
```css=
/*index button css*/
.stats-button {
width: 200px;
height: 200px;
border: none;
color: white;
font-size: 20px;
margin: 10px;
padding: 20px;
box-shadow: 0 10px 10px rgba(0, 0, 0, 0.15);
}
.blue { background-color: #395e85; }
.red { background-color: rgba(158, 83, 83)}
.blue:hover { background-color: #395e857c; }
.red:hover { background-color: rgba(158, 83, 83, 0.53)}
.stats-button i {
font-size: 30px;
margin-bottom: 10px;
}
```
## JS練習
### 版面樣式
#### banner樣式
```html=
<div class="container-fluid mt-3 mb-5 text-dark font-w300">
<h2> <b>-</b> JS練習</h2>
</div>
```
#### bs5 card
[官網連結](https://www.w3schools.com/bootstrap5/bootstrap_cards.php)
```html=
<div class="container">
<div class="row">
<div class="col-6">
<div class="card shadow">
<div class="card-body">
<h4 class="card-title">1.程式執行</h4>
<p class="card-text">若無法理解可以把console.log,改為alert去查看</p>
</div>
</div>
</div>
<div class="col-6">
<div class="card shadow">
<div class="card-body">
<h4 class="card-title">2.區域和全域變數</h4>
<p class="card-text">若無法理解可以把console.log,改為alert去查看</p>
</div>
</div>
</div>
</div>
</div>
```
### 程式執行順序
1. 程式起始點
若不知道程式,從哪裡開始跑,可以先找起始點,下方這兩段是相等的。
```JS=
$(document).ready(function(){
});
``````
<b style="color:red">相等</b>
```JS=
$(function(){
});
```
2. 加入一些function查看
```JS=
function runA(){
console.log('已經跑到A段');
}
function runB(){
console.log('已經跑到B段');
}
function runC(){
console.log('已經跑到C段');
}
$(function(){
console.log('開始執行');
runA();
runB();
runC();
});
```
3. 練習 - 我希望加上function run D(),執行順序為runA -> runB -> runD -> runC。<b style='color:blue'>但我的runD並不能放在我一開始程式起始點</b>
### 全域&區域變數
1. <b>全域變數:</b>在scirpt最上方加上變數,並查看執行順序
```JS=
<script>
var t1='t1';
function runA(){
console.log('已經跑到A段');
console.log(t1);
}
function runB(){
console.log('已經跑到B段');
}
function runC(){
console.log('已經跑到C段');
console.log(t1);
}
$(function(){
console.log('開始執行');
runA();
runB();
runC();
});
</script>
```
2. <b>區域變數:</b>在runB內加上變數,並查看執行順序
```JS=
<script>
var t1='t1';
function runA(){
console.log('已經跑到A段');
console.log(t1);
}
function runB(){
var t2='t2';
console.log('已經跑到B段');
}
function runC(){
console.log('已經跑到C段');
console.log(t1);
console.log(t2);
}
$(function(){
console.log('開始執行');
runA();
runB();
runC();
});
</script>
```
3. 練習-我要怎麼樣才可以把runB的區域變數,傳到runD裡面?
### Jquery button click
1.樣式上先加上兩個button
```JS=
<div class="container mt-4">
<div class="row">
<div class="col-6">
<div class="card shadow">
<div class="card-body">
<h4 class="card-title">3.Jquery - click</h4>
<button class="btn btn-dark">方法1</button>
<button class="btn btn-outline-dark">方法2</button>
</div>
</div>
</div>
</div>
</div>
```
2.<b>方法1</b>直接加上onclick="<functionName>",就可以直接執行function內容。
```JS=
<script>
function button1(){
alert("hi~我是button1");
}
</script>
<button class="btn btn-dark" onclick="button1()">方法1</button>
```
3. <b>方法2</b>需要加上id,並且在程式執行點上進行呼叫,才可以執行。
```J
<script>
function button2(){
alert("hi~我是button2");
}
$(function(){
$("#btn2").click(function(){
button2();
});
});
</script>
<button class="btn btn-outline-dark" id="btn2">方法2</button>
```
4. 練習1-請用方法1的方式,hwBtn1()做加法運算。
練習2-請用方法2的方式,hwBtn2()做減法運算。
可用alert的方式呈現計算結果。
提示如下:
```JS=
function hwBtn1(){
var A=50;
var B=2
}
function hwBtn2(){
var A=100;
var B=20;
}
```
### Jquery change
1. 加上input樣式
```JS=
<div class="col-md-6">
<div class="card shadow">
<div class="card-body">
<h4 class="card-title">4.Jquery - change</h4>
<input class="form-control mb-2" type="text" id="inputTxt" />
<b>內容:</b><span class="font-w300 text-danger" id="showTxt"></span>
</div>
</div>
</div>
```
2. change的Jquery
```JS=
<script>
$("#inputTxt").change(function(){
var inputTxt=$("#inputTxt").val();
$("#showTxt").html(inputTxt);
});
</script>
```
### sessionStorage v.s. localStorage
- sessionStorage 在每次分頁或瀏覽器關掉後就會清除
- localStorage 需要手動清除
#### html 內容
```html=
<div class="container mt-4">
<div class="row">
<div class="col-md-6">
<div class="card shadow">
<div class="card-body">
<h4 class="card-title">5.sessionStorage</h4>
<input class="form-control mb-2" type="text" id="sessionTxt" />
<p id="sessionShow"></p>
<button class="btn btn-primary" onclick="clearSession()">清除</button>
<button class="btn btn-info" onclick="clearAllSession()">全部清除</button>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card shadow">
<div class="card-body">
<h4 class="card-title">6.localStorage</h4>
<input class="form-control mb-2" type="text" id="localTxt" />
<p id="localShow"></p>
<button class="btn btn-primary" onclick="clearLocal()">清除</button>
</div>
</div>
</div>
</div>
</div>
```
#### 紀錄storage內容
```JS=
<script>
$("#sessionTxt").change(function(){
var sessionTxt=$("#sessionTxt").val();
sessionStorage.setItem('session', sessionTxt);
});
$("#localTxt").change(function(){
var localTxt=$("#localTxt").val();
localStorage.setItem('local', localTxt);
});
</script>
```
#### 取得storage內容
```JS=
<script>
$("#sessionTxt").change(function(){
var sessionTxt=$("#sessionTxt").val();
sessionStorage.setItem('session', sessionTxt);
});
$("#localTxt").change(function(){
var localTxt=$("#localTxt").val();
localStorage.setItem('local', localTxt);
});
</script>
```
#### 清除storage內容
```JS=
function clearSession(){
sessionStorage.removeItem("session");
$("#sessionTxt").val("");
}
function clearAllSession(){
sessionStorage.clear();
}
function clearLocal(){
localStorage.removeItem("local");
$("#localTxt").val("");
}
</script>
```
<b>練習</b>:
複製下方的內容至網頁上,按下儲存按鈕後,session的內容會在‵id="showHW"呈現。
需要再多一個清除的button,幫我把功課所記錄的session做清除。
```HTML=
<div class="container mt-4 mb-5">
<div class="row">
<div class="col-md-6">
<div class="card shadow">
<div class="card-body">
<h4 class="card-title">7.sessionStorage HW</h4>
<input class="form-control mb-2" type="text" id="txtHw" />
<button class="btn btn-outline-primary">儲存</button>
<p>內容<span id="showHw"></span></p>
</div>
</div>
</div>
</div>
</div>
```
> 題外練習:HTML DOM Element insertAdjacentHTML()
insertAdjacentHtml() 有幾個不同的模式。
| value | description | |
|--------------|------------------------------------------------------|---------------------------------------|
| afterbegin | After the beginning of the element (first child) | 在元素的開頭之後(第一個子元素之前) |
| afterend | After the element | 在元素之後 |
| beforebegin | Before the element | 在元素之前 |
| beforeend | Before the end of the element (last child) | 在元素的結尾之前(最後一個子元素之後) |
1.以Card為主體,並加上對應的mode,呈現的上下內容是不同的,用JS寫上的insertAdjacentHTML(黃色的)。
2. 若直接在editor寫上HTML(紫藍色),黃色對應紫色呈現狀態,如下圖所示。
圖片如下:
![image](https://hackmd.io/_uploads/rJ3rFzvmC.png)
[參考網址](https://meng.finf.idv.tw/teach/class110/praAdjacent.html)
* 建立/assets/js/navbar.js,程式如下:
```JS=
document.addEventListener("DOMContentLoaded", function () {
const navbar = `
<nav class="navbar navbar-expand-lg navbar-light bg-light p-2 shadow-lg font-w400">
<div class="container-fluid">
<a class="navbar-brand" href="./"><b>Learn</b></a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse justify-content-end" id="navbarNav">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" target="_blank" href="https://hackmd.io/@DV4sdErwTzmcRsdJP9ojiw/HkI5iFmzR">教學文件</a>
</li>
<li class="nav-item">
<a class="nav-link" target="_blank" href="./openssl.php">PHP加密</a>
</li>
</ul>
</div>
</div>
</nav>`;
document.body.insertAdjacentHTML('afterbegin', navbar);
});
```
* 把原本的程式註解掉,並加上script即可。
## 註冊練習
### 資料庫
1. 資料庫型態,可參考該內容 [連結](https://chwang12341.medium.com/mysql-%E5%AD%B8%E7%BF%92%E7%AD%86%E8%A8%98-%E5%9B%9B-mysql%E4%B8%AD%E7%9A%84%E8%B3%87%E6%96%99%E9%A1%9E%E5%9E%8B-data-type-%E5%A6%82%E4%BD%95%E5%89%B5%E5%BB%BAtables%E8%B3%87%E6%96%99%E8%A1%A8-%E5%A6%82%E4%BD%95%E6%93%8D%E4%BD%9C%E8%B3%87%E6%96%99%E8%A1%A8-%E5%BF%AB%E9%80%9F%E7%82%BA%E8%87%AA%E5%B7%B1%E5%89%B5%E5%BB%BA%E4%B8%80%E5%80%8B%E8%B3%87%E6%96%99%E8%A1%A8-927e0c365d6e)
2. 建立資料庫在dbadmin,使用Mysql,關於註冊會建立為下方的架構
![image](https://hackmd.io/_uploads/rJJtyVCf0.png)
3.查看count sql語法
```sql=
SELECT count(id) as CNT
FROM `student_member`
WHERE `userMail` = 'test01@gmail.com'
```
對應呈現內容如下:
![image](https://hackmd.io/_uploads/HJ6C4H0fC.png)
> 關於文字上的條件搜尋:
> <b style='color:red'>=</b> 欄位內容需要一模一樣
> <b style='color:red'>LIKE</b> 只要有符合文字內容即可
>
> 關於數字上的條件搜尋:
> <b style='color:red'><</b> 欄位內容大於搜尋內容
> <b style='color:red'><=</b> 欄位內容大於等於搜尋內容
> <b style='color:red'>></b> 欄位內容小於搜尋內容
> <b style='color:red'>>=</b> 欄位內容小於等於搜尋內容
文字+數字:
> <b style='color:red'>!=</b> 欄位內容不等於搜尋內容
4. 新增sql語法
<b>(!)新增的內容,每一個欄位都需要填寫,若沒有填寫內容可寫"NULL"</b>
```sql=
INSERT INTO `student_member`
(`id`, `userName`, `userMail`, `userPwd`, `createTime`)
VALUES
(NULL, 'test01', 'test01@gmail.com', 'password0001', '2024-05-12 20:01:15');
```
對應呈現內容如下:
![image](https://hackmd.io/_uploads/HkSbWV0GA.png)
### 註冊畫面
在註冊畫面上,我並不會使用bs5,會直接利用CSS去做RWD。
* 建立CSS檔案 ./assets/custom-regLogin.css
背景色gradient [顏色參考網址](https://cssgradient.io/)
```css=
.background {
background-image: linear-gradient(to right, #6a11cb, #2575fc);
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.regLogin-form {
background: white;
padding: 20px;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
width: 450px;
}
input[type="text"], input[type="email"], input[type="password"] {
width: 100%;
padding: 10px;
margin: 10px 0;
border: 1px solid #ccc;
border-radius: 5px;
}
.action-links {
display: flex;
}
.submit-button {
width: 100%;
padding: 10px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}
.submit-button:hover {
background-color: #45a049;
}
.back-button {
width: 25%;
padding: 10px;
background-color: #f44336;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}
.back-button:hover {
background-color: #d32f2f;
}
.next-link {
display: block;
text-align: center;
margin-top: 20px;
color: #2575fc;
}
```
* 建立HTML
```html=
<script>
<link href="./assets/css/custom-regLogin.css" rel="stylesheet">
</script>
<body class="background">
<div>
<div class="regLogin-form">
<h2><b>使用者註冊</b></h2>
<input type="text" placeholder="Username" id="userName">
<input type="email" placeholder="Email" id="userMail">
<input type="password" placeholder="Password" id="userPwd1" >
<input type="password" placeholder="Confirm Password" id="userPwd2" >
<div class="action-links">
<button type="button" class="back-button" onclick="">返回</button> 
<button type="bitton" class="submit-button" id="submitBtn">註冊</button>
</div>
<a href="./login.html" class="next-link">您已經有註冊會員了?</a>
</div>
</div>
</body>
```
### 註冊程式
* Swal官網 [官網連結](https://sweetalert.js.org/)
* 加上Swal(取代alert)
```html=
<head>
<script src="https://unpkg.com/sweetalert/dist/sweetalert.min.js"></script>
</head>
```
* JS程式
```jS=
<script>
function register(){
const userName=$("#userName").val();
const userMail=$("#userMail").val();
const userPwd1=$("#userPwd1").val();
const userPwd2=$("#userPwd2").val();
let err=0;
let errTxtA="",errTxtB="";
if(userPwd1!=userPwd2){
err++;
errTxtA+="兩次的密碼輸入不同";
}
if(!userName || !userMail || !userPwd1 || !userPwd2){
err++;
if(errTxtA!=""){
errTxtB="、";
}
errTxtB+="您輸入的內容有空值";
}
if(err>0){
swal(errTxtA+""+errTxtB);
}else{
$.ajax({
type: "post",
data:{userName:userName,userMail:userMail,userPwd1:userPwd1},
url: "./prg/register.php",
success: function(result, status) {
var obj = JSON.parse(result);
if(obj[0]==true){
swal(obj[1]);
location.href = './login.html';
}else{
swal(obj[1]);
}
},
error: function() {
alert('Internal Server Error');
}
});
}
}
$(document).ready(function() {
$("#submitBtn").on( "click", function() {
register();
});
});
</script>
```
* PHP程式碼
```PHP=
<?php
header("Access-Control-Allow-Origin: *");
require './connectdb.php';
$userName=trim($_POST["userName"]);
$userMail=trim($_POST["userMail"]);
$userPwd=trim($_POST["userPwd1"]);
$mdata=array();
$today=date("Y-m-d H:i:s");
$count = $database->query("SELECT count(id) as CNT FROM `student_member` WHERE `userMail` = '$userMail'")->fetchAll();
//print_r($count);
if($count[0]['CNT']>0){
$data="電子信箱已註冊!";
array_push($mdata,false,$data);
echo json_encode($mdata);
}else{
//在php查看加密方式
$cipher = "aes-128-cfb";
if (in_array($cipher, openssl_get_cipher_methods()))
{
//key&iv可以自己訂
$key = "ABCDEFG@2024";
$iv = "ABCDEFG@2024";
$password = openssl_encrypt($userPwd, $cipher, $key, $options=0, $iv);
$database->query("INSERT INTO `student_member` (`id`, `userName`, `userMail`, `userPwd`, `createTime`) VALUES (NULL, '".$userName."', '".$userMail."', '".$password."', '".$today."');");
$finalId = $database->id();
if($finalId){
$data="新增成功!";
array_push($mdata,true,$data);
echo json_encode($mdata);
}else{
$data="新增有誤!";
array_push($mdata,false,$data);
echo json_encode($mdata);
}
}
}
?>
```
<b>[練習]</b>
1. 兩個密碼若不同,需要直接在畫面上呈現錯誤訊息,而不是按下按鈕才出現錯誤訊息(請用Jquery change)
2. 輸入完電子信箱,需要直接呈現是否可以註冊,可以註冊為綠色字樣,不能註冊請用紅色字樣。
## 登入練習
### 資料庫
* 使用資料庫:
1. 比對我們的user註冊的資料庫,比對密碼。
2. 紀錄使用者登入,並且給予一組亂數作為token。
* 建立使用者登入的資料表
![image](https://hackmd.io/_uploads/S1Tm3XDm0.png)
### 登入畫面
* 建立HTML
```html=
<body class="background">
<div>
<div class="regLogin-form">
<h2><b>使用者登入</b></h2>
<input type="email" placeholder="Email" id="userMail" >
<input type="password" placeholder="Password" id="userPwd">
<div class="action-links">
<button type="button" class="back-button" onclick="window.history.back();">返回</button> 
<button type="bitton" class="submit-button" id="submitBtn">登入</button>
</div>
<a href="./register.html" class="next-link">您並未有會員帳號?</a>
</div>
</div>
</body>
```
### 登入程式
* JS程式
```JS=
<script>
function login(){
const userMail=$("#userMail").val();
const userPwd=$("#userPwd").val();
if(userMail && userPwd){
$.ajax({
type: "post",
data:{userMail:userMail,userPwd:userPwd},
url: "./prg/login.php",
success: function(result, status) {
var obj = JSON.parse(result);
if(obj[0]==true){
sessionStorage.setItem('token',obj[2]);
sessionStorage.setItem('userName',obj[3]);
swal(obj[1]).then((value) => {
location.href = './adminLogin.html';
});
}else{
swal(obj[1]);
}
},
error: function() {
alert('Internal Server Error');
}
});
}
}
$(document).ready(function() {
$("#submitBtn").on( "click", function() {
login();
});
});
</script>
```
* PHP程式
```PHP=
<?php
header("Access-Control-Allow-Origin: *");
require './connectdb.php';
function generateRandomStr($length) {
$bytes = openssl_random_pseudo_bytes($length);
return bin2hex($bytes);
}
//從jquery傳過來的數值
$userMail=trim($_POST["userMail"]);
$userPwd=trim($_POST["userPwd"]);
$mdata=array();
$today=date("Y-m-d H:i:s");
$cipher = "aes-128-cfb";
//透過傳過來的數值(帳號),找到對應的密碼
$oldPwd = $database->query("SELECT `id`,`userName`,`userPwd` FROM `student_member` WHERE `userMail` = '$userMail'")->fetchAll();
$key = "ABCDEFG@2024";
$iv = "ABCDEFG@2024";
//將該密碼做解碼變成明碼
$chkPwd = openssl_decrypt($oldPwd[0]["userPwd"], $cipher, $key, $options=0, $iv);
if($chkPwd===$userPwd){//與輸入的密碼和明碼做對應
$token=generateRandomStr(30);//亂碼
$userId=$oldPwd[0]['id'];
$userName=$oldPwd[0]['userName'];
//查看是否有對應的登入紀錄
$oldInfo = $database->query("SELECT `id`,`userId`,`userName` FROM `student_login` WHERE `userId` = ".$userId." AND `userName` = '".$userName."' ")->fetchAll();
$err=0;
if(count($oldInfo)>0){
//有登入紀錄,就把登入紀錄的token&登入時間資料做更新
$oldId=$oldInfo[0]["id"];
$info=$database->query("UPDATE `student_login` SET `token`='".$token."',`loginTime`='".$today."' WHERE `id` = ".$oldId."");
//確認更新是否有成功
$updtInfo=$info->rowCount();
if(!$updtInfo){
$err++;
}
}else{
//無登入紀錄,就把新增登入紀錄
$database->query("INSERT INTO `student_login` (`id`, `userId`, `userName`, `token`, `loginTime`)
VALUES (NULL, '".$userId."', '".$userName."', '".$token."', '".$today."');");
//確認新增是否有成功
$finalId = $database->id();
if(!$finalId){
$err++;
}
}
if($err==0){
$data="登入成功!";
array_push($mdata,true,$data,$token,$userName);
echo json_encode($mdata);
}else{
$data="登入有誤!";
array_push($mdata,false,$data,$token,$userName);
echo json_encode($mdata);
}
}else{
$data="登入有誤!";
array_push($mdata,false,$data);
echo json_encode($mdata);
}
?>
```
資料庫更新sql語法:
![image](https://hackmd.io/_uploads/ByQ50Ev7R.png)
### 登入後頁面
* 頁面建立
```HTML=
<!DOCTYPE html>
<html lang="zh-tw">
<head>
<title>class110上課練習</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script src="https://unpkg.com/sweetalert/dist/sweetalert.min.js"></script>
</head>
<body >
<div class="container">
<div class="col-4 mt-4">
<div class="card shadow">
<div class="card-body">
<h4 class="card-title"><b>歡迎使用者登入</b></h4>
<p class="card-text">使用sessionStorage作為登入。</p>
<button type="button" class="btn btn-outline-dark px-4" onclick="window.history.back();">返回</button> 
</div>
</div>
</div>
</div>
</body>
</html>
```
* 程式說明:
1. 需要確認是否有sessionStorage "token",若沒有直接返回登入頁面。
2. 確認該token是否有在資料庫內。
* PHP程式
若有做註冊change(確認mail是否可以註冊)的功課,可以拿那一個程式來做修改。
```JS=
<?php
header("Access-Control-Allow-Origin: *");
require './connectdb.php';
$mdata=array();
$token=trim($_POST["token"]);
$count = $database->query("SELECT count(id) as CNT FROM `student_login` WHERE `token` = '$token'")->fetchAll();
if($count[0]['CNT']>0){
array_push($mdata,true);
echo json_encode($mdata);
}else{
array_push($mdata,false);
echo json_encode($mdata);
}
?>
```
* JS程式
```JS=
<script>
function chkLogin(){
var token=sessionStorage.getItem("token");
if(token!==null){
$.ajax({
type: "post",
data:{token:token},
url: "./prg/chkLogin.php",
success: function(result, status) {
var obj = JSON.parse(result);
if(obj[0]==false){
swal({title:"重新登入",icon:"error"}).then((value) => {
location.href = './login.html';
},"error");
}
},
error: function() {
alert('Internal Server Error');
}
});
}else{
swal({title:"重新登入",icon:"error"}).then((value) => {
location.href = './login.html';
},"error");
}
}
$(document).ready(function() {
chkLogin();
});
</script>
```
## 登出
在登入後的頁面加上Navbar,並呈現登出按鈕 & 使用者名稱
* HTML頁面
```html=
<nav class="navbar navbar-expand-sm bg-dark navbar-dark">
<div class="container-fluid">
<a class="navbar-brand" href="./adminLogin.html"><b>Learn</b>_後臺管理</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#collapsibleNavbar">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse justify-content-end" id="collapsibleNavbar">
<ul class="navbar-nav">
<li class="nav-item">
<span class="nav-link" id="loginName"></span>
</li>
<li class="nav-item">
<a class="nav-link" href="#" onclick="logOut()">登出</a>
</li>
</ul>
</div>
</div>
</nav>
```
* JS程式
```JS=
function logOut(){
var token=sessionStorage.getItem("token");
if(token!==null){
$.ajax({
type: "post",
data:{token:token},
url: "./prg/clearLogin.php",
success: function(result, status) {
var obj = JSON.parse(result);
if(obj[0]==true){
swal({title:"您已登出",icon:"info"}).then((value) => {
location.href = './login.html';
},"error");
//清理所有的sesionStorage
sessionStorage.clear();
}
},
error: function() {
alert('Internal Server Error');
}
});
}
}
$(document).ready(function() {
//呈現userName在navbar上
$("#loginName").html(sessionStorage.getItem("userName"));
});
```
* PHP程式
```PHP=
<?php
header("Access-Control-Allow-Origin: *");
require './connectdb.php';
$mdata=array();
$token=trim($_POST["token"]);
$info=$database->query("UPDATE `student_login` SET `token`='' WHERE `token` = '".$token."'");
//確認更新是否有成功
$updtInfo=$info->rowCount();
if(!$updtInfo){
$err++;
}
if($err==0){
array_push($mdata,true);
echo json_encode($mdata);
}else{
array_push($mdata,false);
echo json_encode($mdata);
}
?>
```