<?php
$post_url_url = '';
$directory_prefix = './';
if ( preg_match( '/(^https?:\/\/[^\/]+)?(\/(?:current\/))?([\w\-]+)\//', $_SERVER['REQUEST_URI'], $matches ) )
{
$directory_prefix = '../' . ( strlen( $matches[2] ) > 1 ? '../' : '' );
$post_url_url = $matches[3];
}
function kstripslashes ( $s )
{
if ( get_magic_quotes_gpc() )
{
return stripslashes( $s );
}
return $s;
}
function utf8ord ( $c )
{
$s = strlen( $c );
$o = ord( $c[0] ) & ( 0xff >> $s );
for ( $i = 1; $i < $s; ++$i )
{
$o = $o << 6 | ( ord( $c[$i] ) & 127 );
}
return $o;
}
// character codes from http://www.localizingjapan.com/blog/2012/01/20/regular-expressions-for-japanese-text/
function getKaCount ( $c )
{
$k = 0;
$s = 0;
for ( $i = 0; $i < strlen( $c ); )
{
$o = ord( $c[$i] );
$L = $o < 192 ? 1 : ( $o < 224 ? 2 : ( $o < 240 ? 3 : ( $o < 248 ? 4 : ( $o < 252 ? 5 : ( $o < 254 ? 6 : 1 ) ) ) ) );
$o = utf8ord( substr( $c, $i, $L ) );
$k += ( ( $o >= 0x3041 && $o <= 0x3096 )
|| ( $o >= 0x30a0 && $o <= 0x30ff )
|| ( $o >= 0x3400 && $o <= 0x4db5 )
|| ( $o >= 0x4e00 && $o <= 0x9fcb )
|| ( $o >= 0xf900 && $o <= 0xfa6a )
|| ( $o >= 0x2e80 && $o <= 0x2fd5 )
|| ( $o >= 0x3000 && $o <= 0x303f ) ) ? 1 : 0;
$i += $L;
$s += ( ( $o >= 9 && $o <= 13 ) || $o == 32 || $o == 160 ) ? 0 : 1;
}
return array( $k, $s );
}
function looksLikeSpam ( $c )
{
$disallowed_nocase = array(
'canada goose', 'ebook', '\\.ru', 'url=', '^\\s*$', '\\buggs?\\b',
'cheap jersey', 'nike jersey', 'laboutin', 'louis vuitton', 'pandora jewelry', 'pas cher',
'provigil', 'xanax', 'tramadol', 'klonopin', 'ambien', 'valium', 'flomax', 'oxycontin', 'cialis',
'kyle woodward ::', '\\bair\\s*max\\b', '\\blongchamps?\\b'
);
$disallowed_case = array(
'^\\s*[A-Z][a-z]{3}[A-Z]{4}'
);
$disallowed_nocase = join( '|', $disallowed_nocase );
$disallowed_case = join( '|', $disallowed_case );
$ka_thresh = 0.7;
$ka_count = getKaCount( $c );
$strlen = strlen( $c ) / 2;
return preg_match( "/$disallowed_nocase/i", $c )
|| preg_match( "/$disallowed_case/", $c )
|| ( $strlen % 2 == 0 && substr( $c, 0, $strlen ) == substr( $c, $strlen ) )
|| ( $ka_count[0] / $ka_count[1] > $ka_thresh );
}
//
// Work through redirects if we must
//
if ( !isset( $_as_include ) )
{
require $directory_prefix . 'headers.php';
}
require sprintf( '%sdb.connect.php', $directory_prefix );
require sprintf( '%sclasses/Page.php', $directory_prefix );
require_once sprintf( '%sclasses/Admin.php', $directory_prefix );
$post_id = -1;
$replacement_name = '';
$override = ' AND isVisible = 1';
if ( isset( $_GET['p'] ) )
{
$post_id = intval( $_GET['p'] );
if ( Admin::isLoggedIn() )
{
$override = '';
}
$post_exists_query = $mysql->prepare( 'SELECT blogPostTitle FROM tblBlogPosts WHERE blogPostID = ? ' . $override );
$post_exists_query->bind_param( 'i', $post_id );
$post_exists_query->execute();
$post_exists_query->bind_result( $replacement_name );
if ( !$post_exists_query->fetch() )
{
$post_id = -1;
}
$post_exists_query->close();
}
if ( strlen( $post_url_url ) > 0 )
{
if ( Admin::isLoggedIn() )
{
$override = '';
}
$post_exists_query = $mysql->prepare( 'SELECT blogPostID, blogPostTitle FROM tblBlogPosts WHERE postURL = ? ' . $override );
$post_exists_query->bind_param( 's', $post_url_url );
$post_exists_query->execute();
$post_exists_query->bind_result( $post_id, $replacement_name );
if ( !$post_exists_query->fetch() )
{
// at this point, it *looks* like they've tried to access an old blog post. so let's pipe them to a current blog post.
header( 'Location: /current.php' );
exit;
}
$post_exists_query->close();
}
$comment_array = array(
'name' => '',
'email' => '',
'site' => '',
'comments' => '',
'captcha_error' => ''
);
$action = isset($_POST['action']) ? strtolower($_POST['action']) : '';
$commented = false;
if ( $action == 'comment' )
{
$name = $_POST['name'];
$email = $_POST['email'];
$site = $_POST['site'];
$post_id = intval($_POST['p']);
$comments = kstripslashes( $_POST['comments'] );
$commented = true;
// 2020-12-30: algebra copied from contact-info.php; factor out?
$captcha_id = isset( $_POST['captcha_id'] ) && intval( $_POST['captcha_id'] ) == $_POST['captcha_id'] ? intval( $_POST['captcha_id'] ) : -1;
$captcha_solution = isset( $_POST['captcha'] ) ? preg_replace( '/\s+/', '', $_POST['captcha'] ) : -1;
$fraction_parts = preg_split( '/\//', $captcha_solution );
if ( count( $fraction_parts ) == 1 )
{
$captcha_solution = floatval( strlen( $fraction_parts[0] ) > 0 ? $fraction_parts[0] : -1 );
}
else if ( count( $fraction_parts ) == 2 )
{
if ( strlen( $fraction_parts[0] ) > 0 && floatval( $fraction_parts[1] ) )
{
$captcha_solution = floatval( $fraction_parts[0] ) / floatval( $fraction_parts[1] );
}
else
{
$captcha_solution = -1;
}
}
else
{
$captcha_solution = -1;
}
$captcha_query = $mysql->prepare( 'SELECT capchaSolution FROM tblCapchas WHERE capchaURLID = ? AND NOW() < DATE_ADD( startTime, INTERVAL 12 HOUR )' );
$captcha_query->bind_param( 'i', $captcha_id );
$captcha_query->execute();
$captcha_query->bind_result( $captcha_solution_db );
if ( !$captcha_query->fetch() )
{
$comment_array['captcha_error'] = 'You took too long to comment; try the new CAPTCHA.';
}
else
{
if ( abs( $captcha_solution - floatval( $captcha_solution_db ) ) > 0.001 )
{
$comment_array['captcha_error'] = 'Sorry, your CAPTCHA response wasn\'t accurate enough; try the new CAPTCHA.';
}
}
$captcha_query->close();
$spam_error = 'Your post looks spammy; <a href="/about.php">contact me</a> if you feel wronged or would like more information.';
if ( looksLikeSpam( $comments ) )
{
$comment_array['captcha_error'] = $spam_error;
}
//
// input verification
//
//
// strip tags from name, ensure length (63), escape for mysql
//
$name = strip_tags($name);
if ( strlen($name) > 63 ) {
$name = substr($name,0,63);
}
//
// strip tags from email, ensure length (127), trim spaces, escape for mysql
//
$email = preg_replace('/[\s]/','',$email);
$email = strip_tags($email);
if ( strlen($email) > 127 ) {
$email = substr($email,0,127);
}
//
// strip tags from site, ensure length (255), add http://, escape for mysql
//
$site = strip_tags($site);
if ( !preg_match('/(^ftp:\/\/)|(^https?:\/\/)/',$site) )
{
$site = 'http://'.$site;
}
if ( strlen($site) > 255 )
{
$site = substr($site,0,255);
}
//
// strip tags from comments
//
$comments = kstripslashes( strip_tags( $comments ) );
//
// end input verification
//
if ( strlen( $comment_array['captcha_error'] ) > 0 )
{
$comment_array['name'] = kstripslashes( $name );
$comment_array['email'] = $email;
$comment_array['site'] = $site;
$comment_array['comments'] = $comments;
}
else
{
//
// form and run the query
//
$comment_insert_query = <<<EOQ
INSERT INTO tblBlogPostComments (
blogPostID,
commentDateTime,
commentorName,
commentorGravatar,
commentorSite,
comment
)
VALUES (
?,
NOW(),
?,
?,
?,
?
)
EOQ;
//
// check: is commenting allowed?
//
$comment_allowed_query = $mysql->prepare( 'SELECT allowComments FROM tblBlogPosts WHERE blogPostID = ?' );
$comment_allowed_query->bind_param( 'i', $post_id );
$comment_allowed_query->execute();
$comment_allowed_query->bind_result( $comment_allowed );
if ( $comment_allowed_query->fetch() && $comment_allowed )
{
$comment_allowed_query->close();
$comment_insert_query = $mysql->prepare( $comment_insert_query );
$comment_insert_query->bind_param( 'issss', $post_id, $name, $email, $site, $comments );
$comment_insert_query->execute();
$comment_insert_query->close();
if ( $comment_allowed == 1 )
{
if ( stripos( $_SERVER['REQUEST_URI'], 'current.php' ) !== false )
{
header( sprintf( 'Location: /current.php?p=%d', $post_id ) );
}
else
{
header( 'Location: ./' );
}
exit;
}
}
}
}
$most_recent_post_query_string = <<<EOQ
SELECT
blogPostID,
blogPostTitle,
postHTML,
UNIX_TIMESTAMP( postDateTime ),
postURL,
allowComments
FROM tblBlogPosts
WHERE
(
? < 0
OR blogPostID = ?
) $override
ORDER BY postDateTime DESC
LIMIT 0, 1
EOQ;
$most_recent_post_query = $mysql->prepare( $most_recent_post_query_string );
$most_recent_post_query->bind_param( 'ii', $post_id, $post_id );
$most_recent_post_query->execute();
$most_recent_post_query->bind_result( $most_recent_post_id, $most_recent_post_title, $most_recent_post_html, $most_recent_post_timestamp, $most_recent_post_url, $most_recent_post_allow_comments );
$most_recent_post_query->fetch();
$most_recent_post_query->close();
$post_title = $most_recent_post_title;
$unix_timestamp = $most_recent_post_timestamp;
if ( $post_id < 0 )
{
$post_id = $most_recent_post_id;
}
$headers_query_string = <<<EOQ
SELECT
bph.headerContent,
ht.headerType
FROM
tblBlogPostHeaders bph,
luHeaderTypes ht
WHERE
bph.headerTypeID = ht.headerTypeID
AND bph.blogPostID = ?
EOQ;
$addl_headers = array();
$addl_footers = array();
$headers_query = $mysql->prepare( $headers_query_string );
$headers_query->bind_param( 'i', $post_id );
$headers_query->execute();
$headers_query->bind_result( $header_content, $header_type );
while ( $headers_query->fetch() )
{
switch ( $header_type )
{
case 'Footer':
array_push( $addl_footers, $header_content );
break;
case 'Header':
array_push( $addl_headers, $header_content );
break;
}
}
$headers_query->close();
$page = new Page();
$page->setParentURL( 'current.php' );
$page->setTitle( 'current' );
foreach ( $addl_headers as $i => $h )
{
$page->addHeader( $h );
}
$page->addHeader( <<<EOJX
<script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
EOJX
);
// if ( strlen( $replacement_name ) > 0 )
// {
// wrapPageTop( 'current.php', null, $addl_headers );
// }
// else
// {
// wrapPageTop( null, null, $addl_headers );
// }
$page->printPageHeader();
?>
<h3 style="margin-bottom:0px;"><a href="/<?php print $most_recent_post_url;?>" target="_top"><?php print $post_title; ?></a></h3>
<span style="display:block;margin-bottom:2em;"><?php print date( 'j F Y', $unix_timestamp );?></span>
<?
print $most_recent_post_html;
?>
<p style="margin-top:2em;"><em>Included \(\LaTeX\) graphics are generated at <a href="/latex.php">LaTeX to png</a> or by <a href="https://mathjax.org" target="_new"><img alt="MathJax" style="border:0px;padding-left:0.5ex;" src="https://www.mathjax.org/badge/mj_logo_60x12.png" title="MathJax" /></a>.</em></p>
<h3 style="margin-top:2em;">contemporary entries</h3>
<ul class="blog_history">
<?php
$adjacent_post_query_string = <<<EOQ
SELECT
bp.blogPostID,
bp.blogPostTitle,
UNIX_TIMESTAMP( bp.postDateTime ),
CONCAT( 'current/', bp.postURL )
FROM tblBlogPosts bp
WHERE
bp.isVisible = 1
AND (
SELECT COUNT(*)
FROM tblBlogPosts
WHERE
isVisible = 1
AND (
UNIX_TIMESTAMP( postDateTime ) BETWEEN ? AND UNIX_TIMESTAMP( bp.postDateTime )
OR UNIX_TIMESTAMP( postDateTime ) BETWEEN UNIX_TIMESTAMP( bp.postDateTime ) AND ?
)
AND postDateTime <> bp.postDateTime
) < 3
ORDER BY bp.postDateTime DESC
EOQ;
$adjacent_post_query = $mysql->prepare( $adjacent_post_query_string );
$adjacent_post_query->bind_param( 'ii', $unix_timestamp, $unix_timestamp );
$adjacent_post_query->execute();
$adjacent_post_query->bind_result( $adjacent_post_id, $adjacent_post_title, $adjacent_post_timestamp, $adjacent_post_url );
while ( $adjacent_post_query->fetch() )
{
?>
<li class="blog_history"><?php
if ( $adjacent_post_id == $post_id )
{
?><strong><?php
}
?><a href="/<?php print $adjacent_post_url;?>" target="_top"><?php print $adjacent_post_title;?>
<?php
if ( $adjacent_post_id == $post_id )
{
?></strong><?php
}
?></a> (<?php print date( 'j F Y', $adjacent_post_timestamp );?>)</li>
<?php
}
?>
<li class="blog_history"><br /><a href="/blog-archive.php" target="_top">view all entries »</a></li>
</ul>
<h3 style="margin-top:2em;">comments</h3>
<?php
$comment_query_string = <<<EOQ
SELECT
UNIX_TIMESTAMP( bpc.commentDateTime ),
bpc.commentorName,
bpc.commentorGravatar,
bpc.commentorSite,
bpc.comment
FROM
tblBlogPostComments bpc,
tblBlogPosts bp
WHERE
bpc.blogPostID = ?
AND bp.blogPostID = ?
AND (
bpc.isApproved = 1
OR bp.allowComments <> 2
)
ORDER BY bpc.commentDateTime
EOQ;
$comment_query = $mysql->prepare( $comment_query_string );
$comment_query->bind_param( 'ii', $post_id, $post_id );
$comment_query->execute();
$comment_query->bind_result( $comment_timestamp, $commentor_name, $commentor_gravatar, $commentor_site, $comment );
$has_comments = false;
while ( $comment_query->fetch() )
{
$has_comments = true;
?>
<div class="comment">
<div class="comment_content">
<?php print preg_replace( '/[\r\n]+/', '<br /><br />', $comment ); ?>
</div><div class="comment_signature">
<img src="http://www.gravatar.com/avatar.php?gravatar_id=<?php print md5( $commentor_gravatar ); ?>&size=40" />
<?php
if ( strlen( $commentor_site ) > 0 )
{
?>
<a href="<?php print $commentor_stie; ?>" target="_top"><?php print $commentor_name; ?></a>
<?php
}
else
{
print $commentor_name;
}
?>
(<?php print date( 'j F Y, g:ia', $comment_timestamp ); ?>)
</div>
</div>
<?php
}
$comment_query->close();
if ( !$has_comments )
{
?>
<p style="margin-top:0em;">there are no comments on this post</p>
<?php
}
if ( strlen( $comment_array['captcha_error'] ) > 0 )
{
?>
<span style="color:red;"><?php print $comment_array['captcha_error'];?></span>
<?php
}
else if ( $commented && $most_recent_post_allow_comments == 2 )
{
?>
<span style="font-style:italic;">Comments on this post are pre-moderated; your comment will be approved or rejected shortly.</span>
<?php
}
if ( $most_recent_post_allow_comments || Admin::isLoggedIn() )
{
/*
this was the code to shoot comments back to current.php; this breaks the url, so let's not enter an action and let the browser default to the same page.
action="/current.php?p=<?php print $post_id.(isset($_GET['override'])?'&override':'');?>"*/
?>
<form method="post" style="padding-top:1em;">
<fieldset>
<div class="input_element">
<input id="name" name="name" type="text" value="<?php print $comment_array['name'];?>" /> <label for="name">name</label>
</div>
<div class="input_element">
<input id="email" name="email" type="text" value="<?php print $comment_array['email'];?>" /> <label for="email">email (for <a href="http://gravatar.com/">gravatar</a>)</label>
</div>
<div class="input_element">
<input id="site" name="site" type="text" value="<?php print $comment_array['site'];?>" /> <label for="site">site</label>
</div>
<?php
$captcha_id = time() . '_' . rand();
?>
<div class="input_element">
<input id="captcha" name="captcha" type="text" value="" />
<label for="captcha"> = <img alt="captcha" src="/captcha.php?captchaid=<?php print $captcha_id;?>" style="vertical-align:text-bottom;" /> (3 decimal places)</label>
<input id="captcha_id" name="captcha_id" type="hidden" value="<?php print $captcha_id;?>" />
</div>
<textarea id="comments" name="comments" rows="5" style="width:100%;"><?php print $comment_array['comments'];?></textarea>
<input id="p" name="p" type="hidden" value="<?=$post_id;?>" />
<input id="action" name="action" type="hidden" value="comment" />
<input type="submit" value="comment" />
</fieldset>
</form>
<?php
}
else
{
?>
<p>Sorry, further commenting on this post has been disabled. For more information, <a href="/about.php">contact me</a>.</p>
<?php
}
foreach ( $addl_footers as $i => $f )
{
$page->addFooter( $f );
}
$page->printPageFooter();
?>