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; }