PEEP

Programming Economic Experiments with Php/mysql

with contributions by:
Roel van Veldhuizen
Joep Sonnemans
Jeroen van de Ven
Boris van Leeuwen
Jona Linde
Lucas Molleman

Step by step example of a php-program: prisoner's dilemma

Whatever computer programming language you learn, the first program you make is by tradition the one-liner with the output "Hello world". The experimental economics equivalent of "Hello world" is the prisoner's dilemma, the most studied game in behavioral science. To highlight the most important steps, we make a very simple experiment: repeated partners design with a symmetric payoff matrix. The sequence of the experiment is: login, instructions (several pages), {numberperiods} times the sequence decision-wait-results, questionnaire and payoff screen.
Elements of the experiment that need to be flexible like the number of players, the payoff structure etc are in the database in the table "commonparameters" and the data of the subjects are in the tables "ppnumbers" (per subject) and "decision" (one record per decision).

Download all the files on this page in one zip-file. Remember that you have to change the common.inc file (step 3). You can make your own tables in phpmyadmin (a good exercise) or only make the database and import the tables by importing "peep.sql" in phpmyadmin.

Step 0: Preliminary work

Download and install the combined (free): XAMPP package (windows, OSX and linux). If you use a mac an alternative for XAMPP is the MAMP package (I advise against using the default Apache installation of OSX). The packages includes phpmyadmin which is a very nice interface with mysql (of course in a webpage and of course using php).
Learn the basics html and php (for example on w3schools.com). I suggest you first play an afternoon or so with html before you continue to php.
This is called the 0 step because I assume you have already done this.

Step 1: Make a directory

Make a directory "PDG" in the "htdocs" directory in the XAMP directory. Here we will put all the programming files.

Step 2: Make a database

Start localhost/phpmyadmin/ and make a new database. To keep things tractable, we use the name PDG for this database. Because the layout phpmyadmin regularly changes, your version may look different.

We make a table "commonparameters" were we will put all variables that have to be available in many pages and which can be changed at the start of the session. For example, if you want to change the payoff matrix or the number of players you only have to change that in the database, not in the php-program.

We add the following variables to the table: numberplayers, numberperiods, payoffCC, payoffCD, payoffDC, payoffDD, exchangerate (number of points equal to one euro).

We now have to fill in the parameters, for each a name and a value (I show only the last two):

Now we have to make two more tables in the database, one with information about subjects "ppnumbers" and one with their decisions "decisions". In the ppnumbers table we would like to have the following variables:

The variable tafelnummer is the code for the table in the lab and is a string (VARCHAR) of length 3 (in the CREED-lab the tables have codes like A01, B03, etc). I use the Dutch word and not the English "table" because that word is also used in html, php and mysql. In principle I could use it, but it is not practical because it increases the possibility of hard-to-find bugs! However, I am not very consistent in this in practice ;).
The "pagina" (Dutch for page) is a long string variable because it will contain the path of the page the subject is currently looking at (and these paths can be long if you ever put your program on an external server). The variable "earnings" contains the earnings in points, and (not surprisingly) the variable "euros" contains the earnings in euros.

Finally we need a table "decisions". Here we need the following variables:

in which "time" is the time in seconds. We could have made the decision itself a string but here I have explicitly forbidden to have any other value than "C" and "D".

Step 3: Adapt the common.inc

This is the file that will be loaded by every php page in your program. What we have to change is the name of the database, and eventually the password.
<?php
define ("HOST","localhost");
// fill in correct name of database
define ("DBNAME","PDG");
// fill in correct loginname/password
define ("ADMIN","root");
define ("WWOORD","yourownpassword");
//For this simple experiment we read all common parameters we will ever need.
$table_name="commonparameters";
$connection = @mysql_connect(HOST,ADMIN, WWOORD) or die(mysql_error());
$db = @mysql_select_db(DBNAME,$connection)or die(mysql_error());
$sql="SELECT * FROM $table_name";
$result=@mysql_query($sql,$connection) or die("Couldn't execute query ".$sql);
while ($row=mysql_fetch_array($result)) {
	$name=$row['name'];	
	$value=$row['value'];
	$$name=$value;
}
/>
Note that variables in php that are defined and cannot be changed (in another word: constants) are in all capitals and don't start with a $. The rest of the common.inc file are functions that may come handy.

Step 4: Copy a beginauto.php file to your PDG directory.

This page provides a number to the computer that logs in (the first one that connects a 1, the second a 2 etc.). In the table ppnumbers we add a record with this subject with the tablenumber, if available. After that is done, the page redirects the subject to the first page of the instructions (or to a waiting page if you don't like the instructions to be visible on the screen when the subjects enter the lab).
<?php
include("common.inc");
//Only for use in CREEDlab, when the client is redirected in beginexp.html to this file. Otherwise the table will be empty
$table=$_REQUEST['table'];
//Automatically a number is asigned and also the table (A2, A3 etc) is included in ppnummers
$table_name="ppnumbers";
$connection = @mysql_connect(HOST,ADMIN, WWOORD) or die(mysql_error());
$db = @mysql_select_db(DBNAME,$connection)or die(mysql_error());
$sql="SELECT * FROM $table_name ORDER BY ppnr DESC";
$result=@mysql_query($sql,$connection) or die("Couldn't execute query ".$sql);
if ($row=mysql_fetch_array($result)) {
	$ppnr=$row['ppnr']+1;
} else {
	$ppnr=1;
}
$numberplayers=readCommonParameter(numberplayers);
if ($ppnr>$numberplayers){  //the numberplayers is read by the common.inc file, like all commonparameters
	header("Location: relogin.html");
	exit();
} else {
	setcookie("beheerder", $ppnr); 
	$table_name="ppnumbers";
	$connection = @mysql_connect(HOST,ADMIN, WWOORD) or die(mysql_error());
	$db = @mysql_select_db(DBNAME,$connection)or die(mysql_error());
	$sql2="INSERT INTO $table_name (ppnr, tafelnummer) VALUES (\"$ppnr\", \"$table\")";
	$result=@mysql_query($sql2,$connection) or die("Couldn't execute query ".$sql2);
	header("Location: instruction.php");
	exit();
}
/>

Step 5: Instructions (temporary)

Because you need to know how exactly you present the decision problem to the subject (layout etc) you typically write this part of the program last. For the time being we made an empty page with a link to the decision page.
<?php
include("common.inc");
Header("Cache-Control: must-revalidate");
if (!$_COOKIE['beheerder']){
	header("Location: begin.html");
	exit();
	} 
else {
	$koek=readcookie("beheerder");
	$ppnr=$koek[0];
	}
updateTableOne("ppnumbers","ppnr=$ppnr","pagina",$_SERVER['PHP_SELF']);
/>
<HTML>
<HEAD>
</HEAD>
<BODY>
Instructions...
<p align=center><a Href="decision.php">To the first period</a>
</BODY>
</HTML>

Step 6: Decision page

In this stage we don't spend energy on a nice layout, we keep it simple. Note however that we take the numbers in the payoff matrix from the database so if we change the payoffs for another treatment we don't have to change the program. In a real experiment we would very likely use more neutral labels than "C" and "D"!
We measure the time the player takes in seconds by comparing the time when the server sends the page to the player [$begintijd=time();] with the time when an answer arrives [$tijd=time()-$begintijd;]. This is not extremely precise, especially if the network is slow, but good enough for us now (if needed, you could measure it much more precise at the computer of the player, using javascript).

<?php
Header("Cache-Control: no-cache, must-revalidate");
include("common.inc");
if (!$_COOKIE['beheerder']){
	header("Location: begin.html");
	exit();
} 
$koek=readcookie("beheerder");
$ppnr=$koek[0];
$period=lookUp("ppnumbers","ppnr='$ppnr'","period");
updateTableOne("ppnumbers","ppnr=$ppnr","pagina",$_SERVER['PHP_SELF']);
if ($period==0) {
	$period=1;	
	updateTableOne("ppnumbers","ppnr=$ppnr","period",$period);
}
if (isset($_REQUEST['OK'])) {
	$keus=$_REQUEST['keus']; 
	$begintijd=$_REQUEST['begintijd'];
	$tijd=time()-$begintijd; 
	//we first check whether the decision is already saved; this because of relaoding of page
	$check=lookUp("decisions","period='$period' and ppnr='$ppnr'","decision");
	if ($check==""){	
		insertRecord("decisions","ppnr, period, decision, time","'$ppnr', '$period', '$decision', '$tijd'");
	}
	header("Location: wait.php");
	exit();
}
$begintijd=time();
/>
<HTML>
<HEAD>
</HEAD>
<BODY>
	<!--This javascript function checks if a decision was made before the submit button was clicked-->	
	<script language="JavaScript">
		function confirm_box() {
			if (eval(document.forms['form1'].keus[0].checked)) {
			}
			else if (eval(document.forms['form1'].keus[1].checked)) {
			}
			else {
				alert("Please take a decision!");
				return false;		
			}
			return true;
		}
	</script>
	<H1 align=center>Your decision for period <?php echo $period; ?></H1>
	<font size=+2>
	<table border="1" align="center">
		<tr>
			<td colspan=2 rowspan=2></td>
			<td colspan=2><font color=blue><b>Other</b></font></td>
		</tr>
		<tr>
			<td align=center><font color=blue><b>C</b></font></td>
			<td align=center><font color=blue><b>D</b></font></td>
		</tr>
		<tr>
			<td rowspan=2><font color=red><b>You</b></font></td>
			<td><font color=red><b>C</b></font></td>
			<td align=center><font color=red><b><?php echo $payoffCC; ?></b></font>,
				<font color=blue><b><?php echo $payoffCC; ?></b></font></td>
			<td align=center><font color=red><b><?php echo $payoffDC; ?></b></font>,
				<font color=blue><b><?php echo $payoffDC; ?></b></font></td>
		</tr>
		<tr>
			<td><font color=red><b>D</b></font></td>
			<td align=center><font color=red><b><?php echo $payoffCD; ?></b></font>,
				<font color=blue><b><?php echo $payoffDC; ?></b></font></td>
			<td align=center><font color=red><b><?php echo $payoffDD; ?></b></font>,
				<font color=blue><b><?php echo $payoffDD; ?></b></font></td>
		</tr>
	</table>
	</font>
	<form name="form1" action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post" onsubmit='return confirm_box(this)'>
	<input type='hidden' name='begintijd' id='hiddenField2' value='<?php echo $begintijd; ?>'>
	<table align=center>
		<tr>
			<td align=right><font color=red><b>Your decision:</b></font></td>
			<td><input type="radio" name="keus" value="C">C<br><input type="radio" name="keus" value="D">D</td>
		</tr>
		<tr><td></td><td><button type="submit" name="OK" value="OK">OK</button></td>
	</tr>
	</table>
	</form>
</BODY>
</HTML>

Step 7: Waiting page

After a subject makes a decision, he is referred to a waiting page. This page checks whether all relevant decisions (in this case: only the decision of the partner) are in the database. If so, we go to the results page, if not, a message is displayed that we have to wait. The waiting page is refreshed automatically every few seconds, until all relevant decisions are made and we can proceed to the results.
In our little experiment, we let each pair of subjects (1-2, 3-4, etc) continu when their decisions are complete, they don't wait for the other pairs.

<?php
include("common.inc");
Header("Cache-Control: must-revalidate");
if (!$_COOKIE['beheerder']){
	header("Location: begin.html");
	exit();
} 
$koek=readcookie("beheerder");
$ppnr=$koek[0];
$period=lookUp("ppnumbers","ppnr='$ppnr'","period");
updateTableOne("ppnumbers","ppnr=$ppnr","pagina",$_SERVER['PHP_SELF']);
//we look up whether the partner has made a decision in this period
if ($ppnr % 2 == 0){
	$partner=$ppnr-1;
} else {
	$partner=$ppnr+1;	
}
$decisionpartner=lookUp("decisions","period='$period' and ppnr='$partner'","decision");
if ($decisionpartner!="") {
	header("Location: result.php");
	exit();	
}
?>
<html>
<meta http-equiv="Refresh" content="5">
<body>
We wait for the decision of your partner...
</body>
</html>	

Step 8: Results page

The results page displays decisions of both players, and their payoffs. The players can click to go the next period, or, if it was the last one, to go to the questionnaire.

<?php
include("common.inc");
Header("Cache-Control: must-revalidate");
if (!$_COOKIE['beheerder']){
	header("Location: begin.html");
	exit();
} 
$koek=readcookie("beheerder");
$ppnr=$koek[0];
$period=lookUp("ppnumbers","ppnr='$ppnr'","period");
updateTableOne("ppnumbers","ppnr=$ppnr","pagina",$_SERVER['PHP_SELF']);
if ($ppnr % 2 == 0){
	$partner=$ppnr-1;
} else {
	$partner=$ppnr+1;	
}
$decisionother=lookUp("decisions","period='$period' and ppnr='$partner'","decision");
$owndecision=lookUp("decisions","period='$period' and ppnr='$ppnr'","decision");
$earnings=${"payoff".$owndecision.$decisionother};
$payoffpartner=${"payoff".$decisionother.$owndecision};
//feedback
$tekst="<p align=center><b>Results period ".$period.": </b><br>Your decision was ".$owndecision.", the decision of the orther player was ".$decisionother."<br>Your earnings are ".$earnings." and the earnings of the other player are ".$payoffpartner;
//link depending on whether it is the last period or not
if ($period<$numberperiods){
	$link="<p align=center><a href=\"decision.php\">To the next period</a>";
} else {
	$link="<p align=center><a href=\"period.php\">To the questionairre</a>";
}
$check=lookUp("decisions","period='$period' and ppnr='$ppnr'","decisionother");
if ($check==""){
	//saving the data in the decision table and increasing the period, but only one (not when the page is reloaded)
	updateTableMore("decisions","period='$period' and ppnr='$ppnr'","decisionother='$decisionother', earnings='$earnings'");
	$period=$period+1;
	updateTableOne("ppnumbers","ppnr=$ppnr","period",$period);
}
?>
<html>
<body>
<?php echo $tekst; ?>
<br>
<?php echo $link; ?>
</body>
</html>		

If you like you can also display the results of all previous periods (and you could also do that on the decision page of course). See the code at the earningspage below.

Step 9: Questionnaire

It is common to end with a questionnaire; here we will only ask for gender (radio-buttons), age (input field), major (drop down list) and an open form question (to show how a textfield works). We will save this data in the "ppnumbers" table, so we have to add these variables to the table. Go in phpmyadmin to the table "ppnumbers", tab "Structure" and choose to add 4 variables at the end of the list. We make the variables strings: varchar of limited length for the first three variables, and text for the open form question (unlimited size string).

<?php
$dezepagina=$_SERVER['PHP_SELF'];
include("common.inc");
Header("Cache-Control: must-revalidate");
if (!$_COOKIE['beheerder']){
	header("Location: begin.html");
	exit();
} 
$koek=readcookie("beheerder");
$ppnr=$koek[0];
if (isset($_REQUEST['verzend'])) {
	$age=$_REQUEST['age'];
	$gender=$_REQUEST['gender'];
	$study=$_REQUEST['study'];
	$openvraag=$_REQUEST['openvraag'];
	updateTableMore("ppnumbers","ppnr=\"$ppnr\"","age=\"$age\", gender=\"$gender\", study=\"$study\", comment=\"$openvraag\"");
	header("Location: earnings.php");
	exit();
}
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
 <HEAD>
  <TITLE> New Document </TITLE>
  <META NAME="Generator" CONTENT="EditPlus">
  <META NAME="Author" CONTENT="">
  <META NAME="Keywords" CONTENT="">
  <META NAME="Description" CONTENT="">
 </HEAD>
 <BODY>
 <H1>Questionnaire</H1>
 <p>Please fill in this short questionnaire<br>
<form name="Show" method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">
<table>
<tr>
	<td>Age:</td>
	<td align=left> <input type="text" name="age" size=5></td>
</tr>
<tr>
	<td>Gender:</td>
	<td align=left colspan="9">
	<input type="radio" name="gender" value="male"> Male
	<br>
	<input type="radio" name="gender" value="female"> Female		</td>
</tr>
<tr>
	<td>I study at:</td>
	<td align=left colspan="9">
	<select name='study'>
		<option value="">(choose from list)</option>
		<option value="econ">UVA - Economics and Business</option> 
		<option value="psy">UVA - Social sciences - Psychology</option> 
		<option value="FMG">UVA - Social sciences - not psychology</option> 
		<option value="NWI">UVA - Science</option> 
		<option value="betagamma">UVA - IIS: beta gamma bachelor</option> 
		<option value="Rechten">UVA - Law School</option> 
		<option value="Geestes">UVA - Humanities</option> 
		<option value="Genees">UVA - Medical School</option> 
		<option value="Tand">UVA - Dentistry</option> 
		<option value="andU">Another University</option> 
		<option value="andH">A profesional school</option> 
		<option value="anders">Otherwise</option> </select>
		</SELECT>
		</td>
	</tr>
	<tr>
	<td>What is your impression of the other player?</td>
	<td><textarea rows="4" cols="50" name="openvraag"></textarea></td>
	</tr>
	<tr>
		<td colspan="10" align="center"><br>
		<input name="verzend" type="submit" value="Send"></td>
	</tr>
</table>
</form>
 </BODY>
</HTML>

We can make answering the questions obligatory by using a javascript function like the one in the decision page, for example because we really need to know the gender, but for other questions is may be better not to force an answer, because no answer is better than an unreliable answer. In this example we don't force subjects to give answers.

Step 10: Earningspage

At the end of the experiment the participant will get an overview of her earnings. The total is an amount in points that is exchanged for euros. During the payout participants leave the lab one by one to get paid. We don't want them to be able to see the earnings on the screens of other participants. Of course, we could use a very small font size, but a more elegant solution is that the participant can hide the page (link to "hide.php" on line 35). The hide page gives a link back to the earningspage.

<?php
include("common.inc");
Header("Cache-Control: must-revalidate");
if (!$_COOKIE['beheerder']){
	header("Location: begin.html");
	exit();
} 
$koek=readcookie("beheerder");
$ppnr=$koek[0];
$period=lookUp("ppnumbers","ppnr='$ppnr'","period");
updateTableOne("ppnumbers","ppnr=$ppnr","pagina",$_SERVER['PHP_SELF']);
if ($ppnr % 2 == 0){
	$partner=$ppnr-1;
} else {
	$partner=$ppnr+1;	
}
$resultstable="<table border=1 align=center><tr><td align=center><strong>Period</strong></td><td align=center><strong>Your decision</strong></td><td align=center><strong>Decision Other</strong></td><td align=center><strong>Earnings</strong></td></tr>";
for ($p=1;$p<=$numberperiods;$p++){
	$owndecision=lookUp("decisions","period='$p' and ppnr='$ppnr'","decision");
	$decisionother=lookUp("decisions","period='$p' and ppnr='$ppnr'","decisionother");
	$earnings=lookUp("decisions","period='$p' and ppnr='$ppnr'","earnings");
	$resultstable.="<tr><td>".$p."</td><td align=center>".$owndecision."</td><td align=center>".$decisionother."</td><td align=center>".$earnings."</td></tr>";
}
$totalearnings=lookUp("ppnumbers","ppnr='$ppnr'","earnings");
$euros=$totalearnings/($exchangerate);
$resultstable.="<tr><td colspan=3>Total points:</td><td align=center><strong>".$totalearnings."</strong></td></tr></table>";

?>
<html>
<body>
<h1 align=center>Your earnings</h1>
<?php echo $resultstable; ?>
<p align=center>
Your earnings in euros are: <?php echo $euros; ?>.
<p align=center><a Href="hide.php">Hide earnings</a></p>
</body>
</html>

Step 11: Back to the instructions: a menu

In many experiments the instructions will be more than one page, and we also want to check understanding. It is good practice to use a menu at top of instruction pages. The subjects than know if they are almost finished or not. In the menu only the pages that are already visited are clickable. We will make 5 pages: general instruction "instruction1.php", explanation of the payoff matrix "instruction2.php", two pages with questions to check understanding "instructionquestion1.php" and "instructionquestion2.php" and finally a summary "instructiesummary.php". We have to make a table in our database named "instructions" by running in phpmyadmin the following query:

CREATE TABLE `instructions` (
  `part` int(11) NOT NULL,
  `pagenumber` int(11) default NULL,
  `filename` varchar(80) NOT NULL,
  `nameinmenu` varchar(80) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
INSERT INTO `instructions` VALUES (1, 0, 'instruction1.php', 'Introduction');
INSERT INTO `instructions` VALUES (1, 1, 'instruction2.php', 'Payoff table');
INSERT INTO `instructions` VALUES (1, 2, 'instructionquestion1.php', 'Question 1');
INSERT INTO `instructions` VALUES (1, 3, 'instructionquestion2.php', 'Question 2');
INSERT INTO `instructions` VALUES (1, 4, 'instructionsummary.php', 'Summary');
In addition we have to add a variable "instructionspage" to the ppnumbers table. The layout is quite intuitively; the page you are is printed in bold, the pages you can go to by clicking in the menu are underlined. When the partipant starts with the first page, he can see how many pages there are, but he cannot click to get there immediately.

When he is on the third page, he can go back by clicking at the menu:

When he is back at the first page

he can jump to the third page without visiting the second page again.
Don't forget to change in beginauto.php the reference to the instructions page to instruction1.php (from instruction.php)
The participant will stay at the instructionsummary.php page until the variable startexperiment in the commonparameter table is 1. This means that you have to make such a variable in that table, and when all participants have finished the instruction you have to change its value to 1, see step 13.

Step 12: Relogin

Accidents will happen. However, even if a computer of a participant completely breaks down, you can repair this very easily. If all your pages have the line:
updateTableOne("ppnumbers","ppnr=$ppnr","pagina",$_SERVER['PHP_SELF']);
which updates in the database the present page the participant is looking at, you just put the participant behind another computer (or restart the same one) and open firefox. In the setup of the CREEDlab you will go automatically to the beginauto.php page. Here the server finds that we have already "numberplayers" (as in the table "commonparameters") logged in, and it redirects to "relogin.php". Here you fill in the number of the subject, and it will be redirected to the last page seen.

<?php
include "common.inc";
//check for required fields
if (isset($_REQUEST['reloginpp'])) {
	$ppnr=$_REQUEST['reloginpp'];
	if (lookUp("ppnumbers","ppnr='$ppnr'","ppnr")==""){
		echo "This number is not in de database!";
		exit();
	}
	else {
		writecookie("beheerder",$ppnr);
		//send to last page
		$period=lookUp("ppnumbers","ppnr='$ppnr'","period");
		$pagina=lookUp("ppnumbers","ppnr='$ppnr'","pagina");
		header("Location: ".$pagina);	
	}
}
?>
<html>
<head>
<title>Relogin</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head><div align="center">
  <form name="form2" method="post" action="relogin.php">  
    <table width="90%" border="0" bgcolor="#B6FFD9">
       <tr>
	      <td width="40%"> 
          	<div align="right"><b>Relogin</b> Participant Number:</div>
          </td>
          <div align="left"> 
          <td width="56%"><input type="text" name="reloginpp"> (existing number)
          </div>
          </td>
      </tr>
	<tr>
        <td> 
          <div align="right"></div></td>
        <td> 
          <div align="left"> 
            <input type="submit" name="Proceed" value="Proceed">
          </div></td>
      </tr>
    </table>
  </form>
  <p>
</center>
</div>
</body>
</html>	

Step 13: a monitor page for the experimenter

During the experiment the experimenter wants to know what page the subjects are looking at, and at the end of the session the receipts have to be filled in. You could use phpmyadmin of course, but a self-reloading page with only the info you want is easy to make (or in practice: to copy from another experiment and to adapt). Note that in the top is also a link to start the experiment ("startdeel1.php") which does nothing else than changing the common parameter "startexperiment"" to 1 and than return to the monitor page. Also this could be done in phpmyadmin, but a link in the monitorpage is more convenient. See the section improvements below.

<?php
	include("common.inc");
	$table_name="ppnumbers";
	$connection = @mysql_connect(HOST,ADMIN, WWOORD) or die(mysql_error());
	$db = @mysql_select_db(DBNAME,$connection) or die(mysql_error());
	$sql3="SELECT * FROM $table_name ORDER BY `ppnr` ASC";
	$result=@mysql_query($sql3,$connection) or die("Couldn't execute query ".$sql3);
	$tabel="<table border=1><tr><td><b>ppnr<b></td><td><b>table<b></td><td><b>period<b></td><td><b>earnings<b></td><td><b>euros<b></td><td><b>pagina<b></td><tr>";
	while ($row=mysql_fetch_array($result)) {
		$ppnr=$row['ppnr'];
		$tafelnummer=$row['tafelnummer'];
		$period=$row['period'];
		$earnings=$row['earnings'];
		$euros=$row['euros'];
		$pagina=$row['pagina'];
		$tabel .= "<tr><td>".$ppnr."</td><td align=center>".$tafelnummer."</td><td align=center>".$period."</td><td align=center>".$earnings."</td><td align=center>".$euros."</td><td align=center>".$pagina."</td><tr>";
	}
	$tabel .= "</table>";
?>
<html>
<meta http-equiv="Refresh" content="5">


<body>
	<a href="startdeel1.php">Start experiment</a>
<?php echo $tabel; 
?>
</body>
</html>	

Step 14: Improvements

14.1: Layout with ccs files

So far we have focussed on the functionality of the pages. By using css files (which defines styles to use) you can make the layout much nicer. Even more importantly, reading the same css file at each page makes it easier to change layouts for all pages together by adapting the css file. For example, if you layout the payoff table in this experiment by using css, you can change the colors red/blue that I used to other colors you like better. Because you used the same css-sheet in the instructions and the decision page, you have to change it only once.
One of the nice things of css is that they are easy to "borrow". If you see a webpage with a very nice combination of colors, you "view source" in Chrome or "page source" in Firefox and you can find the link to css files, which you can download and adapt to your own liking.

14.2: Strangers design

In the example above we employed a partner design: the same two players interacted repeatedly. We can easily change that to a strangers design. We have to make several adaptions to the program:

  • We have to change the waiting page wait.php because in a strangers design one has to wait till everbody made a choice (and not only the partner).
  • At the start of every period we have couple the participants again. One way to do this is to add a table "groupcomposition" in the database with one record per participant with the ten numbers of the players he will be coupled with in the ten periods. In practice we are never sure how many subjects will turn up at a session. We can solve this by making a larger table with more records; per participant more records (one for each possible number of players), or we fill the table only when we know how many subjects have shown up. In the zipfile I included a version of a roundrobin.php, which makes a groupcomposition table (you can have different groups in one session whose players never interact). In this version the two players have also different roles, which is not needed in our symmetric PDG.