From: Dylan Lloyd Date: Fri, 25 Mar 2011 00:18:17 +0000 (-0400) Subject: Merge branch 'ajax' into dev X-Git-Url: https://disinclined.org/git/?a=commitdiff_plain;h=8d2cf39d98794c59a92155d9e119db205f431436;hp=75e132f05e9b46a388c2ca3a23e30e57e9d9bc3f;p=dylansserver.git Merge branch 'ajax' into dev --- diff --git a/.htaccess b/.htaccess index f2421fc..d06e66b 100644 --- a/.htaccess +++ b/.htaccess @@ -3,7 +3,11 @@ ErrorDocument 404 /404.php RewriteEngine on +RewriteRule ^captcha/?$ /index.php [L] + RewriteRule ^note/([^/\.]+)?/?$ /index.php?note=$1 [L] +RewriteRule ^note/([^/\.]+)?/comments/?$ /index.php?comments=true¬e=$1 [L] +RewriteRule ^note/([^/\.]+)?/(comments/)?verify/?$ /index.php?comments=true&verify=true¬e=$1 [L] RewriteRule ^notes/?$ notes/page/1 RewriteRule ^notes/page/?$ notes/page/1 diff --git a/captcha.php b/captcha.php new file mode 100644 index 0000000..f7335b6 --- /dev/null +++ b/captcha.php @@ -0,0 +1,19 @@ +recaptcha_privatekey, + $_SERVER["REMOTE_ADDR"], + $_POST["recaptcha_challenge_field"], + $_POST["recaptcha_response_field"]); +if (!$resp->is_valid) { + die ("The reCAPTCHA wasn't entered correctly. Go back and try it again." . + "(reCAPTCHA said: " . $resp->error . ")"); +} else { + echo "success!"; +} + +?> diff --git a/includes/ajax.js b/includes/ajax.js new file mode 100644 index 0000000..6e94941 --- /dev/null +++ b/includes/ajax.js @@ -0,0 +1,56 @@ +$(document).ready(function() { + $('#recaptcha_widget').show(); + $('.submit').click(function() { + $('#not_human').hide(); + $('#blank_comment').hide(); + $('#comment_text').css('border', '1px solid grey') + $('#recaptcha_response_field').css('border', '1px solid grey') + if ($('#comment_text').val() != '') { + var challenge = Recaptcha.get_challenge(); + var response = Recaptcha.get_response(); + var captcha_data = { "challenge" : challenge, + "response" : response}; + $.ajax({ + type: "GET", + url: "/captcha", + data: captcha_data, + success: function(data) { + if (data.split('\n')[0] == 'true') { + var name = $("#comment_name").val(); + var text = $("#comment_text").val(); + if (name == '') { name = "anon" } + var comment_data = { "captcha" : "passed", + "name" : name, + "text" : text}; + $.ajax({ + type: "POST", + // the url may need to be adjusted for + // trailing slashes + url: "verify", + data: comment_data, + success: function() { + var new_post = "

" + name + "

" + + text + "

"; + $('#comments').prepend(new_post); + $('#comment').hide(); + } + }); + } else { + $('#not_human').show(); + $('#recaptcha_response_field').css('border', '2px solid red') + } + }, + error: function() { + console.log('error'); + }, + complete: function() { + Recaptcha.reload(); + } + }); + } else { + $('#blank_comment').show(); + $('#comment_text').css('border', '2px solid red') + } + return false; + }); +}); diff --git a/includes/recaptchalib.php b/includes/recaptchalib.php new file mode 100644 index 0000000..32c4f4d --- /dev/null +++ b/includes/recaptchalib.php @@ -0,0 +1,277 @@ + $value ) + $req .= $key . '=' . urlencode( stripslashes($value) ) . '&'; + + // Cut the last '&' + $req=substr($req,0,strlen($req)-1); + return $req; +} + + + +/** + * Submits an HTTP POST to a reCAPTCHA server + * @param string $host + * @param string $path + * @param array $data + * @param int port + * @return array response + */ +function _recaptcha_http_post($host, $path, $data, $port = 80) { + + $req = _recaptcha_qsencode ($data); + + $http_request = "POST $path HTTP/1.0\r\n"; + $http_request .= "Host: $host\r\n"; + $http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n"; + $http_request .= "Content-Length: " . strlen($req) . "\r\n"; + $http_request .= "User-Agent: reCAPTCHA/PHP\r\n"; + $http_request .= "\r\n"; + $http_request .= $req; + + $response = ''; + if( false == ( $fs = @fsockopen($host, $port, $errno, $errstr, 10) ) ) { + die ('Could not open socket'); + } + + fwrite($fs, $http_request); + + while ( !feof($fs) ) + $response .= fgets($fs, 1160); // One TCP-IP packet + fclose($fs); + $response = explode("\r\n\r\n", $response, 2); + + return $response; +} + + + +/** + * Gets the challenge HTML (javascript and non-javascript version). + * This is called from the browser, and the resulting reCAPTCHA HTML widget + * is embedded within the HTML form it was called from. + * @param string $pubkey A public key for reCAPTCHA + * @param string $error The error given by reCAPTCHA (optional, default is null) + * @param boolean $use_ssl Should the request be made over ssl? (optional, default is false) + + * @return string - The HTML to be embedded in the user's form. + */ +function recaptcha_get_html ($pubkey, $error = null, $use_ssl = false) +{ + if ($pubkey == null || $pubkey == '') { + die ("To use reCAPTCHA you must get an API key from https://www.google.com/recaptcha/admin/create"); + } + + if ($use_ssl) { + $server = RECAPTCHA_API_SECURE_SERVER; + } else { + $server = RECAPTCHA_API_SERVER; + } + + $errorpart = ""; + if ($error) { + $errorpart = "&error=" . $error; + } + return ' + + '; +} + + + + +/** + * A ReCaptchaResponse is returned from recaptcha_check_answer() + */ +class ReCaptchaResponse { + var $is_valid; + var $error; +} + + +/** + * Calls an HTTP POST function to verify if the user's guess was correct + * @param string $privkey + * @param string $remoteip + * @param string $challenge + * @param string $response + * @param array $extra_params an array of extra variables to post to the server + * @return ReCaptchaResponse + */ +function recaptcha_check_answer ($privkey, $remoteip, $challenge, $response, $extra_params = array()) +{ + if ($privkey == null || $privkey == '') { + die ("To use reCAPTCHA you must get an API key from https://www.google.com/recaptcha/admin/create"); + } + + if ($remoteip == null || $remoteip == '') { + die ("For security reasons, you must pass the remote ip to reCAPTCHA"); + } + + + + //discard spam submissions + if ($challenge == null || strlen($challenge) == 0 || $response == null || strlen($response) == 0) { + $recaptcha_response = new ReCaptchaResponse(); + $recaptcha_response->is_valid = false; + $recaptcha_response->error = 'incorrect-captcha-sol'; + return $recaptcha_response; + } + + $response = _recaptcha_http_post (RECAPTCHA_VERIFY_SERVER, "/recaptcha/api/verify", + array ( + 'privatekey' => $privkey, + 'remoteip' => $remoteip, + 'challenge' => $challenge, + 'response' => $response + ) + $extra_params + ); + + $answers = explode ("\n", $response [1]); + $recaptcha_response = new ReCaptchaResponse(); + + if (trim ($answers [0]) == 'true') { + $recaptcha_response->is_valid = true; + } + else { + $recaptcha_response->is_valid = false; + $recaptcha_response->error = $answers [1]; + } + return $recaptcha_response; + +} + +/** + * gets a URL where the user can sign up for reCAPTCHA. If your application + * has a configuration page where you enter a key, you should provide a link + * using this function. + * @param string $domain The domain where the page is hosted + * @param string $appname The name of your application + */ +function recaptcha_get_signup_url ($domain = null, $appname = null) { + return "https://www.google.com/recaptcha/admin/create?" . _recaptcha_qsencode (array ('domains' => $domain, 'app' => $appname)); +} + +function _recaptcha_aes_pad($val) { + $block_size = 16; + $numpad = $block_size - (strlen ($val) % $block_size); + return str_pad($val, strlen ($val) + $numpad, chr($numpad)); +} + +/* Mailhide related code */ + +function _recaptcha_aes_encrypt($val,$ky) { + if (! function_exists ("mcrypt_encrypt")) { + die ("To use reCAPTCHA Mailhide, you need to have the mcrypt php module installed."); + } + $mode=MCRYPT_MODE_CBC; + $enc=MCRYPT_RIJNDAEL_128; + $val=_recaptcha_aes_pad($val); + return mcrypt_encrypt($enc, $ky, $val, $mode, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"); +} + + +function _recaptcha_mailhide_urlbase64 ($x) { + return strtr(base64_encode ($x), '+/', '-_'); +} + +/* gets the reCAPTCHA Mailhide url for a given email, public key and private key */ +function recaptcha_mailhide_url($pubkey, $privkey, $email) { + if ($pubkey == '' || $pubkey == null || $privkey == "" || $privkey == null) { + die ("To use reCAPTCHA Mailhide, you have to sign up for a public and private key, " . + "you can do so at http://www.google.com/recaptcha/mailhide/apikey"); + } + + + $ky = pack('H*', $privkey); + $cryptmail = _recaptcha_aes_encrypt ($email, $ky); + + return "http://www.google.com/recaptcha/mailhide/d?k=" . $pubkey . "&c=" . _recaptcha_mailhide_urlbase64 ($cryptmail); +} + +/** + * gets the parts of the email to expose to the user. + * eg, given johndoe@example,com return ["john", "example.com"]. + * the email is then displayed as john...@example.com + */ +function _recaptcha_mailhide_email_parts ($email) { + $arr = preg_split("/@/", $email ); + + if (strlen ($arr[0]) <= 4) { + $arr[0] = substr ($arr[0], 0, 1); + } else if (strlen ($arr[0]) <= 6) { + $arr[0] = substr ($arr[0], 0, 3); + } else { + $arr[0] = substr ($arr[0], 0, 4); + } + return $arr; +} + +/** + * Gets html to display an email address given a public an private key. + * to get a key, go to: + * + * http://www.google.com/recaptcha/mailhide/apikey + */ +function recaptcha_mailhide_html($pubkey, $privkey, $email) { + $emailparts = _recaptcha_mailhide_email_parts ($email); + $url = recaptcha_mailhide_url ($pubkey, $privkey, $email); + + return htmlentities($emailparts[0]) . "...@" . htmlentities ($emailparts [1]); + +} + + +?> diff --git a/includes/style.css b/includes/style.css index 1af153d..c1cdb12 100644 --- a/includes/style.css +++ b/includes/style.css @@ -5,6 +5,7 @@ h3 { margin-top:15px; + font-family:sans-serif; } a { @@ -134,16 +135,23 @@ li { /* notes */ #notes, #note { - float:right; text-align:right; margin-top:20px; } -#notes h2, #note h2 { +#notes h2 { margin-bottom:10px; font-family:sans-serif; } +#note h2 { + font-family:sans-serif; +} + +#comment_link { + font-size:80%; +} + .note { margin-bottom:40px; } @@ -158,4 +166,70 @@ pre { #navigation { text-align:right; + font-family:sans-serif; +} + +#comments { + border-right:1px solid black; + padding-right:15px; +} + +.comment { + margin-bottom:30px; +} + +#comment { + padding-right:15px; + border-right:1px solid black; + margin-top:15px; + text-align:right; +} + +#comment input { + border:1px solid grey; +} + +#comment textarea { + border:1px solid grey; +} + +#comment .submit { + background:#FFF; + border:1px solid white; + color:blue; + cursor:pointer; + font-size:120%; + font-weight:bold; +} + +#recaptcha_widget { + position:relative; +} + +#recaptcha_image { + position:absolute; + top:0px; + right:0px; +} + +#recaptcha_widget { + display:none; +} + +#not_human { + display:none; + font-weight:bold; + font-family:sans-serif; + color:red; + margin-top:15px; + margin-bottom:15px; +} + +#blank_comment { + display:none; + font-weight:bold; + font-family:sans-serif; + color:red; + margin-top:15px; + margin-bottom:15px; } diff --git a/index.php b/index.php index f151a74..424f850 100644 --- a/index.php +++ b/index.php @@ -1,72 +1,88 @@ config_file); + $config = parse_ini_file($this->config_file, true); $this->db = new mysqli( - $config['domain'], - $config['user'], - $config['password'], - $config['database']); - if (mysqli_connect_errno()) { - echo "Problem connecting to database: "; - echo mysqli_connect_error(); - exit(); - } - ob_start(); + $config[database]['domain'], + $config[database]['user'], + $config[database]['password'], + $config[database]['database']); + if (mysqli_connect_errno()) { + echo "Problem connecting to database: "; + echo mysqli_connect_error(); + exit(); + } + $this->recaptcha_publickey = $config['recaptcha']['publickey']; + $this->recaptcha_privatekey = $config['recaptcha']['privatekey']; + $this->title = $config['site']['default_title']; + $this->home_link = $config['site']['home_link']; + ob_start(); } public static function determine_type() { if (isset($_GET['page']) && is_numeric($_GET['page'])) { - return 'page'; - } else if (isset($_GET['year'])) { - return 'archive'; - } else if (isset($_GET['note'])) { - return 'note'; - } else if ($_SERVER['REQUEST_URI'] == '/') { + return 'page'; + } else if (isset($_GET['year'])) { + return 'archive'; + } else if (isset($_GET['note'])) { + return 'note'; + } else if ($_SERVER['REQUEST_URI'] == '/') { return 'index'; - } else if (isset($_GET['project'])) { + } else if (isset($_GET['project'])) { return 'project'; - } + } else if (isset($_GET['challenge'])) { + return 'captcha'; + } } public function query() { $args = func_get_args(); - $statement = $this->db->prepare($args[0]); - $args = array_slice($args, 1); - call_user_func_array(array($statement, 'bind_param'), &$args); - $statement->execute(); - $return = array(); - $statement->store_result(); - $row = array(); - $data = $statement->result_metadata(); - $fields = array(); - $fields[0] = &$statement; - while($field = $data->fetch_field()) { - $fields[] = &$row[$field->name]; - } - call_user_func_array("mysqli_stmt_bind_result", $fields); - $i = 0; - while ($statement->fetch()) { - foreach ($row as $key1=>$value1) $return[$i][$key1] = $value1; - $i++; - } - $statement->free_result(); - return $return; - } + $statement = $this->db->prepare($args[0]); + $args = array_slice($args, 1); + call_user_func_array(array($statement, 'bind_param'), &$args); + $statement->execute(); + $return = array(); + $statement->store_result(); + $row = array(); + $data = $statement->result_metadata(); + $fields = array(); + $fields[0] = &$statement; + while($field = $data->fetch_field()) { + $fields[] = &$row[$field->name]; + } + call_user_func_array("mysqli_stmt_bind_result", $fields); + $i = 0; + while ($statement->fetch()) { + foreach ($row as $key=>$value) $return[$i][$key] = $value; + $i++; + } + $statement->free_result(); + return $return; + } public function display_head($title = "dylanstestserver", - $home_link = "/") { + $home_link = "/") { $scripts = ""; - $stylesheets = ""; - if (cms::determine_type() == "index") { - $scripts = ""; - $home_link = "http://validator.w3.org/unicorn/check?ucn_uri=dylanstestserver.com&ucn_task=conformance#"; - } - echo <<determine_type() == 'note') { + $scripts = ""; + $scripts .= ""; + $scripts .= ""; + $scripts .= ""; + } + echo << @@ -76,7 +92,7 @@ abstract class cms { "HTML Tidy for Linux (vers 25 March 2009), see www.w3.org"> - $title + $this->title $stylesheets $scripts @@ -85,7 +101,7 @@ abstract class cms {
@@ -99,35 +115,36 @@ END_OF_HEAD; +
END_OF_CONTACT; } public function display_close($show_contact = true) { if ($show_contact) { - $this->display_contact(); - } + $this->display_contact(); + } echo << -
+

END_OF_CLOSE; - ob_flush(); - } + ob_flush(); + } } + class index extends cms { - public function display() { - $this->display_head(); - $this->display_exhibits(); - echo "
    "; - $this->list_projects(); - echo << + + public function display() { + $this->display_head(); + $this->display_exhibits(); + echo "
      "; + $this->list_projects(); + echo <<things i've done for others: @@ -161,57 +178,63 @@ class index extends cms {
    • OTHER_PROJECTS; - // Because of the CSS necessary for the animations, - // the contact link needs to be in #portfolio to clear - // the floats. - echo "
    • "; - $this->display_contact(); - echo "
    • "; - echo "
    "; - $this->display_close($show_contact = false); - } - - protected function display_exhibits() { - echo "
    "; - $sql = "SELECT text FROM projects"; - $result = $this->db->query($sql); - while ($entry = $result->fetch_object()) { - echo $entry->text; - } - echo "
    "; - } - - private function list_projects() { - echo <<"; + $this->display_contact(); + echo ""; + echo "
"; + $this->display_close($show_contact = false); + } + + protected function display_exhibits() { + echo "
"; + $sql = "SELECT text FROM projects"; + $result = $this->db->query($sql); + while ($entry = $result->fetch_object()) { + echo $entry->text; + } + echo "
"; + } + + private function list_projects() { + echo <<

my projects:

HEREDOC; - $sql = "SELECT title FROM projects"; - $result = $this->db->query($sql); - while ($entry = $result->fetch_object()) { - echo "
  • title\">$entry->title
  • "; - } - } + $sql = "SELECT title FROM projects"; + $result = $this->db->query($sql); + while ($entry = $result->fetch_object()) { + echo "
  • $entry->title
  • "; + } + } + } + class project extends index { - protected function display_exhibits() { - echo "
    "; - $sql = "SELECT text FROM projects - WHERE title = ?"; - $result = $this->query($sql, "s", $_GET['project']); - if ($result = $result[0]['text']) { - $text = str_replace("class=\"exhibit\"", "class=\"exhibit\" style=\"display:block;\"", $result); - echo $text; - echo "
    "; - } else { - throw new notFound(); - } - } + + protected function display_exhibits() { + echo "
    "; + $sql = "SELECT text FROM projects + WHERE title = ?"; + $result = $this->query($sql, "s", $_GET['project']); + if ($result = $result[0]['text']) { + $text = str_replace("class='exhibit'", "class='exhibit' style='display:block;'", $result); + echo $text; + echo "
    "; + } else { + throw new notFound(); + } + } + } + class page extends cms { + private $page = 1; private $offset = 0; private $notes_per_page = 4; @@ -219,65 +242,65 @@ class page extends cms { public function __construct() { parent::__construct(); - $this->page_offset(); + $this->page_offset(); } private function page_offset() { - $sql = "SELECT COUNT(*) FROM notes"; - $result = $this->db->query($sql); - $result = $result->fetch_array(); - $this->number_of_pages = ceil($result[0] / $this->notes_per_page); - if (isset($_GET['page']) && is_numeric($_GET['page'])) { - $this->page = (int) $_GET['page']; - } else { - throw new notFound(); - } - if ($this->page > $this->number_of_pages) { - throw new notFound(); - } - if ($this->page < 1) { - throw new notFound(); - } - $this->offset = ($this->page - 1) * $this->notes_per_page; + $sql = "SELECT COUNT(*) FROM notes"; + $result = $this->db->query($sql); + $result = $result->fetch_array(); + $this->number_of_pages = ceil($result[0] / $this->notes_per_page); + if (isset($_GET['page']) && is_numeric($_GET['page'])) { + $this->page = (int) $_GET['page']; + } else { + throw new notFound(); + } + if ($this->page > $this->number_of_pages) { + throw new notFound(); + } + if ($this->page < 1) { + throw new notFound(); + } + $this->offset = ($this->page - 1) * $this->notes_per_page; } public function display() { $this->display_head(); - echo "
    "; + echo "
    "; $sql = "SELECT date_posted, title, url, text FROM notes ORDER BY date_posted DESC - LIMIT ?, ?"; - $result = $this->query($sql, "ii", - $this->offset, - $this->notes_per_page); - foreach ($result as $row => $entry) { - $title = $entry['title']; - $url = '/note/' . $entry['url']; - $date_posted = explode("-", $entry['date_posted']); - $year_posted = $date_posted[0]; - $month_posted = $date_posted[1]; - $datetime_posted = explode(' ', $date_posted[2]); - $day_posted = $datetime_posted[0]; - echo "
    "; - echo "

    $year_posted/$month_posted/$day_posted/$title

    "; - echo $entry['text']; - echo "
    "; - } - echo "
    "; - $this->write_navigation(); + LIMIT ?, ?"; + $result = $this->query($sql, "ii", + $this->offset, + $this->notes_per_page); + foreach ($result as $row => $entry) { + $title = $entry['title']; + $url = '/note/' . $entry['url']; + $date_posted = explode("-", $entry['date_posted']); + $year_posted = $date_posted[0]; + $month_posted = $date_posted[1]; + $datetime_posted = explode(' ', $date_posted[2]); + $day_posted = $datetime_posted[0]; + echo "
    "; + echo "

    $year_posted/$month_posted/$day_posted/$title

    "; + echo $entry['text']; + echo "
    "; + } + echo "
    "; + $this->write_navigation(); $this->display_close(); } private function write_navigation() { - echo "
    "; + echo ""; @@ -285,50 +308,225 @@ class page extends cms { } + class note extends cms { + private $id; + private $comments_enabled = false; + private $failed_captcha; + public $url; + public $title; + public $year_posted; + public $month_posted; + public $day_posted; + public $text; + public $number_of_comments; + public function __construct() { parent::__construct(); - $this->check_exists(); - } - - private function check_exists() { - $sql = "SELECT COUNT(*) FROM notes - WHERE url = ?"; - $results = $this->query($sql, "s", $_GET['note']); - if ($results[0]["COUNT(*)"] != 1) { - throw new notFound(); - } + if (isset($_GET['comments'])) { + $this->comments_enabled = true; + } + $url = htmlspecialchars($_SERVER['REQUEST_URI']); + if (isset($_GET['verify'])) { + $url = substr($url, 0, (strlen($url)-6)); + } + $this->url = $url; + $sql = "SELECT title, date_posted, text, id + FROM notes WHERE url = ?"; + $result = $this->query($sql, "s", + $_GET['note']); + if ($result) { + $entry = $result[0]; + $this->id = $entry["id"]; + $this->title = $entry["title"]; + $date_posted = explode("-", $entry["date_posted"]); + $this->year_posted = $date_posted[0]; + $this->month_posted = $date_posted[1]; + $datetime_posted = explode(' ', $date_posted[2]); + $this->day_posted = $datetime_posted[0]; + $this->text = $entry["text"]; + } else { + throw new notFound(); + } + $sql = "SELECT COUNT(*) FROM comments + WHERE note = $this->id"; + $result = $this->db->query($sql); + $result = $result->fetch_array(); + $this->number_of_comments = $result[0]; + if (isset($_GET['verify'])) { + $this->verify(); + } } public function display() { - $this->display_head(); - $sql = "SELECT title, date_posted, text - FROM notes WHERE url = ?"; - $result = $this->query($sql, "s", - $_GET['note']); - $entry = $result[0]; - $title = $entry["title"]; - $date_posted = explode("-", $entry["date_posted"]); - $year_posted = $date_posted[0]; - $month_posted = $date_posted[1]; - $datetime_posted = explode(' ', $date_posted[2]); - $day_posted = $datetime_posted[0]; - echo "
    "; - echo "

    $year_posted/$month_posted/$day_posted/$title

    "; - echo $entry['text']; - $this->write_navigation(); + $this->display_head(); + $this->display_note(); + if ($this->comments_enabled) { + $this->display_comments(); + $this->display_comment_form(); + } + $this->write_navigation(); $this->display_close(); } + private function verify() { + if (!isset($_POST['captcha'])) { + require_once('includes/recaptchalib.php'); + echo "
    "; + $resp = recaptcha_check_answer ($this->recaptcha_privatekey, + $_SERVER["REMOTE_ADDR"], + $_POST["recaptcha_challenge_field"], + $_POST["recaptcha_response_field"]); + if (!$resp->is_valid) { + $this->failed_captcha = true; + } + } + if (isset($_POST['captcha']) || $resp->is_valid) { + $sql = ("INSERT INTO comments (date_posted, author, + text, note) + VALUES(NOW(), ?, ?, ?)"); + $stmt = $this->db->prepare($sql); + // Checks are needed here (no blank text, + // and a default author needs to be set + // for no-javascript users. + $stmt->bind_param('sss', + htmlspecialchars($_POST['name']), + htmlspecialchars($_POST['text']), + $this->id); + $stmt->execute(); + } + } + + private function display_note() { + echo << +

    $this->year_posted/$this->month_posted/$this->day_posted/$this->title

    + $this->text +
    +END_OF_NOTE; + } + private function write_navigation() { - echo "
    "; - echo "
    "; - echo "

    "; - echo "notes/"; - echo "

    "; + echo << + +END_OF_NAVIGATION; + } + + private function display_comment_link() { + if ($this->number_of_comments > 0) { + $anchor_text = "comments($this->number_of_comments)/"; + } else { + $anchor_text = "comment?"; + } + if (substr($this->url, (strlen($this->url)-1), strlen($this->url)) == '/') { + $url = $this->url . 'comments/'; + } else { + $url = $this->url . '/comments/'; + } + echo "$anchor_text"; + } + + private function display_comments() { + echo "
    "; + $sql= "SELECT date_posted, author, text + FROM comments WHERE note = ? + ORDER BY date_posted DESC"; + $result = $this->query($sql, 'd', $this->id); + foreach ($result as $row => $entry) { + $date_posted = $entry['date_posted']; + $author = $entry['author']; + $text = htmlspecialchars($entry['text']); + $head = "

    $author

    "; + echo << + $head + $text +
    +END_OF_COMMENT; + } echo "
    "; } + + private function display_comment_form() { + $publickey = $this->recaptcha_publickey; + echo << +Recaptcha.create("$publickey", + "recaptcha_div", + { + theme : 'custom', + custom_theme_widget: 'recaptcha_widget', + callback: Recaptcha.focus_response_field + }); + +END_CAPTCHA_STYLE; + require_once('includes/recaptchalib.php'); + $url = $this->url . "verify"; + echo "
    "; + echo << +

    comment:

    + +

    name:

    + + + +
    +

    what's this say?

    +

    enter the numbers you hear:

    + + ( another / + audio / + imagehelp ) + +

    + +

    +
    +
    +
    +



    +
    +END_OF_FORM; + echo recaptcha_get_html($this->recaptcha_publickey); + if ($this->failed_captcha) { + echo << + reCAPTCHA said you're not human,
    + try again? +
    + + + +END_OF_ERRORS; + } else { + echo << + reCAPTCHA said you're not human,
    + try again? + +
    + but you didn't write anything!
    +
    +END_OF_ERRORS; + } + echo << + + +END_OF_FORM; + } } @@ -340,114 +538,138 @@ class archive extends cms { private function check_exists() { $sql = "SELECT COUNT(*) FROM notes - WHERE url = ?"; - $results = $this->query($sql, "s", $_GET['note']); - if ($results[0]["COUNT(*)"] != 1) { - $this->not_found(); - } + WHERE url = ?"; + $results = $this->query($sql, "s", $_GET['note']); + if ($results[0]["COUNT(*)"] != 1) { + $this->not_found(); + } } public function display() { - // this really needs its own pagination... - // there should be a class for that. - $this->display_head(); - switch (true) { - case (isset($_GET['year']) && !isset($_GET['month']) - && !isset($_GET['day'])): - $sql = "SELECT title, url, date_posted, text - FROM notes WHERE YEAR(date_posted) = ? - ORDER BY date_posted DESC"; - $result = $this->query($sql, "d", - $_GET['year']); - break; - case (isset($_GET['year']) && isset($_GET['month']) - && !isset($_GET['day'])): - $sql = "SELECT title, url, date_posted, text - FROM notes WHERE YEAR(date_posted) = ? - AND MONTH(date_posted) = ? - ORDER BY date_posted DESC"; - $result = $this->query($sql, "dd", - $_GET['year'], $_GET['month']); - break; - case (isset($_GET['year']) && isset($_GET['month']) - && isset($_GET['day'])): - $sql = "SELECT title, url, date_posted, text - FROM notes WHERE YEAR(date_posted) = ? - AND MONTH(date_posted) = ? - AND DAY(date_posted) = ? - ORDER BY date_posted DESC"; - $result = $this->query($sql, "ddd", - $_GET['year'], $_GET['month'], - $_GET['day']); - break; - } - if (count($result) >= 1) { - echo "
    "; - foreach ($result as $row => $entry) { - $title = $entry['title']; - $url = '/note/' . $entry['url']; - $date_posted = explode("-", $entry['date_posted']); - $year_posted = $date_posted[0]; - $month_posted = $date_posted[1]; - $datetime_posted = explode(' ', $date_posted[2]); - $day_posted = $datetime_posted[0]; - echo "
    "; - echo "

    $year_posted/$month_posted/$day_posted/$title

    "; - echo $entry['text']; - echo "
    "; - } - echo "
    "; - $this->write_navigation(); - } else { - echo "
    "; - echo "

    sorry, nothing here

    "; - echo "
    Empty set (0.00 sec)
    "; - } + $this->display_head(); + switch (true) { + case (isset($_GET['year']) && !isset($_GET['month']) + && !isset($_GET['day'])): + $sql = "SELECT title, url, date_posted, text + FROM notes WHERE YEAR(date_posted) = ? + ORDER BY date_posted DESC"; + $result = $this->query($sql, "d", + $_GET['year']); + break; + case (isset($_GET['year']) && isset($_GET['month']) + && !isset($_GET['day'])): + $sql = "SELECT title, url, date_posted, text + FROM notes WHERE YEAR(date_posted) = ? + AND MONTH(date_posted) = ? + ORDER BY date_posted DESC"; + $result = $this->query($sql, "dd", + $_GET['year'], $_GET['month']); + break; + case (isset($_GET['year']) && isset($_GET['month']) + && isset($_GET['day'])): + $sql = "SELECT title, url, date_posted, text + FROM notes WHERE YEAR(date_posted) = ? + AND MONTH(date_posted) = ? + AND DAY(date_posted) = ? + ORDER BY date_posted DESC"; + $result = $this->query($sql, "ddd", + $_GET['year'], $_GET['month'], + $_GET['day']); + break; + } + if (count($result) >= 1) { + echo "
    "; + foreach ($result as $row => $entry) { + $title = $entry['title']; + $url = '/note/' . $entry['url']; + $date_posted = explode("-", $entry['date_posted']); + $year_posted = $date_posted[0]; + $month_posted = $date_posted[1]; + $datetime_posted = explode(' ', $date_posted[2]); + $day_posted = $datetime_posted[0]; + echo "
    "; + echo "

    "; + echo "$year_posted/$month_posted/$day_posted/"; + echo "$title

    "; + echo $entry['text']; + echo "
    "; + } + echo "
    "; + $this->write_navigation(); + } else { + echo "
    "; + echo "

    sorry, nothing here

    "; + echo "
    Empty set (0.00 sec)
    "; + } $this->display_close(); } private function write_navigation() { - echo "
    "; - echo "
    "; + echo "
    "; + echo ""; } + } class notFound extends Exception { - public function __construct() { - header("HTTP/1.0 404 Not Found"); - ob_end_clean(); - include("404.php"); - exit(); - } + + public function __construct() { + header('HTTP/1.0 404 Not Found'); + ob_end_clean(); + include('404.php'); + exit(); + } + +} + + +class captcha extends cms { + + public function display() { + $challenge = $_GET['challenge']; + $response = $_GET['response']; + $remoteip = $_SERVER['REMOTE_ADDR']; + $curl = curl_init('http://api-verify.recaptcha.net/verify?'); + curl_setopt ($curl, CURLOPT_POST, 4); + curl_setopt ($curl, CURLOPT_POSTFIELDS, "privatekey=$this->recaptcha_privatekey&remoteip=$remoteip&challenge=$challenge&response=$response"); + $result = curl_exec ($curl); + curl_close ($curl); + } + } + ## now actually do something: switch (cms::determine_type()) { - case "index": + case 'index': $index = new index(); - $index->display(); - break; - case "project": + $index->display(); + break; + case 'project': $project = new project(); - $project->display(); - break; - case "note": + $project->display(); + break; + case 'note': $note = new note; - $note->display(); - break; - case "page": + $note->display(); + break; + case 'page': $page = new page; - $page->display(); - break; - case "archive": + $page->display(); + break; + case 'archive': $archive = new archive; - $archive->display(); - break; + $archive->display(); + break; + case "captcha": + $captcha = new captcha; + $captcha->display(); + break; } ?> diff --git a/notes/notes.php b/notes/notes.php deleted file mode 100644 index e71ae69..0000000 --- a/notes/notes.php +++ /dev/null @@ -1,70 +0,0 @@ -"; - $title = $note['title']; - $date_posted = explode("-", $note['date_posted']); - $year_posted = $date_posted[0]; - $month_posted = $date_posted[1]; - $day_posted = $date_posted[2]; - echo "

    $year_posted/$month_posted/$day_posted/$title

    "; - echo $note['text']; - echo "
    "; - } - } else { - if (isset($_GET['page']) && is_numeric($_GET['page'])) { - $page = (int) $_GET['page']; - } else { - $page = 1; - } - if ($page < 1) { - $page = 1; - } else if ($page > $total_number_of_pages) { - $page = $total_number_of_pages; - } - $page_offset = ($page - 1) * $notes_per_page; - $notes = mysql_query("SELECT title, date_posted, text, url - FROM notes ORDER BY date_posted DESC - LIMIT $page_offset, $notes_per_page"); - while($note = mysql_fetch_array($notes)) { - echo "
    "; - $title = $note['title']; - $date_posted = explode("-", $note['date_posted']); - $year_posted = $date_posted[0]; - $month_posted = $date_posted[1]; - $day_posted = $date_posted[2]; - $url = $note['url']; - echo "

    $year_posted/$month_posted/$day_posted/$title

    "; - echo $note['text']; - echo "
    "; - } - echo "

    "; - if($page != 1){ - if(!$page == 2 && $total_number_of_pages == 2) - echo "first / "; - $previous_page = $page - 1; - echo "prev"; - } - if($page < $total_number_of_pages) { - $forward_page = $page + 1; - echo "next"; - } - if($page != $total_number_of_pages && (!$page == 1 && $total_number_of_pages == 2)){ - echo " / last"; - } - echo "

    "; - } -?> diff --git a/sample.ini b/sample.ini index 67e4350..cb1b244 100644 --- a/sample.ini +++ b/sample.ini @@ -5,3 +5,13 @@ domain = localhost user = dylanstestuser password = "dylanstestpassword" database = dylanstestserver + +[recaptcha] +# sign up here: +# https://www.google.com/recaptcha/admin/create +publickey = +privatekey = + +[site] +default_title = dylanstestserver +home_link = /