my-portfolio/dist/api/blog/blogData.php
rodude123 b4ab7900db added backend search functionality
Signed-off-by: rodude123 <rodude123@gmail.com>
2023-10-31 19:36:51 +00:00

465 lines
15 KiB
PHP

<?php
namespace api\blog;
use api\utils\imgUtils;
use DOMDocument;
use PDO;
use Psr\Http\Message\UploadedFileInterface;
require_once __DIR__ . "/../utils/config.php";
require_once __DIR__ . "/../utils/imgUtils.php";
/**
* Blog Data Class
* Define all functions which either get, update, create or delete posts
*/
class blogData
{
/**
* Get all blog posts
* @return array - Array of all blog posts or error message
*/
public function getBlogPosts(): array
{
$conn = dbConn();
$stmt = $conn->prepare("SELECT * FROM blog ORDER BY featured DESC, dateCreated DESC;");
$stmt->execute();
// set the resulting array to associative
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
if ($result)
{
return $result;
}
return array("errorMessage" => "Error, blog data not found");
}
/**
* Get a blog post with the given ID
* @param string $title - Title of the blog post
* @return array - Array of all blog posts or error message
*/
public function getBlogPost(string $title): array
{
$conn = dbConn();
$stmt = $conn->prepare("SELECT * FROM blog WHERE title = :title;");
$stmt->bindParam(":title", $title);
$stmt->execute();
// set the resulting array to associative
$result = $stmt->fetch(PDO::FETCH_ASSOC);
if ($result)
{
return $result;
}
return array("errorMessage" => "Error, blog post could not found");
}
/**
* Get the latest blog post
* @return array - Array of the latest blog post or error message
*/
public function getLatestBlogPost(): array
{
$conn = dbConn();
$stmt = $conn->prepare("SELECT * FROM blog ORDER BY dateCreated DESC LIMIT 1;");
$stmt->execute();
// set the resulting array to associative
$result = $stmt->fetch(PDO::FETCH_ASSOC);
if ($result)
{
return $result;
}
return array("errorMessage" => "Error, blog post could not found");
}
/**
* Get featured blog post
* @return array - Array of the featured blog post or error message
*/
public function getFeaturedBlogPost(): array
{
$conn = dbConn();
$stmt = $conn->prepare("SELECT * FROM blog WHERE featured = 1;");
$stmt->execute();
$result = $stmt->fetch(PDO::FETCH_ASSOC);
if ($result)
{
return $result;
}
return array("errorMessage" => "Error, blog post could not found");
}
/**
* Get all unique categories
* @return string[] - Array of all categories or error message
*/
public function getCategories(): array
{
$conn = dbConn();
$stmt = $conn->prepare("SELECT DISTINCT categories FROM blog;");
$stmt->execute();
// set the resulting array to associative
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
if ($result)
{
return $result;
}
return array("errorMessage" => "Error, blog post could not found");
}
/**
* Delete a blog post with the given ID
* @param int $ID - ID of the blog post to delete
* @return string - Success or error message
*/
public function deletePost(int $ID): string
{
$conn = dbConn();
$stmtCheckPost = $conn->prepare("SELECT * FROM blog WHERE ID = :ID");
$stmtCheckPost->bindParam(":ID", $ID);
$stmtCheckPost->execute();
$result = $stmtCheckPost->fetch(PDO::FETCH_ASSOC);
if (!$result)
{
return "post not found";
}
if ($result["featured"] === 1)
{
return "cannot delete";
}
$stmt = $conn->prepare("DELETE FROM blog WHERE ID = :ID");
$stmt->bindParam(":ID", $ID);
if ($stmt->execute())
{
$imagUtils = new imgUtils();
$imagUtils->deleteDirectory("../blog/imgs/" . $result["title"] . "_" . $result["folderID"] . "/");
return "success";
}
return "error";
}
/**
* Update the blog post with the given ID
* @param int $ID - ID of the blog post to update
* @param string $title - Title of the blog post
* @param bool $featured - Whether the blog post is featured or not
* @param string $abstract - Abstract of the blog post i.e. a short description
* @param string $body - Body of the blog post
* @param string $bodyText - Body of the blog post as plain text
* @param string $dateModified - Date the blog post was modified
* @param string $categories - Categories of the blog post
* @return bool|string - Success or error message
*/
public function updatePost(int $ID, string $title, bool $featured, string $abstract, string $body, string $bodyText, string $dateModified, string $categories): bool|string
{
$conn = dbConn();
$stmtCheckPost = $conn->prepare("SELECT * FROM blog WHERE ID = :ID");
$stmtCheckPost->bindParam(":ID", $ID);
$stmtCheckPost->execute();
$result = $stmtCheckPost->fetch(PDO::FETCH_ASSOC);
if (!$result)
{
return "post not found";
}
if (!$featured && $result["featured"] === 1)
{
return "unset feature";
}
if ($featured)
{
$stmtUnsetFeatured = $conn->prepare("UPDATE blog SET featured = 0 WHERE featured = 1;");
$stmtUnsetFeatured->execute();
}
$to = "../blog/imgs/" . $title . "_" . $result["folderID"] . "/";
if ($result["title"] !== $title)
{
$from = "../blog/imgs/" . $result["title"] . "_" . $result["folderID"] . "/";
mkdir($to, 0777, true);
rename($result["headerImg"], $to . basename($result["headerImg"]));
$body = $this->changeHTMLSrc($body, $to, $from);
rmdir($from);
}
$from = "../blog/imgs/tmp/";
$newBody = $this->changeHTMLSrc($body, $to, $from);
$stmt = $conn->prepare("UPDATE blog SET title = :title, featured = :featured, abstract = :abstract, body = :body, bodyText = :bodyText, dateModified = :dateModified, categories = :categories WHERE ID = :ID;");
$stmt->bindParam(":ID", $ID);
$stmt->bindParam(":title", $title);
$stmt->bindParam(":featured", $featured);
$stmt->bindParam(":abstract", $abstract);
$stmt->bindParam(":body", $newBody);
$stmt->bindParam(":bodyText", $bodyText);
$stmt->bindParam(":dateModified", $dateModified);
$stmt->bindParam(":categories", $categories);
return $stmt->execute();
}
/**
* Creates a new post di rectory, uploads the header image and moves the images from the
* temp folder to the new folder, then updates the post html to point to the new images, finally
* it creates the post in the database
* @param string $title - Title of the blog post
* @param string $abstract - Abstract of the blog post i.e. a short description
* @param string $body - Body of the blog post
* @param string $bodyText - Body of the blog post as plain text
* @param string $dateCreated - Date the blog post was created
* @param bool $featured - Whether the blog post is featured or not
* @param string $categories - Categories of the blog post
* @param UploadedFileInterface $headerImg - Header image of the blog post
* @return int|string - ID of the blog post or error message
*/
public function createPost(string $title, string $abstract, string $body, string $bodyText, string $dateCreated, bool $featured, string $categories, UploadedFileInterface $headerImg): int|string
{
$conn = dbConn();
$folderID = uniqid();
$targetFile = array("imgLocation" => "../blog/imgs/placeholder.png");
$targetDir = "../blog/imgs/" . $title . "_" . $folderID . "/";
mkdir($targetDir, 0777, true);
if ($headerImg !== null)
{
$imagUtils = new imgUtils();
$targetFile = $imagUtils->uploadFile($targetDir, $headerImg);
}
if (!is_array($targetFile))
{
return $targetFile;
}
$newBody = $this->changeHTMLSrc($body, $targetDir, "../blog/imgs/tmp/");
if ($featured)
{
$stmtMainProject = $conn->prepare("UPDATE blog SET featured = 0 WHERE featured = 1;");
$stmtMainProject->execute();
}
$stmt = $conn->prepare("INSERT INTO blog (title, dateCreated, dateModified, featured, headerImg, abstract, body, bodyText, categories, folderID)
VALUES (:title, :dateCreated, :dateModified, :featured, :headerImg, :abstract, :body, :bodyText, :categories, :folderID);");
$stmt->bindParam(":title", $title);
$stmt->bindParam(":dateCreated", $dateCreated);
$stmt->bindParam(":dateModified", $dateCreated);
$isFeatured = $featured ? 1 : 0;
$stmt->bindParam(":featured", $isFeatured);
$stmt->bindParam(":headerImg", $targetFile["imgLocation"]);
$stmt->bindParam(":abstract", $abstract);
$stmt->bindParam(":body", $newBody);
$stmt->bindParam(":bodyText", $bodyText);
$stmt->bindParam(":categories", $categories);
$stmt->bindParam(":folderID", $folderID);
if ($stmt->execute())
{
return intval($conn->lastInsertId());
}
return "Error, couldn't create post";
}
/**
* Upload the images in the post to temp folder and return image location
* @param UploadedFileInterface $img - Image to upload
* @return string|array - String with error message or array with the location of the uploaded file
*/
public function uploadPostImage(UploadedFileInterface $img): string|array
{
$targetDir = "../blog/imgs/tmp/";
$imagUtils = new imgUtils();
$targetFile = $imagUtils->uploadFile($targetDir, $img);
$file = $targetDir . basename($img->getClientFilename());
if (file_exists($file))
{
return array("url" => $file);
}
if (!is_array($targetFile))
{
return $targetFile;
}
if (file_exists($targetFile["imgLocation"]))
{
return array("url" => $targetFile["imgLocation"]);
}
return "Couldn't upload the image";
}
/**
* Upload the header image of the post and update the database
* @param int $ID - ID of the post
* @param UploadedFileInterface $img - Image to upload
* @return string|array - String with error message or array with the location of the uploaded file
*/
public function uploadHeaderImage(int $ID, UploadedFileInterface $img): string|array
{
$conn = dbConn();
$stmt = $conn->prepare("SELECT * FROM blog WHERE ID = :ID;");
$stmt->bindParam(":ID", $ID);
$stmt->execute();
$result = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$result)
{
return "Couldn't find the post";
}
$targetDir = "../blog/imgs/" . $result["title"] . "_" . $result["folderID"] . "/";
$imagUtils = new imgUtils();
$targetFile = $imagUtils->uploadFile($targetDir, $img);
if (!is_array($targetFile))
{
return $targetFile;
}
if (file_exists($targetFile["imgLocation"]))
{
unlink($result["headerImg"]);
$stmt = $conn->prepare("UPDATE blog SET headerImg = :headerImg WHERE ID = :ID;");
$stmt->bindParam(":ID", $ID);
$stmt->bindParam(":headerImg", $targetFile["imgLocation"]);
$stmt->execute();
if ($stmt->rowCount() > 0)
{
return $targetFile;
}
return "Couldn't update the post";
}
return "Couldn't upload the image";
}
/**
* Change the HTML src of the images in the post to point to the new location
* @param string $body - Body of the post
* @param string $to - New location of the images
* @param string $from - Old location of the images
* @return string - Body of the post with the new image locations
*/
public function changeHTMLSrc(string $body, string $to, string $from): string
{
$htmlDoc = new DOMDocument();
$htmlDoc->loadHTML($body, LIBXML_NOERROR);
$doc = $htmlDoc->getElementsByTagName('body')->item(0);
$imgs = $doc->getElementsByTagName('img');
$srcList = array();
foreach ($imgs as $img)
{
$src = $img->getAttribute("src");
$src = urldecode($src);
$srcList[] = $src;
$fileName = basename($src);
$img->setAttribute("src", substr($to, 2) . $fileName);
}
$files = scandir($from);
foreach ($files as $file)
{
if ($file != "." && $file != "..")
{
if (!in_array($from . $file, $srcList))
{
unlink($from . $file);
}
else
{
rename($from . $file, $to . $file);
}
}
}
$newBody = '';
foreach ($doc->childNodes as $node)
{
$newBody .= $htmlDoc->saveHTML($node);
}
return $newBody;
}
/**
* Get all posts with the given category
* @param string $category - Category of the post
* @return array - Array of all posts with the given category or error message
*/
public function getPostsByCategory(string $category): array
{
$conn = dbConn();
$stmt = $conn->prepare("SELECT * FROM blog WHERE LOCATE(:category, categories) > 0;");
$stmt->bindParam(":category", $category);
$stmt->execute();
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
/**
* Search for a blog post with the given search term
* @param string $searchTerm - Search term
* @return array - Array of all posts with the given search term or error message
*/
public function searchBlog(string $searchTerm): array
{
$conn = dbConn();
$stmt = $conn->prepare("SELECT * FROM blog WHERE MATCH(title, bodyText) AGAINST(:searchTerm IN NATURAL LANGUAGE MODE);");
$stmt->bindParam(":searchTerm", $searchTerm);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
if ($result)
{
$bodyText = array_column($result, "bodyText");
// go through each body plain text and get the sentence before, the sentence with the search term and the sentence after and append it to a new array
foreach ($bodyText as $key => $text)
{
$text = strtolower($text);
$searchTerm = strtolower($searchTerm);
$pos = strpos($text, $searchTerm);
$start = strrpos(substr($text, 0, $pos), ".") + 1;
$end = strpos($text, ".", $pos);
$result[$key]["bodyText"] = substr($text, $start, $end - $start);
}
return $result;
}
return array("errorMessage" => "Error, could not find posts");
}
}