You should all have PHP installed and configured to work with Apache by now. If not, you can find instructions on the page for Lab #4.
PHP was originally created as a way to write simple scripts for small web pages. It stood for "Personal Home Page" at the time. Eventually it grew into a full scripting/programming language, and its creators have since declared that PHP now stands for: "PHP: Hypertext Preprocessor". Yes, the P in "PHP" stands for "PHP". It's not the only recursive acronym you'll encounter in computing.
Regardless of its origins, PHP is now a full-blown programming language, although it is primarily used as a scripting language for web pages. PHP code is usually just added to the HTML code of a web page. If you look at the source code for a web page, anything that's between angle brackets and question marks (like these:<? ... ?>
) is PHP code.
It's worth mentioning that when we write a CGI/PHP script, what we're really doing is writing an HTML page that has a PHP script embedded into it. This is sort of the opposite of what we were doing when we wrote CGI/Python scripts. With Python, we were writing a Python script that printed out HTML. With PHP, we'll be writing HTML code, and inside that HTML code will be bits of PHP code that are calculated and that sometimes generate more HTML.
I think that the w3schools tutorial and associated references for PHP are useful and kept up to date.
For a demonstration, I decided to bring up our good friend buttonclicker.py
and re-implement it as a PHP script buttonclicker.php
. Here is the original Python script (with some of the comments and the bit about favorite words removed to make things simpler):
#!/usr/bin/python
import cgi
import cgitb
cgitb.enable()
form = cgi.FieldStorage()
print "Content-Type: text/html\n"
#Here, we set the value of a variable named "clicks", storing the
#number of times the button has been clicked.
if "clicks" in form and int(form.getvalue("clicks"))>=0:
clicks = int(form.getvalue("clicks")) + 1
else:
clicks = 0
print '''
<html>
<head>
<title>Button Clicker: the Game</title>
</head>
<body>
<h1>Button Clicker: the Game</h1>
'''
#Here, we display how many times the button has already been pressed.
if clicks<=0:
print '<p>Click to begin!</p>'
else:
print '<p>You have clicked ' + str(clicks) + ' times!</p>'
print '''
<form>
<input type="submit" name="action" value="Click!">
'''
print '<input type="hidden" name="clicks" value="' + str(clicks) + '">'
print '''
</form>
</body>
</html>
'''
For the most part, we could through this program line-by-line and convert things to PHP as we go. But one huge change that can be made right off the bat is that those big blocks of HTML code that show up in the triple-quoted print
statements don't need to be part of an explicit print
statement anymore. Why? Because this is now an HTML file that has some PHP code in it, not a Python script that prints some HTML. For similar reasons, we have to enclose all the actual PHP code in a tag that starts <?php
and ends ?>
. In class, we did this as we worked through the rest of the code, but to be clearer here in the notes, let's make that change all at once.
<?php
#!/usr/bin/python
import cgi
import cgitb
cgitb.enable()
form = cgi.FieldStorage()
print "Content-Type: text/html\n"
#Here, we set the value of a variable named "clicks", storing the
#number of times the button has been clicked.
if "clicks" in form and int(form.getvalue("clicks"))>=0:
clicks = int(form.getvalue("clicks")) + 1
else:
clicks = 0
?>
<html>
<head>
<title>Button Clicker: the Game</title>
</head>
<body>
<h1>Button Clicker: the Game</h1>
<?php
#Here, we display how many times the button has already been pressed.
if clicks<=0:
print '<p>Click to begin!</p>'
else:
print '<p>You have clicked ' + str(clicks) + ' times!</p>'
?>
<form>
<input type="submit" name="action" value="Click!">
<?php
print '<input type="hidden" name="clicks" value="' + str(clicks) + '">'
?>
</form>
</body>
</html>
Note that at this point in time, this code is halfway between Python and PHP, and so it won't work as either. Don't try to open it in your browser.
So we went through line by line and modified things to match PHP syntax. We started with that first line #!/usr/bin/python
that tells the server what interpreter to use to run this script. Since this is being served by the Apache and we configured Apache for PHP, it knows to use the PHP interpreter when it encounters it as part of a web page. So we can leave that out. Similarly, we don't need to import any modules or packages to handle CGI; that's a fundamental part of PHP, so the next three lines can be removed too. Because PHP has a built-in array (called $_REQUEST
) that stores the environment variables, we can get rid of the line form = cgi.FieldStorage()
as well. And lastly, the whole file is being served as a web page, so we don't need to specify that this is HTML. So we can dump everything up to that first comment.
Comments in PHP are similar to those in Python and many other languages. Lines that start with #
or //
are comments. Also anything between /*
and */
is also a comment. So we don't have to remove the comments that are there.
So that brings us to the conditional, which is the first actually interesting* part. The syntax for conditionals in PHP requires that the condition** is surrounded by parentheses. And the block of code to be executed if the condition is true should be surrounded by curly braces. Actually, all blocks of code are surrounded by curly braces. You'll see the same style of syntax in many different programming languages, but not in Python, which uses a colon and a line break after the condition and defines blocks of codes using indentation. Also, since line breaks are ignored by PHP (as in many different languages), lines of code need to end with semicolons. Lastly, all Python variables must begin with a dollar sign.
*Relatively speaking.
**A "condition" is a bit of code that evaluates to either true or false, in case you don't remember.
So we can sort of half-translate the conditional to get the following bit of not-quite-PHP/not-quite-Python code:
if ("clicks" in form and int(form.getvalue("clicks")) >= 0) {
$clicks = int(form.getvalue("clicks")) + 1; }
else {
$clicks = 0; }
Now that we've handled the superficial differences in syntax, we need to look at how to access the environment variables in PHP. Instead of having the dictionary-like object form
that we put all the environment variables into, we have a built-in associative array called $_REQUEST
that stores all of the environment variables. An associative array is pretty much exactly the same thing as a Python dictionary, and fortunately the syntax for accessing one is also very similar. So instead of asking "Is "clicks" in form
true?", we'll ask "Is isset($_REQUEST["clicks"])
true?" And instead of using form.getvalue("clicks")
to access the value of the environment variable clicks
, we'll use $_REQUEST["clicks"]
. As a bonus, we don't even need to convert to an integer with int()
. PHP is smart enough to handle that for us.
Making all these changes brings the conditional statement to the following, which is valid PHP now.
if (isset($_REQUEST["clicks"]) and $_REQUEST["clicks"] >= 0) {
$clicks = $_REQUEST["clicks"] + 1; }
else {
$clicks = 0; }
Moving on down the code, the next thing that needs to be changed is the conditional that decides whether to display a Click to begin!
message or a message that shows the numer of times the button has already been clicked. In addition to changing the Python variable clicks
to the PHP variable $clicks
, adding semicolons to end lines, adding braces to code blocks, and using parentheses instead of a colon for the condition, we'll change the Python command print
to the PHP command echo
.* Lastly, the PHP operator for concatenating strings is a period (.
), so those plus signs need to be changed to periods.
*PHP also has a command called print
, but echo
is slightly more versatile. See here for more details.
So this conditional changes from
if clicks<=0:
print '<p>Click to begin!</p>'
else:
print '<p>You have clicked ' + str(clicks) + ' times!</p>'
into
if ($clicks<=0) {
echo '<p>Click to begin!</p>'; }
else {
echo '<p>You have clicked ' . $clicks . ' times!</p>'; }
You can see here one of at least two different ways to construct a line of HTML that has a variable in it. In this case, we used string concatenation to piece together a string to be displayed using the echo
command. But we can also insert the content of a PHP variable directly into a line of HTML. As an example, let's look at the last bit of code that needs to be translated:
<?php
print '<input type="hidden" name="clicks" value="' + str(clicks) + '">'
?>
Now we could translate this just like we did before:
<?php
echo '<input type="hidden" name="clicks" value="' . $clicks . '">';
?>
But it'd be cleaner to not open up a PHP tag just to echo
something. So instead, we can just write HTML, and where we want the contents of the variable $clicks
, we put <?=$clicks?>
. The restult looks like this:
<input type="hidden" name="clicks" value="<?=$clicks?>">
So now we've translated the whole thing into PHP, and it should work. For the record, here's what the code looks like after translating:
<?php
#Here, we set the value of a variable named "clicks", storing the
#number of times the button has been clicked.
if (isset($_REQUEST["clicks"]) and $_REQUEST["clicks"] >= 0) {
$clicks = $_REQUEST["clicks"] + 1; }
else {
$clicks = 0; }
?>
<html>
<head>
<title>Button Clicker: the Game</title>
</head>
<body>
<h1>Button Clicker: the Game</h1>
<?php
#Here, we display how many times the button has already been pressed.
if ($clicks<=0) {
echo '<p>Click to begin!</p>'; }
else {
echo '<p>You have clicked ' . $clicks . ' times!</p>'; }
?>
<form>
<input type="submit" name="action" value="Click!">
<input type="hidden" name="clicks" value="<?=$clicks?>">
</form>
</body>
</html>
Up until this point, what we've been doing with our environment variables is only one of a few ways of sending data to a script. The two methods that are most important for CGI are called "GET" and "POST". What we've been using so far (with the environment variables passed as a visible part of the URL) is the GET method, which is the default method for HTML forms. If we changed the line <form>
in our HTML to <form method="get">
, the page would do exactly the same thing as before because it was defaulting to the GET method. But if we change it to <form method="post">
, it will use the POST method instead.
The POST method works in more-or-less the same way as GET, only it works behind the scenes, where the user can't see what's going on. If you use POST, the environment variables are still sent to the script, but they won't appear in the URL's query string. This has the advantage that it keeps users from altering (either accidentally or purposefully) the query string by hand. But there are situations in which you wouldn't want to use POST. Perhaps the biggest reason is to enable the user to store the web page and the state of the variables in a bookmark. For example, if you're using a web search and the search query and page number are environment variables, it makes sense to use GET, so that the user can bookmark the search results.
In terms of PHP, the built-in associative array $_REQUEST
will retrieve whatever variables have been sent, regardless of whether GET or POST was used. If you want to be more specific, and require that POST is used, you can use $_POST
instead of $_REQUEST
. This is a good thing because it means that the user can't trick the script into accepting input by adding a query string to the URL. You can also force PHP to only access variables sent using GET by using $_GET
instead of $_REQUEST
.