Andrew Sellergren
$_SESSION
is a superglobal variable and an associative array, like $_GET
and $_POST
. We use $_SESSION
to store information about a user that we want to persist as long as he or she is signed in. In Problem Set 7, we store in $_SESSION
a key "id" with a unique numeric identifier for the logged-in user.$_SESSION
as an online shopping cart. Information will usually remain in $_SESSION
as long as the user keeps his browser open. $_SESSION
provides an answer to the problem of HTTP being a stateless protocol, meaning that the connection between the browser and server is not persistent.$_SESSION
was a simple visit counter webpage. When you first visit it, it says "You have visited this site 0 time(s)." However, as you refresh it, that number increments.counter.php
, we called session_start()
to enable the $_SESSION
variable. Then we simply stored within it at index "counter" a numeric value that we increment whenever the user visits. We made a copy of this value in a temporary variable named $counter
before incrementing it. Finally, we print out $counter
using the special <?= $counter ?>
PHP syntax, equivalent to printf
, print
, or echo
.PHPSESSID
keyword. When the user revisits this page, his or her browser will present this alphanumeric string to the server, which will then look up the user in its database and fill in the $_SESSION
variable with his or her information.house
column to our students
table from Friday. We click the Structure tab and then click on the Go button next to "Add 1 column(s)..." Don't worry, these steps are outlined in the Problem Set 7 specification.house
column will be. Obviously, it won't be an INT
. It could be a VARCHAR
, which is a string of variable length. In contrast to CHAR
, which has a fixed length, VARCHAR
only uses the minimum number of bytes necessary to store a string. So if you insert the value Mather
into a VARCHAR
column of length 255, it uses 6 bytes whereas if you insert the value Mather
into a CHAR
column of length 255, it uses 255 bytes. The flipside of this, however, is performance. If your column values have a fixed length, as with the CHAR
type, the database engine can optimize for their lookups because it knows exactly where to jump to access them.INT
type stores 32-bit integers. Having used this for its user id field, Facebook recently faced the problem of running out of integers and had to switch to a BIGINT
type, which store 64-bit integers. DECIMAL
is a type that specified fixed precision, as described in Problem Set 7.VARCHAR
of length 255 for house
. If we choose to, we can also specify a default value of NULL
so long as we check the Null checkbox to indicate that these values are allowed.students
table, the best candidate for this is the id
field. email
is also a possibility, but is less ideal because it's a string instead of an integer and thus proably requires more bytes on average. We can also specify some columns as being UNIQUE
, which will guarantee that duplicate values cannot be inserted. Even if a column is not UNIQUE
, however, we can specify it as an index if we know that we're going to search it frequently. In the case of house
, for example, the values won't be unique, but we'll want MySQL to build up a data structure (usually a B-tree) behind the scenes so that it's easily searchable. This is what specifying a column as an index does.Once we click Save and add house
to our students
table, the existing rows will have a value of NULL
for the new column. If we want to change David's house
value to "Pfoho," we can do it by clicking Edit or we can click the SQL tab and manually execute the following query:
UPDATE students SET house = 'Pfoho' WHERE id = 1;
students
table and set the house
value to "Pfoho" wherever the id
value is 1. Since the id
value is 1 only for David, we're only updating a single row.students
table will have 400 rows that have the value "Mather" as a value for house
. We're wasting bytes by storing this string over and over again. Instead of storing the whole "Mather" string for each of these rows, let's instead store an identifier that maps to "Mather" in another table.We start by creating a new table named houses
which has just 2 columns, id
with type INT
and attributes UNSIGNED
and AUTO_INCREMENT
as well as name
with type VARCHAR
of length 255. Then we insert the values of "Mather" and "Pfoho" into this table by executing the following SQL queries:
INSERT INTO houses (name) VALUES('Mather');
INSERT INTO houses (name) VALUES('Pfoho');
students
table. The type of the house
field should be changed from VARCHAR
to INT
. David's house
value then becomes 1 and Mike's becomes 2. Henceforth, we'll only be using 32 bits to store the house
value as opposed to potentially many more for long house names. This process of factoring out redundant information from our database is called normalization.INT
in parentheses, e.g. INT(11)
, has nothing to do with the size of the column. It refers to the display width of the column.But how do we search for all students who live in Mather? We have to join our students
table with our houses
table using a SQL query like the following:
SELECT * FROM students JOIN houses ON students.house = houses.id;
*
means select all fields from both tables. The ON
syntax specifies which columns map to each other in the two tables. The takeaway here is that if you find yourself storing information redundantly, you should consider factoring it out into separate tables.In Problem Set 7, we provided you with queries like the following:
INSERT INTO table (id, symbol, shares) VALUES(7, 'DVN.V', 10)
ON DUPLICATE KEY UPDATE shares = shares + VALUES(shares);
START TRANSACTION
and a COMMIT
statement, you guarantee that all of them get executed simultaneously. Although this isn't necessary for Problem Set 7, it may prove useful for your Final Project.Consider for the sake of this discussion the following very simple webpage:
<!DOCTYPE html>
<html>
<head>
<title>hello, world</title>
</head>
<body>
hello, world
</body>
</html>
As the indentation in our code has suggested, there is a hierarchy to HTML. We can represent this simple webpage with the following tree:
main
function. Unlike PHP, however, JavaScript is executed clientside, not serverside. The browser itself downloads and executes the JavaScript code on a webpage. This has meaningful implications for intellectual property since it's hard to protect your JavaScript source code from being seen by others.Conditions, Boolean expressions, switch statements, and loops are the same in JavaScript as they are in C and PHP. Variables have a slightly different syntax:
var s = "hello, world";
var
lest you accidentally declare your variable to be global.Arrays in JavaScript are syntactically similar to arrays in PHP:
var numbers = [4, 8, 15, 16, 23, 42];
Associative arrays don't really exist in JavaScript. Instead, JavaScript has objects:
var student =
{
id: 1,
house: "Winthrop House",
name: "Zamyla Chan"
};
One special type of loop in JavaScript mimics the foreach
syntax of PHP:
for (var i in array)
{
// do this with array[i]
}
i
.To include JavaScript in a webpage, we use the <script>
tag, as in blink.html
:
<!--
blink.html
Flashes a greeting.
Computer Science 50
David J. Malan
-->
<!DOCTYPE html>
<html>
<head>
<script>
// toggles visibility of greeting
function blink()
{
var div = document.getElementById('greeting');
if (div.style.visibility == "hidden")
{
div.style.visibility = "visible";
}
else
{
div.style.visibility = "hidden";
}
}
// blink every 500ms
window.setInterval(blink, 500);
</script>
<style>
#greeting
{
font-size: 96pt;
margin: 240px;
text-align: center;
}
</style>
<title>blink</title>
</head>
<body>
<div id="greeting">
hello, world
</div>
</body>
</html>
blink.html
, we resurrect the <blink>
tag which was deprecated from HTML. Ignoring the <script>
tag for now, we see that our HTML consists of almost nothing but a <div>
with the id
set to "greeting." Inside of the <script>
tag, we define a function named blink
. blink
starts by grabbing the <div>
which has id
set to "greeting" using the aptly name getElementById
method of the document
object. It turns out that in JavaScript, there is a special global variable called document
. In addition to data about the webpage, this variable has functions associated with it, one of which retrieves HTML elements according to their unique id
attributes. Functions within an object we'll call methods.div
variable containing a <div>
element, we can change its CSS on the fly by accessing the style
attribute of the object. This style
attribute itself has a visibility
attribute, which we know because we read the documentation. In this function, we toggle the visibility
between "visible" and "hidden."window
. Whereas document
encapsulates the webpage, window
encapsulates the whole browser window. window
has a method named setInterval
which will cause a function to be called regularly. In this case, we pass a pointer to the blink
function to setInterval
so that it will be called every 500 milliseconds. Note that to pass a pointer to the blink
function, we write it as blink
not blink()
. The latter would actually call the function and pass its return value to setInterval
.blink.html
is massive hideous "hello, world" message. If we inspect this element using Chrome Developer Tools, we can see that its CSS style is actually changing every half second.If you take a look at form0.html, you can see that it's a very basic HTML form. When you click Register, you get a simple dump of the data you entered. However, there's no validation done on your inputs. In form1.html, we add a bit of JavaScript which prevents the user from submitting the form if he or she hasn't filled out all the fields:
<!--
form1.html
A form with client-side validation.
David J. Malan
malan@harvard.edu
-->
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script>
// onready
$(document).ready(function() {
// onsubmit
$('#registration').submit(function() {
// validate email
if ($('#registration input[name=email]').val() == '')
{
alert('You must provide your email address!');
return false;
}
// validate password
else if ($('#registration input[name=password]').val() == '')
{
alert('You must provide a password!');
return false;
}
// validate confirmation
else if ($('#registration input[name=password]').val() != $('#registration input[name=confirmation]').val())
{
alert('Passwords do not match!');
return false;
}
// validate agreement
else if (!$('#registration input[name=agreement]').is(':checked'))
{
alert('You must agree to the terms and conditions!');
return false;
}
// valid!
return true;
});
});
</script>
<title>form1</title>
</head>
<body>
<form action="dump.php" method="get" id="registration">
Email: <input name="email" type="text"/>
<br/>
Password: <input name="password" type="password"/>
<br/>
Password (again): <input name="confirmation" type="password"/>
<br/>
I agree to the terms and conditions: <input name="agreement" type="checkbox"/>
<br/><br/>
<input type="submit" value="Register"/>
</form>
</body>
</html>
<script>
tag here actually includes some JavaScript from a library called jQuery. Much like the CS50 Library provided a convenience layer on top of C, jQuery provides a convenience layer on top of JavaScript. In jQuery, there's a special global function named $
. When you pass to this function the document
object, it returns to you a special version of that object with several additional methods. One such method is named ready
, which takes as input a function that should be automatically called whenever the webpage has finished loading. The function we pass to ready
in the above is an anonymous function, a function that has no name. Anonymous functions are useful when we only need to call a function once.$
jQuery function. The $
function can also retrieve HTML elements by their id
attribute, just as getElementById
did. Because the element with id
of "registration" happens to be a form, it has a submit
method (thanks for jQuery) which takes as input a function that should be called when the form is submitted. Here again we pass an anonymous function.<input>
with name
of "email" within the HTML element with id
of "registration." Once we have this HTML element, we call its val
method to get its value. If this value is the empty string, then the user has inputted nothing for the e-mail field. In a similar fashion, we go on to check that the first password field is not empty and that the first password field and the second password field have the same value. Finally, we verify that the checkbox has been checked.onsubmit
event, there are a number of other browser events that you can use to trigger actions. Gmail, for example, most likely uses the onkeydown
and onkeyup
events to implement keyboard shortcuts. We've only just scratched the surface of what JavaScript is capable of!