[Week 9]
[David J. Malan - Harvard University]
[This is CS50. - CS50.TV]
All right. Welcome back. This is CS50, and this is the start of week 9.
Today we focus in particular on design, no longer in the context of C
but in the context of PHP and a bit of SQL and a bit of JavaScript,
particularly toward an end of both pset 7 and also your final project.
In fact, if you are at that point in your final project
where presumably as of an hour or so ago you at least started to give some thought
to your final project and you're thinking you'd like to collaborate with 1 or 2 classmates,
if you're having trouble connecting with said classmates,
feel free to fill out the form at cs50.net/partners/form.
It just asks you who you are, what kind of project you're thinking about,
where you live just for logistical reasons.
And then if you want to keep an eye on over the next week or so the spreadsheet URL there,
you can then see a read-only version of the Google doc
in which we're collecting that information.
So if you want to work with someone, by all means feel free to reach out to people
via that mechanism.
But the majority of folks do work solo. That's totally fine.
So don't feel that this is in any way obligatory.
On Friday it was just me and a few of the team in here,
empty theater for the most part.
There were 3 tourists sitting up there, so that was a little awkward.
What we talked about was databases and we talked about pset 7 a little bit.
And if you didn't happen to catch that on video just yet, that's fine.
I'll try to define any terms that we would otherwise take for granted
based on Friday's lecture.
>> But today we're going to try to get you to the point
of not just being able to do something like pset 7
but really understanding what's going on underneath the hood,
particularly some of the abstractions that we put in place in the functions.php file
to make your lives a bit easier but so that you ultimately understand
so that when the training wheels come off in a few weeks you can still survive
in the real world and do this stuff without any CS50 framework underneath you.
This $_SESSION, for those of you who are familiar
or who already caught the video on Friday, what does SESSION let us do
in a PHP-based web application?
This is a superglobal variable, which means it's similar in spirit to GET and POST
and a few others, but what is this thing useful for?
>> What is SESSION used for? Yeah. [student] Logging in.
Sorry? [student] Logging in. Logging in. Indeed.
In pset 7 we're using this SESSION superglobal to facilitate logging in.
And what's nice about this superglobal is that it's an associative array.
An associative array, recall, is just an array but whose indices no longer have to be numbers
like 012. They can be numbers or they can be even strings.
And so if you've dived into pset 7 yet, you may recall that we are storing a key called ID
inside of this associative array whose value is something like 123--
whatever the currently logged in user's ID is.
The motivation for this is that even after the user has visited localhost
or my website more generally and then they've logged in,
even if they don't click a link or return to my website for 5 minutes
or even an hour or even a day but they leave their browser window open,
via this superglobal can I remember that they are logged in.
>> In other words, it allows me to store slightly long term anything I want about a user.
And you can think of it really as the incarnation of a shopping cart.
Places like Amazon obviously let you put things into a shopping cart,
but HTTP, the protocol that powers the Web, is stateless
in the sense that when you visit a website,
for the most part you don't have some constant network connection
between your browser and the server.
As soon as you've downloaded the HTML and the JPEGs and the GIFs and all that,
the connection goes away and you just have a copy of the HTML and whatnot from the server.
But if the server wants to remember something about you,
the burden is on the server to actually record that information.
And so you the programmer who have control over the server
can put most anything you want inside of this superglobal associative array
and it will be there the next time the user comes back,
whether it's minutes or even days later, unless they close their browser window,
at which point SESSION disappears.
So it's ephemeral storage, it's non-persistent, and it's meant to go away
as soon as the user closes their browser--not just that tab, often the entire browser,
thereby effectively logging the user out.
So how is this thing actually implemented?
Let's take a quick look at a simple example we looked at on Friday.
For those unfamiliar, it was as simple as this.
This is a web page whose sole purpose in life is to tell me
how many times I have visited this page.
This is the first time here on Monday that I visited it, so it says 0 times.
>> But if I start reloading this page, it says 1 time, 2, 3, 4, 5,
and this will eventually just keep on counting up, up, up, up, up
for each time I actually click Reload on it.
So how is this working? Let me go inside of this file called counter.php.
The top part of it is all blue comments, but the interesting part is here.
On line 13 we call this function session_start,
and that is literally all you need to do if you want to have access
to this special superglobal called $_SESSION.
That makes it all possible, and we'll see in a moment how that's all possible.
In line 16 notice what I'm doing.
If the key, called counter--in other words, the index value--"counter"
exists inside of this array called SESSION, then what am I doing with it in the line below?
What is line 18 doing?
>> [inaudible student response] What's that? [student] Storing the value. Good.
It's storing the value that's in SESSION right now in a new local temporary variable,
$counter in all lowercase.
Notice that PHP is already being a little lazy here.
Notice we don't have any mention of int or float or string or anything like that
because PHP is weakly typed, whereby you don't have to specify the type of a variable,
and in this case here I've not even declared it yet.
I'm declaring it inside of these curly braces and unlike C, this is actually okay.
No matter how deeply nested a variable's declaration is in PHP--
inside of curly brace, inside of curly brace and the like--
it will at that moment in time exist for the remainder of the program,
for better or for worse.
So it immediately becomes global as soon as you define it as we're doing here.
>> Otherwise, if I do not find that there's anything in the SESSION superglobal,
I'm apparently initializing this variable counter to 0,
thereby just assuming the user has never been here before.
And then this of course is incrementing the counter how?
I'm updating the value that's inside of this associative array
by setting it equal to whatever counter currently is + 1.
If I scroll down here to the HTML of the page, it's actually pretty simple.
All I have in the body of this page is, "You have visited this site so-and-so times."
And this is a PHP construct.
If you do <?=, this is equivalent effectively to what function?
It's really equivalent to something like printf, which we've seen many times in C,
although as you may know already from the spec in pset 7,
print is also a function that just prints something out, it doesn't actually use format codes,
and you can actually say echo as well.
They're all ever so slightly different even though the net effect is ultimately the same.
So this use of the equals sign is just sort of an elegant way of doing it
more succinctly than you might otherwise be able to.
So that's all this site does. It prints out the value of counter.
How is this all actually happening?
You may recall a week or so ago we started looking underneath the hood
at how a web page works by using this Inspector tab.
>> Chrome has this both in the Mac version, the Windows version, and even the Linux version,
and Firefox and IE have similar mechanisms whereby you have this built-in debugger
inside of the browser.
Let's take a look at the following.
We've got a whole bunch of tabs here, and recall that the leftmost one is Elements,
and no matter how godawful the HTML and JavaScript is in a page,
recall that with the Elements tab you can actually navigate the HTML hierarchically
and nice and neatly.
So if you're trying to learn from a website like Google or Facebook
or really any website, realize that you're probably better off
looking at the source code this way as opposed to viewing the raw source,
which can be a mess, as we've seen especially on Google's site.
So if I instead click on the Network tab here,
let's see what's going on when I visit this page.
First let me clear my cache.
I'm going to go into Settings in Chrome and then go to History
and then Clear all browsing data.
You might be used to doing this for other purposes, [laughter]
but when it comes to developing websites, it's actually useful--
if you're laughing you know. [laughter]
It's actually really useful when developing websites because the reality is
things like cookies and things like cached HTML files, cached JavaScript files
can actually become a big headache, because if for whatever reason
the browser decides to cache some file and yet you've made changes to that file on the server
but the browser hasn't really realized that the file has changed
and therefore does not actually re-download it even when you click the Reload button,
one of the most surefire ways to just make sure the fault is not with your code,
it's with the behavior of the browser, is to go in here in your browser
and just clear the entire history so that there's no confusion.
>> And then if you really want to be paranoid, quit the browser, restart it,
and then make sure all is working as expected.
So in short, clearing cache is good when doing development.
So here we have the Network tab.
I previously had visited the site 9 times, but let me go ahead now and click Reload.
And I'm back down to 0.
Let's actually see how it is that this SESSION superglobal is being implemented.
I'm going to click on the 1 HTTP request that was made,
and this debugging window lets me look inside of that.
Here I see just the response from the server, which isn't interesting.
I've seen this in any number of ways.
But what's technically interesting are the headers.
If I scroll down here and focus on the request headers and click view source,
what I'm going to see is literally the HTTP request
that just went from my browser to the server,
GET being the operative word and then /counter.php being the file name,
HTTP/1.1 just being the version of HTTP that my browser is using.
This line here is a little reminder from browser to server what the name of the server is
that it wants to talk to.
And then the rest of this is sometimes interesting but not relevant right now.
>> This is just kind of a curiosity.
Cryptic though this string is, any time your browser visits a website
it is informing the server what browser you're using
and what operating system you're using and what version thereof.
So if you've ever wondered how websites like CNN and whatnot
know what the percentages are of Mac users on the Web, PC users,
IE users, Chrome users and the like, it's because all of our browsers
are telling every single website out there what we are.
It doesn't necessarily contain personally identifiable information,
but it does tell the server what your IP address is and what browser and OS you are using.
So that's where this information is.
But what's more interesting now when it comes to these sessions is the response header.
Let me click view source next to response.
What's interesting here is a few things.
1, we got back a status code of 200.
We never see this status code because that means all is well.
It means literally okay in contrast to something else.
What's a number we sometimes see that's bad? [student] 404.
404, file not found, 403 you might be stumbling upon already,
which is forbidden, which means you forgot to chmod something, most likely.
And there's a bunch of others.
>> Down here, this is a little crazy.
I really just wrote this file a few minutes ago by pasting it into gedit.
Why did this page expire in 1981 before there really was a Web?
What's going on there?
>> [inaudible student response] The time stamp. But why?
It's somewhat arbitrary, but it's actually useful.
What this is saying to my browser is this PHP file you've just requested has already expired.
In fact, it expired 30 years ago.
But what does that really mean?
It just means the next time the user visits this page,
whether by reloading or typing the URL in the address bar,
make sure you go and fetch a new copy of it.
This is sort of an example of cache busting,
a stupid word that just means trying to discourage browsers
from actually caching HTML that's been sent from a server
so that you don't accidentally hit reload and then see the same version of the file.
You actually want the server to send a new copy.
So the fact that it's 1981 just means that that's what the appliance is choosing
as an arbitrary date in the past.
But the real juicy line is now this one.
Even before 50 you're probably vaguely familiar with cookies.
As of right now, especially among those less comfortable or in between,
what is a cookie in your understanding right now
even though we're about to make your understanding more technical?
What's a cookie? Yeah.
[student] Information about the user, like if they've written their user name or something.
>> Good. It's information about the user, whether they've typed in their user name already.
Cookies are a way whereby servers can remember something about a user.
And what a cookie really is is a text file or some sequence of bytes
that's planted by the server inside of your browser,
and inside of that file or among those bytes is some kind of identifier.
Maybe it's literally your user name, but more often it's something more cryptic-looking
like this thing here--bo8dal3ct and so forth--this really big alphanumeric string
that's really just meant to be a unique identifier for you.
Or you can think of it as sort of a virtual hand stamp.
If you go to some club or an amusement park, to remember that you've actually paid
and gone in, they put a little red sticker on your hand of some sort,
and that reminds the people at the counter that you've already paid
and you can come and go as you please.
Cookies are a little similar in spirit to that.
The first time I visited this website, as I just did after clearing my cache,
the web server, the appliance in this case, put a stamp on my hand
whose name is PHPSESSID, session ID,
whose value is this really long alphanumeric string.
>> So that's now sort of emblazoned on my hand so that the next time I hit reload
or manually visit this URL in a browser,
my browser by definition of HTTP is going to present the hand stamp
again and again and again.
So even though the server doesn't necessarily know who I am,
they at least know that I'm the same user or at least, more specifically, the same browser.
And so this is ultimately how the SESSION superglobal is implemented.
The server has no idea who you are when you revisit a website for the second or the third time
unless you present this hand stamp.
And as soon as you present that hand stamp,
the web server essentially goes into a little database of its own
and checks, okay, I have just seen the hand stamp of user bo8dal3ct and so forth.
Let me see what information the programmer has stored
inside of the superglobal about this user,
and then let me make sure that that data is again inside of the SESSION superglobal
so that the programmer can re-access that data
even if it was set some minutes or hours ago.
So in other words, cookies, which got a bad rap for some time
because of insecurities in browsers and they can really violate our privacy and all this,
they actually have great utility because without them
you would constantly be logging in to every Facebook page you visit
or every Gmail email you read if the browser didn't have some way of remembering
that you've already authenticated.
>> So in this way cookies are sent back and forth across the wire.
Another curiosity about cookies, especially here, is that this is completely in cleartext.
There's no encryption going on here whatsoever,
and indeed I'm using HTTP at the moment.
One of our favorites moments in CS50, which is now 2 years ago,
was around the time a tool called Firesheep came out.
This was a free piece of software that was made by a security researcher
as a wake-up call for the community to say just how atrociously implemented
certain authentication mechanisms on the Web were.
So for some time, Facebook was almost entirely over HTTP, no HTTPS.
And even if you have no idea how the crypto works, S is secure
so it means there's at least some encryption involved.
Facebook did used to encrypt user names and passwords,
but as soon as you looked at your pokes or your messages or your news feed,
all of that was unencrypted.
So was Gmail until just a year or 2 ago.
Any time you logged in, yes, they used secure encryption,
but thereafter they didn't. And why might that be?
Why not just use cryptography all of the time in use cases like this?
What's that? I think I heard something. [student] Speed.
Speed, right? There are ways around this.
But if you just kind of think about it logically, if you encrypt something,
you have to do at least a little more work.
In pset 2 when you implemented Caesar or Vigenere or even Crack,
just printing a string is relatively easy.
Encrypting and then printing a string minimally requires a bit more work.
>> For super popular websites like Google and Facebook,
if you have to do more work for each user for every single web page they visit,
that just takes more CPU time.
And if you need more CPU time, you might need more servers,
which means you might need more money.
And so for many years this just really wasn't best practice.
People would use SSL encryption only when they needed to.
But it turned out, and as this fellow with Firesheep made super clear,
when you guys who are currently on Facebook right now--
Out of curiosity, let's see if you'll fess up.
If you're on Facebook right now in some tab, even if it's not foregrounded,
is your URL HTTP or HTTPS?
[multiple students] S. S? [laughter]
Okay. Any HTTP? Just 1? Okay.
So all of us can hack that guy's Facebook account right now.
For the most part this has become turned on by default, at least in some websites.
And long story short, if your web traffic is not encrypted,
not only does the HTML go back and forth across the WiFis unencrypted,
so do things like cookies go back and forth throughout the air
without any form of encryption.
So if you have just a bit of programming savvy or a bit of Googling skills
to find free software that does this, all you have to do is sit in Starbucks
or sit in an airport where there's generally unencrypted WiFi
and just watch for keywords like Set-Cookie: or PHPSESSID
because if you have the technical savvy to just watch the WiFi
for all of the bits that flow throughout the air for this pattern,
you can then say that guy's PHPSESSID happens to be bo8dal and so forth.
And then again if you're sufficiently technically savvy or have the right tool,
you can then just reconfigure your own browser to start presenting that hand stamp
to Facebook.com, and Facebook is just going to assume that you are that guy
because all they know is not who you are but that you have this unique identifier.
So if you steal that unique identifier and present it to the web server as your own,
they are just going to show you that person's news feed
or that person's messages or pokes.
>> And I would Google now how to activate HTTPS for Facebook perhaps.
But it really is as simple as that.
And so Facebook and Google and the like have gotten really good at this,
but keep an eye out all the more for any websites you visit that don't use HTTP
and have some kind of sensitive information on them,
whether it's financial or personal or the like.
If they're not using this, quite possibly can cookies like this be very easily stolen
and then forged, and that's exactly what Firesheep did.
You didn't have to be a programmer.
All you had to do was have an Internet connection, download this free tool,
and what it would do is you log in and then it would show you the Facebook names
of everyone in Sanders, in this particular demonstration, around you
and all you had to do was click on their name and the software automated the process
of sniffing that cookie, presenting it to Facebook as your own,
and, voila, you're logged in.
So this is another one of those "don't do this" officially.
If you have your own home network and you want to tinker, by all means,
but realize this does cross the line on a university environment.
>> But the goal here is really to emphasize not how to do this
but how to defend against these kinds of things.
And the trivial solution here, even though it itself is flawed,
is to really reduce use of any sites that aren't using HTTPS constantly.
So sites like Facebook and Google increasingly have checkboxes
where you can opt in to this sort of thing,
and banks have had this for years for similar reasons.
So just a little bit of a fear factor if we can. But that's it in a nutshell.
That is how a server remembers who you are.
And as soon as they can remember who you are, they can remember anything about you
that the programmer has stored inside of this special superglobal called $_SESSION.
And for pset 7 we're using it trivially just to remember an int,
namely the unique ID of the user who has logged in,
so that we know they've been there before.
Any questions then on sessions or cookies or the like?
Firesheep doesn't work as well anymore,
and you have to put your computer into a special promiscuous mode
so you're actually listening for traffic besides yourselves.
So if you're currently downloading Firesheep, realize it's not quite as easy
as it once was to demonstrate.
All right. And don't do it in Sanders. Do it at home.
Databases.
One of the things we did in pset 7 very deliberately
was we give you a sample database table for users that has some user IDs,
some user names, and some encrypted passwords therein.
And as you'll see, if you haven't already, you're going to have to change the table a little bit.
You're going to have to add some cache to each of the users in that table,
and you're going to have to add another history table, a portfolios table,
or perhaps call it something else.
But in terms of thinking about how to do this, let's open up this tool
which we used on Friday, but if unfamiliar, the appliance comes with a tool
called phpMyAdmin which is coincidentally written in PHP,
but its purpose in life, after I log in here as jharvard with crimson,
is to give me a user-friendly way of viewing and changing my database.
>> The database that I'm running on the appliance is called MySQL.
This is very popular, and it's a free open source database that's wonderfully easy to use,
especially with front ends like this.
What this tool allows me to do, for instance, is poke around tables.
Let me go ahead and do this.
On Friday we created a table called students that was super simple.
It had 3 columns--id, name, and email--and I manually inserted a couple of rows
like David and Mike in this particular example.
Let's take this a bit further, and let's assume that we want to remember more
than just name and email about a user.
Let me click Structure up here at the top.
And again, the pset walks you through the requisite steps here,
so don't worry if some of this is a bit quick.
Then I'm going to click on here.
I'm going to add some number of columns after email
because I want to add something like house.
I forgot to record a student's house.
Let me click Go, and now we have this form that unfortunately is a little wide from left to right,
but I'm going to call the name of this field house,
and then the type I now have to choose.
So let's have a brief chat about the various types in MySQL
because whereas PHP is weakly typed and it sort of plays fast and loose with types,
in a database especially it's super important to actually use typing to your advantage
because one of the things MySQL and other database engines can do for you
is ensure that you don't put bogus data into your database.
This is sort of free error checking available to you.
>> For house we obviously don't want it to be an int, which is a 32-bit value in MySQL.
We did talk briefly on Friday about varchar, which stands for variable length char.
What is this? This allows you to specify that you want this to be a string of some sort.
You don't really know in advance how long it is,
so we'll arbitrarily say a house name can be 255 characters,
but you could go with 32, 64--any number really.
But the advantage of using a varchar over a field called char is what?
Just intuitively if I scroll down here, notice there's char and there's varchar.
Varchar is variable length char; char is a fixed length char.
So based only on that definition, what's the advantage or disadvantage of each of these?
In other words, who cares about the distinction, or why should you care?
>> Yeah. [student] Varchar has more flexibility but takes up more memory.
Good. Varchar takes up more-- Let's see. I'm not sure if I heard that right.
Can you say that once more?
[student] I said varchar probably has more flexibility but it takes up more memory.
Interesting. Okay. Varchar probably gives you more flexibility but takes up more memory.
The latter isn't necessarily true.
It depends on the context, but let's come back to that.
>> [inaudible student response] Exactly.
It's actually the case that char will typically use more memory
because a char, like in C, is like a string, it's an array of characters.
So if you say a char field of length 255,
the database is literally going to give you 255 characters.
And if the house ends up being M-A-T-H-E-R and 6 characters total,
you're wasting over 200 characters.
>> So a varchar effectively only uses as many characters as is necessary
up to a maximum amount.
But the price you pay is actually performance, potentially.
If you know in advance that all of your strings are going to be 8 characters--
for instance, suppose that you require passwords of length 8--
the upside of using a char field on occasion, though not often,
is to specify a fixed length for something like a password
because now the database can be even smarter.
If it knows that every char field, every string in a column is the same length,
you get back the feature of random access.
You can jump around among the various char fields in your database table
because think of a database as rows and columns.
So if every one of the strings is the same length,
you know that the first one is at byte 0, the next one is at byte 8
and then 16 and then 24 and so forth.
So if all the strings are of the same length, you can jump around much more efficiently.
So that can be a benefit in terms of performance,
but typically you don't have the luxury of knowing in advance,
so a varchar is the way to go.
Here's another detail that even Facebook ran into eventually.
Ints are great, and we sort of use them by default any time we want a number,
but it's only 32 bits.
>> And even though Facebook doesn't quite have 4 billion users now,
there's definitely some people out there with multiple accounts
or accounts that have been opened and then closed,
and so Facebook itself I believe a few years ago had to transition from int
to, as is aptly called, bigint, which is just 64 bits instead.
So this too is a design decision.
You would be amazingly lucky if your final project turns startup,
has 4 billion and 1 users, give or take,
in which case using ints might be a little shortsighted.
But in reality, your users table is probably fine with ints.
But for something like pset 7, like your history table,
you might have thousands, millions of users if you evolve into etrade.com.
So whereas you might not have more than 4 billion users,
those users you do have might have more than 4 billion transactions over time--
buys and sells and things in their history.
So if you do anticipate--again, these are good problems to have if you have this much data--
if you do anticipate data exceeding the size of an int,
going with something like bigint is a direction not frequently enough adopted by designers
because people figure that's not going to be a problem,
but it's this easy to choose something bigger than that.
Decimal we're using in pset 7, which specifies fixed precision
so you can avoid the issues involving floats and doubles and reals and the like.
>> And then there's some other fields here. We'll wave our hands at them to some extent.
But dates, times all have a prescribed format in MySQL,
and the advantage of storing dates as dates and not varchars
means that the database can actually reformat them into different formats,
whether a US format or European format or the like--however you want it--
much more efficiently than if it were just some generic varchar.
And then there's some other binary, varbinary, blobs.
These are binary large objects, and you can also store binary data
as well as geometric data in a database.
But for us we'll typically care about ints and varchars and the like.
Let's finish up this example with house.
House I'm going to arbitrarily say will be 255 chars.
Then default value we could do this.
We could by default put everyone in Mather House, for instance.
That's how we could specify that the database
should ensure that someone always has a value. But I'll leave that be.
In fact, for people who live off campus and not in a house,
maybe I actually want to specify that the default value for house is NULL,
and then I need to check this box and tell the database it's okay if the user's house is NULL.
>> Again, this is another defense mechanism you can put in place
so you don't even have to put it in your PHP code necessarily.
The database will ensure that things are or are not NULL.
And then lastly, Attributes.
None of these are really relevant.
Binary, unsigned--none of those are relevant to a varchar.
Index.
Does anyone know or remember or have a guess as to what an index is
for something like house?
This too is actually an important and relatively easy design decision.
For those who haven't yet seen it, on Friday we talked briefly about primary keys.
In a database table, a primary key is the field or column
that uniquely identifies rows in the table.
So in the current table we have IDs, we have names and emails.
Which of those is the best candidate to be a primary key,
whose role is to uniquely identify rows?
Probably ID.
Arguably, we could also use what though?
Maybe you could use email because in theory it's unique
unless people are sharing email accounts.
But the reality is that if you're using a numeric ID like 1234,
that's only 32 bits, whereas an email address could be this many bytes or this many bytes.
So in terms of efficiency for unique identifiers,
it tends to be good practice just to use an int
even if you have some string candidate that you could arguably use.
>> For something like house, this should not be a primary key
because then only 1 person could live in Mather and 1 person in Currier and the like.
Similarly, this should not be unique.
The difference between primary and unique is that in the case of our current table,
ID would be primary but email is not primary for the reason we just mentioned--
performance--but it should still be unique.
So you can still enforce uniqueness without making the claim
that it's a super important primary field.
But this one is quite helpful: Index.
If you know in advance for your final project, for pset 7, or in general,
that this field house is going to be something you search on a lot
using the select keyword or something else,
then you can preemptively tell the database to work its magic
and make sure that it creates in memory any fancy data structures necessary
to expedite searches based on house.
Maybe it will use a hash table, maybe it will use a linked list.
In reality, it tends to use a tree, often a structure called a B-tree--
not a binary tree but a B-tree--which is a very wide tree
that you might see in a class like CS124, the data structures class.
But in short, you don't have to worry about that when using smart database software.
You can just tell it, "Index this field so I can search on it more efficiently."
>> If you leave this off and you try to search for everyone in the database who lives in Mather,
it will devolve into linear search.
And if you've got 6,000 undergrads all living in some house,
you're going to search the entire table to find the Matherites,
whereas if you say Index, hopefully it will be something close to a logarithmic search
to find those kinds of students.
This is just a free feature to turn on,
even though it does come at a price of some amount of space.
Lastly, auto-increment, this AI field,
which just means if it's an int and you don't want to care to increment it yourself
every time there's a new user, check that,
and each user that gets inserted will automatically get a new ID.
Let's click Save, and now let's find fault with this design.
If I go into Browse, notice that both Mike and my house is NULL.
I can use phpMyAdmin to edit this manually.
I can go in here and type in Mather and then hit Enter,
and now notice the table is different.
But notice I could do something else as well.
David's ID is 1, so phpMyAdmin again is just an administrative tool;
this is not something your users are ever going to see.
So if I instead click the SQL tab up top--
and again, pset 7 will introduce you to more of these queries--
I can manually execute the SQL structured query language command
UPDATE users SET house = 'Pfoho' WHERE id = 1.
These SQL queries are, nicely enough, pretty readable from left to right.
Update the users table, set the field called house to Pfoho
where the user's ID is 1.
Or I could even do where email = 'malan@harvard.edu'.
So long as that uniquely identifies me, that would work as well.
But ID tends to be higher performance, so let's do that.
Let's click Go. Okay, lecture.users doesn't exist. What's my error?
What's the table actually called here?
It's called students just because that's what we did up here at top left.
It's called students, not users. So click Go now.
1 row affected. Query took 0.01 seconds.
If I click Browse now, now Malan lives in Pfoho.
So that's another taste of SQL, but the pset will walk you through a bit more of that.
>> There's a stupid decision I've already made here.
I would argue that this database design is inefficient
because the more people I add to the students table,
the more of us I start adding, the more of the TFs I start adding,
we're going to start to see what redundancies in this table?
>> Yeah. [student] Seeing that it's in students, we're using the same [inaudible]
The same-- Right, exactly.
So if 400 people live in Mather, give or take,
eventually this table is going to have 400 rows that say "Mather," "Mather,"
"Mather," "Mather," "Mather."
We're wasting all of these bytes, and there's a couple of takeaways there.
1, there's the crazy corner case where if someone pays a lot of money
and renames Mather, we now have to change our whole database table.
That's not going to happen often, though Pfoho was once called North House 15 years ago,
so it happens. But that's not all that compelling.
More compelling than a corner case like that of needing to update the data in bulk
for a database is why are you storing M-A-T-H-E-R again and again and again and again?
That's a lot of chars, 6 chars.
Can't we do even better than that, especially for Pforzheimer?
Surely we can do better than that many characters.
Why not just associate a unique identifier with each house
and store that for each user? So let's try this.
Rather than just use the students table, let me go up to my lecture database up here at top left.
Notice here it says Create table.
Let me create a new table called houses.
The number of columns is going to be 2. Enter.
Now I have 2 fields.
I'm going to call this the name, and it's going to be a varchar of length 255,
>> but that's pretty arbitrary. Let me put this down here by convention.
So put an ID up here. Let's give every house a unique identifier.
Let's give every house a name.
Let's specify that the identifier will be unsigned just by convention to only use positive numbers.
Let's go ahead and give this an auto-increment field for now.
And do we need anything else?
Let's go ahead and click Save.
Now I have a second table.
Notice as an aside this is the slightly cryptic SQL command
that you would have had to type manually if not using an administrative tool like phpMyAdmin.
So another reason we use it.
It's wonderfully useful sort of pedagogically because you can click around
and figure out how things work by just copying and pasting what phpMyAdmin did.
But the Create table command is what was just executed, and here is my table.
Let me go ahead now and use raw SQL rather than oversimplify by clicking the Insert tab.
Let me do INSERT INTO houses,
and I'm going to say the name of the house is going to have a value of 'Mather'.
That's it. This syntax is a little more cryptic.
This is the name of the fields we want to insert.
These are the values we want to insert into those fields. Let me click Go.
1 row inserted took 0.02 seconds. Let me click Browse now.
>> Notice if I click Browse, there's Mather, whose ID is by automation the number 1.
Let me do another one. Let me go into the SQL tab.
INSERT INTO houses. The name of the house is going to have a value of Pfoho and so forth.
Go. And I can keep doing this again and again and again.
Or if you get bored using phpMyAdmin, you can just use the Insert tab
and not have to type the raw SQL.
You can just bang it out more quickly by typing, for instance, Currier, Enter,
and now if we click Browse, there's Currier with an ID of 3.
So this is what we mean by auto-increment.
But now we have to fix something in students.
In students what should the data type of the house field now be?
It should be an int, right?
So the goal here is to factor out, otherwise known as normalize, the tables
so that we don't store information redundantly in any of my tables.
And again, the path we were on here is going to say Mather, Mather,
Mather, Mather, Pfoho, Pfoho, Pfoho, Pfoho, which is very redundant
in terms of the wastefulness of the chars.
So let me go ahead and change this by clicking Structure,
and let me go ahead and check off the house field, click Change,
and now I'm going to change this to be an int.
255 is no longer relevant.
Let me go ahead and say that's fine if it's still NULL. Save.
Now table students has been altered successfully,
and notice again house is an int.
As an aside, ignore the number in parentheses when it comes to ints.
>> This is for legacy reasons.
Back in the day when you didn't have GUIs, you instead had a command line environment,
the 10 and 11 respectively specified how many characters you should show
in the terminal window to actually display fields.
It has nothing to do with the bit length of the actual field, so we'll just ignore that for now.
Now I have to go into this table.
And if David lives in Mather, house should not be 0,
which is a default int value closest to NULL.
He should live in house 1.
Let's arbitrarily say that Mike lives in Pfoho, so house number 2.
Now my table looks a little more cryptic.
But consider the efficiency.
I'm now using only 32 bits to identify the house,
which means there's only 1 canonical definition of my house Mather and Pfoho
and that's in the houses table.
So if I want to now rejoin these tables, think of it this way.
Here I have my students table, and on the right-hand side there's these numbers, 1 and 2.
1 is Mather, 2 is Pfoho.
We have those same numbers in this other table, which is called houses,
1 and 2 and 3 for those 3 houses.
What we now want to do is have the ability in code, PHP and SQL,
to sort of rejoin these tables, where if these are the students and these are the houses,
we want to somehow combine them so that 1 lines up with 1,
2 lines up with 2, and so that we can figure out where David
and where Mike and where everyone else lives.
To do this we can execute a SQL query like the following.
SELECT * FROM students JOIN houses ON--
And now what fields do we want to join on?
So students.house = houses.id.
>> A little cryptic, but this part means literally create a new temporary table
that's the result of joining students and houses.
And how do you want to combine the tips of my fingers here?
Set the students' house field equal to the houses' ID field.
And if I now click Go, I get back exactly what I hoped to.
David is in Mather, Mike is in Pfoho, and I also see the unique identifiers.
But the point is now I have a complete table.
And so the takeaway here for pset 7 or really for the final project:
If you find that you're storing any piece of information redundantly,
whether it's a house, maybe it's a city, state, and ZIP
where ZIP can usually but not always be used as a unique identifier,
do go through the exercise mentally and then with something like phpMyAdmin
of factoring out that common data because especially as your website gets more well used
and more popular, this is how you make sure that everything is super fast,
by giving the database as many hints as to uniqueness as possible.
That was a lot.
Any questions? All right. Let's take a 5-minute break there and regroup.
All right.
The following is an example that was used some years ago when I took CS161,
which is the operating systems class at the college
which is known for being amazing but a crazy amount of work,
and it focuses really on some of the low-level problems that arise in operating systems
and also even in the world of databases.
>> The story that was told by my professor, Margo Seltzer, that year was as follows.
Suppose that you have a little dorm fridge for you and your roommate
and both of you really like milk.
So you come home from class one day, your roommate is not yet there,
you open the fridge, and you realize, "Oh damn, we're out of milk."
So you close the fridge, you walk across the street to CVS
and get in the increasingly long lines to buy some milk at CVS.
Meanwhile, your roommate comes home from his or her class,
comes into the room, opens the fridge really wanting some milk,
opens the fridge and, "Damn, no milk."
So he or she closes the fridge, walks out the door, and goes to ABP
or somewhere other than CVS where you're not going to bump into each other
to go get some milk.
Of course a few minutes later, both of you get back home
and now you have twice as much milk as you actually wanted.
And being milk, now it's going to go bad because you like milk
but you don't really like milk, so now you have too much milk, so it's going to sour.
This is an awful, awful situation.
What could have solved this predicament if you were the first roommate home? Yes.
[student] You should have left a note. [laughter]
Good. You should have left a note.
You should have put a Post-it note or the like saying, "Gone for milk,"
and then your roommate conceptually would have been locked out of actually doing that.
Or you could go 1 step further.
You could literally lock the refrigerator with some kind of padlock,
and now your roommate will literally be locked out of the fridge.
If we generalize back to programming,
you can almost think of the fridge as some kind of variable or a struct,
some kind of container for information.
The problem fundamentally here is that both of you were allowed to inspect
or read the state of this data structure,
but you viewed it at different times and yet both of you made a decision
based on the state of the world at those different moments in time.
So had you locked the refrigerator, you would have at least avoided your roommate
from having been able to inspect the state of the world,
so he or she could not have made that same decision.
So databases, as it turns out, have this problem constantly.
>> Let's see if we can construct a scenario.
Suppose that you're sort of a bad guy and you go to Bank of America
or one of the other places in the square that have a couple ATMs side by side,
and somehow you figured out how to duplicate an ATM card--not all that hard.
It's just a magnetic strip.
And so what you want to try to do is play this game
whereby you put 1 card into 1 machine, another card into the other machine,
and you essentially want to try to withdraw money simultaneously,
because imagine that story goes as follows.
The machine on the left takes your card and your PIN,
and then you say, "Give me $100."
The ATM is programmed to first do a select on its database or the equivalent--
whatever database it's using--to see does this user have at least $100 in his or her account?
If so, then spit out the $100 and subtract $100 from their balance.
But of course if there's multiple machines here or multiple ways of inspecting
the state of that world, the bank vault, to see how much money you have,
suppose that just by chance the machine on the left and the right
both ask that question at roughly the same moment in time.
>> And this can certainly happen. ATMs are computers these days.
So if the machine on the left says, "Yes, you have at least $100,"
meanwhile the machine on the right says, "Yes, you have at least $100,"
then both of them proceed to finish their programs and actually spit out the $100
and say, "Previously you had $200."
"Let me update the variable to now be $100 left in the account."
But if both of them have checked your account balance and found that it's $200
and both of them then do the math and say 200 - 100,
the machines have potentially spit out two $100 bills in each machine,
but they've only updated your sum account balance to be $100.
In other words, you've taken out $200, but because they inspected the state of the world
simultaneously and then made a decision based on that value,
they might not do the math ultimately correctly.
So in a bank situation too you really want to have some kind of lockout
so that as soon as you've checked the state of some variable
that's really important, like your account balance,
don't let anyone else make decisions based on that until you are done doing your thing,
where in this case you are the ATM on the left.
Lock everyone else out.
You can actually achieve this effect in a couple of different ways.
>> The simplest way in MySQL is a line of SQL that we gave you
in the problem set specification that looks exactly like this.
Insert into the table--whatever it's called--an id, a symbol, and a share, a number of shares,
the following values, for instance.
If you haven't read the spec yet, this is an example involving how do you go about
buying 10 shares of this penny stock for President Skroob,
whose user ID happens to be the number 7?
This says INSERT INTO table the following id, symbol, and number of shares
of 7, 'DVN.V', and 10.
But--but, but, but--the second line is the important one.
ON DUPLICATE KEY UPDATE shares = shares + VALUES(shares).
So totally cryptic-looking at first glance.
But the fact that this SQL query, even though it wraps onto 2 lines,
is 1 long query, it means it's atomic
in the sense that this query will either be executed all together or not at all.
And by definition of MySQL, that's how they implemented this query.
It is by definition in the manual guaranteed to execute all at once or not at all.
The motivation for this is as follows.
If in this case you are trying to buy 10 shares of stock,
it's kind of the same story as the milk, it's kind of the same story as the ATM.
>> If you make the mistake of not using this syntax
but instead selecting from the database to see how many shares of this penny stock
does President Skroob have, and suppose he has 10 shares,
and then some split second later you then do an UPDATE statement,
which is another statement in SQL that says go ahead and add 10 more shares
to his current 10 so that ideally the total is 20,
the problem is because in today's database systems and because in today's computers
you have multiple processors, multiple cores--
in other words, computers can literally be doing multiple things at once--
there's no guarantee that your SELECT and your UPDATE in this case
are going to happen back to back.
So a bad scenario would be you do the SELECT
to see how many shares of this penny stock does Skroob have,
and then just by chance another database query is executed--
maybe its Skroob in another browser window trying to buy 10 shares
in another window altogether, much like the ATM--
and suppose that another query gets in between SELECT and the UPDATE.
It could be the case that Skroob now loses some number of shares
because another process is inspecting the state of his world,
or he gets more shares than he should have.
We won't go into the particulars of exactly what those particular story lines would be,
but the point is if you have to check a variables value and then make a decision,
if there's a risk of someone else doing something in between those 2 statements,
as can happen in multiprocessor systems, in multicore systems,
computers with the ability to do multiple things at once, bad things can happen
like bank accounts being debited incorrectly, buying twice as much milk,
or in this case the wrong number of shares.
But there's an easier way to think about this.
>> It turns out that SQL also supports, if you configure your table correctly,
something called transactions, which I would argue is actually even easier to understand
than this, but it's not a 1-liner, so it's actually a bit more involved.
There is literally a statement in SQL called START TRANSACTION.
Just like there's SELECT, UPDATE, INSERT, DELETE, and JOIN and a bunch of others,
there are keywords like START TRANSACTION.
And what you then do in the context of pset 7--
you don't have to do this for pset 7; it's explicitly disclaimed as not necessary,
but for final projects it can be useful--
if you call a query of START TRANSACTION and then another query
and then another query and then another, another, and another,
those queries will not actually be executed until you call the SQL statement COMMIT,
at which point, whether it's 2 statements or 20 statements, they will all be executed at once,
which means no one else can accidentally buy too much milk or debit too much money
or buy too many shares because all of your queries will execute
back to back to back to back.
And this is super important, especially when you're doing something like this.
This is an arbitrary example that says let's update the bank account
by setting a balance equal to balance - $1000 where the account number is 2.
And then the second statement is now let's deposit that $1000
into someone else's bank account whose account number is 1.
>> In other words, this is a perfect example of where you want to make sure
that both of these statements happen or not at all
because otherwise the customer is going to get screwed
and you're going to take their money and not deposit it elsewhere,
or the bank is going to get screwed where you're going to deposit the money
but not actually subtract it from the user's account.
So you want both of them to execute together.
Thus enters into the world transactions.
So that's something to keep in the back of your mind,
not so much for the purposes of just a final project,
but if you want to take your final project somewhere,
if you want to start up some company around it,
if you want to solve some student group's problem on campus
and actually have a live, active website, these are the sort of subtle bugs that can arise
if you don't quite think through what can happen if 2 people
are trying to access your website at literally the same moment in time,
whereby their queries might otherwise get interwoven.
>> Ready for some JavaScript, a teaser thereof?
This is our last language for the semester. All right.
Thankfully, JavaScript looks very, very, very similar to the 2 languages, C and PHP,
we've done thus far.
There's no JavaScript in pset 7, but it's an incredibly useful tool
when it comes to doing web-based final projects or really just web programming more generally.
So a quick overview of something called DOM.
Here is a super simple web page that really just says hello, world
both in the title and in the body.
As the indentation has been suggesting for some time,
there is indeed a hierarchy to web pages.
I could draw this same snippet of HTML as a tree,
thinking back to our discussions of data structures in C, as follows.
I have some special root node called the document node,
and we'll see the analog of this in JavaScript in just a moment.
The first child and only child of that in this case is the HTML tag.
There's no direct mapping of the doctype.
That's a special thing, so we should just ignore it when it comes to this DOM,
this Document Object Model tree.
Notice that the HTML tag, which I've depicted arbitrarily as a rectangle,
has 2 children: head and body.
>> Those are similarly drawn as rectangles.
It is meaningful pictorially that head is to the left of body.
The implication is that head comes first in the tree.
So there's actually an ordering to a tree when you draw it like this,
even though the shapes and whatnot are arbitrary.
Head meanwhile has a single child called title,
and title actually has its own child, which is "hello, world",
which I deliberately drew as an oval here to make it slightly different from the rectangle.
These rectangles are elements, whereas hello, world is really a text node.
So it's a node in the tree, but it's a different type of node
so I drew it arbitrarily differently.
Similarly does body have a child called hello, world as well,
so different node even though they're coincidentally the same text,
but I've drawn it using the same shape. So who cares?
Well, what's nice about HTML is that it does have this hierarchical nature.
And what's nice about JavaScript and particularly libraries that are freely available
and popular like jQuery, you can navigate the tree structure so amazingly easy.
Any of the stuff we did in C with pointers and traversing trees and recursing on nodes
left child to right child, all of a sudden we can sort of take for granted
as being amazingly enlightening if not a bit frustrating
but not nearly an efficient way to go about programming.
And so with these higher level languages like JavaScript
we'll be able to navigate this tree much more intuitively.
>> And indeed the syntax is going to be quite familiar.
If you've never seen JavaScript before, this is a really nice reference
from the Mozilla folks, the people who make Firefox,
so do feel free to browse that at your convenience.
What you'll find--and these slides are identical to what we used the other day--
similarly, main is gone.
So when you write a program in JavaScript, there is no main function.
You just start writing code.
But a key distinction between JavaScript and C and PHP
is that whereas C and PHP thus far have been executed server side
by the appliance in this case or more generally by a server,
JavaScript by design is usually executed by a browser.
In other words, you might write JavaScript code, as we're about to,
on a server in the appliance, but you include it among your HTML, among your CSS,
among your GIFs and your PNGs and your JPEGs
so that when the user visits your web page, if you're using JavaScript,
that JavaScript code comes from server to browser,
and it's the browser that actually executes it.
So this has meaningful implications for even intellectual property.
It's kind of silly to even think about protecting your IP when it comes to JavaScript code
because by nature of the language it gets executed usually browser side.
>> You can obfuscate it, which means you can make it look crazy and ugly
with no whitespace, horrible variable names, to make it harder for people to steal your IP,
but the key is that it is executed browser side.
Even though as an aside JavaScript can be used server side,
the most common use case right now is still on the browser.
And here's what it looks like. Here is an if-else if-else construct just like C, just like PHP.
Here is a Boolean expression when you "or" 2 things together.
Here is when you "and" 2 things together.
Here is a switch statement, which is similar to PHP
in that you can switch on different types of values.
Loops similarly have for loops here, which are structured identically to what we've seen before.
While loops; we've got do while loops.
Variables, ever so slightly different.
You do declare variables like you do in PHP and C,
but similarly is JavaScript weakly typed.
You don't specify int or float or string or anything like that usually.
You can specify var.
You don't have to specify var, but it has implications if you don't.
Usually if you omit var, you accidentally create a global variable instead of local.
So let me propose that you almost always just say var and then the name of the variable.
It's not a type, it's just var for variable.
This would be an example, whether it's 123 or "hello, world".
Arrays are present and syntactically similar to PHP.
I'll say var numbers and then I use square brackets again to declare a variable
whose type is array that has these particular numbers in it separated by commas.
And then lastly, this is the only one that really looks different.
Recall that in PHP we would have implemented an associative array for a student
like Zamyla that might look like this, where the variable is called student.
The square brackets mean here comes an array.
>> The fact that I'm not using numeric indices but strings--id, house, and name--
means that this is an associative array,
and these arrows with the equals sign and the angled bracket
means that the key is "id", the value is 1;
the key is "house", the value is Winthrop House;
the key is "name", the value is Zamyla Chan.
So there's 3 keys inside of this associative array, each of which has its own value.
We've seen that in pset 7, or you soon will, in JavaScript same idea,
but it's going to look like this.
So var student--no dollar sign and no mention of type still but var--
equals and then open curly braces because in JavaScript when you have key value pairs,
you actually use something called an object.
And those of you who did take APCS or the like might recall objects from Java
or similar languages.
JavaScript is not Java, first of all.
It was a deliberate design decision years ago to knock off something else that was popular,
its name, even though it has no fundamental relation to Java itself.
JavaScript has objects, and you create them by way of the curly brace notation.
Objects in JavaScript are pretty much equivalent to associative arrays in PHP
when it comes to storing data inside of them.
>> But even more powerfully in JavaScript can you associate very easily functions
inside of an object, and though you can do this in other languages,
it's quite a common paradigm, as we'll see.
In short, this object represents a student, who is particularly Zamyla,
and it's similar conceptually, just syntactically different from this.
Let's actually use JavaScript in a file.
It turns out there's a script tag.
We've seen a style tag and we've seen other HTML tags.
The script tag actually will contain some JavaScript code.
Let me go into the appliance where we have some source code pre-made.
I haven't posted it yet on the website, but I'll do that after class.
Let's open up this one, blink.html.
Back in the 1990s, there was literally an HTML tag called the blink tag,
and this was one of the most wonderfully overused tags on the Internet
whereby you'd visit some 1990s style web page and start seeing text flashing you like this,
the results of the marquis tag, which had text going like this.
One of the few times where the world has actually agreed on a web standard,
everyone across the board killed the blink tag some years ago.
But we can resurrect it with JavaScript as a demonstration of the power you have
when you can write a program inside of a web page.
First let's skip over the new stuff and focus only on the old.
>> Here is the old stuff in this example.
I have an HTML tag, a head tag, and a title tag.
Then I have a body tag here with a div, which recall is just a rectangular division of the page
that I've given a unique ID arbitrarily of "greeting" to,
just so I have a way of uniquely referring to it, that has some very simple text:
hello, world.
Now let me scroll up to the top of this file and see what's new.
The first thing that's new up top is the script tag,
and inside of the script tag notice I've declared a function.
To declare a function in JavaScript, pretty similar to PHP,
you literally write function then the name of the function, parentheses,
and maybe some arguments if it takes any.
Then I've got my curly brace as usual, and now we have some slightly new code,
but let's see what this means.
So var div, this just means give me a variable called div.
I could have called it foo, but I wanted it to be called div
for reasons that will be clear in a second.
Then it turns out in JavaScript--and this is JavaScript code embedded in my web page--
there is a special global variable of sorts called document.
JavaScript is in fact an object-oriented language.
We won't go into detail in 50 as to what that means,
but for now know that an object is pretty much like a struct.
Like we saw way back when in one of the earliest problem sets
where we put a lot of information in a struct,
similarly is document a special struct that comes with the browser,
comes with any web page. It's not something I created.
Inside of this document structure, though, you have not only data
but you also have functions.
>> And any time you have a function inside of a structure, inside of an object,
it's called a method. But it's the same thing.
A method is a function that just so happens to be inside of something else.
So this means that this special global variable called document
has a function called getElementById that literally does that.
It will get you an element from the DOM, Document Object Model tree,
whose ID is in this case greeting.
In other words, all that time we spent on data structures comes into play here.
This picture of a DOM that we had a moment ago,
even though the page is a little different, if I had a div in this picture,
what document.getElementById would return to me would effectively be a pointer
to the rectangle in the tree, a reference to the rectangle in the tree.
So that's what it means to actually call one of those functions.
In this case again it's a div. It's not a body or a title.
So let's see what I then do with this div now that I have it inside of this variable called div.
It turns out with JavaScript you have the ability to tweak the CSS of your page dynamically.
Up until now, all of the CSS we've done, albeit limited, is in style attributes,
or where else have we put CSS?
I kind of spoiled that one. In the style tag at the top of the file.
Or third place has been in?
>> An external file, something .css.
So those are the 3 places we've done CSS thus far,
but the catch is we've hard coded it all.
You decided as you dove into pset 7, we decided before lecture what our CSS would be.
But if you want to change your CSS, you can actually do that
once you have an actual programming language.
CSS, HTML--not programming languages. JavaScript is.
So it turns out that as soon as you have one of those rectangles from the tree
called the DOM, it has itself some data inside of it.
So the div that I just grabbed from the tree has what we'll call a property inside of it
called style, and the style property has itself a property called visibility.
I would know this only by looking up a CSS user's manual.
It turns out there's a visibility CSS property that does what it says.
It makes something visible or not, visible or not.
And how you do that is this.
I'm asking programmatically if the visibility of this div is hidden,
what do I change it to? Visible.
Else if the visibility of this page is not hidden, logically I do make it hidden.
I have no idea why it's visible and hidden and not visible and invisible.
This was a poor design decision along the way.
But those are indeed opposites in CSS: visible and hidden.
All this does is it means change the CSS of my file on and off, on and off
for that particular div.
But again, this is a function called blink. When is the blink function called?
It turns out that there's another special global variable called window,
similar in spirit to document, but whereas the document refers to your web page,
like the DOM tree, the HTML you sent from the server,
window refers to the chrome around it, the address bar, the title bar,
and all of that stuff around your web page.
>> And it turns out that the window object has a special function inside of it called setInterval
that does what it says.
It will set an interval--in this case every 500 milliseconds--
and, take a guess, what's it going to do every 500 milliseconds?
It's going to execute that function blink.
And what's nice here is that we could have done this in C even though we never did.
C does have something called function pointers where you can pass functions around
as arguments.
Similarly in JavaScript can you pass the name of a function into another function.
And notice what I'm doing. I'm not doing this.
If I put parentheses after the blink, that would mean call the blink function.
If I omit them, that means here is the blink function
so that setInterval can call it every 500 milliseconds.
So the end result, atrocious though it is, is that if I go into localhost and go to blink.html,
I now have this happening again and again.
And if I actually Inspect Element, let's see if we can see this.
Let me Inspect Element, let me scroll down just a little bit,
let me choose Elements over here, and notice the DOM inside of Chrome's inspector.
It's literally changing back and forth every 500 milliseconds.
If we go to our friend Nate,
if you ever wondered how this is working, similar idea with an interval,
but Nate is actually making very effective use of color in this particular case here.
So what more can we actually do with this?
Let's open up another example and try something
that's programmatically even more useful than making things blink.
Let me go into our forms directory today and go into form0.
This was the ugliest possible form that I could come up with,
and let me just show you what it looks like in a browser.
>> Let me go into localhost/forms, and this is form0.
This is a super ugly HTML form that has a few fields for email, for password,
password, and then a little checkbox to agree to some terms and conditions.
The catch is if I visit this form and I don't want to give you my email address,
I don't want to agree to the terms and conditions maybe, I can click Register
and it lets me through anyway.
This happens to submit to a stupid PHP file called dump.php.
All it does is print out the contents of $_GET just for diagnostic purposes.
That was what was submitted by the user just now.
But suppose we actually want to validate the user's form submission.
Let me go into version 1.
This is form1.html. It looks aesthetically just as bad, but notice how fancy it is.
If I click Register without cooperating, I get yelled at.
"You must provide your email address."
All right. So let me try that. So malan@harvard.edu. I don't need a password.
Register. "You must provide a password." All right.
So I will provide a password of crimson. Register.
"Passwords do not match." I have to now type in crimson here.
I accidentally checked that. Register.
"You must agree to the terms and conditions." All right. Agree there. Register.
And now it shows me the diagnostic output over there.
>> So what just happened?
We've had this ability to validate form submissions.
In fact, if you did dive into pset 7, there's an apologize function
that makes it pretty easy to yell at the user with a message on the screen.
I'm using a slightly different mechanism, the alert function,
which is not a function that's smiled upon since it makes very ugly user messages.
But let's see what I'm doing here.
This is form1.html, and notice that I have some pretty familiar syntax:
body tag, form tag, action attribute, method attribute.
But notice I've given my form a unique ID for convenience.
Then I've got an email field whose type is text,
a password field whose type is password, confirmation field whose type is password,
and then a checkbox whose name is agreement over here, type is checkbox.
And then I've got a submit button.
But notice at the top what more I have.
First of all, there's another use of the script tag.
If you have some JavaScript code in another file, just like with CSS you can include it.
And you do that with script source, and then notice I'm connecting apparently
to googleapis.com to a very long path but whose file name ends in jquery.min
for minimum .js.
jQuery is a super popular library for JavaScript that just makes JavaScript
all the more user-friendly to use.
It's effectively become a de facto standard.
So even though what you're about to see is not pure JavaScript per se,
it is a library on top of JavaScript much like the CS50 library is a layer
on top of low-level C code; the reality is almost everyone on the Internet uses it.
So these are not training wheels. This is just best practice these days.
Now notice below that is my own script tag, and notice what I've done here.
It turns out that jQuery does something a little fancy.
JavaScript has dollar signs, but they are meaningless.
>> They are like the letter A or B or C.
jQuery has simply adopted the convention or sort of laid claim to the fact
that $ will be their special symbol.
So as soon as you load this global JavaScript file up here with the script tag,
you have access to a special global variable that's called $.
It's more properly called jQuery, but that doesn't look nearly as sexy as $.
But $ has no special meaning. In PHP it had special meaning.
You had to have it in front of a variable.
This is just a sexy thing that they took on.
What is going on here?
Notice I'm passing to the jQuery function my global variable document
and then I'm calling .ready.
What jQuery essentially does is it allows you to take some vanilla JavaScript things
like the document object, the window object,
and if you pass it in to the jQuery function--
and again, to be clear, this is a function called jQuery--
what it does is it returns to you a special version of document
that has more functionality associated with it.
So in raw JavaScript there is no ready function,
but if you pass document to the jQuery function first,
it returns to you a special version of the document object
that has more fancy features.
And that's why people like it. It just makes things easier to do, as we're about to see.
So what does this line of code mean?
This line of code here means when the document is ready--
in other words, once the browser is done reading this file top to bottom--
go ahead and execute the following function.
What's really interesting in JavaScript--and PHP has this as well--
is anonymous functions.
In JavaScript you can declare functions that have no name but they do have a body.
Notice what's happening here.
>> This is a function called ready, and it just means do the following
when the whole web page is ready, when it's all been read in from the server.
What do you want to do? I want to execute a chunk of code.
Notice that we don't want to execute this code right away.
If I omitted this, this would mean immediately start executing these lines of code.
But the fact that I'm saying no, no, no, wrap this in an anonymous function like this
means don't execute it yet; call it eventually.
We saw this a moment ago in our previous form example.
What function did we call eventually, 500 milliseconds later? Blink.
So the same idea.
Again, even if this looks a little weird, just take for now on faith
that to declare an anonymous function that's called eventually,
you simply write function() {
So what code are we going to execute eventually? The following.
This too looks a little new, but this means here's the jQuery function,
and this now is a shortcut.
This snippet of HTML at the bottom of the screen of course has some tree representation.
It's not this. This page is more interesting than this hello, world example.
But there's some tree that corresponds to this HTML.
It would be a pain in the neck to have to implement some kind of recursive function
to start at the root node and then find the node whose ID is registration.
So what jQuery makes super easy for us is literally this.
Go ahead and get me whatever div or whatever form, whatever HTML element
has an ID of registration.
This is equivalent to document.getElementById('registration').
>> Why do people like jQuery?
Because it's shorter to type. But that's all it is. It's the same idea.
Get me the tag whose ID is registration.
And when that tag, which happens to be a form, is submitted,
go ahead and execute this code.
So let's take one look now at how we're doing form validation.
The syntax is admittedly cryptic at first, but what's going on?
If this line of code is true, I'm going to yell at the user to provide his or her email address.
So what is this line of code?
$ means jQuery. Now notice this.
This is kind of like CSS.
If you've dived into CSS yet, you'll know that this means the element whose ID is registration.
The space means find a child or a descendant of registration whose name is input.
And then this thing in square brackets is a little filter.
And even if this looks cryptic, this just means go to the form whose ID is registration,
go to the input element inside of that whose name is email,
and then get its value, whatever its value happens to be--
asdf if that's all I typed or malan@harvard.edu if that's what I typed.
So if the value of the form's email field == nothing, yell at the user.
Else if the value of the password field == nothing, yell at the user.
>> Else if the value of the password field does not equal the value of the confirmation field,
which was the other form element, yell at the user.
And then lastly--and this one too has some new syntax of its own,
but once you've seen it, it's at least a little more reasonable--
else if the form whose ID is registration has an input element whose name is agreement
and it is checked, go ahead and yell at the user.
So I totally admit this is completely overwhelming at first glance.
It's a lot of new syntax. But all of jQuery follows these kinds of patterns.
And honestly, I didn't even know this existed until a few minutes ago.
I Googled, "How do you check if a checkbox is checked in jQuery?"
and this is the syntax, because there's different ways of doing it
with actual raw JavaScript code.
So as the very first page of Problem Set 7 emphasizes,
pset 7 is very much an exercise in bootstrapping yourself
where we've provided, hopefully, a conceptual framework with which to tackle the pset.
>> But as is often the case with web design, it's up to you really to poke around,
incorporate snippets of code and examples from the Web so long as you cite them
per the terms on that first sheet,
and realize that learning HTML, CSS, JavaScript and even SQL
is really meant to be this at-home exercise as we begin to take these training wheels off.
And realize too there's so many more things you can do with a browser.
Inside of most of these elements there are other things called event handlers.
And even though we just looked at ones called onsubmit and onready,
you can do things like onkeydown, onkeyup,
like when the user touches a key, you can listen for that and key up.
Gmail has keyboard shortcuts.
How does Google implement keyboard shortcuts like C for compose?
They listen for events, as they're called, like onkeypress or onkeyup and onkeydown.
If you've ever hovered your mouse over some menu option
and all of a sudden, voila, a menu appears or the graphic changes color,
how are they doing that?
Rather than listen for onready or onsubmit, you listen for onmouseover or onmouseout.
>> So in short, with these very simple basics that we've begun to scratch the surface of today
and we'll dive in further to on Wednesday, you have, increasingly,
power to implement the kinds of things that you're already familiar with.
So let's end there, and we'll continue this on Wednesday.
>> [CS50.TV]