SCRIPTING:

Tasha Tilberg
PHP MULTIPLE POLLS SNAPSHOT CLASS
Include in your pages a Php 5 script that can immediately produce as many polls and surveys as you may want, and that can create on the fly as many SQL tables and as many HTML forms as necessary to accommodate all the polls (from one to scores).
Count votes excluding multiple voting with cookies. Switch between the vote layout and the see result or vote & see results layout.
The class could ideally even work without passing any argument but to the constructor, if you're alright with its default values.
September 2004
{ @ }

The model above is Tasha Tilberg
LOADS OF TASHA TILBERG ON THE NET

HOW YOUR POLLS WOULD LOOK LIKE
See at a glance what this script produces

This Php 5 version script (Php 4 or lower won't do) produces nicely one or even many polls (surveys) in an easy way, so that you can put them online on any page of yours.
Though you cannot produce with it every kind of poll, yet as long as your poll belongs to the quite common type that requires options that can be picked through uniform sets of either:
  • <input type="radio"> buttons (radios allow one choice only among the available options)
  • <input type="checkbox"> buttons (allows for multiple choices)
  • <select> menus (allows for single or multiple choices)
this script can produce such polls with a minimal coding effort by you (all codes provided by me).

Of course, you can custom the answers and the questions, otherwise it would be useless.
Actually, if you really want to implement more complex polls that would require a mix of those form elements, you can even use this class to produce a wider poll where the user is asked to browse to a next page (by a link) after having answered to each set, so to present the surfer with subsequent different sets of form input fields in case you need this, and realize the mentioned "mix" in this way.

You will also see you can aggregate the results, because the script produces the required SQL tables (inside a SQL database named polls) if a given poll table does not exist, and such default SQL tables are arranged after the following template:
  • id: you can even custom this field name if you don't like it.
    I assume now you have some knowledge of what a SQL table is. So, this field stores a unique numerical auto incrementing identifier (from number 1 onward) for the SQL table row, therefore by this identifier you can build subsequent many-to-many SQL tables using such identifier as their foreign key in case you want to store more data or aggregate it or perform data mining with other sql tables.
  • answer: you can even custom this field name if you don't like it.
    A varchar field where you store each of the available answers for this table that represent a poll.
  • vote: you can even custom this field name if you don't like it.
    A field that obviously stores the votes cast for each given answer.
    A cookie gets set after a vote has been expressed and such cookie lasts 1 hour (you can change that too!) so that your users can't keep voting over and over again for a poll.
    Please note that preventing a computer from performing votes by setting in it a cookie which lasts for longer than one hour is not a wise idea as it might seem: computers could be shared and so the voters could be different, actually, though connected from the same computer (think of an internet cafe).
  • So, a very trivial example of how your sql table would look like for a poll that allows only for two answers (yes or no):

    pollX
    id
    answer
    vote
    1
    Yes
    0
    2
    No
    0

    As you can see, the presence in the table pollX of a unique id for each recordset allows you to use such id to interconnect another sql table of your own conception to these results by linking the recordsets of the latter to such pollX table id.
    Needless to stress, I think, that a numerical id is much more convenient a unique identifier to establish a connection with the whole identified recordset (the row identified by such leading id, that is) than it would have been using for such purpose the whole answer field, which would have arguably been unique as well and yet which, being meant to host an answer, could have also hosted a pretty long string (trivial or silly example: "I agree but I could change my mind in the immediate future") - with the related risks of finding no match if by mistake you try to link the answer field and yet you add, say, one whitespace which wasn't there in the answer field instance.
All you need is of course Php and a mySQL support to create tables within a database. Of course it also requires that, in order to interact with the mySQL database, you have a proxy which has granted the privileges to create tables (and a database too actually if you don't want to create it beforehand by yourself, as you'll see) and lock and select and update and insert into them. If you don't know what a proxy is, you can read the Php Mysql Database Management Class essay.
Anyway consider this your first and foremost requirement (or prerequisite) to make this script work:
You must have a proxy that can be logged by a username and a password to a mySQL database, and this proxy must have rights to create (tables), locke them, select, insert, update on all the tables within a database named polls.
Before I illustrate the inner workings of this Php script, I find it useful to show to you the default layout (which of course you could custom as you'll see) in the case of 4 polls (they could have been more or just one). Of course these layouts are only for illustration purposes, you can not actually vote these polls in this example.

<a href="polls_iframe1.html">Php Poll Examples 1</a><br> <a href="polls_iframe3.html">Php Poll Examples 2</a><br> <a href="polls_iframe4.html">Php Poll Examples 3</a><br> <a href="polls_iframe2.html">Php Poll Result Examples</a>
A Tom Wesselmann painting
A Tom Wesselmann painting
Radio Buttons Example
Select Menu Example
Checkbox Buttons Example
A Roy Lichtenstein painting
A Roy Lichtenstein painting

YOUR CODES
Your Class Code and the other codes

Now your codes, so that we finish the premises and we can discuss how this script works in the next section.
The codes are divided as follows and from now on are going to be called this way:
  • The Class Code
  • The Script Code this allows you to discriminate within one same php page whether the user wants to see the results without voting or wants to vote and see the results soon afterwards.
    This is basically an implementation interface for the aforementioned class code, so that by customing this interface you can add much flexibility (for instance you may decide that if one doesn't vote first one can't see the results, or you may decide that only specified registered users can vote: to achieve all these particularities what you need is precisely a second php interface to nest further commands in).
    Thus this default interface is a good and working interface draft to work on.
  • The CSS Code this is optional. The layout for the polls are entirely made by css, that is when building up the html, all the elements that belong to a poll are wrapped within <div> tags to which a class property with predefined class names (so called css selectors) is assigned.
    Thus if you have a css rules definition file where such css classes are defined, by merely changing those css rules you can change the whole feeling of your polls' layouts.
    Therefore, merely to help you, I also include a possible optional and yet full fledged css set of rules meant to be used with the default settings.
A Roy Lichtenstein painting
A Roy Lichtenstein painting
The poll Class Code

lines (with comments and blank lines):
A Roy Lichtenstein painting
A Roy Lichtenstein painting
The poll Script Code
The Css Code
A Tom Wesselmann painting
A Tom Wesselmann painting

DESCRIPTION OF THE CLASS METHODS
How the scripts work and how you can use its methods



Method:
poll

This is the constructor.
This is the only method where you actually have to pass argument, whereas for the other methods, though a consistent amount of arguments is provided yet all of them are optional. But with this method you do have to pass a few arguments at least.
Here are its arguments:
  • $server: defaults to "localhost".
    You must pass it as a web address in case your php proxy does not run on the server meant as localhost.
  • $username: defaults to "root", must be your proxy username, that is the username of the SQL account enabled to connect with the database and manipulate it.
  • $password: defaults to defaults to "triadpass", must be your proxy password, that is the password of the SQL account enabled to connect with the database and manipulate it. In case it must be encrypted by Php methods such as, say, md5(), must be passed as already encrypted.
  • $pollQuestion: defaults to a dumb "Do You Agree?"
    Must be the question that goes with the given current poll.
  • $availableAnswersArray: defaults to an array of three strings: array("Yes", "No", "Don't know")
    Must be an array and each array entry must be one of the possible answers allowed for the poll.
  • $databaseName: defaults to "polls".
    This is the name of the database where your polls are all stored. The method will attempt a connection to such database name. If you are ok with this name, do not even pass the argument. If you keep this default name and such database named "polls" does not exist on your mySQL server, an attempt to create it will be made.
  • $tableName: defaults to "poll" and is the mySQL table name where the data for this poll will be stored.
    Yet if you are to print more polls in one same file, then you have to pass this argument, a different name per each poll, for poll mySQL tables must be different: that is each poll wants its own SQL table and thenceforth its own unique table name.
    If such table name does not exist yet, an attempt to create it within the database will be made. The table structure will be of three fields as previously outlined: id, answer, vote.
  • $idFieldName: optional, defaults to "id" and is the name of the mySQL table first field.
  • $answerFieldName: optional, defaults to "answer" and is the name of the mySQL table second field where the answer for this row is stored.
  • $voteFieldName: optional, defaults to "vote" and is the name of the mySQL table third field where the amount of votes are stored.
  • $createAndPopulate: optional, defaults to 1 and with such value determines that an attempt to create a database and a table with the given passed database and table names must be made if such database or table name does not exist.
    If passed as zero, no attempts to create the database or the tables will be made. It won't hurt you if passed as 1 since if the table or database already exist, it will not duplicate them.
Therefore to initialize an instance of the poll class, a possible signature with $foo as a placeholder variable name is:

$foo=new poll(
'localhost', 'root', 'triadpass'/*Really indispensable arguments over*/,
'How Are You', array('fine','not fine')/*Arguably necessary arguments over*/,
'polls', 'poll_1',
'id', 'answer', 'vote',
1
);



The initialization of such class instance is necessary at all times no matter whether you want to show the layout for a poll or vote or show the results.

Method:
show

$foo->show();

This method shows the layout for voting (not the results that is).
That is, it produces the layout for viewing the "cast your vote" interface so to call it.

This method will produce a html form for each survey, and all the poll fields for the given poll form will be accommodated within this wrapping form, so that each pool resides within its own form in the html document.

The name (<form name="...">) assigned to each of these forms will be the same as the SQL table name passed as the argument named $tableName in the constructor.

Each of these forms will be set to the POST method, so that the values of the submitted fields won't appear as appended in a query string in the location bar and the scripts can retrieve them by analyzing the Php $_POST superglobal.

All the forms will redirect to one very same form property action which must be the name of a php file existing on your server. The name and path of this php file is stored within the class in a static class variable named:
$phpFileName
Whose default value is:
"poll.php"
Therefore your Script Code must reside in a file with such name, for each submitted poll form will attempt to reach such file when its submit button gets clicked!
Please, to understand this better consider how absurd it would have been if I would have arranged a situation where each form would have required to submit to its own different php file: you would have needed a new php file for each new poll!

If you don't like that file name or it does not reside in the same directory of the html document that hosts the poll forms, remember to change this file name and path to the ones that you prefer or that fit: it can be done within the very same code of the Class Script by locating $phpFileName and changing its value.

Additionally, this method show() will append to the action property of the form tag an additional tiny query string which looks like:
?vote=1
so that the Script Code can detect within the scope of the Php $_GET superglobal if the poll.php file is to be queried in order to cast a vote or not - that is: the script relies on $_POST and $_GET both, which is perfectly consistent:
«GET data can exist in a POST request, because [GET data] is simply part of the URL being requested and not reliant on the actual request method»
[by Chris Shiflett' article The Truth about Sessions published on PHP Magazine]
Therefore it is legitimate to rely on $_POST and $_GET at the same time, the former being implemented by setting to POST the form's method, the latter by appending a query string to the same form's action:
<form name="pollX" method="post" action="poll.php?vote=1">

This show() method needs no arguments actually, except perhaps the first two:
  • $fieldType: defaults to "radio" and produces as html form options to cast a vote a set of radio [ ] buttons.
    Accepts as alternative values: "checkbox" to produce sets of checkboxes [ ] or "select" []
  • $fieldName: defaults to "poll[]".
    You may note the square brackets, which by the way constitute a fully valid html name, and that flag to the Php script that the fields are all handled as belonging to an array.
    Such square brackets will be appended by the method itself if omitted, for the whole script relies on them!
    You should not worry about this, the script will look after it all by itself, expecting each poll answer submitted via form as an array.
    Do not worry about the name of the form fields being identical throughout manifold forms: what matters is that the name of each hierarchically higher poll form is different from the name of another poll form, then each form can have within itself a set of fields whose names are identical to the names of the fields within another poll form, for forms behave as object oriented elements where each form name encapsulates a fully independent arena: as long as the names of the form tags hosting each poll are different, no worry that the names of the field tags wrapped within such form tags may cause any problem even if the field names are the same.

    Therefore upon submission, if the field names is for all fields the default "poll[]" name, then the php superglobal $_POST for the posted (submitted) variable named "poll" will therefore report an array of at least one entry (or of course empty if no vote was expressed):
    [poll] => Array ( [0] => 3 )
    The stored value for the reported entry (only one in this case, assuming multiple answers to one question were not possible as in the case of radio buttons) is in this example 3: actually, that number is the value of the value of the id field in the queried mySQL table for this poll, because such is what is assigned as value to each form field:
    <input type="radio" name="poll[]" value="1">
    <input type="radio" name="poll[]" value="2">
    <input type="radio" name="poll[]" value="3">
    etc...
    In this [poll] => Array ( [0] => 3 ) case it appears that within the range of the submitted variable poll, the answer that was picked by the surfer was only one -array of one entry alone- and was the answer whose id identification in the currently referred poll mySQL table was: 3.

    Which the "currently referred poll mySQL table" is, will be stored in each form within an hidden field which is as such:
    <input type="hidden" name="submittedPollSQLTableName" value="poll">
    In this field, which is obviously to appear within the $_POST php superglobal variable as well once the form is submitted, the stored value is the $tableName as passed to the constructor, and the name for each form will always be the same passed $tableName passed to the constructor as well - namely in the $_POST the currently submitted mySQL table name will appear as:
    [submittedPollSQLTableName] => poll
    Perhaps calling it just tableName would have been more consistent, but I preferred a longer name that seems more descreptive. Yet you can change that in the class byb locating the class variable:
    private $submittedPoll='submittedPollSQLTableName';
    and changing such posted name in there.

    To see a complete $_POST set, for a poll where multiple answers were allowed, an example could be:
    Array
    (
        [poll] => Array
            (
                [0] => 2
                [1] => 3
                [2] => 6
            )
    
        [submittedPollSQLTableName] => poll2
    )

    This means that in the poll identified by the sql table name poll2 the surfer has voted for as many as three options (evidently the poll allowed for multiple choices like in the case of checkbox button happens) which are the ones identified by the sql poll2 id fields that carry as values: 2, 3, 6


Method:
select

A secondary method. If you chose to pass as first argument of show() the string "select" to produce a drop down menu, well before calling in show() with such argument call in select() and pass to it two arguments:
  • $size: the size value of the menu: defaults to 1 namely only one option is visible by default, to see the others must scroll.
  • $multiple: defaults to zero, pass it as 1 to allow for a drop down menu where multiple options can be selected (it is normally done by keeping pressed the CTRL keyboard key while selecting with the mouse pointer).


Method:
vote

$foo->vote();

Requires no argument.
The script code I propose in bundle with the class code is set in such a way that if the html button "Vote" is clicked but no answer was picked for the poll (that is, an actual vote was not expressed), the next method named result is called in, and thus only the results gets displayed.

Given the arguments passed to the constructor, and inspecting the $_POST php superglobal for the array whose name is drawn after the parameter $fieldName passed to show(), this method will perfectly understand which mySQL table must be addressed and that the field meant to host the amount of votes must be incremented by one in all the instances whose id field will match one of the $_POST[$fieldName] array entries.

So your poll.php file can check whether:
if($_GET['vote'])
and if that holds true (namely there is in the location address a query string that starts with vote=) it means that the poll.php file has been addressed to express a vote with a submission from some poll form: if this condition holds true, also the $_POST variables are therefore in place so call this method in: $foo->vote(); and it will take care of scanning the $_POST accordingly.

The method sets a cookie to prevent too many subsequent votes from one same machine. This cookie is set only if an actual option (vote) has been picked from the html form.
The cookie expires after one hour and is a different cookie for each form (as long as a computer allows for accepting cookies from one same domain). To change the expire time, you must hardcode in the class code the variable named:
private $cookieDuration
or set it to public and change it by $foo->cookieDuration=Number;

Method:
result

$foo->result();

Shows the results for a given poll, the one whose parameters have been stored in this class instance upon initialization.
Requires no arguments actually. Yet you may consider passing one at least, the first one which defaults to 1 and accepts three possible values:
  1. 0: means you do not want to print the text of the expressed votes but you only want to show the histograms.
  2. 1: means you want to print the text of the expressed votes too and that this should be printed beside each answer description.
  3. 2: means you want to print the text of the expressed votes too and that this should be printed inside each histogram bar (I would advise against this option though, makes things a bit clustered perhaps).
The methods named:
show()
results()

would actually allow you to pass much more arguments beside those described. Yet these arguments all have default values of course and are meant to hold div tags with preassigned css class names so that you can format your layouts. I suggest to you not to change these arguments and to rely entirely on your css style declaration in the css file (I provided a possible one as the so called css Code).
The div wrapper and class names for a show() layout are as follows:
<div class="poll"> <div class="question">Do You Agree? <div class="afterQuestion"></div> </div> <div class="record"> <div class="answer">Yes</div> <div class="vote"> <input type="checkbox" name="poll[]" value="1"> </div> </div> </div>
The div wrapper and class names for a result() layout are as follows:
<div class="poll2"> <div class="question2">Do You Agree? <div class="afterQuestion2"></div> </div> <div class="record2"> <div class="answer2">Yes <div class="percent">2 votes (14.29%)</div> </div> <div class="vote2" style="width: 14.29%; background-color: #ff0000">&nbsp;</div> </div> </div>
Feel free to check and study a little bit the Script Code, meant to be your poll.php file, to see all these statements in action - in that case I also use a loop to dinamically build on the fly a set of as many as 4 polls. These polls files are ideally nested within frames, maybe iframe tags, so that they can be submitted without escaping the whole contents of a main document.
You can also readapt the css Codes; the css rules I propose actually are simply meant to work as a draft that you can copy and subsequently modify accordingly to your own layout preferences: if you do not change the css selector names but you do change the items within the curly brackets, you will see the consequences being immediately reflected in the layouts. Feel free to make trials, and have fun: I made all the hard work for you, you just need a little bit of attention on your own using the class script as it is, and using the other draft scripts (poll.php and the css file) as a working starting point.