1
0
Fork 0

Initial commit

This commit is contained in:
sloum 2023-12-19 15:55:46 -08:00
commit 8489054f25
14 changed files with 2466 additions and 0 deletions

9
404.php Normal file
View File

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>404 - Page Not Found</title>
</head>
<body>
<h1>404 - Page Not Found</h1>
</body>
</html>

12
admin-bar-partial.php Normal file
View File

@ -0,0 +1,12 @@
<?php $logged_in = $_COOKIE["checkin"] ?? null; ?>
<?php if ( $logged_in && $logged_in == "waiting for expiry" ): ?>
<nav class="admin-bar">
<ul>
<li><a href="/admin.php">Admin Area</a>
<li><a href="/logout.php">Log Out</a>
</ul>
</nav>
<?php endif; ?>

97
admin.php Normal file
View File

@ -0,0 +1,97 @@
<?php
$logged_in = $_COOKIE["checkin"] ?? null;
if ( !$logged_in || $logged_in != "waiting for expiry" ) {
header("Location: /blog_log.php");
die();
}
$post_success = $_GET["success"] ?? null;
// Get the file list
$files = array_values( array_diff( scandir( "./posts" ), array('..', '.')));
rsort($files);
include_once "common.php";
?>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Administration</title>
<style>
header, main{width:90%;max-width:900px;margin:2em auto}
hr.small-divider{width:25%;margin: 2em auto}
textarea{width:100%;height:50vh}
input[type=text]{width:100%}
.logout{position:absolute;top:0;right:2em;padding:0.5em;border: 1px solid black}
table{width:100%}
.error{background:darkred;color:pink}
ul.inline li{display:inline-block; margin:0}
ul.inline li:not(:last-child)::after{content: ' | '}
ul.list-style-none{list-style:none;margin:0;padding:0}
.post-list tbody tr:nth-child(odd){background-color: #DDD}
td{padding-left:1em}
details {border: 1px solid #aaa;border-radius: 4px;padding: 0.5em 0.5em 0}
summary {font-weight: bold;margin: -0.5em -0.5em 0;padding: 0.5em}
details[open] summary {border-bottom: 1px solid #aaa;margin-bottom: 0.5em}
thead{background: #333;color:#EEE}
</style>
</head>
<body class="admin">
<header>
<h1>Website Admin</h1>
<a href="/logout.php" class="logout">Log Out</a>
</header>
<main>
<?php if ( $post_success === "0" ): ?>
<div class="error">
<h2>Error</h2>
<p>There was a server error preventing your update from succeeding. Please check with your server admin to resolve the issue.</p>
</div>
<?php elseif ( $post_success === "1" ): ?>
<p>New post successfully added!</p>
<?php endif; ?>
<form action="/new-post.php" method="post">
<h2>New Post</h2>
<p>
<label>Title: <input type="text" name="post_title"></label>
</p>
<p>
<label>Post (markdown):<br><textarea name="post_body" required></textarea>
</p>
<input type="submit" value="Submit">
</form>
<hr class="small-divider">
<details class="post-list" open>
<summary>Posts</summary>
<table>
<thead>
<tr>
<th>Post Title</th>
<th>Post Date</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<?php
foreach( $files as $f ) {
$parts = split_filename( $f );
$link = make_post_link( $f );
$out = <<<HTML
<tr>
<td>$link</td>
<td>{$parts["time"]}</td>
<td>
<ul class="inline list-style-none">
<li>Edit</li>
<li><a href="delete_post.php?f=%s">Delete</a></li>
</ul>
</td>
</tr>
HTML;
printf( $out, $parts["raw"] );
}
?>
</tbody>
</table>
</details>
</main>
</body>
</html>

56
backend-header.php Normal file
View File

@ -0,0 +1,56 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title><?php echo $page_title; ?></title>
</head>
<body>
<header>
<h1><?php echo $site_name; ?></h1>
</header>
<main>
<form action="/new-post.php">
<h2>New Post</h2>
<label>Title: <input type="text" name="post_title"></label>
<label>Post (markdown):<br><textarea name="post_body"></textarea>
<input type="submit" value="Submit">
</form>
<hr class="small-divider">
<details>
<summary>Posts</summary>
<table>
<thead>
<tr>
<th>Post Title</th>
<th>Post Date</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</details>
<hr>
<form action="/new-post.php">
<h2>New Page</h2>
<label>Page Name <input type="text" name="page_name"></label>
<label>Add to menu? <input type="checkbox" name="page_in_menu"></label>
<label>Post (markdown):<br><textarea name="page_body"></textarea>
<input type="submit" value="Submit">
</form>
<hr class="small-divider">
<details>
<summary>Pages</summary>
<table>
<thead>
<tr>
<th>Page URL</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</details>
</main>
</body>
</html>

50
blog_log.php Normal file
View File

@ -0,0 +1,50 @@
<?php
const PW_FILE = "./blog_pass_hash.txt";
$invalid = false;
$logged_in = $_COOKIE["checkin"] ?? null;
if ( $logged_in && $logged_in == "waiting for expiry" ) {
header("Location: /admin.php");
die();
}
$secret = $_POST["secret"] ?? null;
if ( $secret ) {
$secret = hash( "sha256", $secret );
if ( $secret ) {
$current = file_get_contents( PW_FILE );
if ( $current) {
if ( $secret == $current ) {
setcookie("checkin", "waiting for expiry", time()+60*60*24*30, "/", "", false, true);
header("Location: /admin.php");
die();
} else {
$invalid = true;
}
} else {
$success = file_put_contents( PW_FILE, $secret );
if ( !$success ) die( "Internal server error" );
setcookie("checkin", "waiting for expiry", time()+60*60*24*30, "/", "", false, true);
header("Location: /admin.php");
die();
}
}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<title>A secret opens the door</title>
</head>
<body>
<div>
<?php if ( $invalid ): ?>
<p id="error-message">
An invalid secret was whispered.
</p>
<?php endif; ?>
<form action="/blog_log.php" method="post">
<label>Whisper a secret&mldr; <input type="password" name="secret" <?php echo $invalid ? 'aria-describedby="error-message"' : ''; ?>></label>
</form>
</div>
</body>
</html>

39
common.php Normal file
View File

@ -0,0 +1,39 @@
<?php
function make_post_link( $a ) {
$parts = split_filename( $a );
return sprintf(
'<a href="post.php?f=%s">%s</a>',
$parts["encoded"],
$parts["title"]
);
}
function title_from_filename( $fn ) {
$fn = str_replace( ".md", "", $fn );
$fn = urldecode( $fn );
return $fn;
}
function make_date_from_stamp( $ts ) {
// Expects "time" from split_filename
$date = date( "m/d/y", (int)$ts );
return $date;
}
function split_filename( $fn ) {
$parts = explode( "_", $fn, 2);
$out = [];
$out["time"] = make_date_from_stamp( $parts[0] );
$out["title"] = title_from_filename( $parts[1] );
$out["raw"] = urlencode( $fn );
$out["encoded"] = $fn;
return $out;
}
function read_post( $fn_raw ) {
// Expects "raw" from split_filename
$path = "posts/" . $fn_raw;
$data = file_get_contents( $path );
return $data;
}

42
config.php Normal file
View File

@ -0,0 +1,42 @@
<?php
/*
* This will appear in the header and title
* for much of the site.
*/
const SITE_NAME = "My Website";
/*
* Raw HTML, no markdown. Introductory content
* goes here. It will appear on the index.php
* page at the top (above the posts).
*/
const TOP_BLURB = <<<HTML
HTML;
/*
* Raw HTML, no markdown. Content for after
* main body goes here. It will appear on the
* index.php page at the bottom (below the posts).
*/
const FOOT_BLURB = <<<HTML
HTML;
/*
* If truthy, will replace the default
* site header. It will automatically be
* placed inside a <header> element.
*/
const SITE_HEADER = false;
/*
* If truthy, will replace the default
* site footer. It will automatically be
* placed inside a <footer> element.
*/
const SITE_FOOTER = false;
/*
* Change the base language of your site here.
*/
const LANG = "en";

21
css/admin-bar.css Normal file
View File

@ -0,0 +1,21 @@
nav.admin-bar{
position: absolute;
right: 2em;
top: 0;
}
nav.admin-bar ul{list-style:none;display:inline-block;padding:0;margin:0}
nav.admin-bar ul li{
display:inline-block;
padding:0.5em;
background-color:#333;
color: #EEE;
margin: 0 5px;
border-radius: 0 0 10px 10px;
box-shadow: 3px 3px 5px silver;
}
nav.admin-bar :any-link {
color: white;
text-decoration: none;
}

19
css/style.css Normal file
View File

@ -0,0 +1,19 @@
header{padding:1em 0}
header h1{font-size: 1.2rem;border-bottom:3px solid #333;display:inline-block}
header h1 a{text-decoration: none; color: inherit}
.article-head{margin-bottom:4em;padding:1em 0;border-bottom:1px dashed #333}
.article-head h1, .article-head .date{display:inline-block}
.article-head .date{margin-left:2em;font-style:italic}
blockquote{border-left:3px solid #333;padding-left:1em}
pre{border:1px dotted #333;background-color:#333;color:white;border-radius:10px;padding:1em;margin:2em 0}
body.post{color:#444;font-family:sans-serif;padding-left:2em}
body.post main h1,
body.post main h2,
body.post main h3,
body.post main h4,
body.post main h5,
body.post main h6{font-family:serif}
body.post main{max-width:900px}
body.post main p

39
index.php Normal file
View File

@ -0,0 +1,39 @@
<?php
// Get the file list
$files = array_values( array_diff( scandir( "./posts" ), array('..', '.')));
rsort($files);
include_once "common.php";
include_once "config.php";
?>
<!DOCTYPE html>
<html lang="en">
<head>
<title><?php echo SITE_NAME; ?></title>
<link rel="stylesheet" href="/css/style.css">
<link rel="stylesheet" href="/css/admin-bar.css">
</head>
<body class="index">
<?php include_once "admin-bar-partial.php"; ?>
<header>
<?php if ( SITE_HEADER ): ?>
<?php echo SITE_HEADER; ?>
<?php else: ?>
<h1><a href="/"><?php echo SITE_NAME; ?></a></h1>
<?php endif; ?>
</header>
<main>
<?php
echo TOP_BLURB;
if ( count( $files ) > 0 ) {
echo "<ul>";
foreach( $files as $f ) {
$link = make_post_link( $f );
echo "<li>$link</li>";
}
echo "</ul>";
}
?>
</main>
<?php if (FOOT_BLURB) echo FOOT_BLURB; ?>
</body>
</html>

8
logout.php Normal file
View File

@ -0,0 +1,8 @@
<?php
$logged_in = $_COOKIE["checkin"] ?? null;
if ( $logged_in && $logged_in == "waiting for expiry" ) {
setcookie("checkin", "", time() - 3600);
}
header("Location: /blog_log.php");
die();

28
new-post.php Normal file
View File

@ -0,0 +1,28 @@
<?php
// Bounce if not logged in
$logged_in = $_COOKIE["checkin"] ?? null;
if ( !$logged_in || $logged_in != "waiting for expiry" ) {
header("Location: /blog_log.php");
die();
}
$ts = time();
$title = isset( $_POST["post_title"] ) ? trim( $_POST["post_title"] ) : null;
$body = isset( $_POST["post_body"] ) ? trim( $_POST["post_body"] ) : null;
// Bounce if requirements are not met for the post
if ( !$title || !$body || $title == "" || $body == "" ) {
header("Location: /blog_log.php?success=0");
die();
}
// Try to write the file
$success = file_put_contents( "./posts/" . $ts . "_" . urlencode( $title ) . ".md", $body );
if ( $success ) {
// Yay! Redirect to admin
header("Location: /admin.php?success=1");
die();
} else {
header("Location: /admin.php?success=0");
die();
}

1995
parsedown.php Normal file

File diff suppressed because it is too large Load Diff

51
post.php Normal file
View File

@ -0,0 +1,51 @@
<?php
include_once "common.php";
include_once "config.php";
$f = $_GET["f"] ?? null;
if ( !$f ) {
header("Location: 404.php");
die();
}
$parts = split_filename( $f );
$data = read_post( $parts["raw"] );
if ( !$data ) {
header("Location: 404.php");
die();
}
include_once "parsedown.php";
$html = Parsedown::instance()->text( $data );
?>
<!DOCTYPE html>
<html lang="en">
<head>
<title><?php echo $parts["title"]; ?></title>
<link rel="stylesheet" href="/css/style.css">
<link rel="stylesheet" href="/css/admin-bar.css">
</head>
<body class="post">
<?php include_once "admin-bar-partial.php"; ?>
<header>
<?php if ( SITE_HEADER ): ?>
<?php echo SITE_HEADER; ?>
<?php else: ?>
<h1><a href="/"><?php echo SITE_NAME; ?></a></h1>
<?php endif; ?>
</header>
<main>
<div class="article-head">
<h1><?php echo $parts["title"]; ?></h1>
<p class="date"><?php echo $parts["time"]; ?></p>
</div>
<div class="article-body">
<?php echo $html; ?>
</div>
</main>
<?php if ( SITE_FOOTER ): ?>
<footer>
<?php echo SITE_FOOTER; ?>
</footer>
<?php endif; ?>