Andrew Sellergren
<form>
tag to take user input. The action
attribute specified the URL to which to send the user's input and the method
attribute specified how we would send that input. If we type in "computer science" to our mock Google, we get redirected to the URL http://www.google.com/search?q=computer+science. As you can see, our query is embedded directly in the URL because we set the method
attribute to be "get." The "+" is a placeholder for a space.There's a lot we can do to make our implementation of Google prettier. Let's begin just by centering the content:
<!--
search1.html
David J. Malan
malan@harvard.edu
Demonstrates style attribute.
-->
<!DOCTYPE html>
<html>
<head>
<title>CS50 Search</title>
</head>
<body style="text-align: center">
<h1>CS50 Search</h1>
<form action="http://www.google.com/search" method="get">
<input name="q" type="text"/>
<br/>
<input type="submit" value="CS50 Search"/>
</form>
</body>
</html>
<body>
tag a style
attribute which has some CSS in it. The convention for CSS is to specify the property followed by a colon followed by the property value. Properties are separated with semicolons.CSS can also be factored out into a <style>
tag for the whole page:
<!--
search2.html
David J. Malan
malan@harvard.edu
Demonstrates style tag.
-->
<!DOCTYPE html>
<html>
<head>
<style>
body
{
text-align: center;
}
</style>
<title>CS50 Search</title>
</head>
<body>
<h1>CS50 Search</h1>
<form action="http://www.google.com/search" method="get">
<input name="q" type="text"/>
<br/>
<input type="submit" value="CS50 Search"/>
</form>
</body>
</html>
search2.html
and search1.html
are identical in how they are rendered, but search2.html
is arguably a little cleaner because all of the CSS can be found in a single place.We can take the factoring out process one step further by putting all of our CSS in a file and linking to it from our HTML:
<!--
search3.html
David J. Malan
malan@harvard.edu
Demonstrates link tag.
-->
<!DOCTYPE html>
<html>
<head>
<link href="search3.css" rel="stylesheet"/>
<title>CS50 Search</title>
</head>
<body>
<h1>CS50 Search</h1>
<form action="http://www.google.com/search" method="get">
<input name="q" type="text"/>
<br/>
<input type="submit" value="CS50 Search"/>
</form>
</body>
</html>
<link>
tag is somewhat comparable to the #include
directive in C: it tells the browser to include something from another file. In this case, we're including the same CSS style rules we had in search1.html
and search2.html
. The advantage of factoring out our CSS into a separate file is that we can now include that file in multiple webpages if we so desire.In search4.html
we introduce the <div>
tag:
<!--
search4.html
David J. Malan
malan@harvard.edu
Demonstrates img tag (and block-level elements).
-->
<!DOCTYPE html>
<html>
<head>
<style>
#header
{
text-align: center;
}
#content
{
text-align: center;
}
#content input
{
margin: 5px;
}
#footer
{
font-size: smaller;
font-weight: bold;
margin: 20px;
text-align: center;
}
</style>
<title>CS50 Search</title>
</head>
<body>
<div id="header">
<img alt="CS50 Search" src="logo.gif"/>
</div>
<div id="content">
<form action="http://www.google.com/search" method="get">
<input name="q" type="text"/>
<br/>
<input type="submit" value="CS50 Search"/>
</form>
</div>
<div id="footer">
Copyright (c) CS50
</div>
</body>
</html>
<div>
tag asks the browser for an invisible rectangle which can be styled separately from the rest of the page. Here we ask for three divisions named header
, content
, and footer
. In our CSS, we can specify styles for these divisions using rules that start with the #
, e.g. #header
, #content
, and #footer
. The value of the id
attribute should be unique across the entire page.alt
attribute for the benefit of those who might not be able to view this image, whether from disability or browser limitations.<input>
tags within the element whose id
attribute is set to content
.main
function in PHP. Whatever code you write can be fed directly to the interpreter. Unlike C, which is a compiled language, PHP is an interpreted language, which means that it is translated to 0's and 1's at runtime.In PHP, variable names begin with $
. To declare an array of numbers, you can write the following:
$numbers = [4, 8, 15, 16, 23, 42];
$numbers
. C is a so-called strongly typed language in that it requires you to declare an explicit type for every variable. PHP is not strongly typed, but rather is loosely typed. You don't need to inform PHP in advance as to what data type you're going to fill a variable with. Consequently, functions can also return multiple types.One extra loop type available in PHP is the foreach loop:
foreach ($array as $element)
{
// do this with $element
}
$element
. With the foreach construct, you don't need to keep track of the numeric index of the array element.For the past few weeks, we've only worked with arrays whose indices are numbers. In PHP, there's another type of array called an associative array whose indices can be strings, objects, etc.:
$staff = [ "foo" => "bar", "baz" => "qux" ];
As with other languages, let's start by writing a "hello, world" program in PHP:
<?php
printf("hello, world\n");
?>
<?php
and ?>
) which tell the interpreter where code begins and ends. PHP has a function printf
which is identical to C's implementation.php
. To execute the code above which is stored in a file named hello1.php
, we run php hello1.php
from the command line.In hello2.php
, we add a line to the top of the file that will allow us to execute it directly from the command line:
#!/bin/php
<?php
printf("hello, world\n");
?>
/bin/
is a directory containing binaries. This first line, called a shebang as short for sharp (#
) bang (!
), tells the operating system what program to pass this code to. Now we can run ./hello2.php
instead of php hello2.php
.hello2.php
directly, though, we get a permission denied error. That's because hello2.php
is only world-readable, not world-executable. To give the world the ability to execute this program, we run chmod a+x hello2.php
. Note that the file extensions are just a human convention. This same file could just be named hello2
or even hello2.rb
or hello2.c
and it would still execute.hello3.php
introduces a trick for finding the php
executable:
#!/bin/env php
<?php
printf("hello, world\n");
?>
/bin/env
is a program which will find and run the program whose name it's given as a command-line argument, in this case php
. This way, if you don't know where php
is installed on a system, you can still run your code. From the command line, you can also run which php
to find where php
is installed.Let's try reimplementing our "99 Bottles of Beer" lyrics program in PHP:
<?php
/****************************************************************************
* beer1.php
*
* David J. Malan
* malan@harvard.edu
*
* Sings "99 Bottles of Beer on the Wall."
*
* Demonstrates a for loop.
***************************************************************************/
// ask user for number
$n = readline("How many bottles will there be? ");
// exit upon invalid input
if ($n < 1)
{
printf("Sorry, that makes no sense.\n");
exit(1);
}
// sing the annoying song
printf("\n");
for ($i = $n; $i > 0; $i--)
{
printf("%d bottle(s) of beer on the wall,\n", $i);
printf("%d bottle(s) of beer,\n", $i);
printf("Take one down, pass it around,\n");
printf("%d bottle(s) of beer on the wall.\n\n", $i - 1);
}
// exit when song is over
printf("Wow, that's annoying.\n");
exit(0);
?>
GetString
anymore, we have the built-in PHP function readline
. Instead of using the return
statement as in C, we call the exit
function in PHP.The syntax for defining a function in PHP is fairly similar to that in C:
<?php
/****************************************************************************
* return.php
*
* David J. Malan
* malan@harvard.edu
*
* Cubes a variable.
*
* Demonstrates use of parameter and return value.
***************************************************************************/
$x = 2;
printf("x is now %d\n", $x);
printf("Cubing...\n");
$x = cube($x);
printf("Cubed!\n");
printf("x is now %d\n", $x);
/**
* Cubes argument.
*/
function cube($a)
{
return $a * $a * $a;
}
?>
cube
function and there are no types for the arguments. There is, however, the keyword function
which begins the declaration. No need for a function prototype in PHP, either.To show how straightforward PHP is, let's try reimplementing Problem Set 5. speller.php
is nearly identical to speller.c
, so we won't focus on that. Notice, though, that it it includes dictionary.php
by way of the require
function, similar to the #include
in C. So let's start writing dictionary.php
:
<?php
$table = [];
function check($word)
{
}
function load($dictionary)
{
}
function size()
{
}
function unload()
{
}
?>
Just like in Problem Set 5, we have 4 functions that we need to implement. And, with a single line of code, we've created a hash table to store our dictionary of words. Our check
function will be nothing more than checking if a particular word exists as a key in the hash table:
<?php
$table = [];
function check($word)
{
if (isset($table[$word]))
return true;
else
return false;
}
function load($dictionary)
{
}
function size()
{
}
function unload()
{
}
?>
Here, the word itself is the index in the hash table. load
is slightly more complicated:
<?php
$table = [];
function check($word)
{
if (isset($table[$word]))
return true;
else
return false;
}
function load($dictionary)
{
$words = file($dictionary)
foreach ($words as $word)
{
$table[$word] = true;
}
}
function size()
{
return count($table);
}
function unload()
{
$table = [];
}
?>
file
function in PHP opens a file and returns an array of its lines. We then loop through these lines using the foreach
construct, assigning each line to a temporary variable named $word
. We then set that word as a key in our hash table, with the value arbitrarily set to true
.size
by just counting the number of entries in the hash table and unload
by assigning an empty array to $table
../speller text
emits a single misspelled word "bar." We implemented Problem Set 5 in a matter of minutes! We pay for this, though, in performance. If we run the C version of speller
on the King James Bible, it takes less than 0.5 seconds to spell check. If we run the PHP version of speller
on the King James Bible, it takes more than 3 seconds to spell check. As always, there's a trade-off between development effort and performance. In general, interpreted languages like PHP are slower than compiled languages like C, mostly because interpreted languages have to go through the extra step of being translated to 0's and 1's at runtime. Given that the bottleneck for browsing the web is usually network latency, we don't necessarily have to worry about the performance difference between an interpreted language and a compiled language. There's also less risk for making mistakes with memory in PHP.Back at the turn of the 19th century when David was a freshman at Harvard, the process of registering for intramural sports was painfully manual. You had to fill out a paper form and actually drop it off at the dorm room of the proctor in charge. David decided to change all that by implementing an online registration form. Although his original implementation was in Perl, we can recreate it in PHP:
<?php
/*************************************************************
* froshims0.php
*
* David J. Malan
* malan@harvard.edu
*
* Implements a registration form for Frosh IMs.
* Submits to register0.php.
*****************************************************************/
?>
<!DOCTYPE html>
<html>
<head>
<title>Frosh IMs</title>
</head>
<body style="text-align: center;">
<h1>Register for Frosh IMs</h1>
<form action="register0.php" method="post">
Name: <input name="name" type="text"/>
<br/>
<input name="captain" type="checkbox"/> Captain?
<br/>
<input name="gender" type="radio" value="F"/> Female
<input name="gender" type="radio" value="M"/> Male
<br/>
Dorm:
<select name="dorm">
<option value=""></option>
<option value="Apley Court">Apley Court</option>
<option value="Canaday">Canaday</option>
<option value="Grays">Grays</option>
<option value="Greenough">Greenough</option>
<option value="Hollis">Hollis</option>
<option value="Holworthy">Holworthy</option>
<option value="Hurlbut">Hurlbut</option>
<option value="Lionel">Lionel</option>
<option value="Matthews">Matthews</option>
<option value="Mower">Mower</option>
<option value="Pennypacker">Pennypacker</option>
<option value="Stoughton">Stoughton</option>
<option value="Straus">Straus</option>
<option value="Thayer">Thayer</option>
<option value="Weld">Weld</option>
<option value="Wigglesworth">Wigglesworth</option>
</select>
<br/>
<input type="submit" value="Register"/>
</form>
</body>
</html>
<?php
and ?>
) contain nothing but comments (which are enclosed by /*
and */
).<head>
and <body>
tags. Within the <body>
, there's a <form>
whose action
attribute is register0.php
. We see input
tags with type
set to "text," "checkbox," and "radio." Text and checkbox should be self-explanatory, but radio refers to the bulleted buttons for which the user can only choose 1 option. To enforce this mutual exclusivity, we have to set the name
attribute for both input
tags to the same value, in this case "gender." To create a dropdown menu, we use the select
tag with option
tags within it. These option
tags have a string that's displayed to the user as well as a value
attribute which is actually passed to the back end. Finally we have our submit button which displays "Register" as its value
attribute.register0.php
URL that was specified in the action
attribute of the form. Unlike with our CS50 Search example, this URL doesn't have any of our inputs embedded in it. That's because we used the POST method of sending data rather than the GET method. Because POST sends data via the headers rather than the URL, it is useful for submitting passwords, credit card numbers, and anything that's sensitive. It's also useful for sending data that's too large to embed in the URL, for example an uploaded photo.register0.php
is a quick example of commingling PHP and HTML:
<?php
/***************************************************************
* register0.php
*
* David J. Malan
* malan@harvard.edu
*
* Dumps contents of $_POST.
***************************************************************/
?>
<!DOCTYPE html>
<html>
<head>
<title>Frosh IMs</title>
</head>
<body>
<pre>
<?php print_r($_POST); ?>
</pre>
</body>
</html>
<pre>
HTML tags, we enter PHP mode by inserting the <?php
and ?>
. Once we're in PHP mode, we access a variable named $_POST
. This is an associative array which PHP constructs for you whenever you pass in data via the POST method. If we had used the GET method, the data would be available in the $_GET
variable. print_r
is a function which prints recursively, meaning it prints everything that's nested within a variable. When we pass the $_POST
variable to print_r
, we see the four inputs that the user provided, each with a key that corresponds to the name
attribute of the input
. $_POST
and $_GET
are known as superglobal variables because they're available everywhere.If we want to dress up our webpage a little, we can make use of CSS that other people have written. froshims1.php
demonstrates how we can link to their code:
<?php
/*************************************************************
* froshims1.php
*
* David J. Malan
* malan@harvard.edu
*
* Implements a registration form for Frosh IMs.
* Submits to register1.php.
* Demonstrates Bootstrap (http://twitter.github.com/bootstrap).
*****************************************************************/
?>
<!DOCTYPE html>
<html>
<head>
<link href="bootstrap/css/bootstrap.min.css" rel="stylesheet"/>
<title>Frosh IMs</title>
</head>
<body style="margin: 20px;">
<h1>Register for Frosh IMs</h1>
<form action="register1.php" method="post">
<fieldset>
<label>Name</label>
<input name="name" type="text"/>
<label class="checkbox">
<input name="captain" type="checkbox"/> Captain?
</label>
<label class="radio">
<input name="gender" type="radio" value="F"/> Female
</label>
<label class="radio">
<input name="gender" type="radio" value="M"/> Male
</label>
<label>
<select name="dorm">
<option value=""></option>
<option value="Apley Court">Apley Court</option>
<option value="Canaday">Canaday</option>
<option value="Grays">Grays</option>
<option value="Greenough">Greenough</option>
<option value="Hollis">Hollis</option>
<option value="Holworthy">Holworthy</option>
<option value="Hurlbut">Hurlbut</option>
<option value="Lionel">Lionel</option>
<option value="Matthews">Matthews</option>
<option value="Mower">Mower</option>
<option value="Pennypacker">Pennypacker</option>
<option value="Stoughton">Stoughton</option>
<option value="Straus">Straus</option>
<option value="Thayer">Thayer</option>
<option value="Weld">Weld</option>
<option value="Wigglesworth">Wigglesworth</option>
</select>
</label>
<button class="btn" type="submit">Register</button>
</fieldset>
</form>
</body>
</html>
<link>
tag, we can import the bootstrap.min.css
file from our server. It's not perfect, but it certainly makes our form a little more attractive. To make use of this CSS, we changed our HTML. We encapsulated our entire form within a <fieldset>
tag and added <label>
tags to each input. We're also using class
attributes for our tags.In register2.php
, we begin to do some validation of the user's inputs:
<?php
/***********************************************************************
* register2.php
*
* Computer Science 50
* David J. Malan
*
* Implements a registration form for Frosh IMs. Informs user of
* any errors.
**********************************************************************/
?>
<!DOCTYPE html>
<html>
<head>
<title>Frosh IMs</title>
</head>
<body>
<?php if (empty($_POST["name"]) || empty($_POST["gender"]) || empty($_POST["dorm"])): ?>
You must provide your name, gender, and dorm! Go <a href="froshims2.php">back</a>.
<?php else: ?>
You are registered! (Well, not really.)
<?php endif ?>
</body>
</html>
empty
function returns true if the given variable is empty. Thus, our if condition here checks if the any of the name, gender, or dorm inputs is empty, in which case it prompts the user to go back and enter them again. The colon at the end of the if condition tells the PHP interpreter to spit out as HTML everything that follows and that precedes an else or endif keyword.In register3.php
, we take the extra step of actually e-mailing the user's information:
<?php
/***********************************************************************
* register3.php
*
* Computer Science 50
* David J. Malan
*
* Implements a registration form for Frosh IMs. Reports registration
* via email. Redirects user to froshims3.php upon error.
**********************************************************************/
// require PHPMailer
require("PHPMailer/class.phpmailer.php");
// validate submission
if (!empty($_POST["name"]) && !empty($_POST["gender"]) && !empty($_POST["dorm"]))
{
// instantiate mailer
$mail = new PHPMailer();
// use SMTP
$mail->IsSMTP();
$mail->Host = "smtp.fas.harvard.edu";
// set From:
$mail->SetFrom("jharvard@cs50.net");
// set To:
$mail->AddAddress("jharvard@cs50.net");
// set Subject:
$mail->Subject = "registration";
// set body
$mail->Body = "This person just registered:\n\n" .
"Name: " . $_POST["name"] . "\n" .
"Captain: " . $_POST["captain"] . "\n" .
"Gender: " . $_POST["gender"] . "\n" .
"Dorm: " . $_POST["dorm"];
// send mail
if ($mail->Send() == false)
{
die($mail->ErrInfo);
}
}
else
{
header("Location: http://localhost/~jharvard/froshims/froshims3.php");
exit;
}
?>
<!DOCTYPE html>
<html>
<head>
<title>Frosh IMs</title>
</head>
<body>
You are registered! (Really.)
</body>
</html>
PHPMailer
. Objects have their own functions within them called methods. To call one of these methods in PHP, we use the arrow (->
) notation. So once we have a PHPMailer
object in a variable named $mail
, we call the IsSMTP
method of that object by writing $mail->IsSMTP()
. We set the mail server to be smtp.fas.harvard.edu
and call a few more methods to set the to and from addresses as well as the subject and body. We know the names of these methods simply by reading the documentation for PHPMailer. To construct a body for our message, we use the dot operator (.
) to concatenate the user's inputs into one long string. Finally, we call the Send
method and voila, we have just registered a user for freshman intramurals!