前一部分如何使用PHP,Slim和MySQL创建REST API,我们已经学习了有关REST API的基本概念,并通过安装所需的工具来准备好您的开发环境。我希望每个人都对REST和其他技术领域有很好的了解。另外我假设你已经安装了所有必需的工具。
今天我们将学习如何设置PHP项目并编写REST API的实际代码。我们还将学习编写必要的SQL查询来执行数据库CRUD操作。
8.启动PHP项目
众所周知,IDE使开发过程更容易。因此,我建议您使用IDE来开发PHP项目,而不是使用普通的记事本。你可以去Eclipse,Aptana Studio,PhpStorm或Netbeans。PHP项目目录结构
下图将让您了解我们现在要开发的项目的目录结构。
libs – 所有第三方库都在这里。在我们的例子中,我们将Slim库放在这里
include – 我们构建的所有助手类都放在这里
index.php – 负责所有API请求
.htaccess – url结构规则和其他apache规则
现在让我们开始PHP项目
1)转到安装 wamp 的目录。通常,wamp将安装在C:\ wamp中。(如果您安装了任何其他软件而不是WAMP,则应该转到该软件推荐的目录)。
2)作为第一步,我们开始创建所需的目录。在wamp文件夹中,转到www文件夹(c:\ wamp \ www \)并创建一个名为task_manager的文件夹。该文件夹将是我们项目的父目录。在task_manager内部再创建两个名为libs,include和v1的文件夹。
3)现在,粘贴Slim库里面的库文件夹。Slim的下载链接在前一部分中提供。
4)通常,当index.php包含在url中时,Slim框架会起作用,这会使url格式不正确。因此,使用.htacess规则,我们可以从url中删除index.php并制作一些友好的URL。在v1文件夹中创建一个名为.htaccess的文件并粘贴以下代码。(请注意,此文件名不应包含名称中的任何其他扩展名,例如.txt)
9准备助手类
首先,我们开始编写此项目中所需的一组辅助类。这些辅助类提供了与数据库交互所需的必要功能。
1)内部包含文件夹创建名为Config.php的文件,其中包含以下内容。此文件包含整个项目配置,如数据库连接参数和其他变量。
config.php文件
/**
* Database configuration
*/
define (‘DB_USERNAME’, ‘root’);
define(‘DB_PASSWORD’, ”);
define(‘DB_HOST’, ‘localhost’);
define(‘DB_NAME’, ‘task_manager’);
define(‘USER_CREATED_SUCCESSFULLY’, 0);
define(‘USER_CREATE_FAILED’, 1);
define(‘USER_ALREADY_EXISTED’, 2);
?>
2)创建另一个名为 DbConnect.php的 类此类文件主要负责数据库连接。
DbConnect.php
/**
* Handling database connection
*
* @author Ravi Tamada
*/
class DbConnect {
private $conn;
function __construct() {
}
/**
* Establishing database connection
* @return database connection handler
*/
function connect() {
include_once dirname(__FILE__) . ‘./Config.php’;
// Connecting to mysql database
$this->conn = new mysqli(DB_HOST, DB_USERNAME, DB_PASSWORD, DB_NAME);
// Check for database connection error
if (mysqli_connect_errno()) {
echo “Failed to connect to MySQL: ” . mysqli_connect_error();
}
// returing connection resource
return $this->conn;
}
}
?>
3)加密密码
保护用户密码的最佳方法是不将它们存储为纯文本,而是在存储到db之前对所有密码进行加密。以下类负责加密用户密码。创建另一个名为PassHash.php的文件并粘贴以下代码。
PassHash.php
class PassHash {
// blowfish
private static $algo = ‘$2a’;
// cost parameter
private static $cost = ‘$10’;
// mainly for internal use
public static function unique_salt() {
return substr(sha1(mt_rand()), 0, 22);
}
// this will be used to generate a hash
public static function hash($password) {
return crypt($password, self::$algo .
self::$cost .
‘$’ . self::unique_salt());
}
// this will be used to compare a password against a hash
public static function check_password($hash, $password) {
$full_salt = substr($hash, 0, 29);
$new_hash = crypt($password, $full_salt);
return ($hash == $new_hash);
}
}
?>
4)现在创建另一个名为DbHandler.php的类。该类是我们项目中的重要文件之一,它提供了对数据库执行CRUD操作所必需的功能。每个函数都由它的名称和注释自我解释,我不必解释它们。
DbHandler.php
/**
* Class to handle all db operations
* This class will have CRUD methods for database tables
*
* @author Ravi Tamada
*/
class DbHandler {
private $conn;
function __construct() {
require_once dirname(__FILE__) . ‘./DbConnect.php’;
// opening db connection
$db = new DbConnect();
$this->conn = $db->connect();
}
/* ————- `users` table method —————— */
/**
* Creating new user
* @param String $name User full name
* @param String $email User login email id
* @param String $password User login password
*/
public function createUser($name, $email, $password) {
require_once ‘PassHash.php’;
$response = array();
// First check if user already existed in db
if (!$this->isUserExists($email)) {
// Generating password hash
$password_hash = PassHash::hash($password);
// Generating API key
$api_key = $this->generateApiKey();
// insert query
$stmt = $this->conn->prepare(“INSERT INTO users(name, email, password_hash, api_key, status) values(?, ?, ?, ?, 1)”);
$stmt->bind_param(“ssss”, $name, $email, $password_hash, $api_key);
$result = $stmt->execute();
$stmt-> close ();
// Check for successful insertion
if ($result) {
// User successfully inserted
return USER_CREATED_SUCCESSFULLY;
} else {
// Failed to create user
return USER_CREATE_FAILED;
}
} else {
// User with same email already existed in the db
return USER_ALREADY_EXISTED;
}
return $response;
}
/**
* Checking user login
* @param String $email User login email id
* @param String $password User login password
* @return boolean User login status success/fail
*/
public function checkLogin($email, $password) {
// fetching user by email
$stmt = $this->conn->prepare(“SELECT password_hash FROM users WHERE email = ?”);
$stmt->bind_param(“s”, $email);
$stmt->execute();
$stmt->bind_result($password_hash);
$stmt->store_result();
if ($stmt->num_rows > 0) {
// Found user with the email
// Now verify the password
$stmt->fetch();
$stmt->close();
if (PassHash::check_password($password_hash, $password)) {
// User password is correct
return TRUE;
} else {
// user password is incorrect
return FALSE;
}
} else {
$stmt->close();
// user not existed with the email
return FALSE;
}
}
/**
* Checking for duplicate user by email address
* @param String $email email to check in db
* @return boolean
*/
private function isUserExists($email) {
$stmt = $this->conn->prepare(“SELECT id from users WHERE email = ?”);
$stmt->bind_param(“s”, $email);
$stmt->execute();
$stmt->store_result();
$num_rows = $stmt->num_rows;
$stmt->close();
return $num_rows > 0;
}
/**
* Fetching user by email
* @param String $email User email id
*/
public function getUserByEmail($email) {
$stmt = $this->conn->prepare(“SELECT name, email, api_key, status, created_at FROM users WHERE email = ?”);
$stmt->bind_param(“s”, $email);
if ($stmt->execute()) {
$user = $stmt->get_result()->fetch_assoc();
$stmt->close();
return $user;
} else {
return NULL;
}
}
/**
* Fetching user api key
* @param String $user_id user id primary key in user table
*/
public function getApiKeyById($user_id) {
$stmt = $this->conn->prepare(“SELECT api_key FROM users WHERE id = ?”);
$stmt->bind_param(“i”, $user_id);
if ($stmt->execute()) {
$api_key = $stmt->get_result()->fetch_assoc();
$stmt->close();
return $api_key;
} else {
return NULL;
}
}
/**
* Fetching user id by api key
* @param String $api_key user api key
*/
public function getUserId($api_key) {
$stmt = $this->conn->prepare(“SELECT id FROM users WHERE api _key = ?”);
$stmt->bind_param(“s”, $api_key);
if ($stmt->execute()) {
$user_id = $stmt->get_result()->fetch_assoc();
$stmt->close();
return $user_id;
} else {
return NULL;
}
}
/**
* Validating user api key
* If the api key is there in db, it is a valid key
* @param String $api_key user api key
* @return boolean
*/
public function isValidApiKey($api_key) {
$stmt = $this->conn->prepare(“SELECT id from users WHERE api_key = ?”);
$stmt->bind_param(“s”, $api_key);
$stmt->execute();
$stmt->store_result();
$num_rows = $stmt->num_rows;
$stmt->close();
return $num_rows > 0;
}
/**
* Generating random Unique MD5 String for user Api key
*/
private function generateApiKey() {
return md5(uniqid(rand(), true));
}
/* ————- `tasks` table method —————— */
/**
* Creating new task
* @param String $user_id user id to whom task belongs to
* @param String $task task text
*/
public function createTask($user_id, $task) {
$stmt = $this->conn->prepare(“INSERT INTO tasks(task) VALUES(?)”);
$stmt->bind_param(“s”, $task);
$result = $stmt->execute();
$stmt->close();
if ($result) {
// task row created
// now assign the task to user
$new_task_id = $this->conn->insert_id;
$res = $this->createUserTask($user_id, $new_task_id);
if ($res) {
// task created successfully
return $new_task_id;
} else {
// task failed to create
return NULL;
}
} else {
// task failed to create
return NULL;
}
}
/**
* Fetching single task
* @param String $task_id id of the task
*/
public function getTask($task_id, $user_id) {
$stmt = $this->conn->prepare(“SELECT t.id, t.task, t.status, t.created_at from tasks t, user_tasks ut WHERE t.id = ? AND ut.task_id = t.id AND ut.user_id = ?”);
$stmt->bind_param(“ii”, $task_id, $user_id);
if ($stmt->execute()) {
$task = $stmt->get_result()->fetch_assoc();
$stmt->close();
return $task;
} else {
return NULL;
}
}
/**
* Fetching all user tasks
* @param String $user_id id of the user
*/
public function getAllUserTasks($user_id) {
$stmt = $this->conn->prepare(“SELECT t.* FROM tasks t, user_tasks ut WHERE t.id = ut.task_id AND ut.user_id = ?”);
$stmt->bind_param(“i”, $user_id);
$stmt->execute();
$tasks = $stmt->get_result();
$stmt->close();
return $tasks;
}
/**
* Updating task
* @param String $task_id id of the task
* @param String $task task text
* @param String $status task status
*/
public function updateTask($user_id, $task_id, $task, $status) {
$stmt = $this->conn->prepare(“UPDATE tasks t, user_tasks ut set t.task = ?, t.status = ? WHERE t.id = ? AND t.id = ut.task_id AND ut.user_id = ?”);
$stmt->bind_param(“siii”, $task, $status, $task_id, $user_id);
$stmt->execute();
$num_affected_rows = $stmt->affected_rows;
$stmt->close();
return $num_affected_rows > 0;
}
/**
* Deleting a task
* @param String $task_id id of the task to delete
*/
public function deleteTask($user_id, $task_id) {
$stmt = $this->conn->prepare(“DELETE t FROM tasks t, user_tasks ut WHERE t.id = ? AND ut.task_id = t.id AND ut.user_id = ?”);
$stmt->bind_param(“ii”, $task_id, $user_id);
$stmt->execute();
$num_affected_rows = $stmt->affected_rows;
$stmt->close();
return $num_affected_rows > 0;
}
/* ————- `user_tasks` table method —————— */
/**
* Function to assign a task to user
* @param String $user_id id of the user
* @param String $task_id id of the task
*/
public function createUserTask($user_id, $task_id) {
$stmt = $this->conn->prepare(“INSERT INTO user_tasks(user_id, task_id) values(?, ?)”);
$stmt->bind_param(“ii”, $user_id, $task_id);
$result = $stmt->execute();
$stmt->close();
return $result;
}
}
?>
10.处理API调用
现在我们拥有REST API所需的所有类。现在我们可以启动代码来处理所有单独的api调用。
在v1文件夹中创建一个名为index.php的文件并添加以下代码。这里我们包括必需的库和其他辅助函数。
verifyRequiredParams() – 此函数验证请求中的必需参数。
validateEmail() – 验证电子邮件地址是否有效。
echoRespnse() – 此函数将使用状态代码回显 json 响应。
require_once ‘../include/DbHandler.php’;
require_once ‘../include/PassHash.php’;
require ‘.././libs/Slim/Slim/Slim.php’;
\Slim\Slim::registerAutoloader();
$app = new \Slim\Slim();
// User id from db – Global Variable
$user_id = NULL;
/**
* Verifying required params posted or not
*/
function verifyRequiredParams($required_fields) {
$error = false;
$error_fields = “”;
$request_params = array();
$request_params = $_REQUEST;
// Handling PUT request params
if ($_SERVER[‘REQUEST_METHOD’] == ‘PUT’) {
$app = \Slim\Slim:: getInstance ();
parse_str($app->request()->getBody(), $request_params);
}
foreach ($required_fields as $field) {
if (!isset($request_params[$field]) || strlen(trim($request_params[$field])) <= 0) {
$error = true;
$error_fields .= $field . ‘, ‘;
}
}
if ($error) {
// Required field(s) are missing or empty
// echo error json and stop the app
$response = array();
$app = \Slim\Slim::getInstance();
$response[“error”] = true;
$response[” message “] = ‘Required field(s) ‘ . substr($error_fields, 0, -2) . ‘ is missing or empty’;
echoRespnse(400, $response);
$app->stop();
}
}
/**
* Validating email address
*/
function validateEmail($email) {
$app = \Slim\Slim::getInstance();
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$response[“error”] = true;
$response[“message”] = ‘Email address is not valid’;
echoRespnse(400, $response);
$app->stop();
}
}
/**
* Echoing json response to client
* @param String $status_code Http response code
* @param Int $response Json response
*/
function echoRespnse($status_code, $response) {
$app = \Slim\Slim::getInstance();
// Http response code
$app->status($status_code);
// setting response content type to json
$app->contentType(‘application/json’);
echo json_encode($response);
}
$app->run();
?>
11.用户注册
为了与API交互,用户必须首先在我们的系统中注册。一旦他注册了API密钥,就会生成并存储在数据库中。此API密钥仅对该用户是私有的。
在index.php中添加以下代码。此功能处理用户注册。
在下表中,您可以找到有关URL,HTTP方法和需要发布的参数的API请求信息。
URL /register
Method POST
Params name, email, password
成功注册后,将发布以下json响应。
{
“error”: false,
“message”: “You are successfully registered”
}
结果:
如果请求缺少必需参数,则将发出以下json。
{
“error”: true,
“message”: “Required field(s) email, password is missing or empty”
}
结果:
12.用户登录
添加以下代码以处理用户登录。验证用户凭据后,将在json响应中发出该用户的API密钥。在所有剩余的api调用中,api密钥应包含在请求头中。
index.php
/**
* User Login
* url – /login
* method – POST
* params – email, password
*/
$app->post(‘/login’, function() use ($app) {
// check for required params
verifyRequiredParams(array(’email’, ‘password’));
// reading post params
$email = $app->request()->post(’email’);
$password = $app->request()->post(‘password’);
$response = array();
$db = new DbHandler();
// check for correct email and password
if ($db->checkLogin($email, $password)) {
// get the user by email
$user = $db->getUserByEmail($email);
if ($user != NULL) {
$response[“error”] = false;
$response[‘name’] = $user[‘name’];
$response[’email’] = $user[’email’];
$response[‘apiKey’] = $user[‘api_key’];
$response[‘createdAt’] = $user[‘created_at’];
} else {
// unknown error occurred
$response[‘error’] = true;
$response[‘message’] = “An error occurred. Please try again”;
}
} else {
// user credentials are wrong
$response[‘error’] = true;
$response[‘message’] = ‘Login failed. Incorrect credentials’;
}
echoRespnse(200, $response);
});
URL /login
Method POST
Params email, password
成功登录后,将发布以下json。
{
“error”: false,
“name”: “zhangsa”,
“email”: “123@qq.com”,
“apiKey”: “22d575d8c31a11b070c5eb519bbd1d3b”,
“createdAt”: “2019-04-07 16:38:28”
}
结果:
如果凭据错误,您可以期待以下json。
{
“error”: true,
“message”: “Login failed. Incorrect credentials”
}
13.验证API密钥
在处理任务数据时,我们需要通过阅读授权字段来使用请求标头中的API密钥来识别用户。基本上我们将查看匹配的API密钥的数据库并获取适当的用户。如果用户表中没有API密钥,那么我们将停止执行并回显错误json。
在index.php中添加以下方法。每次在对数据库执行任何相关操作之前,都会执行authenticate()方法。
index.php
/**
* Adding Middle Layer to authenticate every request
* Checking if the request has valid api key in the ‘Authorization’ header
*/
function authenticate(\Slim\Route $route) {
// Getting request headers
$headers = apache_request_headers();
$response = array();
$app = \Slim\Slim::getInstance();
// Verifying Authorization Header
if (isset($headers[‘Authorization’])) {
$db = new DbHandler();
// get the api key
$api_key = $headers[‘Authorization’];
// validating api key
if (!$db->isValidApiKey($api_key)) {
// api key is not present in users table
$response[“error”] = true;
$response[“message”] = “Access Denied. Invalid Api key”;
echoRespnse(401, $response);
$app->stop();
} else {
global $user_id;
// get user primary key id
$user = $db->getUserId($api_key);
if ($user != NULL)
$user_id = $user[“id”];
}
} else {
// api key is missing in header
$response[“error”] = true;
$response[“message”] = “Api key is misssing”;
echoRespnse(400, $response);
$app->stop();
}
}
如果请求标头中缺少api密钥,则将使用400状态代码回显以下json。
{
“error”: true,
“message”: “Api key is misssing”
}
如果api密钥无效,则json将回显401状态代码。
{
“error”: true,
“message”: “Access Denied. Invalid Api key”
}
Api通过身份验证调用(在请求中包含API密钥)
以下是API调用应在请求标头中具有Api密钥。这些api调用主要处理用户的任务数据,如创建,读取,更新和删除。
相关文章
本站已关闭游客评论,请登录或者注册后再评论吧~