此篇文章主要是通过一个简单案例的后端接口开发过程,介绍一种接口开发方式,作为笔者本人的一个阶段性接口开发学习经验总结。其中案例是一个便签的相关接口,包含对用户和便签的信息管理。因为笔者本人能力所限,难免有差错,还希望读者能够对不正确的地方进行指正。文章也可在笔者的个人博客上查看:https://blog.csdn.net/ice_bear221/article/details/125355144
说明:
初学阶段不必掌握很多,遇到问题及时搜索,相关内容在附录中也有一些学习链接
说明:
也可以选择其他具有上述功能的软件。
https://www.freesion.com/article/952678790/
http://www.cxfeng.com/soft/79220.html
https://blog.csdn.net/weixin_34618077/article/details/115638512
https://blog.csdn.net/weixin_42306958/article/details/122155484
https://blog.csdn.net/H176Nhx7/article/details/120320235
https://www.pianshen.com/article/8072692518/
https://www.fujieace.com/navicat/15-for-mysql.html
说明:
因为笔者的电脑已经配置了一些环境,并未对上述链接内容进行验证,如果安装过程出现问题,也请自行在网上查找相关的软件安装教程。
实现一个便签程序的后端接口。
用户可以进行账号注册、账号注销、登录,以及修改密码。
用户登录后可以添加、删除、修改、查询便签列表、查看便签内容。
便签包含标题、内容、一张图片,其中标题不能为空,内容和图片可以为空。
- 建立项目数据库notes
- 在notes中建立两张数据表user和note,用于存储用户信息和便签信息
- user表包含(用户id,账号,密码)
- note表包含(便签id,用户id,标题,内容,图片url,创建时间)
- 用户接口
- 注册
- 登录
- 注销
- 修改密码
- 便签接口
- 添加便签
- 删除便签
= 修改便签
- 根据用户id查询便签列表
- 根据便签id查询便签内容
字段 | 含义 | 类型 | 大小 | 是否可为空 | 默认值 | 说明 |
---|---|---|---|---|---|---|
uid | 用户id | int | 否 | 无 | 主键 | |
account | 账号 | string | 11 | 否 | 无 | 手机号 |
password | 密码 | string | [6, 20] | 否 | 无 | 此处采用明文存储 |
字段 | 含义 | 类型 | 大小 | 是否可为空 | 默认值 | 说明 |
---|---|---|---|---|---|---|
nid | 便签id | int | 否 | 主键 | ||
uid | 用户id | int | 否 | 用户表外键 | ||
title | 标题 | string | 30 | 否 | ||
content | 内容 | string | 200 | 是 | null | |
imgUrl | 图片url | string | 200 | 是 | null | |
createTime | 创建时间 | datetime | 否 | 创建或修改后的时间 |
errCode | errInfo |
---|---|
0 | 成功 |
1 | 请求资源不存在 |
2 | 请求方法不允许 |
3 | 请求资源不允许 |
4 | 请求功能错误 |
5 | 请求参数错误 |
6 | 请求方法错误 |
7 | 数据表创建出错 |
8 | sql语句执行出错 |
9 | 文件类型错误 |
10 | 文件大小错误 |
11 | 存储文件出错 |
10001 | 用户id不能为空 |
10002 | 账号重复 |
10003 | 缺少账号 |
10004 | 两次密码不一致 |
10005 | 账号或密码错误 |
10006 | 用户不存在 |
10007 | 密码错误 |
10008 | 缺少密码 |
10009 | 缺少确认密码 |
10010 | 缺少新密码 |
10101 | 便签id不能为空 |
10102 | 缺少标题 |
10103 | 便签不存在 |
10104 | 缺少时间 |
- 用户注册
请求地址:http://localhost/notes/user/register
请求方式:POST
请求类型:content-Type:application/json
请求参数:
{
"account": "12345678910",
"password": "123456",
"rePassword": "123456"
}
响应参数:
成功:
{
"errCode": 0,
"errCode": "注册成功"
}
失败:
{
"errCode": 10003,
"errCode": "缺少账号"
}
{
"errCode": 10004,
"errCode": "两次密码不一致"
}
{
"errCode": 10008,
"errCode": "缺少密码"
}
{
"errCode": 10009,
"errCode": "缺少确认密码"
}
{
"errCode": 8,
"errCode": "sql语句执行错误"
}
- 用户登录
请求地址:http://localhost/notes/user/login
请求方式:POST
请求类型:content-Type:application/json
请求参数:
{
"account": "12345678910",
"password": "123456"
}
响应参数:
成功:
{
"errCode": 0,
"errCode": "登录成功",
"data": {
"uid": 1,
"account": "12345678910"
}
}
失败:
{
"errCode": 10003,
"errCode": "缺少账号"
}
{
"errCode": 10008,
"errCode": "缺少密码"
}
{
"errCode": 10005,
"errCode": "账号或密码错误"
}
{
"errCode": 8,
"errCode": "sql语句执行错误"
}
- 用户注销
请求地址:http://localhost/notes/user/logout
请求方式:POST
请求类型:content-Type:application/json
请求参数:
{
"uid": 1,
"password": "123456"
}
响应参数:
成功:
{
"errCode": 0,
"errCode": "注销成功",
}
失败:
{
"errCode": 10001,
"errCode": "用户id不能为空"
}
{
"errCode": 10008,
"errCode": "缺少密码"
}
{
"errCode": 10006,
"errCode": "用户不存在"
}
{
"errCode": 10007,
"errCode": "密码错误"
}
{
"errCode": 8,
"errCode": "sql语句执行错误"
}
- 修改密码
请求地址:http://localhost/notes/user/editPass
请求方式:POST
请求类型:content-Type:application/json
请求参数:
{
"uid": 1,
"password": "123456",
"rePassword": "123456",
"newPassword": "654321"
}
响应参数:
成功:
{
"errCode": 0,
"errCode": "修改成功",
}
失败:
{
"errCode": 10001,
"errCode": "用户id不能为空"
}
{
"errCode": 10008,
"errCode": "缺少密码"
}
{
"errCode": 10009,
"errCode": "缺少确认密码"
}
{
"errCode": 10010,
"errCode": "缺少新密码"
}
{
"errCode": 10006,
"errCode": "用户不存在"
}
{
"errCode": 10007,
"errCode": "密码错误"
}
{
"errCode": 10004,
"errCode": "两次密码不一致"
}
{
"errCode": 8,
"errCode": "sql语句执行错误"
}
- 添加便签
请求地址:http://localhost/notes/note/add
请求方式:POST
请求类型:content-Type:multipart/form-data
请求参数:
Content-Disposition: form-data; name="uid" 1
Content-Disposition: form-data; name="title" 这是一个标题
Content-Disposition: form-data; name="content" 这是便签内容
Content-Disposition: form-data; name="createTime" 2022-01-01 01:01:01
Content-Disposition: form-data; name="img"; filename="IMG20191125153658.jpg"
Content-Type: image/jpeg
(data)
响应参数:
成功:
{
"errCode": 0,
"errCode": "添加成功",
}
失败:
{
"errCode": 10001,
"errCode": "用户id不能为空"
}
{
"errCode": 10006,
"errCode": "用户不存在"
}
{
"errCode": 10102,
"errCode": "缺少标题"
}
{
"errCode": 10104,
"errCode": "缺少时间"
}
{
"errCode": 10,
"errCode": "文件大小错误"
}
{
"errCode": 9,
"errCode": "文件类型错误"
}
{
"errCode": 11,
"errCode": "存储文件出错"
}
{
"errCode": 8,
"errCode": "sql语句执行错误"
}
- 删除便签
请求地址:http://localhost/notes/note/delById
请求方式:POST
请求类型:content-Type:application/json
请求参数:
{
"uid": 1,
"nid": 1
}
响应参数:
成功:
{
"errCode": 0,
"errCode": "删除成功",
}
失败:
{
"errCode": 10001,
"errCode": "用户id不能为空"
}
{
"errCode": 10101,
"errCode": "便签id不能为空"
}
{
"errCode": 10006,
"errCode": "用户不存在"
}
{
"errCode": 10103,
"errCode": "便签不存在"
}
{
"errCode": 8,
"errCode": "sql语句执行错误"
}
- 修改便签
请求地址:http://localhost/notes/note/editByNId
请求方式:POST
请求类型:content-Type:multipart/form-data
请求参数:
Content-Disposition: form-data; name="uid" 1
Content-Disposition: form-data; name="nid" 1
Content-Disposition: form-data; name="title" 这是新标题
Content-Disposition: form-data; name="content" 这是新便签内容
Content-Disposition: form-data; name="createTime" 2022-01-02 10:00:00
Content-Disposition: form-data; name="img"; filename="IMG20191125153658.jpg"
Content-Type: image/jpeg
(data)
响应参数:
成功:
{
"errCode": 0,
"errCode": "修改成功"
}
失败:
{
"errCode": 10101,
"errCode": "便签id不能为空"
}
{
"errCode": 10103,
"errCode": "便签不存在"
}
{
"errCode": 10001,
"errCode": "用户id不能为空"
}
{
"errCode": 10006,
"errCode": "用户不存在"
}
{
"errCode": 10102,
"errCode": "缺少标题"
}
{
"errCode": 10104,
"errCode": "缺少时间"
}
{
"errCode": 10,
"errCode": "文件大小错误"
}
{
"errCode": 9,
"errCode": "文件类型错误"
}
{
"errCode": 11,
"errCode": "存储文件出错"
}
{
"errCode": 8,
"errCode": "sql语句执行错误"
}
- 查询便签列表
请求地址:http://localhost/notes/note/viewListByUid
请求方式:POST
请求类型:content-Type:application/json
请求参数:
{
"uid": 1,
"offset": 0,
"limit": 20
}
响应参数:
成功:
{
"errCode": 0,
"errCode": "查询成功",
"data": [
{
"nid": 1,
"title": "这是一个标题"
},
{
"nid": 2,
"title": "新的便签"
}
]
}
失败:
{
"errCode": 10001,
"errCode": "用户id不能为空"
}
{
"errCode": 10006,
"errCode": "用户不存在"
}
{
"errCode": 8,
"errCode": "sql语句执行错误"
}
- 查询便签内容
请求地址:http://localhost/notes/note/viewByNid
请求方式:POST
请求类型:content-Type:application/json
请求参数:
{
"nid": 1
}
响应参数:
成功:
{
"errCode": 0,
"errCode": "查询成功",
"data": {
"nid": 1,
"title": "这是一个标题",
"content": "这是便签内容",
"imgUrl": "http://localhost/notes/uploads/abasdfsdf.jpg",
"createTime": "2022-01-02 10:00:00"
}
}
失败:
{
"errCode": 10101,
"errCode": "便签id不能为空"
}
{
"errCode": 10103,
"errCode": "便签不存在"
}
{
"errCode": 8,
"errCode": "sql语句执行错误"
}
添加如下代码:
# 开启重定向
RewriteEngine on
# 访问的不是文件
RewriteCond %{REQUEST_FILENAME} !-f
# 访问的不是文件夹
RewriteCond %{REQUEST_FILENAME} !-d
# 重定向到访问index.php文件
RewriteRule ^(.*)$ index.php/$1 [L]
说明:
添加.htaccess文件之前的访问链接为:http://localhost/notes/index.php/user/login
添加.htaccess文件之后的访问链接为:http://localhost/notes/user/login
只要访问的内容不是文件和文件夹,都会重定向到访问:http://localhost/notes/index.php
// 此文件用于保存一些默认配置
define("HOST", 'localhost'); // 配置主机名,本机是localhost或127.0.0.1
define("DBNAME", "notes"); // 项目数据库名,
define("DBUSER", "root"); // 登录数据库用户名
define("DBPASS", ""); // 密码
define("VERSION", "1.0"); // 接口版本
define("DOMAIN", "http://localhost/notes"); // 项目位置
require_once __DIR__."/conf.php"; // 引入conf.php文件
//
// 生成并返回数据库连接对象,用于操作数据库
$db = new PDO("mysql:host=".HOST.";dbname=".DBNAME, DBUSER, DBPASS);
return $db;
/**
* Description of Errors
*保存项目错误码
* @author 1
*/
class Errors {
// 错误码5位
//
// 系统相关 0-9999
const OK = 0;
const REQUEST_IS_NULL = 1;
const REQUEST_METHOD_NOT_ALLOWED = 2;
const REQUEST_RESOUTCE_NOT_ALLOWED = 3;
const REQUEST_FUNCTION_IS_ERROR = 4;
const REQUEST_PARAMETER_ERROR = 5;
const REQUEST_METHOD_IS_ERROR = 6;
const BUILD_TABLE_ERROR = 7;
const SQL_EXECUTE_ERROR = 8;
const FILE_TYPE_IS_ERROR = 9;
const FILE_SIZE_IS_ERROR = 10;
const STORE_FILE_OCCURRED_ERROR = 11;
// 用户类相关 10001-10099
const USER_ID_CONNOT_NULL = 10001;
const ACCOUNT_REPEAT = 10002;
const ACCOUNT_IS_MISSING = 10003;
const PASSWORD_IS_NOT_SAME = 10004;
const ACCOUNT_OR_PASSWORD_ERROR = 10005;
const USER_IS_NOT_EXISTS = 10006;
const PASSWORD_IS_ERROR = 10007;
const PASSWORD_IS_MISSING = 10008;
const REPASSWORD_IS_MISSING = 10009;
const NEW_PASSWORD_IS_MISSING = 10010;
// 便签类相关 10101-10199
const NOTE_ID_CONNOT_NULL = 10101;
const TITLE_IS_MISSING = 10102;
const NOTE_IS_NOT_EXISTS = 10103;
const TIME_IS_MISSING = 10104;
}
require_once 'lib/conf.php';
/**
* Description of Tools
* 封装较常用的函数
* @author 1
*/
class Tools {
/**
* 打印调试信息
* @param type $message print info
*/
public static function _debug($message) {
var_dump($message);
}
/**
* 打印json格式信息
* @param type $errInfo 返回信息
* @param type $errCode 返回信息提示码
* @param type $data 返回数据
*/
public static function printJson($errInfo, $errCode, $data=null) {
$return["errCode"] = $errCode;
$return["errInfo"] = $errInfo;
if (!empty($data))
$return["data"] = $data;
else if (!is_null($data))
{
$return["data"] = [];
}
header("Content-Type:application/json;charset:utf-8");
echo json_encode($return, JSON_PRETTY_PRINT + JSON_UNESCAPED_UNICODE + JSON_UNESCAPED_SLASHES);
}
/**
* 根据检查条件和所给文件类型判断文件是够可接受
* @param string $type
* @param int $flag
* @return bool
*/
public static function checkFileType($type, $flag) {
$allowImgType = ["jpg", "jpeg", "png", "bmp"];
$allowDocType = ["doc", "docx", "ppt", "pptx", "xls", "xlsx", "txt"];
$allowType = ["jpg", "jpeg", "png", "bmp",
"doc", "docx", "ppt", "pptx", "xls", "xlsx",
"zip", "7z", "rar", "txt"];
if ($flag == 0) {
// 是否满足可接受的所有文件类型
return in_array($type, $allowType);
}
else if ($flag == 1) {
// 是否满足可接受的图片类型
return in_array($type, $allowImgType);
}
}
/**
* 检查文件大小是否满足条件
* @param int $fileSize 待检查文件大小
* @param int $allowSize 可接受大小
* @return type
*/
public static function checkFileSize($fileSize, $allowSize) {
return $fileSize <= $allowSize;
}
/**
* 创建多级文件夹
* @param type $dirName
*/
public static function createDir($dirName) {
if (!file_exists("$dirName")) {
mkdir($dirName, 0777, true);
}
}
/**
* 存储文件,返回文件url
* @param string $fileDir 文件存储路径
* @param string $filename 临时文件地址
* @param string $fileType 文件类型
* @return string
*/
public static function storeFile($fileDir, $filename, $fileType) {
// 生成文件路径
$filePath = $fileDir."/".md5($filename).".".$fileType;
// 将临时文件存入目标路径
if (!move_uploaded_file($filename, $filePath)) {
// 存储失败后返回空
return null;
}
else {
// 存储成功
$url = DOMAIN."/".$filePath;
return $url;
}
}
}
require_once __DIR__.'/Errors.php';
require_once __DIR__.'/Tools.php';
/**
* Description of Rest
*
* @author 1
*/
class Rest {
// 设置允许的请求方法和资源
private $_allowMethod = ["GET", "POST"];
private $_allowResource = ["user", "note"];
// 请求的方法、资源、功能
private $_requestMethod;
private $_requestResource;
private $_requestFunction;
// 资源类对象
private $_db;
/**
* 构造函数
* @param PDO $db
*/
public function __construct(PDO $db) {
$this->_db = $db;
}
/**
* api启动方法
*/
public function run() {
try {
// 获取并检查请求的方法和资源
$this->setRequestMethod();
$this->setRequestResource();
// 根据请求的资源分发请求,交给对应的资源类处理
switch ($this->_requestResource) {
default : {
Tools::printJson("请求内容为空", Errors::REQUEST_IS_NULL);
}
}
} catch (Exception $exc) {
Tools::printJson($exc->getMessage(), $exc->getCode());
}
}
/**
* 获取post提交的数据
* @return type array
* @throws Exception 请求参数错误
*/
private function getBody() {
// 获取post请求提交的信息
$postData = file_get_contents("PHP://input");
// post请求提交的参数不能为空
if (empty($postData))
{
throw new Exception("请求参数错误", Errors::REQUEST_PARAMETER_ERROR);
}
// 将获取的请求参数进行json解码,用于后续操作
return json_decode($postData, true);
}
/**
* 获取并检查请求的方法
* @throws Exception 请求方法不被允许
*/
private function setRequestMethod() {
// 获取请求方法
$this->_requestMethod = $_SERVER["REQUEST_METHOD"];
// 检查请求方法是否被允许
if (!in_array($this->_requestMethod, $this->_allowMethod))
{
throw new Exception("请求方法不被允许", Errors::REQUEST_METHOD_NOT_ALLOWED);
}
}
/**
* 获取请求的资源、功能
* @throws Exception 请求资源不被允许
*/
private function setRequestResource() {
// 若访问的rl为http://localhost/notes/user/login,则$_SERVER["PATH_INFO"]为 /user/login
$path = $_SERVER["PATH_INFO"];
$params = explode('/', $path);
$this->_requestResource = $params[1];
if (!in_array($this->_requestResource, $this->_allowResource))
{
throw new Exception("请求资源不被允许", Errors::REQUEST_RESOUTCE_NOT_ALLOWED);
}
if (!empty($params[2]))
{
$this->_requestFunction = $params[2];
}
}
}
// 下面引入资源类
require_once './class/Rest.php';
// 下面创建资源对象
$db = require_once './lib/db.php';
// 创建启动类对象,并启动
$api = new Rest($db);
$api->run();
说明:
笔者这里为了方便,没有依次介绍每个功能的编写以及测试,而是将所有的内容放在一起,读者练习时可以在写完一个功能后,先看后面的接口测试,检验接口情况。
/**
* Description of User
* 用户类功能
* @author 1
*/
class User {
private $_db;
/**
* 构造函数
* @param PDO $db
*/
public function __construct(PDO $db) {
$this->_db = $db;
}
}
/**
* Description of User
* 用户类功能
* @author 1
*/
class User {
private $_db;
/**
* 构造函数
* @param PDO $db
*/
public function __construct(PDO $db) {
$this->_db = $db;
}
/**
* 创建数据表
*/
public function buildDb() {
// 建立用户表
// 检查notes数据库中是否包含user表
$sql = "select count(1) from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA='notes' and TABLE_NAME='user'";
$sm = $this->_db->prepare($sql);
// 执行sql语句
if ($sm->execute()) {
// 获取执行结果
$re = $sm->fetch(PDO::FETCH_COLUMN);
// 表不存在,开始建立
if (!$re) {
$sql = "create table user (
uId int primary key not null auto_increment comment '用户id',
account varchar(11) unique not null comment '手机号',
password varchar(20) not null comment '密码'
)";
$sm = $this->_db->prepare($sql);
if ($sm->execute()) {
Tools::printJson("建表成功", Errors::OK);
} else {
Tools::printJson("建表失败", Errors::BUILD_TABLE_ERROR);
}
}
else {
Tools::printJson("表已经存在", Errors::OK);
}
} else {
Tools::printJson("sql语句执行失败", Errors::SQL_EXECUTE_ERROR);
}
}
/**
* 用户注册
* @param Object $postData
* @throws Exception
*/
public function register($postData) {
// 检查参数
if (!key_exists("account", $postData) || empty($postData["account"])) {
throw new Exception("缺少账号", Errors::ACCOUNT_IS_MISSING);
}
if (!key_exists("password", $postData) || empty($postData["password"])) {
throw new Exception("缺少密码", Errors::PASSWORD_IS_MISSING);
}
if (!key_exists("rePassword", $postData) || empty($postData["rePassword"])) {
throw new Exception("缺少确认密码", Errors::REPASSWORD_IS_MISSING);
}
if (!($postData["password"] === $postData["rePassword"])) {
throw new Exception("两次密码不一致", Errors::PASSWORD_IS_NOT_SAME);
}
// 将用户信息添加进数据库
// 注意在每行结尾的"前添加空格,否则可能导致sql语句执行错误
$sql = "insert into user(account, password) "
. "values(:account, :password) ";
// 进行预处理
$sm = $this->_db->prepare($sql);
// 绑定数据
$sm->bindParam(":account", $postData["account"]);
$sm->bindParam(":password", $postData["password"]);
// 执行sql语句
if (!$sm->execute()) {
throw new Exception("sql语句执行错误", Errors::SQL_EXECUTE_ERROR);
}
else {
Tools::printJson("注册成功", Errors::OK);
}
}
/**
* 用户登录
* @param type $postData
* @throws Exception
*/
public function login($postData) {
// 检查参数
if (!key_exists("account", $postData) || empty($postData["account"])) {
throw new Exception("缺少账号", Errors::ACCOUNT_IS_MISSING);
}
if (!key_exists("password", $postData) || empty($postData["password"])) {
throw new Exception("缺少密码", Errors::PASSWORD_IS_MISSING);
}
// 查询数据库信息
$sql = "select uid, account from user "
. "where account = :account "
. "and password = :password ";
// 进行预处理
$sm = $this->_db->prepare($sql);
// 绑定数据
$sm->bindParam(":account", $postData["account"]);
$sm->bindParam(":password", $postData["password"]);
// 执行sql语句
if (!$sm->execute()) {
throw new Exception("sql语句执行错误", Errors::SQL_EXECUTE_ERROR);
}
else {
// 获取查询结果
$returnData = $sm->fetch(PDO::FETCH_ASSOC);
// 检查结果并返回信息
if (empty($returnData)) {
throw new Exception("账号或密码错误", Errors::ACCOUNT_OR_PASSWORD_ERROR);
}
else {
Tools::printJson("登录成功", Errors::OK, $returnData);
}
}
}
/**
* 修改密码
* @param type $postData
* @throws Exception
*/
public function editPass($postData) {
// 检查参数
if (!key_exists("uid", $postData) || empty($postData["uid"])) {
throw new Exception("用户id不能为空", Errors::USER_ID_CONNOT_NULL);
}
if (!key_exists("password", $postData) || empty($postData["password"])) {
throw new Exception("缺少密码", Errors::PASSWORD_IS_MISSING);
}
if (!key_exists("rePassword", $postData) || empty($postData["rePassword"])) {
throw new Exception("缺少确认密码", Errors::REPASSWORD_IS_MISSING);
}
if (!key_exists("newPassword", $postData) || empty($postData["newPassword"])) {
throw new Exception("缺少新密码", Errors::NEW_PASSWORD_IS_MISSING);
}
if (!($postData["password"] === $postData["rePassword"])) {
throw new Exception("两次密码不一致", Errors::PASSWORD_IS_NOT_SAME);
}
// 判断用户是否存在,以及查询原密码进行比对
$sql = "select password from user "
. "where uid = :uid ";
$sm = $this->_db->prepare($sql);
$sm->bindParam(":uid", $postData["uid"]);
if (!$sm->execute()) {
throw new Exception("sql语句执行错误", Errors::SQL_EXECUTE_ERROR);
}
else {
$returnData = $sm->fetch(PDO::FETCH_ASSOC);
// 检查用户信息
if (empty($returnData)) {
throw new Exception("用户不存在", Errors::USER_IS_NOT_EXISTS);
}
else {
if (!($postData["password"] === $returnData["password"])) {
throw new Exception("密码错误", Errors::PASSWORD_IS_ERROR);
}
else {
// 更新用户密码
$sql = "update user set password = :newPassword "
. "where uid = :uid ";
$sm = $this->_db->prepare($sql);
$sm->bindParam(":uid", $postData["uid"]);
$sm->bindParam(":newPassword", $postData["newPassword"]);
if (!$sm->execute()) {
throw new Exception("sql语句执行错误", Errors::SQL_EXECUTE_ERROR);
}
else {
Tools::printJson("修改成功", Errors::OK);
}
}
}
}
}
/**
* 用户注销
* @param type $postData
* @throws Exception
*/
public function logout($postData) {
// 检查参数
if (!key_exists("uid", $postData) || empty($postData["uid"])) {
throw new Exception("用户id不能为空", Errors::USER_ID_CONNOT_NULL);
}
if (!key_exists("password", $postData) || empty($postData["password"])) {
throw new Exception("缺少密码", Errors::PASSWORD_IS_MISSING);
}
// 判断用户是否存在,以及查询原密码进行比对
$sql = "select password from user "
. "where uid = :uid ";
$sm = $this->_db->prepare($sql);
$sm->bindParam(":uid", $postData["uid"]);
if (!$sm->execute()) {
throw new Exception("sql语句执行错误", Errors::SQL_EXECUTE_ERROR);
}
else {
$returnData = $sm->fetch(PDO::FETCH_ASSOC);
// 检查用户信息
if (empty($returnData)) {
throw new Exception("用户不存在", Errors::USER_IS_NOT_EXISTS);
}
else {
if (!($postData["password"] === $returnData["password"])) {
throw new Exception("密码错误", Errors::PASSWORD_IS_ERROR);
}
else {
// 开启事务,保证下面的sql语句全部执行正确后才修改数据库内容
$this->_db->beginTransaction();
// 删除用户发布的所有便签,此时还没有添加note数据表,可以先忽略
/*
$sql = "delete from note where uid = :uid ";
$sm = $this->_db->prepare($sql);
$sm->bindParam(":uid", $postData["uid"]);
if (!$sm->execute()) {
// 数据库回滚
$this->_db->rollBack();
throw new Exception("sql语句执行错误", Errors::SQL_EXECUTE_ERROR);
}
*
*/
// 删除用户
$sql = "delete from user where uid = :uid ";
$sm = $this->_db->prepare($sql);
$sm->bindParam(":uid", $postData["uid"]);
if (!$sm->execute()) {
// 数据库回滚
$this->_db->rollBack();
throw new Exception("sql语句执行错误", Errors::SQL_EXECUTE_ERROR);
}
else {
// 提交数据库操作
$this->_db->commit();
Tools::printJson("注销成功", Errors::OK);
}
}
}
}
}
}
// 下面引入资源类
require_once './class/Rest.php';
require_once './class/User.php'; // 引入User类
// 下面创建资源对象
$db = require_once './lib/db.php';
$user = new User($db); // 创建User资源类对象
// 创建启动类对象,并启动
$api = new Rest($db, $user);
$api->run();
require_once __DIR__.'/Errors.php';
require_once __DIR__.'/Tools.php';
/**
* Description of Rest
*
* @author 1
*/
class Rest {
// 设置允许的请求方法和资源
private $_allowMethod = ["GET", "POST"];
private $_allowResource = ["user", "note"];
// 请求的方法、资源、功能
private $_requestMethod;
private $_requestResource;
private $_requestFunction;
// 资源类对象
private $_db;
private $_user;
/**
* 构造函数
* @param PDO $db
*/
public function __construct(PDO $db, User $user) {
$this->_db = $db;
$this->_user = $user;
}
/**
* api启动方法
*/
public function run() {
try {
// 获取并检查请求的方法和资源
$this->setRequestMethod();
$this->setRequestResource();
// 根据请求的资源分发请求,交给对应的资源类处理
switch ($this->_requestResource) {
case "user": {
$this->sendUser();
break;
}
default : {
Tools::printJson("请求内容为空", Errors::REQUEST_IS_NULL);
}
}
} catch (Exception $exc) {
Tools::printJson($exc->getMessage(), $exc->getCode());
}
}
/**
* 处理用户业务
* @throws Exception
*/
private function sendUser() {
switch ($this->_requestMethod) {
case "POST": {
switch ($this->_requestFunction) {
case "buildDb": {
$this->_user->buildDb();
break;
}
case "register": {
$this->_user->register($this->getBody());
break;
}
case "login": {
$this->_user->login($this->getBody());
break;
}
case "editPass": {
$this->_user->editPass($this->getBody());
break;
}
case "logout": {
$this->_user->logout($this->getBody());
break;
}
default : {
Tools::printJson("请求功能不存在", Errors::REQUEST_FUNCTION_IS_ERROR);
}
}
break;
}
default: {
throw new Exception("该资源没有此方法的接口", Errors::REQUEST_METHOD_IS_ERROR);
}
}
}
/**
* 获取post提交的数据
* @return type array
* @throws Exception 请求参数错误
*/
private function getBody() {
// 获取post请求提交的信息
$postData = file_get_contents("PHP://input");
// post请求提交的参数不能为空
if (empty($postData))
{
throw new Exception("请求参数错误", Errors::REQUEST_PARAMETER_ERROR);
}
// 将获取的请求参数进行json解码,用于后续操作
return json_decode($postData, true);
}
/**
* 获取并检查请求的方法
* @throws Exception 请求方法不被允许
*/
private function setRequestMethod() {
// 获取请求方法
$this->_requestMethod = $_SERVER["REQUEST_METHOD"];
// 检查请求方法是否被允许
if (!in_array($this->_requestMethod, $this->_allowMethod))
{
throw new Exception("请求方法不被允许", Errors::REQUEST_METHOD_NOT_ALLOWED);
}
}
/**
* 获取请求的资源、功能
* @throws Exception 请求资源不被允许
*/
private function setRequestResource() {
// 若访问的rl为http://localhost/notes/user/login,则$_SERVER["PATH_INFO"]为 /user/login
$path = $_SERVER["PATH_INFO"];
$params = explode('/', $path);
$this->_requestResource = $params[1];
if (!in_array($this->_requestResource, $this->_allowResource))
{
throw new Exception("请求资源不被允许", Errors::REQUEST_RESOUTCE_NOT_ALLOWED);
}
if (!empty($params[2]))
{
$this->_requestFunction = $params[2];
}
}
}
/**
* Description of Note
* 便签类功能
* @author 1
*/
class Note {
private $_db;
/**
* 构造函数
* @param PDO $db
*/
public function __construct(PDO $db) {
$this->_db = $db;
}
}
/**
* Description of Note
* 便签类功能
* @author 1
*/
class Note {
private $_db;
/**
* 构造函数
* @param PDO $db
*/
public function __construct(PDO $db) {
$this->_db = $db;
}
/**
* 创建数据表
*/
public function buildDb() {
// 建立便签表
// 检查notes数据库中是否包含note表
$sql = "select count(1) from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA='notes' and TABLE_NAME='note'";
$sm = $this->_db->prepare($sql);
// 执行sql语句
if ($sm->execute()) {
// 获取执行结果
$re = $sm->fetch(PDO::FETCH_COLUMN);
// 表不存在,开始建立
if (!$re) {
$sql = "create table note (
nid int primary key not null auto_increment comment '便签id',
uid int not null comment '用户id',
title varchar(30) not null comment '标题',
content varchar(200) null comment '内容',
imgUrl varchar(200) null comment '图片url',
createTime datetime not null comment '创建或修改后的时间',
foreign key(uid) references user(uid)
)";
$sm = $this->_db->prepare($sql);
if ($sm->execute()) {
Tools::printJson("建表成功", Errors::OK);
} else {
Tools::printJson("建表失败", Errors::BUILD_TABLE_ERROR);
}
}
else {
Tools::printJson("表已经存在", Errors::OK);
}
} else {
Tools::printJson("sql语句执行失败", Errors::SQL_EXECUTE_ERROR);
}
}
/**
* 添加便签
* @throws Exception
*/
public function add() {
// 获取请求参数
$postData = $_POST;
$fileData = $_FILES;
// 检查参数
if (!key_exists("uid", $postData) || empty($postData["uid"])) {
throw new Exception("用户id不能为空", Errors::USER_ID_CONNOT_NULL);
}
if (!key_exists("title", $postData) || empty($postData["title"])) {
throw new Exception("缺少标题", Errors::TITLE_IS_MISSING);
}
if (!key_exists("createTime", $postData) || empty($postData["createTime"])) {
throw new Exception("缺少时间", Errors::TIME_IS_MISSING);
}
// 检查用户是否存在
$sql = "select count(1) 'count' from user "
. "where uid = :uid ";
$sm = $this->_db->prepare($sql);
$sm->bindParam(":uid", $postData["uid"]);
if (!$sm->execute()) {
throw new Exception("sql语句执行出错", Errors::SQL_EXECUTE_ERROR);
}
else {
$returnData = $sm->fetch(PDO::FETCH_ASSOC);
if (empty($returnData["count"])) {
throw new Exception("用户不存在", Errors::USER_IS_NOT_EXISTS);
}
}
// 如果含有图片,先保存到文件夹内
if (!key_exists("img", $fileData) || empty($fileData["img"]) || $fileData["img"]["size"] == 0) {
$postData["imgUrl"] = null;
}
else {
// 存储图片
// 检查图片类型
$type = explode(".", $fileData["img"]["name"]);
$fileType = $type[count($type) - 1];
if (!Tools::checkFileType($fileType, 1)) {
throw new Exception("文件类型错误", Errors::FILE_TYPE_IS_ERROR);
}
// 检查图片大小,<=8M
if (!Tools::checkFileSize($fileData["img"]["size"], 8388608)) {
throw new Exception("文件大小错误", Errors::FILE_SIZE_IS_ERROR);
}
// 创建图片文件夹,存储图片
$fileDir = "uploads/img";
Tools::createDir($fileDir);
$url = Tools::storeFile($fileDir, $fileData["img"]["tmp_name"], $fileType);
if (is_null($url)) {
throw new Exception("存储文件出错", Errors::STORE_FILE_OCCURRED_ERROR);
}
$postData["imgUrl"] = $url;
}
// 保存信息到数据库
$sql = "insert into note(uid, title, content, createTime, imgUrl) "
. "values(:uid, :title, :content, :createTime, :imgUrl) ";
$sm = $this->_db->prepare($sql);
$sm->bindParam(":uid", $postData["uid"]);
$sm->bindParam(":title", $postData["title"]);
$sm->bindParam(":content", $postData["content"]);
$sm->bindParam(":createTime", $postData["createTime"]);
$sm->bindParam(":imgUrl", $postData["imgUrl"]);
if (!$sm->execute()) {
throw new Exception("sql语句执行出错", Errors::SQL_EXECUTE_ERROR);
}
else {
Tools::printJson("添加成功", Errors::OK);
}
}
/**
* 修改便签
* @throws Exception
*/
public function editByNid() {
// 获取请求参数
$postData = $_POST;
$fileData = $_FILES;
// 检查参数
if (!key_exists("uid", $postData) || empty($postData["uid"])) {
throw new Exception("用户id不能为空", Errors::USER_ID_CONNOT_NULL);
}
if (!key_exists("nid", $postData) || empty($postData["nid"])) {
throw new Exception("便签id不能为空", Errors::NOTE_ID_CONNOT_NULL);
}
if (!key_exists("title", $postData) || empty($postData["title"])) {
throw new Exception("缺少标题", Errors::TITLE_IS_MISSING);
}
if (!key_exists("createTime", $postData) || empty($postData["createTime"])) {
throw new Exception("缺少时间", Errors::TIME_IS_MISSING);
}
// 检查用户是否存在
$sql = "select count(1) 'count' from user "
. "where uid = :uid ";
$sm = $this->_db->prepare($sql);
$sm->bindParam(":uid", $postData["uid"]);
if (!$sm->execute()) {
throw new Exception("sql语句执行出错", Errors::SQL_EXECUTE_ERROR);
}
else {
$returnData = $sm->fetch(PDO::FETCH_ASSOC);
if (empty($returnData["count"])) {
throw new Exception("用户不存在", Errors::USER_IS_NOT_EXISTS);
}
}
// 检查便签是否存在
$sql = "select count(1) 'count' from note "
. "where uid = :uid "
. "and nid = :nid ";
$sm = $this->_db->prepare($sql);
$sm->bindParam(":uid", $postData["uid"]);
$sm->bindParam(":nid", $postData["nid"]);
if (!$sm->execute()) {
throw new Exception("sql语句执行出错", Errors::SQL_EXECUTE_ERROR);
}
else {
$returnData = $sm->fetch(PDO::FETCH_ASSOC);
if (empty($returnData["count"])) {
throw new Exception("便签不存在", Errors::NOTE_IS_NOT_EXISTS);
}
}
// 如果含有图片,先保存到文件夹内
if (!key_exists("img", $fileData) || empty($fileData["img"]) || $fileData["img"]["size"] == 0) {
$postData["imgUrl"] = null;
}
else {
// 存储图片
// 检查图片类型
$type = explode(".", $fileData["img"]["name"]);
$fileType = $type[count($type) - 1];
if (!Tools::checkFileType($fileType, 1)) {
throw new Exception("文件类型错误", Errors::FILE_TYPE_IS_ERROR);
}
// 检查图片大小,<=8M
if (!Tools::checkFileSize($fileData["img"]["size"], 8388608)) {
throw new Exception("文件大小错误", Errors::FILE_SIZE_IS_ERROR);
}
// 创建图片文件夹,存储图片
$fileDir = "uploads/img";
Tools::createDir($fileDir);
$url = Tools::storeFile($fileDir, $fileData["img"]["tmp_name"], $fileType);
if (is_null($url)) {
throw new Exception("存储文件出错", Errors::STORE_FILE_OCCURRED_ERROR);
}
$postData["imgUrl"] = $url;
}
// 保存信息到数据库
$sql = "update note set title = :title, content = :content, "
. "createTime = :createTime, imgUrl = :imgUrl "
. "where nid = :nid ";
$sm = $this->_db->prepare($sql);
$sm->bindParam(":nid", $postData["nid"]);
$sm->bindParam(":title", $postData["title"]);
$sm->bindParam(":content", $postData["content"]);
$sm->bindParam(":createTime", $postData["createTime"]);
$sm->bindParam(":imgUrl", $postData["imgUrl"]);
if (!$sm->execute()) {
throw new Exception("sql语句执行出错", Errors::SQL_EXECUTE_ERROR);
}
else {
Tools::printJson("修改成功", Errors::OK);
}
}
/**
* 查询便签列表
* @param type $postData
* @throws Exception
*/
public function viewListByUid($postData) {
// 检查参数
if (!key_exists("uid", $postData) || empty($postData["uid"])) {
throw new Exception("用户id不能为空", Errors::USER_ID_CONNOT_NULL);
}
if (!key_exists("offset", $postData) || empty($postData["offset"])) {
$postData["offset"] = 0;
}
if (!key_exists("limit", $postData) || empty($postData["limit"])
|| $postData["limit"] > 20) {
$postData["limit"] = 20;
}
// 检查用户是否存在
$sql = "select count(1) 'count' from user "
. "where uid = :uid ";
$sm = $this->_db->prepare($sql);
$sm->bindParam(":uid", $postData["uid"]);
if (!$sm->execute()) {
throw new Exception("sql语句执行出错", Errors::SQL_EXECUTE_ERROR);
}
else {
$returnData = $sm->fetch(PDO::FETCH_ASSOC);
if (empty($returnData["count"])) {
throw new Exception("用户不存在", Errors::USER_IS_NOT_EXISTS);
}
}
// 查询便签列表
$sql = "select nid, title from note "
. "where uid = :uid "
. "limit :offset, :limit ";
$sm = $this->_db->prepare($sql);
$sm->bindParam(":uid", $postData["uid"]);
$sm->bindParam(":offset", $postData["offset"], PDO::PARAM_INT);
$sm->bindParam(":limit", $postData["limit"], PDO::PARAM_INT);
if (!$sm->execute()) {
throw new Exception("sql语句执行出错", Errors::SQL_EXECUTE_ERROR);
}
else {
$returnData = $sm->fetchAll(PDO::FETCH_ASSOC);
Tools::printJson("查询成功", Errors::OK, $returnData);
}
}
/**
* 查询便签内容
* @param type $postData
* @throws Exception
*/
public function viewByNid($postData) {
// 检查参数
if (!key_exists("nid", $postData) || empty($postData["nid"])) {
throw new Exception("便签id不能为空", Errors::NOTE_ID_CONNOT_NULL);
}
// 检查便签是否存在
$sql = "select count(1) 'count' from note "
. "where nid = :nid ";
$sm = $this->_db->prepare($sql);
$sm->bindParam(":nid", $postData["nid"]);
if (!$sm->execute()) {
throw new Exception("sql语句执行出错", Errors::SQL_EXECUTE_ERROR);
}
else {
$returnData = $sm->fetch(PDO::FETCH_ASSOC);
if (empty($returnData["count"])) {
throw new Exception("便签不存在", Errors::NOTE_IS_NOT_EXISTS);
}
}
// 查询便签内容
$sql = "select nid, title, content, imgUrl, createTime from note "
. "where nid = :nid ";
$sm = $this->_db->prepare($sql);
$sm->bindParam(":nid", $postData["nid"]);
if (!$sm->execute()) {
throw new Exception("sql语句执行出错", Errors::SQL_EXECUTE_ERROR);
}
else {
$returnData = $sm->fetch(PDO::FETCH_ASSOC);
Tools::printJson("查询成功", Errors::OK, $returnData);
}
}
/**
* 删除便签
* @param type $postData
* @throws Exception
*/
public function delById($postData) {
// 检查参数
if (!key_exists("uid", $postData) || empty($postData["uid"])) {
throw new Exception("用户id不能为空", Errors::USER_ID_CONNOT_NULL);
}
if (!key_exists("nid", $postData) || empty($postData["nid"])) {
throw new Exception("便签id不能为空", Errors::NOTE_ID_CONNOT_NULL);
}
// 检查用户是否存在
$sql = "select count(1) 'count' from user "
. "where uid = :uid ";
$sm = $this->_db->prepare($sql);
$sm->bindParam(":uid", $postData["uid"]);
if (!$sm->execute()) {
throw new Exception("sql语句执行出错", Errors::SQL_EXECUTE_ERROR);
}
else {
$returnData = $sm->fetch(PDO::FETCH_ASSOC);
if (empty($returnData["count"])) {
throw new Exception("用户不存在", Errors::USER_IS_NOT_EXISTS);
}
}
// 检查便签是否存在
$sql = "select count(1) 'count' from note "
. "where uid = :uid "
. "and nid = :nid ";
$sm = $this->_db->prepare($sql);
$sm->bindParam(":uid", $postData["uid"]);
$sm->bindParam(":nid", $postData["nid"]);
if (!$sm->execute()) {
throw new Exception("sql语句执行出错", Errors::SQL_EXECUTE_ERROR);
}
else {
$returnData = $sm->fetch(PDO::FETCH_ASSOC);
if (empty($returnData["count"])) {
throw new Exception("便签不存在", Errors::NOTE_IS_NOT_EXISTS);
}
}
// 删除便签
$sql = "delete from note "
. "where uid = :uid "
. "and nid = :nid ";
$sm = $this->_db->prepare($sql);
$sm->bindParam(":uid", $postData["uid"]);
$sm->bindParam(":nid", $postData["nid"]);
if (!$sm->execute()) {
throw new Exception("sql语句执行出错", Errors::SQL_EXECUTE_ERROR);
}
else {
Tools::printJson("删除成功", Errors::OK);
}
}
}
// 下面引入资源类
require_once './class/Rest.php';
require_once './class/User.php'; // 引入User类
require_once './class/Note.php'; // 引入Note类
//
// 下面创建资源对象
$db = require_once './lib/db.php';
$user = new User($db); // 创建User资源类对象
$note = new Note($db); // 创建Note资源类对象
// 创建启动类对象,并启动
$api = new Rest($db, $user, $note);
$api->run();
require_once __DIR__.'/Errors.php';
require_once __DIR__.'/Tools.php';
/**
* Description of Rest
*
* @author 1
*/
class Rest {
// 设置允许的请求方法和资源
private $_allowMethod = ["GET", "POST"];
private $_allowResource = ["user", "note"];
// 请求的方法、资源、功能
private $_requestMethod;
private $_requestResource;
private $_requestFunction;
// 资源类对象
private $_db;
private $_user;
private $_note;
/**
* 构造函数
* @param PDO $db
*/
public function __construct(PDO $db, User $user, Note $note) {
$this->_db = $db;
$this->_user = $user;
$this->_note = $note;
}
/**
* api启动方法
*/
public function run() {
try {
// 获取并检查请求的方法和资源
$this->setRequestMethod();
$this->setRequestResource();
// 根据请求的资源分发请求,交给对应的资源类处理
switch ($this->_requestResource) {
case "user": {
$this->sendUser();
break;
}
case "note": {
$this->sendNote();
break;
}
default : {
Tools::printJson("请求内容为空", Errors::REQUEST_IS_NULL);
}
}
} catch (Exception $exc) {
Tools::printJson($exc->getMessage(), $exc->getCode());
}
}
/**
* 处理便签业务
* @throws Exception
*/
private function sendNote() {
switch ($this->_requestMethod) {
case "POST": {
switch ($this->_requestFunction) {
case "buildDb": {
$this->_note->buildDb();
break;
}
case "add": {
$this->_note->add();
break;
}
case "editByNid": {
$this->_note->editByNid();
break;
}
case "viewListByUid": {
$this->_note->viewListByUid($this->getBody());
break;
}
case "viewByNid": {
$this->_note->viewByNid($this->getBody());
break;
}
case "delById": {
$this->_note->delById($this->getBody());
break;
}
default : {
Tools::printJson("请求功能不存在", Errors::REQUEST_FUNCTION_IS_ERROR);
}
}
break;
}
default: {
throw new Exception("该资源没有此方法的接口", Errors::REQUEST_METHOD_IS_ERROR);
}
}
}
/**
* 处理用户业务
* @throws Exception
*/
private function sendUser() {
switch ($this->_requestMethod) {
case "POST": {
switch ($this->_requestFunction) {
case "buildDb": {
$this->_user->buildDb();
break;
}
case "register": {
$this->_user->register($this->getBody());
break;
}
case "login": {
$this->_user->login($this->getBody());
break;
}
case "editPass": {
$this->_user->editPass($this->getBody());
break;
}
case "logout": {
$this->_user->logout($this->getBody());
break;
}
default : {
Tools::printJson("请求功能不存在", Errors::REQUEST_FUNCTION_IS_ERROR);
}
}
break;
}
default: {
throw new Exception("该资源没有此方法的接口", Errors::REQUEST_METHOD_IS_ERROR);
}
}
}
/**
* 获取post提交的数据
* @return type array
* @throws Exception 请求参数错误
*/
private function getBody() {
// 获取post请求提交的信息
$postData = file_get_contents("PHP://input");
// post请求提交的参数不能为空
if (empty($postData))
{
throw new Exception("请求参数错误", Errors::REQUEST_PARAMETER_ERROR);
}
// 将获取的请求参数进行json解码,用于后续操作
return json_decode($postData, true);
}
/**
* 获取并检查请求的方法
* @throws Exception 请求方法不被允许
*/
private function setRequestMethod() {
// 获取请求方法
$this->_requestMethod = $_SERVER["REQUEST_METHOD"];
// 检查请求方法是否被允许
if (!in_array($this->_requestMethod, $this->_allowMethod))
{
throw new Exception("请求方法不被允许", Errors::REQUEST_METHOD_NOT_ALLOWED);
}
}
/**
* 获取请求的资源、功能
* @throws Exception 请求资源不被允许
*/
private function setRequestResource() {
// 若访问的rl为http://localhost/notes/user/login,则$_SERVER["PATH_INFO"]为 /user/login
$path = $_SERVER["PATH_INFO"];
$params = explode('/', $path);
$this->_requestResource = $params[1];
if (!in_array($this->_requestResource, $this->_allowResource))
{
throw new Exception("请求资源不被允许", Errors::REQUEST_RESOUTCE_NOT_ALLOWED);
}
if (!empty($params[2]))
{
$this->_requestFunction = $params[2];
}
}
}