文章目录
- 前言
-
- [📚 PHP 基础知识点解析](#📚 PHP 基础知识点解析)
-
- 第1行:`<?php`
- 第2行:命名空间
- 第3-8行:引入类文件
- 第10行:定义类
- 第12行:定义属性
- 第13-21行:构造函数
- 第23-29行:显示登录页面
- 第31-54行:处理登录请求
-
- [1. `Request::post()` - 获取POST数据](#1.
Request::post()- 获取POST数据) - [2. `empty()` 和 `isset()` - 判断变量](#2.
empty()和isset()- 判断变量) - [3. `die()` - 终止脚本](#3.
die()- 终止脚本) - [4. 数据库链式查询](#4. 数据库链式查询)
- [5. `md5()` - 密码加密](#5.
md5()- 密码加密) - [6. `Cookie::set()` - 写入Cookie](#6.
Cookie::set()- 写入Cookie) - [7. `Cache::store('redis')` - Redis缓存](#7.
Cache::store('redis')- Redis缓存)
- [1. `Request::post()` - 获取POST数据](#1.
- [🎯 完整登录流程总结](#🎯 完整登录流程总结)
前言
结合常见的登录页,来入门PHP,掌握基础知识
📚 PHP 基础知识点解析
第1行:<?php
php
<?php
知识点:PHP开始标签
<?php是 PHP 代码的开始标记- 告诉服务器"从这里开始是 PHP 代码"
- PHP 代码必须写在
<?php和?>之间 - 文件最后一行可以省略
?>(推荐做法)
第2行:命名空间
php
namespace app\admin\controller;
知识点:什么是命名空间?
想象一个图书馆:
- 有很多书架(命名空间)
- 每个书架上有很多书(类)
- 为了找到特定的书,你需要知道它在哪个书架
app\admin\controller 就是这个类所在的"书架位置"
app\ → 应用目录
admin\ → admin模块
controller\ → 控制器目录
为什么需要? 防止不同地方有同名的类冲突。
第3-8行:引入类文件
php
use think\Controller;
use think\Db;
use think\facade\Request;
use think\facade\Cache;
use think\facade\Cookie;
use think\facade\Config;
知识点:use 关键字(导入类)
use 就像"借书":
use think\Controller= "我要借用 ThinkPHP 框架里的 Controller 类"- 之后在代码里就可以直接写
Controller,不用写完整路径
类比理解:
php
use think\Controller;
相当于:
require "框架路径/Controller.php";
6个引入的类:
| 类 | 作用 | 类比 |
|---|---|---|
think\Controller |
控制器基类 | 模板框架 |
think\Db |
数据库操作类 | 数据库工具箱 |
think\facade\Request |
请求处理 | 收件员(接收请求) |
think\facade\Cache |
缓存管理 | 记事本(临时存储) |
think\facade\Cookie |
Cookie管理 | 贴纸(浏览器存储) |
think\facade\Config |
配置管理 | 设置文件 |
第10行:定义类
php
class Login extends Controller
知识点:类和方法
php
class 类名
├── extends 继承(基于某个类创建)
└── { 代码 }
class Login= 定义一个叫 Login 的类extends Controller= 继承 ThinkPHP 的 Controller 基类- 就像"继承家业",子类可以使用父类的所有功能
类比理解:
php
class Login extends Controller
↓ ↓
儿子 父亲
儿子继承了父亲的功能,同时还自己的方法
第12行:定义属性
php
private $db;
知识点:变量(属性)和作用域
php
private $db;
↓ ↓
私有 变量名
类型
| 关键字 | 含义 | 谁能访问 |
|---|---|---|
private |
私有 | 只有这个类内部能访问 |
public |
公共 | 任何地方都能访问 |
protected |
保护 | 只有自己和子类能访问 |
$db 这个变量用来存储数据库连接对象。
第13-21行:构造函数
php
public function __construct(){
parent::__construct();
$db_host = Config::get('database.hostname');
$db_user = Config::get('database.username');
$db_pwd = Config::get('database.password');
$db_port = Config::get('database.hostport');
$this->db = Db::connect('mysql://'.$db_user.':'.$db_pwd.'@'.$db_host.':'.$db_port.'/ym_manage#utf8');
}
知识点:构造函数 __construct()
-
什么是构造函数? 对象被创建时自动运行的函数
-
什么时候运行?
new Login()时自动执行new Login() → 自动调用 __construct()
逐行解析:
php
public function __construct(){
↓
构造函数(创建对象时自动调用)
php
parent::__construct();
↓ ↓
父类 调用父类的方法
parent::__construct()= 调用父类的构造函数- ThinkPHP 要求:子类构造函数必须调用父类构造函数
php
$db_host = Config::get('database.hostname');
- 从配置文件中读取数据库地址
$db_host存储"主机地址"(如 127.0.0.1)
php
$this->db = Db::connect('mysql://...');
Db::connect()= 建立数据库连接$this->db= 把连接对象存到当前实例的$db属性mysql://用户名:密码@地址:端口/数据库名#编码
第23-29行:显示登录页面
php
public function login()
{
$ht_name = Config::get('app.HT_NAME');
$this->assign('ht_name',$ht_name);
return $this->fetch();
}
知识点:方法(函数)
php
public function 方法名()
↓
公开方法
逐行解析:
php
public function login()
- 定义一个公开方法叫
login() - 用户访问
/admin/login/login时触发
php
$ht_name = Config::get('app.HT_NAME');
- 读取应用配置中的站点名称
- 之前我们看到
HT_NAME= "Dreamcasino"
php
$this->assign('ht_name',$ht_name);
- 把变量传递给视图模板
- 语法:
$this->assign('模板变量名', PHP变量)
php
return $this->fetch();
fetch()= 渲染视图模板return= 返回渲染后的 HTML 内容
执行流程:
用户访问 /admin/login/login
↓
执行 login() 方法
↓
读取配置、分配变量
↓
渲染视图文件 → 返回 HTML
↓
浏览器显示登录页面
第31-54行:处理登录请求
php
public function doLogin()
{
// 第1步:获取表单数据
$data = Request::post();
// 第2步:验证数据
if(empty($data)){ die('参数有误'); }
if(isset($data['username']) && empty($data['username'])){ die('参数有误'); }
if(isset($data['password']) && empty($data['password'])){ die('参数有误'); }
// 第3步:获取用户名密码
$username = $data['username'];
$password = $data['password'];
// 第4步:查询数据库验证用户
$res = $this->db->table('admin')
->where('username',$username)
->where('isagent','0')
->find();
if(empty($res)){ die('登录失败'); }
// 第5步:验证密码
$passwd = md5($password.$res['salt']);
if($passwd == $res['password']){
// 登录成功:写Cookie和Redis
Cookie::set('admin_user_id',$res['id'],3600*2); // 浏览器Cookie
Cache::store('redis')->set('admin_user_'.$res['id'],'login',3600*2); // Redis缓存
die('success');
}
// 第6步:登录失败
die('登录失败');
}
知识点详解:
1. Request::post() - 获取POST数据
php
$data = Request::post();
Request= 请求类(收件员)::post()= 静态方法(不用创建对象直接调用)- 作用:获取表单POST提交的数据
类比:
POST数据就像邮寄的包裹
Request.post() = 打开包裹,取出里面的东西
2. empty() 和 isset() - 判断变量
php
empty($data) // 判断$data是否为空
isset($data['username']) // 判断$data['username']是否存在
empty($data['username']) // 判断是否为空字符串
| 函数 | 作用 |
|---|---|
isset() |
判断变量是否存在 |
empty() |
判断是否为空(包括0、""、null、false) |
3. die() - 终止脚本
php
die('参数有误');
die()= 输出内容并终止脚本- 类似
exit()
4. 数据库链式查询
php
$res = $this->db->table('admin')
->where('username', $username)
->where('isagent', '0')
->find();
ThinkPHP 的链式查询(像搭积木):
php
$this->db->table('admin') 第1步:指定表名
↓
->where('username', $username) 第2步:添加条件1
↓
->where('isagent', '0') 第3步:添加条件2
↓
->find() 第4步:获取一条数据
生成的 SQL:
sql
SELECT * FROM admin WHERE username='xxx' AND isagent='0' LIMIT 1
5. md5() - 密码加密
php
$passwd = md5($password.$res['salt']);
md5()= 不可逆的加密函数$res['salt']= 数据库里存的随机盐值- 密码 =
md5(用户输入的密码 + 盐)
为什么加盐?
php
没加盐:md5('123456') = 固定结果,容易被彩虹表破解
加盐后:md5('123456' + '随机盐') = 不固定,无法破解
6. Cookie::set() - 写入Cookie
php
Cookie::set('admin_user_id', $res['id'], 3600*2);
| 参数 | 含义 |
|---|---|
| 第1个 | Cookie名称 |
| 第2个 | Cookie值 |
| 第3个 | 有效期(秒),3600=1小时,3600*2=2小时 |
7. Cache::store('redis') - Redis缓存
php
Cache::store('redis')->set('admin_user_'.$res['id'], 'login', 3600*2);
| 部分 | 含义 |
|---|---|
Cache::store('redis') |
使用Redis驱动 |
->set(...) |
写入缓存 |
'admin_user_'.$res['id'] |
缓存键名(拼接用户ID) |
🎯 完整登录流程总结
php
┌─────────────────────────────────────────────────────────┐
│ 1. 用户访问 /admin/login/login │
│ → 显示登录页面(login方法) │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 2. 用户填写表单,点击登录 │
│ → POST提交到 /admin/login/doLogin │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 3. doLogin方法执行: │
│ ├─ 接收POST数据 │
│ ├─ 验证数据不为空 │
│ ├─ 查询数据库验证用户名 │
│ ├─ 验证密码(md5+盐加密对比) │
│ ├─ 登录成功:写Cookie + Redis + 返回"success" │
│ └─ 登录失败:返回"登录失败" │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 4. 前端收到"success" │
│ → 跳转到后台首页 │
└─────────────────────────────────────────────────────────┘