<?php /* vim: set tabstop=4: */ /* * blogs class - provides functions for blogs */ // PHP Notices are fun, but we don't really want to see them right now error_reporting(E_ALL ^ E_NOTICE); // Initialise the database require_once("/usr/share/adodb/adodb.inc.php"); $BlogDB = NewADOConnection('postgres8'); $BlogDB->Connect('dbname=blogs'); $BlogDB->SetFetchMode(ADODB_FETCH_ASSOC); // Some useful validation functions require_once("validation.lib.php"); // Some useful miscellaneous functions require_once("miscfunctions.lib.php"); /* a stub of an error handler scale of 1-5, 5 being warnings, 1 being fatal errors? 1 : fatal 2 : dberror 3 4 : bad input 5 : not found/doesnt exist etc */ function error($level, $error) { echo("<p class=\"errorinfo\">"._("Level ").$level._(" error - ").$error."</p>"); } //A bit of a nicer error handler, to allow errors encounterd in the construction phase to be displayed in the 'correct' place function error_exc($e) { if (!isset($e->error) || !isset($e->errormsg)) { echo("<p class=\"errorinfo\">"._("Level 0 error - no error message available")."</p>"); } else { echo("<p class=\"errorinfo\">"._("Level ").$e->error._(" error - ").$e->errormsg."</p>"); } } //Our Blogs Class class blogs { //Blog ID var $id; //Blogger's Details var $userName; var $realName; //Blog Details var $title; var $description; var $cssFile; //Date formats var $shortDateFormat; var $longDateFormat; //Paths var $httpPath; var $blogPath; var $basePath; var $adminPath; //bools var $comment_moderation; var $editor; //surely this should be in admin.lib? it doesnt seem to be used in blog.lib var $currentEntry; //Errors var $error; var $errormsg; //SVN Revision... the closest thing we've got to a version number var $svnRevision; //Constructor - checks we've been given a valid username, and pulls in generic blog info function blogs($user) { global $BlogDB; //set the error string first, so we dont wipe out any errors $this->error = null; $this->errormsg = null; //set the locale setlocale(LC_ALL, 'en_GB'); //check the username if(!safeuname($user)) { $this->error = 1; $this->errormsg = "No such user"; return; } else { //check to see if the user has a blog $sql = $BlogDB->GetRow("SELECT id, name, title, description, css, moderate, editor from users where username = '".$user."' and enabled = true;"); if (!$sql) { $this->error = 1; $this->errormsg = "No such user"; return; } else { //pull in the blog details $this->id = $sql['id']; $this->userName = $user; $this->realName = $sql['name']; $this->title = $sql['title']; $this->description = $sql['description']; $this->cssFile = $sql['css']; $this->shortDateFormat = "%x %X"; $this->longDateFormat = "%c"; //set path for all http stuff.. ie images, css and so on $this->httpPath = "/Blogs/"; //make the httpPath work nicely if we're not in a subdir //if(substr($this->httpPath, -1)!="/") { // $this->httpPath .= "/"; //} //path for the blog viewer with no user $this->basePath = "/Blogs/"; //path to this blog $this->blogPath = $this->basePath.$this->userName."/"; //path to the admin bits $this->adminPath = $this->httpPath."Admin/"; $this->comment_moderation = ($sql['moderate']=='t') ? TRUE : FALSE; $this->editor = ($sql['editor']=='t') ? TRUE : FALSE; $this->currentEntry = ""; $this->svnRevision = getSVNRevision(); //setup the session session_name("BlogSession"); session_start(); } } } // print a blog entry, when provided with a database $row containing one. function printEntry($row, $commentLink = true, $titleLink = true) { global $pathlist; echo "<div class=\"box\">\n"; echo "<div class=\"boxhead\"><h2>"; if ($titleLink) { echo "<a href=\"{$this->blogPath}entry/". htmlentities($row['shortsubject']) ."\">". htmlentities($row['subject']) ."</a>"; } else { echo htmlentities($row['subject']); } if ($pathlist[3]=="entry") { // If we're displaying a single entry, hack the pathlist into shape $pathlist[3]=$row['subject']; unset($pathlist[4]); } echo "</h2></div>\n"; echo "<div class=\"boxcontent\">\n"; echo $row['body'] . "\n"; echo "</div>\n"; echo "<div class=\"boxfoot\"><p>[ Entry posted at: ".strftime($this->longDateFormat,strtotime($row['timestamp'])); if ($commentLink) { echo " | <a href=\"".$this->blogPath."entry/{$row['shortsubject']}\">Comments</a>: ".$this->commentCount($row['id']); } else { echo " | ".$this->commentCount($row['id'])." comment(s)..."; } echo " | Cat: <a href=\"".$this->blogPath."category/{$row['category']}\">".$this->categoryName($row['category'])."</a> "; if($this->checkSessionOwner()){ echo "| <a href=\"".$this->adminPath."update/{$row['shortsubject']}\">"._("Edit")."</a> "; //delete link, disabled for now //echo "| <a href=\"".$this->adminPath."deleteentry/{$row['shortsubject']}\">"._("Delete")."</a>"; } echo " ]</p></div>\n"; echo "</div>\n"; } // print lots of blog entries function printEntries($offset=0, $limit=15, $constraint='') { global $BlogDB; //get the entries from the database $sql = $BlogDB->GetAll("SELECT id, category, subject, body, timestamp, shortsubject from entries where user_id = '".$this->id."' ".$constraint." order by timestamp desc limit ".$limit." offset ".$offset.";"); //return an error if we cant find any if (count($sql) < 1) { error(5,"No relevant posts"); } else { //print each entry while ($sqlRow = array_shift($sql)) { $this->printEntry($sqlRow); } //archive link echo "<div class=\"archivelink\"><a href=\"{$this->blogPath}Archive/\">"._("archived posts...")."</a></div>"; } } // print old entries sorted by either date (default), subject or category function printArchive($request) { switch(trim($request[0])) { case 'category' : array_shift($request); $this->printArchiveByCategory($request); break; case 'subject' : array_shift($request); $this->printArchiveBySubject($request); break; case 'date' : array_shift($request); $this->printArchiveByDate($request); break; default : $this->printArchiveByDate($request); } } // print a list of entries by date function printArchiveByDate($request) { global $BlogDB; $request = preg_grep('/.+/', $request); // Remove any additional silly extra elements due to additional /'s //get the refinements if set $year = (isset($request[0]) && is_numeric($request[0])) ? $request[0] : ""; $month = (isset($request[1]) && is_numeric($request[1])) ? $request[1] : ""; $day = (isset($request[2]) && is_numeric($request[2]) ) ? $request[2] : ""; // Get the last request option (sort order) after the date $lastIndex = count($request) - 1; $order = strtoupper($request[$lastIndex]); //this ensures order is sane switch($order) { case 'ASC' : $strOppositeOrder = 'Descending'; $oppositeOrder = 'DESC'; $strOrder = 'Ascending'; break; case 'DESC' : default : $strOppositeOrder = 'Ascending'; $oppositeOrder = 'ASC'; $strOrder = 'Descending'; $order = 'DESC'; } if($month=="" && $day=="") { $enddate = $year+1; } elseif($month != "" && $day=="") { $enddate = $year.(sprintf("%02d", $month+1)); } else { $enddate = $year.$month.(sprintf("%02d", $day+1)); } $sql = "SELECT shortsubject,subject,timestamp FROM entries WHERE ".((!$year)? "" : "timestamp >= $year$month$day AND timestamp < $enddate AND ") . "user_id = '".$this->id."' ORDER BY timestamp " . $order; $result = $BlogDB->GetAll($sql); $requestPath = (count($request) > 0)?implode ( $request, '/' ) . '/':''; $curyear = ""; $curmonth = ""; $curday = ""; echo "<div class=\"td\"><h2>Sorted By <a href=\"" . $this->blogPath . "Archive/date/\">Date</a> (" . $strOrder . ")</h2><a href=\"" . $this->blogPath . "Archive/date/" . $requestPath . "" . $oppositeOrder . "\"> Sort " . $strOppositeOrder . "</a> || Sort By <a href=\"" . $this->blogPath . "Archive/category\">Category</a> | <a href=\"" . $this->blogPath . "Archive/subject\"> Subject </a><br />"; if ( count($result) >= 1 ) { while($row = array_shift($result)){ if($curyear!=date("Y", strtotime($row['timestamp']))) { $curyear = date("Y", strtotime($row['timestamp'])); echo "<h1><a href=\"".$this->blogPath."Archive/$curyear\">$curyear</a></h1>"; } if($curmonth!=date("F", strtotime($row['timestamp']))) { $curmonth = date("F", strtotime($row['timestamp'])); echo "<h2><a href=\"".$this->blogPath."Archive/".date("Y/m", strtotime($row['timestamp']))."\">$curmonth</a></h2>\n"; } if($curday!=date("l jS", strtotime($row['timestamp']))) { $curday = date("l jS", strtotime($row['timestamp'])); echo "<h3><a href=\"".$this->blogPath."Archive/".date("Y/m/d", strtotime($row['timestamp']))."\">$curday</a></h3>\n"; } echo date("g:ia", strtotime($row['timestamp']))." - <a href=\"{$this->blogPath}entry/{$row['shortsubject']}\">". htmlentities($row['subject']) ."</a><br />\n"; } } else { error(5,"No Entries Available" . ($allentries ? '' : " for $year" . ($month != '' ? "/$month":'') . ($day != '' ? "/$day":''))); } echo "</div>"; } //print a list of entries by category function printArchiveByCategory($request) { global $BlogDB; // Check for a category id // There must be a better way to check that it isn't $order $request = preg_grep('/.+/', $request); // Remove any additional silly extra elements due to additional /'s if (isset($request[0]) && (strtoupper($request[0]) != 'ASC') && (strtoupper($request[0]) != 'DESC')) { $category = $this->makeCleanString($request[0]); if (strlen($category) < 3) $allentries = true; } else { $allentries = true; } $lastIndex = count($request) - 1; // Get the last request option after the date $order = 'ASC'; if (isset($request[$lastIndex]) && (($lastIndex > 0) || isset($allentries)) && (strlen($request[$lastIndex]) > 2)) { $order = strtoupper($request[$lastIndex]); array_pop($request); } switch($order) { case 'DESC' : $strOppositeOrder = 'Ascending'; $oppositeOrder = 'ASC'; $strOrder = 'Descending'; break; case 'ASC' : default : $strOppositeOrder = 'Descending'; $oppositeOrder = 'DESC'; $strOrder = 'Ascending'; $order = 'ASC'; } $sql = "SELECT shortsubject,subject,timestamp, name FROM entries AS e,categories AS c WHERE " . ($allentries ? "" : " lower(c.name) = '" . $category . "' AND ") . "e.user_id = '".$this->id."' AND e.category = c.id ORDER BY " . ($allentries? "name " . $order . " ,timestamp ASC" : "timestamp " . $order ); $result = $BlogDB->GetAll($sql); $requestPath = (count($request) > 0)?implode ( $request, '/' ) . '/':''; $dbCategory = ''; echo "<div class=\"td\"><h2>Sorted By <a href=\"" . $this->blogPath . "Archive/category/\">Category</a> (" . $strOrder . ")</h2><a href=\"" . $this->blogPath . "Archive/category/" . $requestPath . "" . $oppositeOrder . "\"> Sort " . $strOppositeOrder . "</a> || Sort By <a href=\"" . $this->blogPath . "Archive/date\">Date</a> | <a href=\"" . $this->blogPath . "Archive/subject\"> Subject </a><br />"; if ( count($result) >= 1 ) { while($row = array_shift($result)){ if($dbCategory != $row['name']) { $dbCategory = $row['name']; echo "<h1><a href=\"".$this->blogPath."Archive/category/$dbCategory\">$dbCategory</a></h1>"; } echo date("d/m/Y", strtotime($row['timestamp'])) . " - <a href=\"{$this->blogPath}entry/{$row['shortsubject']}\">". htmlentities($row['subject']) ."</a><br />\n"; } echo "</div>"; } else { error(5,"No Entries Available" . (isset($category) ? " in $category":'')); } } //print a list of entries by title function printArchiveBySubject ($request) { global $BlogDB; // Look for a single character to show subjects by $request = preg_grep('/.+/', $request); // Remove any additional silly extra elements due to additional /'s if (isset($request[0]) && (preg_match('/^[a-z]$/i', $request[0]))) { $letter = strtolower($request[0]); } else { $allentries = true; } // Get whether it is Ascending or Descending $lastIndex = count($request) - 1; // Get the last request option after the date $order = 'ASC'; if (isset($request[$lastIndex]) && !is_numeric($request[$lastIndex])) { $order = strtoupper($request[$lastIndex]); array_pop($request); } switch($order) { case 'DESC' : $strOppositeOrder = 'Ascending'; $oppositeOrder = 'ASC'; $strOrder = 'Descending'; break; case 'ASC' : default : $strOppositeOrder = 'Descending'; $oppositeOrder = 'DESC'; $strOrder = 'Ascending'; $order = 'ASC'; } $requestPath = (count($request) > 0)?implode ( $request, '/' ) . '/':''; // lower() exists in PG and MySQL, but given that db abstraction is wanted, is it part of the SQL standard? // Should a better method be used? $sql = "SELECT shortsubject,subject,timestamp FROM entries WHERE ".(($allentries)? "" : "lower(subject) LIKE '" . $letter . "%' AND ") . "user_id = '".$this->id."' ORDER BY subject " . $order; $result = $BlogDB->GetAll($sql); echo "<div class=\"td\"><h2>Sorted By <a href=\"" . $this->blogPath . "Archive/subject/\">Subject</a> (" . $strOrder . ")</h2><a href=\"" . $this->blogPath . "Archive/subject/" . $requestPath . "" . $oppositeOrder . "\"> Sort " . $strOppositeOrder . "</a> || Sort By <a href=\"" . $this->blogPath . "Archive/date\">Date</a> | <a href=\"" . $this->blogPath . "Archive/category\"> Category </a><br /><a href=\"" . $this->blogPath . "Archive/subject/a/$order\">a</a> | <a href=\"" . $this->blogPath . "Archive/subject/b/$order\">b</a> | <a href=\"" . $this->blogPath . "Archive/subject/c/$order\">c</a> | <a href=\"" . $this->blogPath . "Archive/subject/d/$order\">d</a> | <a href=\"" . $this->blogPath . "Archive/subject/e/$order\">e</a> | <a href=\"" . $this->blogPath . "Archive/subject/f/$order\">f</a> | <a href=\"" . $this->blogPath . "Archive/subject/g/$order\">g</a> | <a href=\"" . $this->blogPath . "Archive/subject/h/$order\">h</a> | <a href=\"" . $this->blogPath . "Archive/subject/i/$order\">i</a> | <a href=\"" . $this->blogPath . "Archive/subject/j/$order\">j</a> | <a href=\"" . $this->blogPath . "Archive/subject/k/$order\">k</a> | <a href=\"" . $this->blogPath . "Archive/subject/l/$order\">l</a> | <a href=\"" . $this->blogPath . "Archive/subject/m/$order\">m</a> | <a href=\"" . $this->blogPath . "Archive/subject/n/$order\">n</a> | <a href=\"" . $this->blogPath . "Archive/subject/o/$order\">o</a> | <a href=\"" . $this->blogPath . "Archive/subject/p/$order\">p</a> | <a href=\"" . $this->blogPath . "Archive/subject/q/$order\">q</a> | <a href=\"" . $this->blogPath . "Archive/subject/r/$order\">r</a> | <a href=\"" . $this->blogPath . "Archive/subject/s/$order\">s</a> | <a href=\"" . $this->blogPath . "Archive/subject/t/$order\">t</a> | <a href=\"" . $this->blogPath . "Archive/subject/u/$order\">u</a> | <a href=\"" . $this->blogPath . "Archive/subject/v/$order\">v</a> | <a href=\"" . $this->blogPath . "Archive/subject/w/$order\">w</a> | <a href=\"" . $this->blogPath . "Archive/subject/x/$order\">x</a> | <a href=\"" . $this->blogPath . "Archive/subject/y/$order\">y</a> | <a href=\"" . $this->blogPath . "Archive/subject/z/$order\">z</a><br />"; if ( count($result) >= 1 ) { while($row = array_shift($result)){ echo date("d/m/Y", strtotime($row['timestamp'])) . " - <a href=\"{$this->blogPath}entry/{$row['shortsubject']}\">". htmlentities($row['subject']) ."</a><br />\n"; } } else { error(5, "No Entries Available" . ($allentries ? '' : " beginning with '$letter'")); } echo "</div>"; } //print Prev/Next nav bar function printNavigationBar($id) { global $BlogDB; $sql = $BlogDB->GetRow("SELECT timestamp from entries WHERE id='".$id."'"); $prev = $BlogDB->GetAll("SELECT id, shortsubject, subject FROM entries WHERE timestamp < '".$sql['timestamp']."' AND user_id = '".$this->id."' ORDER BY timestamp DESC LIMIT 1"); $next = $BlogDB->GetAll("SELECT id, shortsubject, subject FROM entries WHERE timestamp > '".$sql['timestamp']."' AND user_id = '".$this->id."' ORDER BY timestamp ASC LIMIT 1;"); if (count($prev)>0) $prevRow=array_shift($prev); if (count($next)>0) $nextRow=array_shift($next); echo "<div class=\"navbar\"><div><div><div>\n"; echo "<ul class=\"blognav\">"; if ($prevRow['shortsubject']!="") echo "<li class=\"prev\"><a href=\"{$this->blogPath}entry/{$prevRow['shortsubject']}\">< ".htmlentities($prevRow['subject'])."</a></li>"; if ($nextRow['shortsubject']!="") echo "<li class=\"next\"><a href=\"{$this->blogPath}entry/{$nextRow['shortsubject']}\">".htmlentities($nextRow['subject'])." ></a></li>"; echo "</ul>\n"; echo "<br style=\"clear: both:\" /></div></div></div></div>\n"; } //print one entry and its comments function printEntryAndComments($shortsubject) { global $BlogDB; $shortsubject = $this->makeCleanString($shortsubject); $sql = $BlogDB->GetRow("SELECT id, category, subject, body, timestamp, shortsubject from entries where shortsubject='".$shortsubject."' and user_id = ".$this->id." LIMIT 1;"); if (!$sql) { error(5,"No relevant posts"); } else { $this->currentEntry = $sql['shortsubject']; $this->printNavigationBar($sql['id']); $this->printEntry($sql, false, false); $this->printComments($sql['id']); $this->printCommentForm($sql['id']); } } //print lots of comments function printComments($postid, $offset=0, $limit=15) { global $BlogDB; $sql = $BlogDB->GetAll("SELECT timestamp, name, email, body, host, id FROM comments WHERE post = ".$postid." and moderated = true ORDER BY timestamp ASC limit ".$limit." OFFSET ".$offset.";"); echo "<div id=\"comments\">\n"; if (count($sql) > 0) { $blogOwner = $this->checkSessionOwner(); if($blogOwner) { echo "<form name=\"deletecomments\" id=\"deletecomments\" method=\"post\" action=\"{$this->adminPath}deletecomments/{$this->currentEntry}\">\n"; } $count=0; while ($sqlRow = array_shift($sql)) { $this->printComment($sqlRow, $blogOwner, $count++); } if($blogOwner) { echo "<div style=\"width: 100%; text-align: right\">\n"; echo "<input type=\"submit\" name=\"submit\" value=\"Delete Comments\" />\n"; echo "</div>\n"; echo "</form>\n"; } } echo "</div>\n"; } //print a comment function printComment($row, $printCheckBox=FALSE, $checkBoxNum=0) { echo "<div class=\"box\">\n"; echo "<div class=\"boxhead\"><h3>" . htmlentities($row['name']) . " writes:</h3></div>"; echo "<div class=\"boxcontent\"><p>" . nl2br(htmlentities(br2nl($row['body']))) . "</p></div>\n"; echo "<div class=\"boxfoot\"><p>[ " .strftime($this->longDateFormat,strtotime($row['timestamp'])); if($printCheckBox){ echo " | <input class=\"smallcheckbox\" type=\"checkbox\" id=\"comment{$checkBoxNum}\" name=\"comment[{$checkBoxNum}]\" value=\"{$row['id']}\" />\n"; echo "<label for=\"comment{$checkBoxNum}\">Delete</label>\n"; } echo " ]</p></div>\n"; echo "</div>\n"; } //counts the number of comments function commentCount($entry) { global $BlogDB; $sql = $BlogDB->GetCol("SELECT count(id) from comments where post = ".$entry." and moderated = true;"); return $sql[0]; } //returns a category name function categoryName($category) { global $BlogDB; $sql = $BlogDB->GetCol("SELECT name from categories where id = ".$category.";"); return $sql[0]; } //prints a form so people can comment function printCommentForm($id) { echo "<div class=\"entry\">\n"; echo "<h2>Add Comment<a id=\"cmt\"></a></h2>\n"; echo "<div class=\"td\">\n"; if ($this->commentError != "") { echo "<p class=\"invalid\">*** " . $this->commentError . " ***</p>\n"; } elseif (isset($_POST['submit'])) { echo "<p>Thank you for your comment</p>\n"; } // try to work out the viewer's name + email //seems a bit silly to check for the existance of the session stuff in two places, its probably fair to assume if one is set, the other will be too //these need the same validation checks as when we put things into the db, else people can inject what ever html they like into our pages if(isset($_SESSION['realName'])) { $name = $_SESSION['realName']; } elseif(isset($_COOKIE['Blog_CommentRealName'])) { $name = $_COOKIE['Blog_CommentRealName']; } else { $name = ""; } if(isset($_SESSION['userName'])) { $email = $_SESSION['userName']."@sucs.org"; } elseif(isset($_COOKIE['Blog_CommentEmailAddress'])) { $email = $_COOKIE['Blog_CommentEmailAddress']; } else { $email = ""; } echo "<form onsubmit=\"return postcomment('".$this->httpPath."', '".$this->userName."', '".$id."')\" action=\"".$this->blogPath."postcomment/".$id."\" method=\"post\" id=\"commentform\">\n"; echo "<div class=\"row\">\n"; echo "<label for=\"author\">Name (required)</label>\n"; echo "<span class=\"textinput\"><input type=\"text\" name=\"author\" id=\"author\" value=\"$name\" size=\"40\" maxlength=\"50\" tabindex=\"1\" /></span>\n"; echo "</div>\n"; echo "<div class=\"row\">\n"; echo "<span class=\"textinput\"><input type=\"text\" name=\"email\" id=\"email\" value=\"$email\" size=\"40\" maxlength=\"70\" tabindex=\"2\" /></span>\n"; echo "<label for=\"email\">E-mail (required, not displayed)</label>\n"; echo "</div>\n"; echo "<div class=\"row\">\n"; echo "<span class=\"textinput\"><textarea name=\"comment\" id=\"comment\" cols=\"50\" rows=\"10\" tabindex=\"3\">" . (($this->commentError != "") ? strip_tags($_POST['comment']) : "") . "</textarea></span>\n"; echo "</div>\n"; echo "<div class=\"row\">\n"; echo "<span class=\"textinput\"><input name=\"submit\" type=\"submit\" id=\"submit\" tabindex=\"4\" value=\"Submit Comment\" /></span>"; echo "<img src=\"".$this->httpPath."img/spinner.gif\" alt=\"\" id=\"spinner\"/>\n"; echo "<label class=\"invalid\" for=\"submit\" id=\"errors\"></label>\n"; echo "</div>\n<div class=\"clear\"></div>"; echo "</form>\n"; echo "</div>\n"; echo "</div>\n"; } //takes a string and strips it, making it safe to put in a URL function makeCleanString($string,$externalSource=false) { //externalSource meaning directly inputed by a user, in most cases this should be false.. appart from starting a new post $string = strtolower($string); $string = preg_replace("/[^a-z0-9\- _]/i", "", $string); $string = str_replace(" ", "-",trim($string)); if ($externalSource) { $string = str_replace("_", "-",$string); } $string = urlencode($string); return $string; } //handles posting of comments function newComment($id, $printentry=TRUE) { global $BlogDB; $author = ""; $email = ""; $comment = ""; //check the post exists, and is part of this blog $row = $BlogDB->GetRow("SELECT subject, id from entries where user_id = ".$this->id." and id = '".$id."';"); if (!$row) { error(1,_("Invalid blog entry, This entry may have been removed..?")); return; } //pull in the unadulterated subject for later on $subject = $row['subject']; $postid = $row['id']; //set hostname if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { $host = addslashes($_SERVER['HTTP_X_FORWARDED_FOR']) . " : " . addslashes($_SERVER['REMOTE_ADDR']); } else { $host = addslashes($_SERVER['REMOTE_ADDR']); } //sanitise comment if (isset($_POST['comment']) && trim($_POST['comment']) != "") { if(strip_tags($_POST['comment']) == $_POST['comment']) { $comment = addslashes(nl2br(trim($_POST['comment']))); } else { $this->commentError = _("HTML within comments is not allowed, Please remove all html tags and try again"); $element = "comment"; } } else { $this->commentError = _("Please check the comment field"); $element = "comment"; } //decided if the comment is likly to be spam if (checkSpam($host,$_POST['comment'])) { $spam = true; //force this comment though moderation $this->comment_moderation = true; } else { $spam = false; } //sanitise email if (isset($_POST['email']) && trim($_POST['email']) != "" && validEmail(trim($_POST['email']))) { $email = addslashes(trim($_POST['email'])); } else { $this->commentError = _("Check email address, it does not apear to be valid."); $element = "email"; } //sanitse author if (isset($_POST['author']) && trim($_POST['author']) != "") { if(eregi("^([a-z0-9]+ *)+$", $_POST['author'])) { $author = addslashes(nl2br(trim(strip_tags($_POST['author'])))); } else { $this->commentError = _("Invalid name. We only allow alphanumeric names!"); $element = "author"; } } else { $this->commentError = _("Please give us your name."); $element = "author"; } //if no errors have been raised so far commit to the db if ($this->commentError == "") { // do we need to set the moderated flag on this comment? if(!$this->comment_moderation) { $moderated = TRUE; } else { //check the list of 'authorised' commentors if(count($BlogDB->GetAll("SELECT name FROM authorised_emails WHERE user_id={$this->id} AND email='{$email}'"))>0) { $moderated = TRUE; } else { $moderated = FALSE; } } //actualy insert the new comment and check it worked $query = "INSERT INTO comments (post, name, email, body, host, moderated, spam) VALUES ('{$postid}','{$author}','{$email}','{$comment}','{$host}', ".(($moderated) ? "true" : "false").", ".(($spam) ? "true" : "false").")"; if(!$BlogDB->Execute($query)) { error(2,_("Database commit failed -").$BlogDB->ErrorMsg()); } //send out an notificaiton email if we have succeeded unless we think its spam or moderation has been bypassed else { if(!$spam or !$moderated) mail($this->userName . "@sucs.org", "Blog comment on \"".$subject."\"", "You've received a comment from ".$author." on your blog post \"".$subject.". The comment is:\n==========\n".$comment.(($moderated) ? "" : "\n==========\nPlease login to your blog admin page to approve or delete this comment."), "From: Your Blog <noreply@sucs.org>"); //inform the commentor if the message has been tagged for modderation if(!$moderated) { echo "<p class=\"updateinfo\">"._("Your comment has been added, but before it appears here it must be accepted by the blog owner.")."</p>"; } //or pass out the comment useing the standard form elseif(!$printentry) { $time = strftime($this->longDateFormat, time()); $this->printComment(array('name'=>$author, 'body'=>$comment, 'timestamp'=>$time)); } //reprint the entire entry (for the case where we're not useing the ajax goodness) if($printentry) { $this->printEntryAndComments($shortSubject); } //if we dont have a valid session store the name & email in there own cookies if(!isset($_SESSION['realName'])) { setcookie("Blog_CommentRealName", $author, time()+604800); setcookie("Blog_CommentEmailAddress", $email, time()+604800); } ob_end_flush(); return array(TRUE); } //else return our error and the status gumf for the benifit of the ajax goodness } else { echo $this->commentError; return array(FALSE, $element); } } //reutrns the id of the message assosiated with a short subject function shortSubjectToID($shortsubject) { global $BlogDB; $sql = $BlogDB->GetRow("SELECT id from entries where user_id = ".$this->id." and shortsubject = '".$shortsubject."';"); if ($sql) { return $sql['id']; } else { error(3,"No such post"); } } //reutrns the short subject of the message given message function IDToShortSubject($id) { global $BlogDB; $sql = $BlogDB->GetRow("SELECT shortsubject from entries where user_id = ".$this->id." and id = '".$id."';"); if ($sql) { return $sql['shortsubject']; } else { error(3,"No such post"); } } // Blog menu function menu() { global $smarty, $session; $submenu = array(); if ($session->loggedin && blogger($session->username)) $submenu[_("My Blog")] = "{$this->httpPath}{$session->username}"; if ($session->username != $this->userName) $userblog = $this->userName._("'s Blog"); $submenu[$userblog] = $this->blogPath; if ($session->username == $this->userName) $archiveblog = _("My Archive"); else $archiveblog = $this->userName._("'s Archive"); $submenu[$archiveblog] = "{$this->blogPath}Archive/"; if ($this->checkSessionOwner() && blogger($session->username)){ $submenu[_("Blog admin")] = "{$this->adminPath}"; } $menu = $smarty->get_template_vars("menu"); $menu[Blogs] = $submenu; $smarty->assign("menu", $menu); } // Check the session to see if the user is browsing her own blog function checkSessionOwner() { global $session; $maxSessionAge = 3600; // if the session's expired then nuke it if ($session->username != $this->userName) { return FALSE; } else { // the time's not up and the usernames match so it's probably the right user. return TRUE; } } } // a pseudo-class to list all blog users class bloglist { var $title; var $description; var $httpPath; var $listPath; var $adminPath; var $cssFile; var $svnRevision; // the SVN revision number of the currently running blog // don't do anything apart from setting up default variables function bloglist() { $this->title = _("Blogs"); $this->description = _("Swansea University Computer Society member web logs"); $this->httpPath = "/Blogs/"; //if(substr($this->httpPath, -1)!="/") { // $this->httpPath .= "/"; //} $this->basePath = "/Blogs/"; $this->adminPath = $this->httpPath."Admin/"; $this->cssFile = "blog.css"; $this->svnRevision = getSVNRevision(); // setup the session purely so we get the debug bits.. session_name("BlogSession"); session_start(); } // print a nice list of blog users and when they last updated function listBlogs() { global $BlogDB, $session; $sql = $BlogDB->GetAll("SELECT max(entries.timestamp) AS ts, users.username, users.description, users.name, users.title FROM entries LEFT JOIN users ON entries.user_id = users.id GROUP BY users.username, users.name, users.title, users.description ORDER BY ts DESC;"); if (count($sql) > 0) { echo "<div class=\"td\">\n"; echo "<p>"._("Welcome to SUCS Blogs - The multi-user web log system created by SUCS members for SUCS members.")."</p>\n"; echo "<p>"._("Browse the blogs below or use the links on the left to navigate the site. Happy blogging!")."</p>\n"; if ($session->loggedin && !blogger($session->username)) echo "<p>"._("Want to join the ranks of SUCS bloggers? - ")."<a href=\"{$this->adminPath}signup\">"._("Start a Blog!")."</a></p>\n"; echo "</div>\n"; echo "<div id=\"listofblogs\">\n"; echo "<table class=\"border\">\n"; echo "<tr><th class=\"bname\">"._("Name")."</th><th class=\"btitle\">"._("Blog")."</th><th class=\"bupdated\">"._("Last Updated")."</th></tr>"; while($row = array_shift($sql)) { echo "<tr>\n"; echo " <td>".$row['name']."</td>\n"; echo " <td><a href=\"".$this->basePath.$row['username']."\" title=\"".$row['description']."\">".$row['title']."</a></td>\n"; echo " <td>".$this->timeDiff(strtotime($row['ts']))." ago</td>\n"; echo "</tr>\n"; } echo "</table>\n"; echo "</div>\n"; } else { error(3,_("No blogs")); } } //Returns a textual diff between two time stamps function timeDiff($first, $second=0) { if($second == 0) { $second = time(); } $diff = max($first, $second) - min($first, $second); if($diff>604800) { $ret = round($diff/604800); return $ret.(($ret>1)? _(" weeks") : _(" week")); } elseif($diff>86400) { $ret = round($diff/86400); return $ret.(($ret>1)? _(" days") : _(" day")); } elseif($diff>3600) { $ret = round($diff/3600); return $ret.(($ret>1)? _(" hours") : _(" hour")); } elseif($diff>60) { $ret = round($diff/60); return $ret.(($ret>1)? _(" minutes") : _(" minute")); } else { return $diff.(($diff>1)? _(" seconds") : _(" second")); } } // Blog menu - links displayed when the blog list is displayed function menu() { global $smarty, $session; if ($session->loggedin) { $submenu = array(); if (blogger($session->username)) { $submenu[_("My Blog")] = "{$this->httpPath}{$session->username}"; $submenu[_("Blog admin")] = "{$this->adminPath}"; } else { $submenu[_("Start a Blog")] = "{$this->adminPath}signup"; } $menu = $smarty->get_template_vars("menu"); $menu[Blogs] = $submenu; $smarty->assign("menu", $menu); } } }