Home > PHP >
Polls and Comments with PHP and MySQL | Sitemap Search |
|
Sections Membership Features
Recent comments
very difficult by alfin Taking the credit for another persons work ? by curious dude. |
Polls and Comments with PHP and MySQLPosted by martin on 1 Jun 2002, last updated on 30 Aug 2002. Create a poll voting and comments system with the help of PHP and MySQL. Explains in details the script and database design. What do you need:
So, I don't think you have to spend any money to get these wonderful software packages, and you should be ready to go if you already have them. What are you expected to already know:
A word about the configurationsI use a .htaccess file to setup PHP. If you have any trouble using the code try using these settings. If you get escaped quotes (like \' instead of ') you should use php_value arg_separator.output "&" php_value arg_separator.input "&" php_flag register_globals off php_flag short_open_tag off php_flag magic_quotes_gpc off Getting startedGlobally included code
function connect_db() {
global $link;
$db_host = "localhost";
$db_username = 'username';
$db_pass = 'password';
$db_name = 'database_name';
$link = @mysql_connect($db_host, $db_username, $db_pass)
or die ("Could not connect to database");
@mysql_select_db ($db_name)
or die ("Could not select database");
}
This is a function that connects to the database; I put this in a file that's included from every page at the site. If you think you don't understand anything you should check out the PHP manual. The
<?php
if ( !isset($link) )
connect_db();
$res = @mysql_query("select count from poll where id=0")
or die("Query cm p0 failed");
$result = mysql_fetch_object($res);
$poll = (int) $HTTP_GET_VARS['poll'];
if ( ($poll < 1) or ($poll > $result->count) ) {
mt_srand ((double) microtime() * 1000000);
$poll = mt_rand(1,$result->count);
}
?>
Connect to the database if no connection is established yet, and get the total number of polls available. Check if a GET variable
<form method="get" action="poll.php"
onsubmit="return validateVote(this.vote)">
<table border="0" summary="poll inputs">
<?php
$res = @mysql_query("select title, count, last from poll where id=$poll")
or die("Query poll failed");
$result = mysql_fetch_object($res);
?>
<tr><td><?php echo $result->title?></td></tr>
<?php
$total = $result->count;
$date = $result->last;
$res = @mysql_query("select text, vote from poll_data where id=$poll")
or die("Query poll_data failed");
while ($row = mysql_fetch_object ($res)) {
$input ='<input type="radio" name="vote" value="' .
$row->vote . '" />';
echo "<tr><td>$input $row->text</td></tr>";
}
?>
<tr><td>Total votes: <?php echo $total?></td></tr>
<tr><td>Last vote: <?php echo $date?></td></tr>
<tr><td><input type="submit" value="Vote" />
<a href="poll.php?poll=<?php echo $poll?>"
title="View the current poll results">Results</a></td></tr>
</table>
<div>
<input type="hidden" id="poll" name="poll" value="<?php echo $poll?>" />
</div>
</form>
This one defines the form which is submitted to the polls handling page, in my case Now for the client-side validation function that is run
function validateVote(vote) {
valid = false;
// Opera 5.05 Linux does not support for/in on this object
for ( var i = 0; i < vote.length; i++ ) {
if ( vote[i].checked ) {
valid = true;
break;
}
}
if ( ! valid ) {
alert("You must choose one");
}
return valid;
}
Well, that's all for the include code (this is usually shown on every page). The only other thing you may consider is protecting the file that holds the db username and password, in case PHP isn't there to process the code with something like this in a .htaccess file:
<Files "my_db_password_in_here.php">
Order deny,allow
Deny from all
</Files>
Now to get our hands on the input handling code. The Poll Handling Code
<?php
require "global_includes_file.php";
if ( !isset($link) )
connect_db();
$res = @mysql_query("select count from poll where id=0")
or die("Query polls failed");
$result = mysql_fetch_row($res);
$polls = $result[0];
$poll = (int) $HTTP_GET_VARS['poll'];
if ( $poll > $polls or $poll < 1 )
$poll = 1;
Include a
$poll_voted = (int) $HTTP_COOKIE_VARS['voted'];
$poll_bit = ( 1 << $poll );
if ( !($poll_voted & $poll_bit) ) {
$poll_ok = true;
} else {
$poll_ok = false;
}
$vote = (int) $HTTP_GET_VARS['vote'];
if ( $poll_ok and $vote > 0 and $vote < 6 ) { // count the vote
$cookie_voted = $poll_voted | $poll_bit;
setcookie('voted', $cookie_voted, time()+2592000); // one month time
$sql = "update poll set count=count+1, last=now() where id=$poll";
@mysql_query($sql) or die('Query p2 failed');
$sql = "update poll_data set count=count+1 " .
"where id=$poll and vote=$vote";
@mysql_query($sql) or die('Query p3 failed');
}
Now we do not require visitors to register, just to vote but we neither allow them to vote again and again (except if they erase the cookies, but that's another story in which case you definitely need user registration (there are two articles on evolt: Creating a Login Script with PHP 4 and Creating a Login Script with PHP 4 - Part II on evolt). Make sure you read the articles, if this is what you need. To get by on cookies, get one called To finish the voting update the total number of votes and the current choice (increment by one). I'm not quite sure if MySQL applies locking and other stuff when you pass the queries this way, but this is definitely safer than extracting the value from the database and then explicitly setting it to a value that is incremented in PHP.
function my_esc($input) {
return mysql_escape_string(htmlspecialchars($input) );
}
if ( $HTTP_SERVER_VARS['REQUEST_METHOD'] == 'POST' ) {
$comment = my_esc($HTTP_POST_VARS['fComments']);
$subject = my_esc($HTTP_POST_VARS['fSubject']);
$name = my_esc($HTTP_POST_VARS['fName']);
if ( $name == '' )
$name = 'anonymous';
$email = my_esc($HTTP_POST_VARS['fEmail']);
$poll = (int) $HTTP_POST_VARS['poll'];
if ( $comment != '' )
$sql = "insert into comments " .
"(name, subject, email, comment, date, poll)" .
"values('$name', '$subject', '$email', " .
"'$comment', now(), $poll)"
@mysql_query($sql)
or die('Query add comments failed');
}
Define a function that should escape the HTML and SQL if some
smarty guy has decided to pass it to see what can happen.
I'm not quite sure if this name is OK according to the PHP coding standards but anyway it's short and convenient, think up something else if you want. This is where you should change the code if you definitely want Check if any POSTing has happened, if so escape all the variables passed, and instead of displaying nothing replace the name with "anonymous". If any comments have been POSTed we are ready to begin_head(); ?> <meta name="description" content="Poll results and comments" /> <title>Think up one</title> <?php begin_body() ?> That's supposed you have a function called< code>begin_head() that prints the document type declaration and stuff. Remember we used cookies, so nothing but headers should have been printed until now. The other function begins the body and prints some headers (like navbar or logo, etc.).
<h1>Poll results and comments</h1>
<?php
if ( !$poll_ok and $vote )
echo "<p>You are not allowed to vote again</p>";
$sql = "select title, count, last from poll where id=$poll";
$res = @mysql_query($sql)
or die("Query c2 failed");
$result = mysql_fetch_object($res);
echo "<h2>$result->title</h2>";
$total = $result->count;
$date = $result->last;
?>
Print the first level header of the page and a message that the user is not allowed to vote again, if they've tried. Query the database to get the title, total count and last vote date for the current poll. I know the query failed messages are not user friendly, unfortunately I found that out long after I started using this code.
<table border="0" cellspacing="5" summary="votes statistics">
<?php
$sql = "select text, count from poll_data where id=$poll";
$res = @mysql_query($sql)
or die("Query c3 failed");
if ( mysql_num_rows($res) == 0 ) {
echo "<tr><td><p>Sorry still nothing in here</p></td><
;/tr>";
} else {
while ($row = mysql_fetch_object ($res)) {
$share = round(100 * $row->count / $total, 2);
echo "<tr><td>$row->text</td>
<td>$share% ($row->count)</td></tr>";
}
}
?>
</table>
<p>
Total votes: <?php echo $total?><br />
Last vote: <?php echo $date?>
</p>
Print a table with the poll results, if any. Otherwise a message will be shown, which is needed. Without it you will get a division by zero error when calculating the percentage share of each choice.
<h2>Other polls</h2>
<?php
$res = @mysql_query("select * from poll where id!=$poll and id!=0")
or die("Query c4 failed");
?>
<table border="0" cellspacing="5" summary="other polls">
<tr><th>Poll</th>
<th>Votes</th>
<th>Comments</th>
</tr>
<?php
while ($row = mysql_fetch_object ($res)) {
?>
<tr><td><a
href="poll.php?poll=<?php echo "$row->id" .'">' .
$row->title?></a></td>
<td><?php echo $row->count?></td>
<td><?php echo $row->comments?></td>
</tr>
<?php
}
?>
</table>
Print a table with links to other polls to be viewed/voted for.
Note the query
<h2>Comments</h2>
<div>
<?php
$sql = "select name, subject, email, comment, date " .
"from comments where poll=$poll&q
uot;;
$res = @mysql_query($sql)
or die("Query poll comments failed");
if ( mysql_num_rows($res) == 0 ) {
echo "<p>Sorry still nothing in here</p>";
} else {
while ($row = mysql_fetch_object ($res)) {
?>
<div class="commenthead">
<div class="subject"><?php echo $row->subject ?></div>
<div class="info">by <a href="mailto:<?php echo $row->email ?>">
<?php echo $row->name ?></a> on
<?php echo gmdate('d M Y g:ia', strtotime($row->date)) ?> GMT
</div>
</div>
<div class="comment">
<?php echo $row->comment ?>
</div>
<?php
}
}
?>
</div>
Now for the comments: get all for the current poll from the database (or if nothing is available say so). Iterate over each comment and print its subject. On the next line print the name provided (you may consider not creating it as a
<h2>Say your mind</h2>
<form method="post" action="<?php echo $HTTP_SERVER_VARS['PHP_SELF']?>"
onsubmit="return validateString(this.comment)">
<div><input type="hidden" name="poll" value="<?php echo $poll?>" /></div>
<div class="formwrapper">
<div class="row">
<label for="fName"
title="Write down your name here (optional)">Name:</label>
<span><input type="text" name="fName" id="fName" size="25"
title="Write down your name here (optional)" tabindex="1" /></span>
</div>
<div class="row">
<label for="fEmail"
title="Write down your e-mail here (optional)">E-mail:</label>
<span><input type="text" name="fEmail" id="fEmail" size="25"
title="Write down your e-mail here (optional)" tabindex="2" /></span>
</div>
<div class="row">
<label for="fSubject"
title="Write down a short subject, maximum 60 chars">Subject:</label>
<span><input type="text" name="fSubject" id="fSubject" size="25"
title="Write down a short subject, maximum 60 chars" tabindex="3" />
</span>
</div>
<div class="row">
<textarea cols="40" rows="6" name="fComments" id="fComments"
title="Just write the message here" tabindex="4"></textarea>
</div>
<div class="row" style="padding-bottom : 10px;">
<input type="submit" value="Submit comment"
title="Submit the comment" tabindex="5" />
<input type="reset" value="Clear form"
title="Clears the text box" tabindex="6" />
</div>
</div>
</form>
<p>Note: All fields except the comments are optional.</p>
This is pretty straight forward XHTML so I don't think anyone
should need an explanation. The function that handles
function validateString(str) {
if ( str.value && str.value.length > 0 ) return true
else {
alert("You don't think I can read your mind do you?");
str.focus();
return false;
}
}
Database stuffI apologize for the mixed case database queries; MySQL doesn't care about it so I don't feel I need to type all keywords in uppercase. You first have to create the database and then use
CREATE TABLE poll ( id int NOT NULL auto_increment, title varchar(100) NOT NULL default '', count int NOT NULL default '1', last date, PRIMARY KEY (id) ); CREATE TABLE poll_data ( id int NOT NULL default '0', text char(50) NOT NULL default '', count int NOT NULL default '1', vote tinyint NOT NULL default '0' ); create table comments( name varchar(30) not null default '', subject varchar(50) not null default '', email varchar(30) not null default '', comment text not null default '', date datetime not null default '', poll int not null default '0', ); StylesheetYou can use the following selectors in a stylesheet linked from the
To finish upThe code and a more advanced version of it is available for download. CommentsComments DoS by zhware on 1 Nov 2002 12:22am GMT Maybe adding one more table in witch to put IP address for some period (maybe 1 min) will prevent your from DoS via comments. Something like * On "Submit" from form: 1. is IP address in the table? - no goto 4 2. is the IP from before 1 min? - no display message and quit 3. Remove old IP 4. Add new IP (or just change the timestamp) 5. Add comment 6. display "success" and quit The IP address is in $_SERVER["REMOTE_ADDR"] Re: Comments DoS by martin on 1 Nov 2002 7:31am GMT I'm aware of this but the tutorial would have been much more complicated. Besides there are people (behind AOL proxies for example) who get a different IP for every request and I wouldn't like to impose limits on C class networks. great by irmakerol on 11 Nov 2002 9:58pm GMT great poll but cant install it. the page keeps saying poll query failed.. Poorly Written For n00bies by zigote (zigote@zigote.com) on 17 Dec 2002 4:48pm GMT I'm not posting this to be rude, or even to criticize the writer. I really don't see how this really works... Files are missing with no explanation. MySQL tables are missing from downloaded files. config.php is requiring a DB.php file? Why is that ? add.php is calling html_form.php. In the source above or downloaded files, I see nothing of html_form.php Anyways, And the list goes on. This tutorial is not for the n00bie, I suggest you'll be wasting your time getting this to work. You're better off starting from scratch. im not with you by () on 18 Dec 2002 8:51pm GMT well the better of all these site's tuts is that they give u the idea on how can it work. If you're looking for a n00b poll script go hotscripts.com/PHP there are better (i mean better explained) tuts on how to do it. ;) no comment by zigote (zigote@zigote.com) on 24 Dec 2002 6:46am GMT I agree they are better explained at hotscripts.. I just thought that this tutorial didn't explain the most important details. Missing table by guillem () on 14 Jan 2003 8:10pm GMT The poll i downloaded from your site at http://martin.f2o.org/download/ section it refers somewhere to a sql table called PAGE. But looks like it's not in the sql file you provide. Could you paste the content of that table here? thanks :) question? by may (hfaiedh1@voila.fr) on 16 Jun 2003 5:11pm GMT I would like to know more about PHP and MYSQL. how I can asked my Database? article by () on 25 Aug 2003 4:32pm GMT Very good tutorial question by rianto (rianto_cyber@yahoo.com) on 2 Sep 2003 6:45am GMT im very like with your site because i get more knowledge...thank very much shit by () on 30 Jun 2004 1:22am GMT your site is shit and none of the scripts work shit by () on 30 Jun 2004 2:06am GMT none of your scripts work mysql by christian (prestochris2003@yahoo.com) on 16 Jul 2004 8:14am GMT mysql simple the best Nice by Lewis () on 18 Aug 2004 2:57pm GMT Hey nice tutorial, nice site aswell comments by viktoria () on 11 Jan 2005 2:28am GMT very nice. thanks a lot. |