<?php
/************************************************************************
* *
* Copyright (C) 2001 Stuart Reeves *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* The GNU General Public License is available from: *
* http://www.gnu.org/copyleft/gpl.html *
* *
************************************************************************/
/* Stuart's lns (lame node system) */
/* UserInput provides a method of checking user-entered data so that various problems, such as
* disallowed HTML and invalid names, are flagged */
class UserInput
{
// Basic entered information from the user
var $nodename,
$link,
$author,
$contact,
$text,
$protected,
$metatype,
$silentupdate;
var $username,
$superuser,
$timestamp;
// Constructor
function UserInput($nodename,
$author,
$contact,
$link,
$text,
$protected,
$metatype,
$silentupdate) {
$this->nodename = $nodename;
$this->link = $link;
$this->author = $author;
$this->contact = $contact;
$this->text = $text;
$this->metatype = $metatype;
if ($silentupdate)
$this->silentupdate = true;
else
$this->silentupdate = false;
if ($protected)
$this->protected = true;
else
$this->protected = false;
$this->superuser = false;
}
/* Various get functions */
function getNodename() {
return $this->nodename;//stripslashes(htmlentities($this->nodename, ENT_QUOTES)));
}
function getAuthor() {
return $this->author;
}
function getContact() {
return $this->contact;
}
function getLink() {
return $this->link;
}
function setLink($link) {
$this->link = $link;
}
function getText() {
return $this->text;
}
function setText($text) {
$this->text = $text;
}
function getProtected() {
return $this->protected;
}
function getMetatype() {
return $this->metatype;
}
function setMetatype($metatype) {
$this->metatype = $metatype;
}
function getSilentupdate() {
return $this->silentupdate;
}
/* Sets the currently logged in username. This automatically fills in the author and
* contact details.
*
* Args: $username - Current session username */
function setUsername($username) {
if (isset($username)) {
$this->username = $username;
$this->author = $username;
$this->contact = "?node=" . FINGER_NODE . "&_username=$username";
}
}
function setSuperuser($superuser) {
$this->superuser = $superuser;
}
function setProtected($protected) {
$this->protected = $protected;
}
/* Set the unique timestamp for this user input session. This means that a particular node is
* being edited.
*
* Args: $timestamp - The timestamp of the node to edit */
function setTimestamp($timestamp) {
$this->timestamp = $timestamp;
}
/* Checks whether a contact exists for the user input object.
*
* Returns: true (boolean) - the contact field exists
* false (boolean) - the contact field does not exist */
function contactExists() {
if($this->contact != "")
return true;
else
return false;
}
/* Parses the text input for link elements and line breaks
*
* Args: $args[0] (string) - Optional argument for text to parse if this method is
* being used statically
*
* Returns: $parsedText (string) - Parsed text according to rules in "header.php.inc" */
function getParsedText() {
$args = func_get_args();
$parsedText = "";
if (isset($args[0]))
$parsedText = $args[0];
else
$parsedText = $this->text;
if (DISALLOW_NODETEXT_HTML)
$parsedText = htmlspecialchars($this->text);
// Replace special link brackets ("[" and "]"). We perform two regexp replacements firstly
// for the "[displayed text|nodename]" syntax, and then for any undetected "[nodename]"
// directives.
$parsedText = preg_replace(NODE_PARSE_REGEXP, NODE_PARSE_REPLACE, $parsedText);
$parsedText = preg_replace(NODE_PARSE_REGEXP2, NODE_PARSE_REPLACE2, $parsedText);
//if ($parseText == $this->text)
// echo "Error<br />\n";
// Replace newline chars with HTML <br />
$parsedText = preg_replace("/([^>]{1})\r/", "$1<br />\n", $parsedText);
return $parsedText;
}
/* Cleans up the nodename string according to header rules.
*
* Returns: $nodename (string) - the cleaned up nodename string */
function getCleanNodename($nodename) {
// Nodename is disallowed dangerous URL-parsed characters, like "&" and "="
$nodename = trim(preg_replace(DISALLOWED_NODENAME_CHARS, "", $nodename));
$nodename = htmlentities($nodename, ENT_QUOTES);
$nodename = stripslashes($nodename);
return $nodename;
}
function getCleanAuthor($author) {
// Check that correct info has been input
if ($author == "")
$author = "Anonymous";
else {
// Author is allowed most characters, but no HTML tags
$author = strip_tags($author);
$author = stripslashes($author);
$author = htmlspecialchars($author, ENT_QUOTES);
}
return $author;
}
function getCleanContact($contact) {
// Contact is not allowed inverted commas and the like. Special URL-parsed chars like
// "&" are not allowed for obvious reasons.
$contact = strip_tags($contact);
$contact = stripslashes($contact);
$contact = trim(preg_replace(DISALLOWED_CONTACT_CHARS, "", $contact));
// Check contact information
if ($contact != "") {
if (strchr($contact, "@")) {
if (substr($contact, 0, 7) != "mailto:")
$contact = "mailto:$contact";
} else if (substr($contact, 0, 7) != "http://")
$contact = "http://$contact";
}
return $contact;
}
function getCleanText($text) {
$text = strip_tags($text, ALLOWED_HTML);
$text = stripslashes($text);
// Temporary fix to disallow JavaScript
$text = preg_replace("/(<[\w\s\=\-\"]*\")(javascript:[^\"]*)(\">)/",
"$1$3", $text);
return $text;
}
function getCleanLink($link) {
// For external links or for files, assuming any input link is HTTP by default
// (unless protocol is specified)
if ($link != "") {
$link = strip_tags($link);
$slashes_pos = strpos($link, "://");
$protocol = substr($link, 0, $slashes_pos);
if ($protocol == "") $link = "http://$link";
}
return $link;
}
/* Tests validity of user input to the object created.
*
* Returns: true (boolean) - The nodename exists
* false (boolean) - The nodename does not exist */
function check() {
// Check the nodename is there
if ($this->nodename != "") {
$this->nodename = $this->getCleanNodename($this->nodename);
// Extra fields for anonymous users
if (!isset($this->username)) {
$this->author = $this->getCleanAuthor($this->author);
$this->contact = $this->getCleanContact($this->contact);
}
// Check the other required fields are there
if ($this->text != "" || $this->link != "") {
$this->text = $this->getCleanText($this->text);
$this->link = $this->getCleanLink($this->link);
} else
return false;
return true;
} else
return false;
}
/* Submits input data to the database. Note that nodes are never, by default, set to hidden.
*
* Args: $host - Database server hostname
* $user - Database username
* $passwd - Database password
* $db - Database name
* $table - Table name
*
* Returns: 1 (integer) - Node creation was successful
* -1 (integer) - Node creation failed due to protected node
* 0 (integer) - Creation failed due to access error */
function createNode($host, $user, $passwd, $db, $table) {
$query = "SELECT * FROM $table WHERE nodename = '$this->nodename'";
$link = mysql_connect($host, $user, $passwd);
$dbselect = mysql_select_db($db, $link);
$dbquery = mysql_query($query, $link);
$code = 0;
// We must iterate through all the rows. If any are protected or hidden, we consider the
// whole node to be protected/hidden (i.e. not editable/addable to).
while ($nodedata = mysql_fetch_object($dbquery)) {
if (($nodedata->protected == 't' && !$this->superuser) || $nodedata->hidden == 't') {
$code = -1;
break;
}
}
// If the previous security check has passed, insert the data as a new row or update
// that entry.
if ($code != -1) {
$parsedText = $this->getParsedText();
$parsedText = addslashes($parsedText);
// Set the protection based on whether the submitter is a superuser or not
$protText = "f";
if ($this->superuser && $this->protected)
$protText = "t";
// Set the raw type: normal node, picture node or external link node
$rawType = RAWTYPE_DEFAULT;
if ($this->link != "") {
// Cut up the link to see if it is a picture or not
$filetype = substr($this->link,
strrpos($this->link, ".") + 1,
strlen($this->link));
if (preg_match(IMAGE_TYPES, $filetype))
$rawType = RAWTYPE_IMAGE;
else
$rawType = RAWTYPE_EXT_LINK;
}
// Anonymous users
if (!isset($this->username)) {
// Anonymous users cannot make METATYPE_HOME nodes
if ($this->metatype != METATYPE_HOME) {
$query = "INSERT INTO $table VALUES (\"$this->nodename\",
\"$this->link\",
NULL,
\"$this->author\",
\"$this->contact\",
\"$parsedText\",
\"$protText\",
\"\",
NULL,
\"$rawType\",
\"$this->metatype\")";
$code = 1;
} else
$code = -1;
} else {
// If the timestamp is set, then we assume we are in edit mode
if (isset($this->timestamp)) {
// Check the ownership of the node to edit.
$userQuery = "SELECT username FROM $table WHERE ts = '$this->timestamp'";
$dbquery = mysql_query($userQuery, $link);
if (mysql_num_rows($dbquery) == 1) {
$nodedata = mysql_fetch_object($dbquery);
if ($nodedata->username == $this->username) {
// Set the update to be ``silent'', i.e. timestamp is preserved
$tsText = "";
if ($this->silentupdate)
$tsText = "ts = ts,";
$query = "UPDATE $table SET $tsText
text = '$parsedText',
link = '$this->link',
protected = '$protText',
rawtype = '$rawType',
metatype = '$this->metatype'
WHERE username = '$this->username'
AND ts = '$this->timestamp'";
$code = 1;
} else
$code = 0;
} else
$code = 0;
} else {
// Make sure there are no other nodes with a metatype of METATYPE_HOME (we
// only allow one METATYPE_HOME node per user).
if ($this->metatype == METATYPE_HOME) {
$homeQuery = "SELECT * FROM $table WHERE metatype = '" . METATYPE_HOME .
"' AND username = '$this->username'";
// Return -1 if the user's home node already exists
if (mysql_num_rows(mysql_query($homeQuery, $link)) == 1) {
mysql_close($link);
return -1;
}
}
$query = "INSERT INTO $table VALUES (\"$this->nodename\",
\"$this->link\",
NULL,
\"$this->username\",
\"\?node=" . FINGER_NODE .
"\&_username=$this->username\",
\"$parsedText\",
\"$protText\",
\"\",
\"$this->username\",
\"$rawType\",
\"$this->metatype\")";
$code = 1;
}
}
// Perform query and recreate indices for searches
if ($code == 1) {
mysql_query($query, $link);
mysql_query("REPAIR TABLE $table QUICK");
}
} // End if
mysql_close($link);
return $code;
}
/* Deletes a node. The session username and timestamp variables must be set to proceed.
* If a superuser is logged in, then any nodes may be deleted, not just ones in edit. If the
* node to delete is part of a node where there are other writeups above it, then the content
* is deleted, but is left to indicate that something is missing.
*
* Args: $host ...
* $table - Database information
*
* Returns: 1 (integer) - Node deletion was successful
* 0 (integer) - Node deletion failed due to access error (e.g. username
* and/or timestamp were not set or username doesn't match
* node's username)
* -1 (integer) - Problem with database (i.e. non-unique timestamp or no
* matching results) */
function deleteNode($host, $user, $passwd, $db, $table) {
if (isset($this->username) && isset($this->timestamp)) {
$link = mysql_connect($host, $user, $passwd);
$dbselect = mysql_select_db($db, $link);
/* Find out whether this node has other entries. If this is the case then the node
* to be deleted will be replaced with a marker indicating that there was once a node
* here. */
$rowsQuery = "SELECT nodename FROM $table WHERE nodename = '$this->nodename'
AND ts > '$this->timestamp'";
$uniqueQuery = "SELECT username FROM $table WHERE nodename = '$this->nodename'
AND ts = '$this->timestamp'";
$rows = mysql_num_rows(mysql_query($rowsQuery, $link));
$dbquery = mysql_query($uniqueQuery, $link);
$unique = mysql_num_rows($dbquery);
$code = 0;
if ($unique == 1) {
$nodedata = mysql_fetch_object($dbquery);
if ($this->superuser || $nodedata->username == $this->username) {
if ($rows > 0) {
// If there are several writeups for this node, then we delete the data
// but leave the timestamp etc. as a marker
$query = "UPDATE $table SET ts = ts,
text = '',
link = '',
author = '',
contact = '',
username = ''
WHERE nodename = '$this->nodename'
AND ts = '$this->timestamp'";
mysql_query($query, $link);
} else {
// Check that there is not a deleted entry before this one (if this is
// the case, we delete it)
$totRowsQuery = "SELECT * FROM $table WHERE nodename = '$this->nodename'
AND ts < '$this->timestamp'
ORDER BY ts DESC";
$dbquery = mysql_query($totRowsQuery, $link);
if (mysql_num_rows($dbquery) > 0) {
$validEntry = false;
while (!$validEntry && $nodedata = mysql_fetch_object($dbquery)) {
// Remove each entry below this one that is also marked for
// deletion
if ($nodedata->text == "" && $nodedata->link == "") {
$query = "DELETE FROM $table
WHERE nodename = '$nodedata->nodename'
AND ts = '$nodedata->ts'";
mysql_query($query, $link);
} else
$validEntry = true;
}
}
// Deal with the case for a single node writeup
$query = "DELETE FROM $table WHERE nodename = '$this->nodename'
AND ts = '$this->timestamp'";
mysql_query($query, $link);
}
$code = 1;
} else
$code = 0;
} else
$code = -1;
mysql_close($link);
return $code;
} else
return 0;
}
} // End class UserInput
?>