diff --git a/README.md b/README.md index 2ede294..3e218ce 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ # fibable -A little PHP file-based blog engine. \ No newline at end of file +A little PHP file-based blog engine. + +This is a lightweight and not yet finished blog engine, written in PHP, working without database, only with directory structure and files and a sort of Markdown format. diff --git a/config.php b/config.php new file mode 100644 index 0000000..df4a2e0 --- /dev/null +++ b/config.php @@ -0,0 +1,14 @@ + "https://example.com" +]; diff --git a/css/blog.css b/css/blog.css new file mode 100644 index 0000000..87925bd --- /dev/null +++ b/css/blog.css @@ -0,0 +1,5 @@ +@charset "utf-8"; + +* { box-sizing: border-box; } + +body { font-family: sans-serif; } diff --git a/data/cache/default.phtml b/data/cache/default.phtml new file mode 100644 index 0000000..7947b73 --- /dev/null +++ b/data/cache/default.phtml @@ -0,0 +1,8 @@ +
+

L'article que vous cherchez n'existe pas

+ +
+

+ Il n'y a rien à voir ici ! Vous avez du vous tromper de chemin ! +

+ diff --git a/data/serial/default.pobj b/data/serial/default.pobj new file mode 100644 index 0000000..d1efe76 --- /dev/null +++ b/data/serial/default.pobj @@ -0,0 +1 @@ +O:7:"Article":5:{s:5:"title";s:40:"L'article que vous cherchez n'existe pas";s:4:"date";s:10:"2023-08-01";s:3:"ref";s:2:"01";s:4:"tags";a:2:{i:0;s:4:"blog";i:1;s:5:"essai";}s:4:"view";s:26:"./data/cache/default.phtml";} diff --git a/index.php b/index.php new file mode 100644 index 0000000..59f28e7 --- /dev/null +++ b/index.php @@ -0,0 +1,10 @@ +run(); diff --git a/lib/Article.php b/lib/Article.php new file mode 100644 index 0000000..8b3e3de --- /dev/null +++ b/lib/Article.php @@ -0,0 +1,17 @@ +view; + } + +} diff --git a/lib/ArticleDate.php b/lib/ArticleDate.php new file mode 100644 index 0000000..e9aecff --- /dev/null +++ b/lib/ArticleDate.php @@ -0,0 +1,14 @@ +str = $str; + } + +} diff --git a/lib/ArticleManager.php b/lib/ArticleManager.php new file mode 100644 index 0000000..39e8d7d --- /dev/null +++ b/lib/ArticleManager.php @@ -0,0 +1,118 @@ +articles[] = self::getArticle($file_path); + } + } + } + } + return $dates; + } + + private static function getArticle(string $file_path): Article + { + $pattern = "|(./data)/articles/([0-9]+)/([0-9]+)/([0-9]+)/([0-9]+)\.txt|"; + $replacement = "$1/serial/$2$3$4$5.pobj"; + $serial_path = preg_replace($pattern, $replacement, $file_path); + return file_exists($serial_path) ? + unserialize(file_get_contents($serial_path)) : + self::createArticle($file_path, $serial_path); + } + + private static function createArticle(string $file_path, string $serial_path): Article + { + $parser = new ArticleParser(); + $article = $parser->parse($file_path); + file_put_contents($serial_path, serialize($article)); + TagManager::add($article->tags, substr(basename($serial_path), 0, -5)); + return $article; + } +} diff --git a/lib/ArticleParser.php b/lib/ArticleParser.php new file mode 100644 index 0000000..45a1a20 --- /dev/null +++ b/lib/ArticleParser.php @@ -0,0 +1,122 @@ +$1"; + const REPLACE_ITALIC = "$1"; + const REPLACE_UNDERLINE = "$1"; + + private bool $in_p = false; + private array $content = []; + private array $p = []; + + public function parse(string $file_path): Article + { + $article = new Article(); + $article->date = preg_replace(self::PATTERN_DATE, self::REPLACE_DATE, $file_path); + $article->ref = preg_replace(self::PATTERN_DATE, self::REPLACE_REF, $file_path); + $lines = file($file_path, FILE_IGNORE_NEW_LINES); + foreach ($lines as $line) { + if (substr($line, 0, 2) === "# ") { + $article->title = substr($line, 2); + continue; + } + if (substr($line, 0, 3) === "## ") { + $this->closeParagraph(); + $this->content[] = "

" . substr($line, 3) . "

"; + continue; + } + if (substr($line, 0, 4) === "### ") { + $this->closeParagraph(); + $this->content[] = "

" . substr($line, 4) . "

"; + continue; + } + if (substr($line, 0, 5) === "#### ") { + $this->closeParagraph(); + $this->content[] = "
" . substr($line, 5) . "
"; + continue; + } + if (preg_match(self::PATTERN_TAGS, $line, $matches)) { + $article->tags = explode(",", $matches[1]); + continue; + } + if (preg_match(self::PATTERN_IMG, $line, $matches)) { + $this->closeParagraph(); + $this->content[] = "
"; + $this->content[] = " \"$matches[3]\""; + $this->content[] = "
$matches[3]
"; + $this->content[] = "
"; + continue; + } + if ($line === "") { + $this->closeParagraph(); + continue; + } else { + if (!$this->in_p) { + $this->content[] = "

"; + $this->in_p = true; + } + $this->p[] = $this->parseLine($line); + } + } + $this->closeParagraph(); + array_unshift($this->content, + "

", + "

" . $article->title . "

", + " ", + "
" + ); + $this->content[] = ""; + $view_path = "./data/cache/{$article->date}_{$article->ref}.phtml"; + file_put_contents($view_path, " " . implode("\n ", $this->content) . "\n"); + $article->view = $view_path; + $this->content = []; + return $article; + } + + private function closeParagraph() + { + if ($this->in_p) { + $this->content[] = " " . implode("
", $this->p); + $this->content[] = "

"; + $this->in_p = false; + $this->p = []; + } + } + + private function parseLine(string $line): string + { + $patterns = [ + self::PATTERN_BOLD, + self::PATTERN_ITALIC, + self::PATTERN_UNDERLINE + ]; + $replacements = [ + self::REPLACE_BOLD, + self::REPLACE_ITALIC, + self::REPLACE_UNDERLINE + ]; + return preg_replace($patterns, $replacements, htmlspecialchars($line, ENT_HTML5, UTF-8)); + } + + private function getHtmlTags(array $tags): string + { + $html = ""; + foreach ($tags as $tag) { + $html .= "$tag"; + } + return $html; + } + +} diff --git a/lib/Blog.php b/lib/Blog.php new file mode 100644 index 0000000..f4a2df8 --- /dev/null +++ b/lib/Blog.php @@ -0,0 +1,113 @@ +loadConfig(); + $this->render(); + } + + private function loadConfig() + { + require_once "config.php"; + foreach ($links as $title => $url) { + $this->links[] = new Link($title, $url); + } + } + + private function render() + { + extract($this->populateViews()); + include "views/index.phtml"; + } + + private function populateViews(): array + { + return array_merge( + ["lang" => BLOG_LANGUAGE], + $this->populateHeader(), + $this->populateMainView(), + $this->populateBio(), + $this->populateNavByTag(), + $this->populateNavByLatest(), + $this->populateFooter() + ); + } + + private function populateHeader(): array + { + return [ + "title" => BLOG_TITLE, + "has_sub_title" => BLOG_SUB_TITLE !== "", + "sub_title" => BLOG_SUB_TITLE + ]; + } + + private function populateMainView(): array + { + $variables = []; + $view = filter_input(INPUT_GET, "view", FILTER_SANITIZE_STRING) ?: "single"; + $variables["view"] = $view; + switch ($view) { + case "single": + $date = filter_input(INPUT_GET, "date", FILTER_SANITIZE_STRING); + $ref = filter_input(INPUT_GET, "ref", FILTER_SANITIZE_STRING); + $variables["article"] = ($date !== null and $ref !== null) ? + ArticleManager::get(str_replace("-", "", $date) . $ref) : + ArticleManager::getNewest(); + break; + case "tags": + $tag = filter_input(INPUT_GET, "tag", FILTER_SANITIZE_STRING) ?: ""; + $variables["articles"] = ArticleManager::getMultiple(TagManager::getFromTag($tag)); + break; + case "archives": + $variables["dates"] = ArticleManager::getAll();; + break; + } + return $variables; + } + + private function populateBio(): array + { + return [ + "author" => AUTHOR_NICKNAME, + "bio" => AUTHOR_BIOGRAPHY, + ]; + } + + private function populateNavByTag(): array + { + return ["tags" => TagManager::getTags()]; + } + + private function populateNavByLatest(): array + { + return [ + "latest" => ArticleManager::getLatestArticles(ARTICLE_COUNT_IN_NAV) + ]; + } + + private function populateFooter(): array + { + return [ + "has_links" => count($this->links) > 0, + "links" => $this->links, + "footer" => $this->getFooterString() + ]; + } + + private function getFooterString(): string + { + $currentYear = getdate()["year"]; + $footerYear = BLOG_CREATION_YEAR . + (BLOG_CREATION_YEAR !== $currentYear ? " - $currentYear" : ""); + $footerAuthor = AUTHOR_NICKNAME . + (AUTHOR_REALNAME !== "" ? " (" . AUTHOR_REALNAME . ")" : ""); + return "$footerYear. $footerAuthor"; + } + +} diff --git a/lib/Link.php b/lib/Link.php new file mode 100644 index 0000000..ce914c2 --- /dev/null +++ b/lib/Link.php @@ -0,0 +1,15 @@ +title = $title; + $this->url = $url; + } + +} diff --git a/lib/TagManager.php b/lib/TagManager.php new file mode 100644 index 0000000..96cf169 --- /dev/null +++ b/lib/TagManager.php @@ -0,0 +1,29 @@ + + +
  • +

    str?>

    + +
  • + + diff --git a/views/aside.phtml b/views/aside.phtml new file mode 100644 index 0000000..90f8d98 --- /dev/null +++ b/views/aside.phtml @@ -0,0 +1,7 @@ + diff --git a/views/bio.phtml b/views/bio.phtml new file mode 100644 index 0000000..3117918 --- /dev/null +++ b/views/bio.phtml @@ -0,0 +1,7 @@ +
    +
    + <?=$author?> +
    +
    +

    +
    diff --git a/views/footer.phtml b/views/footer.phtml new file mode 100644 index 0000000..bb0b7a7 --- /dev/null +++ b/views/footer.phtml @@ -0,0 +1,10 @@ + diff --git a/views/header.phtml b/views/header.phtml new file mode 100644 index 0000000..1f9cc0e --- /dev/null +++ b/views/header.phtml @@ -0,0 +1,6 @@ +
    +

    + +

    + +
    diff --git a/views/index.phtml b/views/index.phtml new file mode 100644 index 0000000..d46d673 --- /dev/null +++ b/views/index.phtml @@ -0,0 +1,16 @@ + + + + + <?=$title?> + + + + + + diff --git a/views/main.phtml b/views/main.phtml new file mode 100644 index 0000000..27b8e9e --- /dev/null +++ b/views/main.phtml @@ -0,0 +1,3 @@ +
    + +
    diff --git a/views/nav-by-latest.phtml b/views/nav-by-latest.phtml new file mode 100644 index 0000000..8ea3d9e --- /dev/null +++ b/views/nav-by-latest.phtml @@ -0,0 +1,6 @@ + diff --git a/views/nav-by-tag.phtml b/views/nav-by-tag.phtml new file mode 100644 index 0000000..d4ac6ac --- /dev/null +++ b/views/nav-by-tag.phtml @@ -0,0 +1,5 @@ + diff --git a/views/single.phtml b/views/single.phtml new file mode 100644 index 0000000..f5c588f --- /dev/null +++ b/views/single.phtml @@ -0,0 +1,3 @@ +
    +render(); ?> +
    diff --git a/views/tags.phtml b/views/tags.phtml new file mode 100644 index 0000000..67f02b1 --- /dev/null +++ b/views/tags.phtml @@ -0,0 +1,5 @@ +