Location: PHPKode > scripts > PHP Shoutbox > php_shoutbox/post.php
<?php
/*
** Post class
** Handles all database things dealing with the "posts" table.  All the get_* 
** functions return HTML-friendly code.  All the set_* functions do sanity
** checks (string length, etc).  All queries use prepared statements to prevent
** SQL injections.
**
** Also, the database is not "trusted", so if your database gets injected with
** values that don't pass the above mentioned sanity checks an error will be
** set.
**
** Note: do not rely on the function get_error() for hard-coded error messages,
** they may change over time!
** 
*/

class Post
{
	private $error_desc; // string to hold error information

	// database fields
	private $date;
	private $id;
	private $name;
	private $message;
	private $ip;

	// used in error checking
	public static $max_name_length = 20;
	public static $max_message_length = 255;
	public static $post_threshhold = 120; 	// min number of seconds between 
						// posts for a given IP address

	function __construct()
	{
		$this->date = -1;
		$this->id = -1;
		$this->name = '';
		$this->message = '';
		$this->ip = '';
	}

	/*
	** accessors
	**
	** input: none
	** output: HTML-friendly private member variables
	*/
	public function get_error()
	{
		return htmlentities($this->error_desc, ENT_QUOTES);
	}

	public function get_id()
	{
		return htmlentities($this->id, ENT_QUOTES);
	}

	public function get_name()
	{
		$ret = $this->name;

		// cut off long lines to prevent horizontal scroll bars
		$ret = wordwrap($ret, 10, ' ', true);
		
		// replace html entities
		$ret = htmlentities($ret, ENT_QUOTES);

		// replace newlines with breaks
		$ret = nl2br($ret);

        return $ret;
	}

	public function get_message()
	{
		$ret = $this->message;

		$ret = wordwrap($ret, 60, " ", true);
		$ret = htmlentities($ret, ENT_QUOTES);
		$ret = nl2br($ret);

		return $ret;
	}

	public function get_ip()
	{
		return htmlentities($this->ip, ENT_QUOTES);
	}

	public function get_date()
	{
		return htmlentities($this->date, ENT_QUOTES);
	}

	/*
	** mutators
	**
	** input: values to set private member variables to
	** output: false (and set error_desc) if error, true if success
	*/
	public function set_id($value)
	{
		if (!is_numeric($value) || $value < 1)
		{
			$this->error_desc = 'id must be numeric, greater than 1';
			return false;
		}

		$this->id = $value;
		return true;
	}

	public function set_name($value)
	{
		$length = strlen($value);
		if ($length < 3 || $length > Post::$max_name_length)
		{
			$this->error_desc = 'name must be between 3 and ' 
				. Post::$max_name_length . ' characters';
			return false;
		}

		$this->name = $value;
		return true;
	}

	public function set_message($value)
	{
		$length = strlen($value);
		if ($length < 1 || $length > Post::$max_message_length)
		{
			$this->error_desc = 'message must be between 3 and ' 
				. Post::$max_message_length . ' characters';
			return false;
		}

		$this->message = $value;
		return true;
	}

	public function set_ip($value)
	{
		$length = strlen($value);
		if ($length < 7 || $length > 15)
		{
			$this->error_desc = 'ip must be between 7 and 15 characters';
			return false;
		}

		$this->ip = $value;
		return true;
	}

	public function set_date($value)
	{
		if (!is_numeric($value))
		{
			$this->error_desc = 'incorrect date format';
			return false;
		}
		else
		{
			$this->date = $value;
		}

		return true;
	}

	/*
	** save
	**
	** input: PDO database handle
	** output: false (and set error_desc) if error, true if success
	*/
	public function save($db)
	{
		// make sure this ip didn't write to db within the minimum 
		// threshhold time
		$sql = 'SELECT post_date
				FROM posts
				WHERE post_ip = :ip
				ORDER BY post_id DESC';

		try
		{
			$statement = $db->prepare($sql);
			$statement->execute(array(':ip' => $_SERVER['REMOTE_ADDR']));
			
		}
		catch (Exception $exc)
		{
			$error_desc = 'problem with SQL';
			return false;
		}

		$result = $statement->fetchAll();

		if (isset($result[0]) && 
			($result[0]['post_date'] + Post::$post_threshhold) > time())
		{
			$this->error_desc = 'ip address already posted (minimum time between posts is 
						' . Post::$post_threshhold . ' seconds)';
			return false;
		}

		// new ip, let them post:
		$sql = 'INSERT INTO posts (post_name, post_message, post_ip, post_date)
				VALUES (:name, :message, :ip, :date)';
		
		try
		{
			$statement = $db->prepare($sql);
		}
		catch (Exception $exc)
		{
			$this->error_desc = 'problem with SQL';
			return false;
		}

		// execute statement
		try
		{
			$statement->execute(array(':name' => $this->name,
						':message' => $this->message,
						':ip' => $this->ip,
						':date' => $this->date));
		}
		catch (Exception $exc)
		{
			$this->error_desc = 'problem inserting into database';
			return false;
		}

		// check to make sure statement inserted
		if ($statement->rowCount() == 0)
		{
			$this->error_desc = 'problem inserting into database';
			return false;
		}

		return true;
	}

	/*
	** retrieve
	**
	** sets private member variables from data in database according to post_id
	**
	** input: PDO database handle
	** output: false (and set error_desc) if error, true if success
	*/
	public function retrieve($db)
	{
		if (!is_numeric($this->id) || $this->id < 1)
		{
			$this->error_desc = 'invalid id';
			return false;
		}

		$sql = 'SELECT post_name, post_message
				FROM posts
				WHERE post_id = :id';
		
		try
		{
			$statement = $db->prepare($sql);
			$statement->execute(array(':id' => $this->id));
		}
		catch (Exception $exc)
		{
			$error_desc = 'problem with SQL';
			return false;
		}

		$results = $statement->fetchAll();

		// make sure we found a match
		if(count($results) == 0)
		{
			$this->error_desc = 'no rows matching that id';
			return false;
		}

		// set vars, check to make sure data is in correct format
		if (!$this->set_name($results[0]['post_name']) ||
			!$this->set_message($results[0]['post_message']))
		{
			$error_desc = 'invalid row, possible database corruption!';
			return false;
		}
		
		return true;	
	}

	/*
	** get_posts (static)
	**
	** returns array of all postss in the database in DESC order.
	** can return array with no data.
	**
	** input: PDO database handle
	** output: false (and set error_desc) if error, array if success
	*/
	public static function get_posts($db)
	{
		$posts = array();
		$results = array();
		$sql = 'SELECT post_name, post_message
				FROM posts
				ORDER BY post_id DESC';

		try
		{
			$statement = $db->prepare($sql);
			$statement->execute();
		}
		catch (Exception $exc)
		{	
			$error_desc = 'problem with SQL';
			return false;
		}

		$results = $statement->fetchAll(PDO::FETCH_ASSOC);

		if (count($results) > 0)
		{		
			for($i = 0; $i < count($results); $i++)
			{
				$post = new Post();
				if (!$post->set_name($results[$i]['post_name']) ||
					!$post->set_message($results[$i]['post_message']))
				{
					$error_desc = 'invalid row found in database';
					return false;
				}
				
				array_push($posts, $post);
			}
		}

		return $posts;
	}

	/*
	** prune (static)
	**
	** deletes all posts with lower ids than $num'th row (in DESC order)
	** eg: we want to keep 15 of newest posts, get 15 highest
	** post_ids and delete all post_ids below that.
	**
	** input: PDO database handle, number of posts to keep
	** output: false if error, true if success
	*/
	public static function prune($db, $num)
	{
		if (!is_numeric($num) || $num < 1)
		{
			return false;
		}

		// delete posts with post_ids between 1 and lowest post_id of set of
		// newest $num posts
		
		$sql_sel = 'SELECT post_id
					FROM posts
					ORDER BY post_id DESC
					LIMIT '.$num.', 1';
		$sql_del = 'DELETE FROM posts WHERE post_id <= :id';
		try
		{
			$statement = $db->prepare($sql_sel);
			$statement->execute();
			$results = $statement->fetchAll(PDO::FETCH_ASSOC);
			if (isset($results[0]))
			{
				$statement = $db->prepare($sql_del);
				$statement->execute(array(':id' => $results[0]['post_id']));
			}
		}
		catch (Exception $exc)
		{	
			return false;
		}
		
		return true;
	}
}
?>
Return current item: PHP Shoutbox