Last active
June 18, 2016 00:17
-
-
Save migurski/76484b2df82a90838ea69c7b3bfe623b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// What's this blog's title? | |
$blog_title = "tecznotes"; | |
// What's this blog's description (for outgoing RSS feed)? | |
$blog_description = "Michal Migurski's notebook, listening post, and soapbox."; | |
// What's this blog's primary language (for outgoing RSS feed)? | |
$blog_language = "en"; | |
// Where are this blog's entries kept? | |
$datadir = "/Users/migurski/Sites/mike.teczno.com/blosxom"; | |
// Where are this blog's comments kept? | |
$commentsdb = 'comments/comments3.db'; | |
// What's my preferred base URL for this blog (leave blank for automatic)? | |
// $url = "http://mike.teczno.com/blosxom/blosxom.php?"; | |
// Should I stick only to the datadir for items or travel down the | |
// directory hierarchy looking for items? If so, to what depth? | |
// 0 = infinite depth (aka grab everything), 1 = datadir only, n = n levels down | |
$depth = 0; | |
// How many entries should I show on the home page? | |
$num_entries = 5; | |
// What file extension signifies a blosxom entry? | |
$file_extension = 'txt'; | |
// What is the default flavour? | |
$default_flavour = "html"; | |
// What's this blog's timezone? | |
putenv('TZ=America/Los_Angeles'); | |
// For the comment captchas | |
require 'recaptcha/recaptchalib.php'; | |
$recaptcha_public_key = '...'; | |
$recaptcha_private_key = '...'; | |
// For the short URLs | |
require_once 'shlong/shlong.php'; | |
function wikisyntax($body, $new_img=false) | |
{ | |
// old, nano-blogger style naming | |
$body = preg_replace('/^DATE: .+\n/', '\1', $body); | |
if(!preg_match('/<\w+[^>]*>/', $body)) { | |
if($new_img) { | |
// links with thumbnails: [http://example.com/img.gif http://example.com/thumb.gif] | |
$body = preg_replace('#\[((http|https|mailto):\S+)\s+(http:\S+\.(gif|jpg|png))(\s+\.(\w+))?\]#i', '<a href="\1" target="_blank"><img src="\3" class="\6" border="1" alt=""/></a>', $body); | |
// just a picture | |
$body = preg_replace('#\[(http:\S+\.(gif|jpg|png))(\s+\.(\w+))?\]#', '<img src="\1" class="\4" border="1" alt=""/>', $body); | |
} else { | |
// links with thumbnails: [http://example.com/img.gif http://example.com/thumb.gif] | |
$body = preg_replace('#\[((http|https|mailto):\S+)\s+(http:\S+\.(gif|jpg|png))\]#i', '<a href="\1" target="_blank"><img class="old" src="\3" border="1" alt=""/></a>', $body); | |
// just a picture | |
$body = preg_replace('#\[(http:\S+\.(gif|jpg|png))\]#', '<img class="old" src="\1" border="1" alt=""/>', $body); | |
} | |
// pictures linked from text: [http://example.com/img.gif Text] | |
$body = preg_replace('#\[(http:\S+\.(gif|jpg|png))\s+(\S[^\]]*)\]#', '<a href="\1" target="_blank">\3</a>', $body); | |
// links with text: [http://example.com Text] | |
$body = preg_replace('#\[((http|https|mailto):\S+)\s+(\S[^\]]*)\]#', '<a href="\1">\3</a>', $body); | |
// //italic// and **bold** | |
$body = preg_replace('#([^:])//(.+?)//#is', '\1<em>\2</em>', $body); | |
$body = preg_replace('#\*\*(.+?)\*\*#is', '<strong>\1</strong>', $body); | |
$body = preg_replace('#--(.+?)--#is', '<span style="text-decoration: line-through;">\1</span>', $body); | |
$body = preg_replace('#__(.+?)__#is', '<span style="text-decoration: underline;">\1</span>', $body); | |
$new_body = ''; | |
$in = ''; | |
foreach(preg_split("/\n|\r|\r\n/", $body) as $line) { | |
if(preg_match('/^$/', $line)) { | |
if($in != '') { | |
$new_body .= "</${in}>"; | |
$in = ''; | |
} | |
} elseif(preg_match('/^\|\s*(.*)$/', $line, $m)) { | |
if($in == '') { | |
$in = 'blockquote'; | |
$new_body .= '<blockquote>'; | |
} elseif($in != 'blockquote') { | |
$new_body .= "</${in}><blockquote>"; | |
$in = 'blockquote'; | |
} | |
$new_body .= "${m[1]} "; | |
} elseif(preg_match('/^\*\s*(.*)$/', $line, $m)) { | |
if($in == '') { | |
$in = 'ul'; | |
$new_body .= '<ul>'; | |
} elseif($in != 'ul') { | |
$new_body .= "</${in}><ul>"; | |
$in = 'ul'; | |
} | |
$new_body .= "<li>${m[1]}</li> "; | |
} elseif(preg_match('/^#\s*(.*)$/', $line, $m)) { | |
if($in == '') { | |
$in = 'ol'; | |
$new_body .= '<ol>'; | |
} elseif($in != 'ol') { | |
$new_body .= "</${in}><ol>"; | |
$in = 'ol'; | |
} | |
$new_body .= "<li>${m[1]}</li> "; | |
} else { | |
if($in == '') { | |
$in = 'p'; | |
$new_body .= '<p>'; | |
} elseif($in != 'p') { | |
$new_body .= "</${in}><p>"; | |
$in = 'p'; | |
} | |
$new_body .= "${line} "; | |
} | |
} | |
$body = $new_body; | |
} | |
return $body; | |
} | |
function scrub_comment($content) | |
{ | |
// handle special characters | |
$content = htmlspecialchars($content); | |
// link up URLs | |
$content = preg_replace('#(https?://\S+\w)#i', '<a href="\1">\1</a>', $content); | |
// take advantage of white-space: pre-wrap | |
return $content; | |
// convert various weird line breaks | |
$content = str_replace("\r\n", "\n", $content); | |
$content = str_replace("\r", "\n", $content); | |
// cut up into paragraphs | |
$content = preg_replace("#\n\n+#", '</p><p>', $content); | |
// replace remaining breaks | |
$content = str_replace("\n", '<br/>', $content); | |
return "<p>{$content}</p>"; | |
} | |
//$script_dir = dirname($_SERVER['SCRIPT_NAME']); | |
//$request_dir = $_SERVER['SCRIPT_URL']; | |
//chdir(trim(substr($request_dir, strlen($script_dir)), '/')); | |
/** | |
* Pull one post by name. | |
*/ | |
function get_post_by_name($post_path) | |
{ | |
return array('name' => substr(basename($post_path), 0, -4), | |
'path' => preg_replace('#^(\./)*#', '', substr($post_path, 0, -4)), | |
'file' => $post_path, | |
'type' => 'file', | |
'time' => filemtime($post_path)); | |
} | |
/** | |
* Pull posts out of a directory in reverse-chronological order. | |
*/ | |
function get_posts_recursively($path='.') | |
{ | |
static $post_lists; | |
if(!isset($post_lists)) | |
$post_lists = array(); | |
if(is_array($post_lists[$path])) | |
return $post_lists[$path]; | |
$posts = array(); | |
if($dir = opendir($path)) { | |
while(($file = readdir($dir)) !== false) { | |
$file_path = implode(DIRECTORY_SEPARATOR, array($path, $file)); | |
switch(true) { | |
case substr($file, 0, 1) == '.': | |
// do nothing | |
break; | |
case is_dir($file): | |
$posts = array_merge($posts, get_posts_recursively($file_path)); | |
break; | |
case substr($file, -4) == ".{$GLOBALS['file_extension']}": | |
$posts[] = get_post_by_name($file_path); | |
break; | |
} | |
} | |
usort($posts, create_function('$f1, $f2', 'return $f1["time"] < $f2["time"];')); | |
} | |
$post_lists[$path] = $posts; | |
return $post_lists[$path]; | |
} | |
/** | |
* Pull posts by date in reverse-chronological order. | |
*/ | |
function get_posts_dy_date($date_string) | |
{ | |
$date_parts = explode('/', $date_string); | |
$year = intval($date_parts[0]); | |
$month = isset($date_parts[1]) ? intval($date_parts[1]) : 1; | |
$day = isset($date_parts[2]) ? intval($date_parts[2]) : 1; | |
if(!checkdate($month, $day, $year)) | |
return array(); | |
switch(count($date_parts)) { | |
case 1: // year | |
$compare = sprintf('%04d-', $year); | |
break; | |
case 2: // month | |
$compare = sprintf('%04d-%02d-', $year, $month); | |
break; | |
case 3: // day | |
$compare = sprintf('%04d-%02d-%02d ', $year, $month, $day); | |
break; | |
default: // uh... | |
return array(); | |
} | |
$posts = array(); | |
foreach(get_posts_recursively() as $post) | |
if(substr(date('Y-m-d ', $post['time']), 0, strlen($compare)) == $compare) | |
$posts[] = $post; | |
return $posts; | |
} | |
function get_page_title($path_info) | |
{ | |
$path_parts = explode('/', $path_info); | |
$first_parts = array_slice($path_parts, 0, -1); | |
$last_part = end($path_parts); | |
$is_front = in_array($path_info, array('', 'index')); | |
$is_index = in_array($last_part, array('', 'index')); | |
switch(true) { | |
case $is_front: | |
return $GLOBALS['blog_title']; | |
case !$is_index && is_file("./{$path_info}.{$GLOBALS['file_extension']}"): | |
list($post_title, $post_body) = get_post_title_body("./{$path_info}.{$GLOBALS['file_extension']}"); | |
return "{$post_title} ({$GLOBALS['blog_title']})"; | |
case $is_index && is_dir(join(DIRECTORY_SEPARATOR, $first_parts)): | |
case $is_index && !in_array(0, array_map('is_numeric', $first_parts)): | |
return "posts ".(count($first_parts) <= 2 ? 'in' : 'on')." ".join(DIRECTORY_SEPARATOR, $first_parts)." ({$GLOBALS['blog_title']})"; | |
default: | |
return "? ({$GLOBALS['blog_title']})"; | |
} | |
} | |
function get_posts($path_info) | |
{ | |
$path_parts = explode('/', $path_info); | |
$first_parts = array_slice($path_parts, 0, -1); | |
$last_part = end($path_parts); | |
$is_front = in_array($path_info, array('', 'index')); | |
$is_index = in_array($last_part, array('', 'index')); | |
switch(true) { | |
case $is_front: | |
return array_slice(get_posts_recursively(), 0, $GLOBALS['num_entries']); | |
case !$is_index && is_file("./{$path_info}.{$GLOBALS['file_extension']}"): | |
return array(get_post_by_name("./{$path_info}.{$GLOBALS['file_extension']}")); | |
case $is_index && is_dir(join(DIRECTORY_SEPARATOR, $first_parts)): | |
return array_slice(get_posts_recursively(join(DIRECTORY_SEPARATOR, $first_parts)), 0, $GLOBALS['num_entries']); | |
case $is_index && !in_array(0, array_map('is_numeric', $first_parts)): | |
return get_posts_dy_date(join(DIRECTORY_SEPARATOR, $first_parts)); | |
default: | |
return array(); | |
} | |
} | |
function get_post_title_body($post_path) | |
{ | |
static $post_titles_bodies; | |
if(!isset($post_titles_bodies)) | |
$post_titles_bodies = array(); | |
if(is_array($post_titles_bodies[$post_path])) | |
return $post_titles_bodies[$post_path]; | |
$post_titles_bodies[$post_path] = preg_split("/\n|\r|\r\n/", file_get_contents($post_path), 2); | |
return $post_titles_bodies[$post_path]; | |
} | |
function get_post_comments($path) | |
{ | |
$comments = array(); | |
if($dbh = new SQLite3($GLOBALS['commentsdb'], SQLITE3_OPEN_READONLY)) | |
{ | |
$q = sprintf("SELECT post, author, url, content, timestamp | |
FROM comments | |
WHERE post = '%s' | |
ORDER BY timestamp ASC", | |
$dbh->escapeString($path)); | |
$res = $dbh->query($q); | |
while($comment = $res->fetchArray(SQLITE3_ASSOC)) | |
$comments[] = $comment; | |
$dbh->close(); | |
} | |
return $comments; | |
} | |
function add_post_comment($path, $author, $url, $content) | |
{ | |
if($dbh = new SQLite3($GLOBALS['commentsdb'], SQLITE3_OPEN_READWRITE)) | |
{ | |
$q = sprintf("INSERT INTO comments | |
(post, author, url, content, timestamp) | |
VALUES('%s', '%s', '%s', '%s', %d)", | |
$dbh->escapeString($path), | |
$dbh->escapeString($author), | |
$dbh->escapeString($url), | |
$dbh->escapeString($content), | |
time()); | |
$res = $dbh->exec($q); | |
$dbh->close(); | |
} | |
return $res; | |
} | |
function render_head($flavour, $page_title) | |
{ | |
ob_start(); | |
include "head.{$flavour}.php"; | |
return ob_get_clean(); | |
} | |
function render_post($post, $flavour) | |
{ | |
extract($post); // -> name, path, type, time, file | |
list($title, $body) = get_post_title_body($file); | |
$comments = get_post_comments($path); | |
$captcha_html = recaptcha_get_html($GLOBALS['recaptcha_public_key'], null, false, 'Poof.'); | |
$at_permalink = ("http://{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}" == "{$GLOBALS['url']}{$path}.{$GLOBALS['flavour']}"); | |
$comments_ok = ($post['time'] > time() - 90*86400); // && ($post['time'] > strtotime("February 3 2008")); | |
ob_start(); | |
include "post.{$flavour}.php"; | |
return ob_get_clean(); | |
} | |
function render_foot($flavour) | |
{ | |
ob_start(); | |
include "foot.{$flavour}.php"; | |
return ob_get_clean(); | |
} | |
function render_calendar($t=null) | |
{ | |
$t = isset($t) ? $t : time(); | |
$post_counts = array(); | |
/* | |
foreach(get_posts_dy_date(date('Y/m', $t)) as $post) { | |
$post_day = intval(date('j', $post['time'])); | |
$post_counts[$post_day] = isset($post_counts[$post_day]) ? $post_counts[$post_day] + 1 : 1; | |
} | |
*/ | |
foreach(get_posts_dy_date(date('Y/m', $t)) as $post) | |
$post_counts[intval(date('j', $post['time']))] = true; | |
$calendar = '<table class="calendar">'; | |
$calendar .= '<tr><th colspan="7" class="calendar_month_head"><a href="'.$GLOBALS['url'].date('Y/m', $t).'/">'.date('F Y', $t).'</a></th></tr>'; | |
$calendar .= '<tr> | |
<th class="calendar_day_head">Su</th> | |
<th class="calendar_day_head">M</th> | |
<th class="calendar_day_head">Tu</th> | |
<th class="calendar_day_head">W</th> | |
<th class="calendar_day_head">Th</th> | |
<th class="calendar_day_head">F</th> | |
<th class="calendar_day_head">Sa</th> | |
</tr>'; | |
$month_days = intval(date('t', $t)); | |
$month_day = intval(date('j', $t)); | |
$week_day = intval(date('w', $t)); | |
for($start_day = $month_day - $week_day; $start_day > 1; $start_day -= 7) { | |
// keep decrementing... | |
} | |
// $d: day of month, $w: day of week | |
// increment both until we roll past the last day of the month and reach a saturday | |
for($d = $start_day, $w = 0; $d <= $month_days || $w % 7; $d++, $w = ($w + 1) % 7) { | |
if($w == 0) | |
$calendar .= '<tr>'; | |
if($post_counts[$d]) { | |
$time = mktime(0, 0, 0, intval(date('m', $t)), $d, intval(date('Y', $t))); | |
$calendar .= '<td class="calendar_day_link"><a href="'.$GLOBALS['url'].date('Y/m/d', $time).'/">'.$d.'</a></td>'; | |
} elseif($d >= 1 && $d <= $month_days) { | |
$calendar .= '<td class="calendar_day_nolink">'.$d.'</td>'; | |
} else { | |
$calendar .= '<td class="calendar_day_noday"> </td>'; | |
} | |
if($w == 6) | |
$calendar .= '</tr>'; | |
} | |
$calendar .= '</table>'; | |
return $calendar; | |
} | |
function render_recentposts() | |
{ | |
if($GLOBALS['flavour'] != 'html') | |
return ''; | |
$recent = '<ol class="recentstories">'; | |
foreach(array_slice(get_posts_recursively(), 0, 20) as $post) { | |
extract($post); // -> name, path, type, time, file | |
list($title, $body) = get_post_title_body($file); | |
$recent .= '<li><a href="'.$GLOBALS['url'].$path.'.'.$GLOBALS['flavour'].'">'.htmlspecialchars($title).'</a></li>'; | |
} | |
$recent .= '</ol>'; | |
return $recent; | |
} | |
function render_flatarchives() | |
{ | |
if($GLOBALS['flavour'] != 'html') | |
return ''; | |
$recent = '<ul class="flatarchives">'; | |
$archives = array(); | |
$year_ago = date('Y', time() - (86400 * 365)); | |
foreach(get_posts_recursively() as $post) { | |
extract($post); // -> name, path, type, time, file | |
if(date('Y', $time) >= $year_ago) { | |
$m = date('Y-m', $time); | |
$posts = $archives[$m]['posts'] ? ($archives[$m]['posts'] + 1) : 1; | |
$name = date('F', $time); | |
$year = date('Y', $time); | |
$path = date('Y/m', $time); | |
$archives[$m] = compact('posts', 'name', 'year', 'path'); | |
} else { | |
$y = date('Y', $time); | |
$posts = $archives[$y]['posts'] ? ($archives[$y]['posts'] + 1) : 1; | |
$name = date('Y', $time); | |
$year = ''; // not here | |
$path = date('Y', $time); | |
$archives[$y] = compact('posts', 'name', 'year', 'path'); | |
} | |
} | |
foreach($archives as $archive) | |
$recent .= '<li><a href="'.$GLOBALS['url'].$archive['path'].'/">'.$archive['name'].'</a> '.$archive['year'].' ('.$archive['posts'].')</li>'; | |
$recent .= '</ul>'; | |
return $recent; | |
} | |
/* | |
function path_dates($path_info) | |
{ | |
if(preg_match('#^(\d{4})(/(\d{1,2}))?(/(\d{1,2}))?$#', $path_info, $matches)) { | |
$y = intval($matches[1]); | |
$m = 1; | |
$d = 1; | |
$p = 'year'; | |
if(isset($matches[3])) { | |
$m = intval($matches[3]); | |
$p = 'month'; | |
} | |
if(isset($matches[5])) { | |
$d = intval($matches[5]); | |
$p = 'day'; | |
} | |
if(checkdate($m, $d, $y)) { | |
$start = mktime(0, 0, 0, $m, $d, $y); | |
switch($p) { | |
case 'day': | |
$end = mktime(23, 59, 59, $m, $d, $y); | |
break; | |
case 'month': | |
$end = mktime(23, 59, 59, $m, intval(date('t', $start)), $y); | |
break; | |
case 'year': | |
$end = mktime(23, 59, 59, 12, 31, $y); | |
break; | |
} | |
} | |
return array($start, $end); | |
} | |
return false; | |
} | |
*/ | |
if(empty($url)) | |
$url = isset($_SERVER['REDIRECT_URL']) | |
? "http://{$_SERVER['HTTP_HOST']}".substr($_SERVER['REDIRECT_URL'], 0, strlen($_SERVER['REDIRECT_URL']) - strlen($_SERVER['REDIRECT_QUERY_STRING'])).'/' | |
: "http://{$_SERVER['HTTP_HOST']}{$_SERVER['SCRIPT_NAME']}?"; | |
list($path_info, $flavour) = preg_split('/\.(\w+)$/', ltrim($_SERVER['QUERY_STRING'], '/'), 2, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY); | |
$flavour = $flavour ? $flavour : $default_flavour; | |
if($_SERVER['REQUEST_METHOD'] == 'POST') { | |
switch($_POST['action']) { | |
case 'comment': | |
$res = recaptcha_check_answer($GLOBALS['recaptcha_private_key'], $_SERVER['REMOTE_ADDR'], $_POST['recaptcha_challenge_field'], $_POST['recaptcha_response_field']); | |
if($res->is_valid && add_post_comment($path_info, $_POST['author'], $_POST['url'], $_POST['content'])) { | |
unset($_POST['author']); | |
unset($_POST['url']); | |
unset($_POST['content']); | |
} else { | |
$GLOBALS['comment_post_failed'] = true; | |
} | |
break; | |
} | |
} | |
switch($flavour) { | |
case 'html': | |
case 'htmlf': | |
case 'senate': | |
case 'congress': | |
header('Content-type: text/html'); | |
break; | |
case 'rss': | |
header('Content-type: application/rss+xml'); | |
break; | |
case 'xml': | |
header('Content-type: application/atom+xml'); | |
break; | |
} | |
print render_head($flavour, get_page_title($path_info)); | |
foreach(get_posts($path_info) as $post) | |
print render_post($post, $flavour); | |
print render_foot($flavour); | |
?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment