Last active
December 20, 2024 15:03
-
-
Save hoangsonww/41eeb072773417e4feec3489a5fcaab2 to your computer and use it in GitHub Desktop.
A single-file PHP backend for a Blog Management API with user authentication, role-based access control, and CRUD operations for posts and comments using SQLite.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| // Enable CORS and set content type | |
| header('Access-Control-Allow-Origin: *'); | |
| header('Content-Type: application/json'); | |
| // SQLite database connection | |
| $db = new PDO('sqlite:blog.db'); | |
| $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); | |
| // Initialize tables | |
| function initializeDatabase($db) { | |
| $db->exec("CREATE TABLE IF NOT EXISTS users ( | |
| id INTEGER PRIMARY KEY AUTOINCREMENT, | |
| username TEXT NOT NULL UNIQUE, | |
| password TEXT NOT NULL, | |
| role TEXT NOT NULL CHECK (role IN ('admin', 'author')) | |
| )"); | |
| $db->exec("CREATE TABLE IF NOT EXISTS posts ( | |
| id INTEGER PRIMARY KEY AUTOINCREMENT, | |
| title TEXT NOT NULL, | |
| content TEXT NOT NULL, | |
| author_id INTEGER NOT NULL, | |
| created_at TEXT DEFAULT CURRENT_TIMESTAMP, | |
| FOREIGN KEY (author_id) REFERENCES users(id) | |
| )"); | |
| $db->exec("CREATE TABLE IF NOT EXISTS comments ( | |
| id INTEGER PRIMARY KEY AUTOINCREMENT, | |
| post_id INTEGER NOT NULL, | |
| author_id INTEGER NOT NULL, | |
| content TEXT NOT NULL, | |
| created_at TEXT DEFAULT CURRENT_TIMESTAMP, | |
| FOREIGN KEY (post_id) REFERENCES posts(id), | |
| FOREIGN KEY (author_id) REFERENCES users(id) | |
| )"); | |
| } | |
| initializeDatabase($db); | |
| // Authentication functions | |
| function generateToken($username) { | |
| return base64_encode($username . '.' . time()); | |
| } | |
| function verifyToken($token) { | |
| $decoded = base64_decode($token); | |
| if ($decoded) { | |
| $parts = explode('.', $decoded); | |
| return (count($parts) === 2) ? $parts[0] : false; | |
| } | |
| return false; | |
| } | |
| // Response helper function | |
| function sendResponse($status_code, $data) { | |
| http_response_code($status_code); | |
| echo json_encode($data); | |
| exit; | |
| } | |
| // Route handling | |
| $method = $_SERVER['REQUEST_METHOD']; | |
| $path = explode('/', trim($_SERVER['PATH_INFO'], '/')); | |
| $input = json_decode(file_get_contents('php://input'), true); | |
| // Handle user registration | |
| if ($method === 'POST' && $path[0] === 'register') { | |
| $username = $input['username'] ?? null; | |
| $password = $input['password'] ?? null; | |
| $role = $input['role'] ?? 'author'; | |
| if (!$username || !$password || !in_array($role, ['admin', 'author'])) { | |
| sendResponse(400, ['error' => 'Invalid input']); | |
| } | |
| $hashedPassword = password_hash($password, PASSWORD_BCRYPT); | |
| try { | |
| $stmt = $db->prepare("INSERT INTO users (username, password, role) VALUES (?, ?, ?)"); | |
| $stmt->execute([$username, $hashedPassword, $role]); | |
| sendResponse(201, ['message' => 'User registered successfully']); | |
| } catch (PDOException $e) { | |
| sendResponse(400, ['error' => 'Username already exists']); | |
| } | |
| // Handle user login | |
| } elseif ($method === 'POST' && $path[0] === 'login') { | |
| $username = $input['username'] ?? null; | |
| $password = $input['password'] ?? null; | |
| if (!$username || !$password) { | |
| sendResponse(400, ['error' => 'Invalid input']); | |
| } | |
| $stmt = $db->prepare("SELECT * FROM users WHERE username = ?"); | |
| $stmt->execute([$username]); | |
| $user = $stmt->fetch(PDO::FETCH_ASSOC); | |
| if ($user && password_verify($password, $user['password'])) { | |
| $token = generateToken($username); | |
| sendResponse(200, ['token' => $token, 'role' => $user['role']]); | |
| } else { | |
| sendResponse(401, ['error' => 'Invalid credentials']); | |
| } | |
| // Handle creating a new post | |
| } elseif ($method === 'POST' && $path[0] === 'posts') { | |
| $token = $_SERVER['HTTP_AUTHORIZATION'] ?? ''; | |
| $username = verifyToken($token); | |
| if (!$username) { | |
| sendResponse(401, ['error' => 'Unauthorized']); | |
| } | |
| $stmt = $db->prepare("SELECT * FROM users WHERE username = ?"); | |
| $stmt->execute([$username]); | |
| $user = $stmt->fetch(PDO::FETCH_ASSOC); | |
| if ($user['role'] !== 'author' && $user['role'] !== 'admin') { | |
| sendResponse(403, ['error' => 'Forbidden']); | |
| } | |
| $title = $input['title'] ?? null; | |
| $content = $input['content'] ?? null; | |
| if (!$title || !$content) { | |
| sendResponse(400, ['error' => 'Invalid input']); | |
| } | |
| $stmt = $db->prepare("INSERT INTO posts (title, content, author_id) VALUES (?, ?, ?)"); | |
| $stmt->execute([$title, $content, $user['id']]); | |
| sendResponse(201, ['message' => 'Post created successfully']); | |
| // Handle retrieving all posts | |
| } elseif ($method === 'GET' && $path[0] === 'posts') { | |
| $stmt = $db->query("SELECT posts.id, posts.title, posts.content, users.username as author, posts.created_at | |
| FROM posts JOIN users ON posts.author_id = users.id"); | |
| $posts = $stmt->fetchAll(PDO::FETCH_ASSOC); | |
| sendResponse(200, $posts); | |
| // Handle creating a comment | |
| } elseif ($method === 'POST' && $path[0] === 'comments') { | |
| $token = $_SERVER['HTTP_AUTHORIZATION'] ?? ''; | |
| $username = verifyToken($token); | |
| if (!$username) { | |
| sendResponse(401, ['error' => 'Unauthorized']); | |
| } | |
| $stmt = $db->prepare("SELECT * FROM users WHERE username = ?"); | |
| $stmt->execute([$username]); | |
| $user = $stmt->fetch(PDO::FETCH_ASSOC); | |
| $postId = $input['post_id'] ?? null; | |
| $content = $input['content'] ?? null; | |
| if (!$postId || !$content) { | |
| sendResponse(400, ['error' => 'Invalid input']); | |
| } | |
| $stmt = $db->prepare("INSERT INTO comments (post_id, author_id, content) VALUES (?, ?, ?)"); | |
| $stmt->execute([$postId, $user['id'], $content]); | |
| sendResponse(201, ['message' => 'Comment added successfully']); | |
| // Handle retrieving comments for a specific post | |
| } elseif ($method === 'GET' && $path[0] === 'comments' && isset($path[1])) { | |
| $postId = $path[1]; | |
| $stmt = $db->prepare("SELECT comments.id, comments.content, users.username as author, comments.created_at | |
| FROM comments JOIN users ON comments.author_id = users.id | |
| WHERE comments.post_id = ?"); | |
| $stmt->execute([$postId]); | |
| $comments = $stmt->fetchAll(PDO::FETCH_ASSOC); | |
| sendResponse(200, $comments); | |
| // Handle invalid endpoints | |
| } else { | |
| sendResponse(405, ['error' => 'Method not allowed or invalid endpoint']); | |
| } | |
| ?> |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Blog Management API
A simple yet comprehensive PHP backend for a Blog Management API that allows user registration, login, role-based access control, and CRUD operations for blog posts and comments. This backend uses an SQLite database and is implemented in a single PHP file.
Features
Setup Instructions
Requirements
Installation
Download or Clone the Gist
Download the
blog-api.phpfile or clone this Gist to your local machine.Run the PHP Server
Navigate to the directory containing
blog-api.phpand run the PHP development server:This command will start the server at
http://localhost:8000.API Endpoints
1. Register User
POST /registeradminorauthor.{ "username": "user1", "password": "password123", "role": "author" }2. Login User
POST /login{ "username": "user1", "password": "password123" }3. Create a Blog Post
POST /postsAuthorizationheader with a valid token.Authorization:Bearer <token>{ "title": "My First Post", "content": "This is the content of the post." }4. Retrieve All Blog Posts
GET /posts5. Create a Comment
POST /commentsAuthorizationheader with a valid token.Authorization:Bearer <token>{ "post_id": 1, "content": "This is a comment on the post." }6. Retrieve Comments for a Specific Post
GET /comments/{post_id}Usage Examples
1. Register a New User
Use a tool like Postman or
curlto send aPOSTrequest to register a new user.2. Login as a User
Send a
POSTrequest to login as a user and obtain an authentication token.3. Create a New Post
Send a
POSTrequest to create a new blog post using the token obtained from the login.Error Handling
The API returns appropriate HTTP status codes and JSON error messages for different error scenarios:
Security Considerations
bcrypt.Contributing
Feel free to fork this Gist and contribute by submitting pull requests with improvements or additional features.
License
This project is open-source and available under the MIT License.