Files
MSPE/api/news.php
T

274 lines
7.2 KiB
PHP
Executable File

<?php
/**
* MSPE News/Articles API
*/
require_once 'config.php';
$method = $_SERVER['REQUEST_METHOD'];
$id = $_GET['id'] ?? null;
switch ($method) {
case 'GET':
if ($id) {
getArticle($id);
} else {
getArticles();
}
break;
case 'POST':
requireAuth();
if (!empty($_POST['id'])) {
updateArticle($_POST['id']);
} else {
createArticle();
}
break;
case 'PUT':
requireAuth();
if (!$id) {
jsonResponse(['success' => false, 'message' => 'Article ID required'], 400);
}
updateArticle($id);
break;
case 'DELETE':
requireAuth();
if (!$id) {
jsonResponse(['success' => false, 'message' => 'Article ID required'], 400);
}
deleteArticle($id);
break;
default:
jsonResponse(['success' => false, 'message' => 'Method not allowed'], 405);
}
function getArticles() {
global $db;
$articles = $db->getAll('news');
// Apply filters
$category = $_GET['category'] ?? null;
$status = $_GET['status'] ?? null;
$limit = (int)($_GET['limit'] ?? 10);
$offset = (int)($_GET['offset'] ?? 0);
if ($category) {
$articles = array_filter($articles, function($a) use ($category) {
return $a['category'] === $category;
});
}
if ($status) {
$articles = array_filter($articles, function($a) use ($status) {
return $a['status'] === $status;
});
}
// Sort by date (newest first)
usort($articles, function($a, $b) {
return strtotime($b['created_at']) - strtotime($a['created_at']);
});
// For public API, only show published articles
if (!checkAuth()) {
$articles = array_filter($articles, function($a) {
return ($a['status'] ?? 'draft') === 'published';
});
}
$total = count($articles);
$articles = array_slice(array_values($articles), $offset, $limit);
jsonResponse([
'success' => true,
'data' => $articles,
'total' => $total,
'limit' => $limit,
'offset' => $offset
]);
}
function getArticle($id) {
global $db;
$article = $db->get('news', $id);
if (!$article) {
jsonResponse(['success' => false, 'message' => 'Article not found'], 404);
}
// Check if published or user is authenticated
if (($article['status'] ?? 'draft') !== 'published' && !checkAuth()) {
jsonResponse(['success' => false, 'message' => 'Article not found'], 404);
}
jsonResponse([
'success' => true,
'data' => $article
]);
}
function createArticle() {
global $db;
// Handle multipart form data or JSON
if (!empty($_FILES)) {
$data = $_POST;
} else {
$data = getRequestBody();
}
// Validate required fields
if (empty($data['title'])) {
jsonResponse(['success' => false, 'message' => 'Title is required'], 400);
}
// Sanitize text fields (allow safe HTML in content)
$data['title'] = sanitize($data['title']);
$data['excerpt'] = sanitize($data['excerpt'] ?? '');
$data['category'] = sanitize($data['category'] ?? '');
$data['author'] = sanitize($data['author'] ?? 'Admin');
// Sanitize rich content: strip dangerous tags/attributes while allowing formatting
if (!empty($data['content'])) {
$data['content'] = sanitizeRichText($data['content']);
}
// Handle image upload
if (!empty($_FILES['featured_image'])) {
$upload = handleFileUpload($_FILES['featured_image'], 'news');
if ($upload['success']) {
$data['featured_image'] = $upload['path'];
}
}
// Generate slug if not provided
if (empty($data['slug'])) {
$data['slug'] = generateSlug($data['title']);
} else {
$data['slug'] = generateSlug($data['slug']);
}
$data['slug'] = ensureUniqueNewsSlug($data['slug']);
// Set defaults
$data['status'] = $data['status'] ?? 'draft';
$data['author'] = $data['author'] ?? 'Admin';
$data['views'] = 0;
$article = $db->insert('news', $data);
jsonResponse([
'success' => true,
'message' => 'Article created successfully',
'data' => $article
], 201);
}
function updateArticle($id) {
global $db;
$existing = $db->get('news', $id);
if (!$existing) {
jsonResponse(['success' => false, 'message' => 'Article not found'], 404);
}
// Handle multipart form data or JSON
if (!empty($_FILES)) {
$data = $_POST;
} else {
$data = getRequestBody();
}
// Handle image upload
if (!empty($_FILES['featured_image'])) {
$upload = handleFileUpload($_FILES['featured_image'], 'news');
if ($upload['success']) {
$data['featured_image'] = $upload['path'];
}
}
// Update slug if title changed
if (!empty($data['title']) && empty($data['slug'])) {
$data['slug'] = generateSlug($data['title']);
} elseif (!empty($data['slug'])) {
$data['slug'] = generateSlug($data['slug']);
}
if (!empty($data['slug'])) {
$data['slug'] = ensureUniqueNewsSlug($data['slug'], $id);
}
// Sanitize text fields
if (!empty($data['title'])) $data['title'] = sanitize($data['title']);
if (!empty($data['excerpt'])) $data['excerpt'] = sanitize($data['excerpt']);
if (!empty($data['category'])) $data['category'] = sanitize($data['category']);
if (!empty($data['author'])) $data['author'] = sanitize($data['author']);
// Sanitize rich content: strip dangerous tags/attributes while allowing formatting
if (!empty($data['content'])) {
$data['content'] = sanitizeRichText($data['content']);
}
$article = $db->update('news', $id, $data);
jsonResponse([
'success' => true,
'message' => 'Article updated successfully',
'data' => $article
]);
}
function deleteArticle($id) {
global $db;
$existing = $db->get('news', $id);
if (!$existing) {
jsonResponse(['success' => false, 'message' => 'Article not found'], 404);
}
$db->delete('news', $id);
jsonResponse([
'success' => true,
'message' => 'Article deleted successfully'
]);
}
function generateSlug($title) {
$slug = strtolower($title);
$slug = preg_replace('/[^a-z0-9]+/', '-', $slug);
$slug = trim($slug, '-');
return $slug !== '' ? $slug : 'article';
}
function ensureUniqueNewsSlug($baseSlug, $excludeId = null) {
global $db;
$articles = $db->getAll('news');
$used = [];
foreach ($articles as $article) {
if (!empty($excludeId) && ($article['id'] ?? null) === $excludeId) {
continue;
}
$slug = (string)($article['slug'] ?? '');
if ($slug !== '') {
$used[$slug] = true;
}
}
if (!isset($used[$baseSlug])) {
return $baseSlug;
}
$i = 2;
while (isset($used[$baseSlug . '-' . $i])) {
$i++;
}
return $baseSlug . '-' . $i;
}