SAM LEVATICH: Welcome to section for this week. I am not Andi. Andi has fallen sick this day, and I have been sort of called in last minute to take over. It's flu season, so make sure that you are staying clean, washing your hands, and eating healthy so that you, too, are not bedridden. But without further ado, let's get started. Today, we're going to talk about PHP a little bit-- how PHP relates to HTML, how it relates to CSS, and some of the web stuff you did on the last assignment. We're going to talk a little bit about SQL and how you can work with databases, which is a pretty key component of P set 8-- P set 7. P set 7. And then we're going to talk a little bit about how view controllers work and why that's a philosophy behind some modern web pages and different design. Pretty much a lot of types of apps and applications you might ship are using this model, view controller framework, that you will be using in P set 7, so I'll talk a little bit about why that's become popular, why it's important and nice. And then I'll finally move on to some tips about tackling P set 7. And if we have time left over at the end, we can actually do some work on that together. So, PHP. In fact, you may have noticed this-- you didn't really have to dive into it-- but P set 6 had some PHP code that was going on. And because PHP is a C-like language, PHP, unlike HTML and CSS, is a programming language, whereas HTML and CSS are static. They're markup languages dealing with style and visual layout. PHP is the real deal. PHP has loops, it has conditions-- all that stuff that's fun about C. It has a few things that are a little bit better than C, which we'll see, but I think the easiest way to talk about the PHP is just to dive in. So I'm going to go right into the IDE at this point. The first thing we're going to do is actually look a little bit at some of the PHP code that was in P set 6. So the way that we do that-- before, the way that we were running the server for the appliance was that we would have to type-- either use your implementation or the staff's implementation of server.c by going into directory and running server.c with either no arguments-- so just call it on the local host, which is what you probably did most of the time-- and then feeding it a directory-- with which to use as its root where the website would be run, basically. This week for P set 7, as great as our code for server.c is, there are people who have already written these fine things over at CS50 that have a little bit more functionality, a server program that's capable of dealing with a little more of the intricacies that we'll see in both P set 7 and P set 8. And the way that you start up the server is by just typing, "apache50." And before you do anything, you want to make sure that Apache 50 is not already running as it is on my machine, which I did to test it. And you do that by calling apache50. Stop, and you'll see that it's stopping the web server, if you can look there at the bottom of the terminal window. And then just to start, we're going to call, "apache50 start." And then we're going to feed it a directory. Now, because we want to look at some of the P set 6 code that we had implemented, I actually copied a little bit of the P set 6 code into my own folder, which you can see on the left there. It's called "SECTION8" in all capital letters because I'm just so excited to be live-streamed today. So if we run this, it should all work pretty effectively. It says, OK, our site is now available at the address of the IDE, basically, which is what you were using exactly as it was in P set 7-- P set 6. All my indexes are one index today. So we can go to that address, if you'll remember, by just clicking this little button in the upper right. And you'll recall this code, which happened when you went into hello.php. And what the code is designed to do is when you typed in a name here-- if you say Sam because that's my name-- and I click Say Hello, when we went to the next page, that name was supposed to be displayed. It would say, "Hello, Sam" or "Hello," whatever name you put into it even though we went to an entirely new web page. And this is the sort of thing that PHP can do for you. PHP is able to pass data between two web pages. This is a totally different page. You'll see the title is "hello" here. Actually, they have the same title, but I promise they are different web pages if we look at the source. And you can pass the data that's entered in this text field, you submit it to the next page that's being called up, and then that data is able to be there in its present form. Now we haven't yet implemented this ourselves, which is what we're going to do right now to sort get a flavor for how PHP works, but the key idea is that PHP-- you can sort of think of it like a function. Something that PHP can let you do is it can take parameters that you input into an HTML page through the use of PHP and forms, and it can pass those as parameters to the next page that it loads up. In this case, we're loading up this page with the "Say hello" button. But for now, I actually deleted some of that code in the hello.php that was being run that was actually displaying the "hello, world" or "hello, Sam" or "hello," whatever was just input. So for right now, we're going to do that, basically. We're going to recreate that and also add some more functionality, do a little bit more with it, see what PHP is really capable of. So first, let's talk about this file, hello.php. So if we zoom in a little bit-- and now I'm sort of trying to scroll all the way around-- there we go. You'll see it's called hello.php, but the syntax of it looks like an HTML file. This is because the actual PHP in this file is all stuck between these question mark-caret blocks. Everything right here is considered PHP code. And you'll notice that when I did a comment, you'll see the familiar two forward slashes. And if you'll recall, in HTML, if I type a comment, it looks something closer to this, which is a comment in HTML. So really everything between these two angle brackets is now PHP code, which is reflected in the fact that this little comment symbol is turned into a comment. So every time you write PHP code, even if there's no HTML code outside of it, it's always going to be enclosed in these angle brackets with question marks. You can sort of think about it-- how all of the code that ran in your C programs was enclosed in an int main, void, curly brace, end curly brace statement. And you'll see curly braces in PHP, too, but this is sort of like the main method of PHP. So now, how do we do anything in PHP? Now, PHP is a programming language that's very C-like, but it operates on the web. So one thing that you'll immediately-- one of the first things you really did with C was you printed stuff out, right? So in C we did that with a printf function. We gave it a string, probably with a new line, and then we terminated it with a semicolon. So the way that we're going to do that in PHP-- because it's not quite printf. It's a little bit of different syntax. The way that we print things out in PHP is we say, "echo hello" or "echo" any word. And that has the effect of doing printf with a string, "hello." And it adds the new line to it. So let's right now make sure-- I'll zoom out again a little bit-- let's make sure that that code is working because there might very well be a bug in this code that we will have to tackle. So the server is already running. So if we scroll back down to the bottom, yup, the server is still running. So if we just tap on this little bit right here-- welcome-- we should get-- great. We still are having the familiar "Say hello" dialogue, but when I type in "hi," we'll see that the text "hello" was indeed printed out, which is exactly as we expected because echo in PHP is just like a printf statement. So back to the code, how in P set 6 did the distribution code you are provided make it so that PHP would output the thing that you typed in on the previous screen? And to sort of examine why that happens, we're going to go into index.html, which is the original file, the file that shows up on this screen with the "Say hello" button. You notice that there's all the classic things we've come to expect from HTML such as these things, these tags enclosed in angle brackets, like PHP but without the question marks, which indicates a special thing to HTML. We have title, which is "hello." And you'll notice that as we saw, the title is "hello" in both cases. Let's change this one to "say" just so we can distinguish ourselves where we are. But we've got a body. And then the interesting bit, the bit that shows up in the HTML, is this form element. And so we've got a form. And this is the key. This is how we're working with PHP. The action parameter of form says that hello.php is what we're going to send the values in this form to. This is where we're passing the parameters, so to speak. You'll notice another thing here is that the method is "get." There are two primary methods by which will be using PHP to pass data between websites-- web pages, rather-- in this assignment. And those methods are "get" and "post." There are some subtle differences between get and post that we will get into-- we will "get" into, if you will. But for all intents and purposes, get and post are both just ways that you pass parameters with slightly different executions. For now, we're going to use get because get was what was used originally in the PHP file of P set 6. And actually, if we go in and look before we've edited anything else, I'm going to say hi to-- what's your name? AUDIENCE: Elliot. SAM LEVATICH: Oh, gosh. I don't know how to spell that. Could you spell that for me? AUDIENCE: E-L-L-I-O-T. SAM LEVATICH: I-O-T? AUDIENCE: Yeah. SAM LEVATICH: Perfect. OK. I guess I did know how to spell that. Sorry about that. But if we say "Say hello," it's not it's not going to show up on the screen yet because we modified the code a little bit. But if we do "Say hello"-- OK, so "hello" is here. But if we take a closer look at the URL itself, we'll see that it ends with hello.php?name=Elliot. So, this is a way of communicating to the next web page the parameters that we've passed. We said name=Elliot. And that's ultimately how P set 6 accessed the variable that we passed in through the form. And this is something that is peculiar to a get request. A get request makes the parameters known in the URL of the website. And you'll recall, too, in P set 6 that you had to write a function that dealt with the fact that this query string could exist after a file. There could be a question mark followed by basically any number of characters. And that's exactly what's going on here. And the reason you had to parse that in your implementation of server.c in P set 6 is so that you could tell the PHP code that name=Elliot. You needed to be able to parse that out of the URL so that the PHP file in question knew what it was dealing with. So hopefully this gives the motivation to server.c now that we're moving on outside of C into PHP. So let's actually focus on accessing the things passed through a get request now at this point. I'm going to save this. We didn't change anything. It looks like we've got a input field. We're setting some properties, as we can do an HTML. These are simple things. We don't need these. But we've got autocomplete off, which basically says-- you know, when you type things into the web, sometimes it tries to fill that in for you. So it's a nice thing. We want to turn it off for this purpose. That was a CS50 decision. So we can delete that if we wanted. Autofocus just sticks the cursor in the form right at the beginning. Again, not too important. But name="name"-- it's a little tricky because it's name and name. But we could've changed this to something else. And in fact, that's what we'll do right now. We'll say "person," which is sort of like name if a person is defined by their name. So let's close this, reopen up our website since our server is still running Apache 50, and we'll say, hello, here's Elliot again. Why not? Hello. And if we go up here, we'll see then instead of name=Elliot, it says person=Elliot. And that's a direct result of the fact that we just changed name="person." So in an input element of an HTML form, the name field is the identifier for the parameter that's being passed. It's like if you're creating a function "add" that took in two integers and you said int a and int b. That would be name a, and if you wanted another form, which we can do just by copying and pasting, then we would have name b. So now we'll have two parameters that are being passed through get to the next website-- the next web page, hello.php. And we can actually see that again if we want. This is the easiest way to deal with the web code in the IDE, basically. You start up the server, get it running, and then every time you make some changes, just close that file just to be safe. Pressing the back button is a little tricky because it might load an earlier version, not the most updated one. And then you just click your button again, pop right up-- oh, and now there are two forms. And so if we type one thing into each one-- "jason hirshhorn," for instance-- we say hello. We look up at our parameters. It looks like we've got, as expected, a=jason and b=hirshhorn, which represents the two parameters that we passed to this function. So now let's actually get to implementing that functionality that we had in P set 6. So right now we're just echoing hello. And that's not very useful. We want to echo some variable that was passed to us. And we know the name of this variable. We have a and we have b. So we could choose to echo either one. But how do we access it? Well, there are certain global variables in PHP. And I'm going to write them in comments here. The two most important ones are get and post for our purposes right now. These are the arrays or, technically, the dictionaries where our variables that we're passing to the next web page live. And we shall soon see how to use them. Another brief note about PHP code and some specifics of it-- in C, to declare a variable or to use variables, you first had to declare them. And what you had to do when you declared them was say int a or char b. You had to declare the types of these variables before you created them. PHP-- you don't need to do any of that. PHP does not ask for the type of variable. And the way that you create a variable-- rather than saying int, char, string-- which is really char *, as we know-- rather than doing all of that, because everything is of the same type, typeless, we can just use one character, which is the dollar sign. And you'll see it's already popping up, little autocomplete things. And it's saying that _GET and _POST are two options that I have available to me. Some of these other things are other global variables in PHP that you'll be using over the course of P set 7. For now we're going to focus on get and post. But this is a helpful thing that the IDE does where once you've typed in that dollar sign, it'll start filling in global variables or variables you've already defined. So if you wanted to define a variable called "string," you could just set it equal to "hi." And it's basically as simple as that. And then we could do something like "echo $string." The IDE should be throwing some errors if I'm doing anything wrong, so hopefully I'm doing everything right. But bugs always do arise. Another tricky thing about PHP is that it's not compiled. So with C programs, you would do the daily routine of-- basically, you would make edits to your code, you'd save it, and then you would make it, where make was the step that called the compiler, clang, to make your code, this text file, into an executable. PHP is C-like, but it's executed on the fly by your web browser. So there's no way to know. Make would throw those helpful errors, right? It would be like, you didn't declare this variable before you tried to use it. You did all this bad stuff-- segfault, segfault, all that sort of fun times that came with make. PHP is a double-edged sword because you won't get those errors, but that also means that you won't know really what's wrong with your program if you just run it and it's not working. But the debugger should point out some hopefully helpful little things syntactically that you can fix. So now if we go over to-- say, let's close that. Reopen. And we're back to here. So we've got a variable and a variable b. And these won't ultimately matter. We'll call them h and g for no particular reason. And we say hello. Now it looks like our string "hi" is indeed printing. We created a variable called "string," set it equal to "hi." Notice that we didn't have to do malloc or make a character array. In PHP, because variables are typeless, a string is the same as a char for all intents and purposes. This could be "hi." This could be just the character k. This can be a number 1. And it doesn't care. PHP doesn't care about the type of your variable. Or, it does care. It cares when you try and do things with it, but it does not care in the declaration step. And just like you can in C, you can declare strings on the stack like this though saying "stack" is a little bit of a potential misnomer when we're talking about PHP. But we don't have to worry about that. So we got our string "hi," and we echo string. So now we've discussed variables. So now we need to talk about get and post and perform the final thing that's needed to really get this back up to the functionality of the P set 6. So right now we're echoing the string, but we do have these variables get and post. And because we're using the method get, it seems natural that our variable that we're interested in, both a and b, will be located in the array or dictionary, technically get. So if we set up get like this with your groups-- I pressed enter and it didn't like it-- but here we have get. And so get already exists. So we can already start to access some of the elements of get. If we do get, this syntax for arrays in PHP is very C-like. We have our two square brackets. So if we say get in a normal array, we could access the zeroth index, the first index. PHP is zero index. We could say zero, one, two-- stuff like this. And I've been saying that get is technically a dictionary. So what PHP is doing under the hood, which is a little bit nicer than C, is it already is giving you some dictionary functionality, which is really hash tables, or tries to, supposedly. Or, technically it could be a try as well. But PHP is implementing a hash table, which forms an effective dictionary. And so we know the name of our variable, right? It's being passed in the query string by PHP. We have a=h and b=g where and b are the names of the variables. So the way that we can access the value that corresponds to the key in our dictionary is just by saying _GET_GET["a"]. So now we have _GET["a"]. And if we just replace inside our echo, if we echo _GET_GET["a"]-- and we'll see if the debugger throws any errors about this-- we'll save that and close this out. Open it up. So we're just doing a right now, so b shouldn't matter. "her" and "him"-- "hum." "her" and "hum." Sounds good. And it printed out "her," which is crazy. But that's exactly what was happening in P set 6. Basically, what P set 6 was doing-- echo hello, name-- where it had a variable name and it just asks you to type in that bit of text. There was also some additional code where it included if statements, which we can do right now. We can say if exists, which is a functionality within PHP, _GET with the underscore, "name"-- which is basically saying, "if name has been filled in" because we could have just clicked the button to submit the form without typing anything into that field. And we wrap that in our friendly curly braces. We can have an else statement. And that's all within the PHP angle bracket, question mark, angle bracket, if you will. And now we'll see if this works. I keep waiting for it to debug and crap out on me, basically, but it hasn't yet. Maybe it will now because I talked about. Yup. It did, in fact. So, nothing is showing up. That's because of something wrong that I wrote in the PHP code. And I mentioned the debugging is tricky because in PHP, we didn't compile it beforehand and the compiler wasn't like, here's where your errors are. But what we can do is-- do people remember how to look at the different network requests that PHP-- or that websites send? [? Malin ?] did this in lecture once or twice. You remember where we go to find the different debts and 200 OKs, all these codes that are being sent through HTTP from web page to web page? Does anyone remember where we go to do that? AUDIENCE: Page Source. SAM LEVATICH: Page source. Exactly. If you go to Page Source-- perfect. So Page Source pulls up the inspector. And I'm using Safari. A lot of you will probably be using Chrome or Firefox. But as long as you're in any modern browser-- and feel free to follow along if you want. You can type up this code or just look inside the P set 6 directory for some similar stuff. hello.php is what we're currently working on emulating. So there are a variety of tabs. We can look at all the resources. We can see the source code. So looks like it didn't get past body in the end. It found an error in PHP and it stopped loading the whole web page. We don't even have an end tag for HTML or anything. And if we look at the network, we can see that we're being sent a request. This is the domain. This is the address. It's a document. We're using the get method. And it's red. Or, it was red when I wasn't selecting it. How do I unselect it? Well, it was red. Let me refresh. There it is. Now it's red. So it's red, which means it failed, which is bad. So let's examine why it did fail. So all that the Page Source can basically tell you is your thing didn't work, which we can already see. So ideally there would be a more useful tool. And there are some browser extensions that allow you to debug PHP, but we're not going to be writing a ton of PHP, so it's probably just best to look through your code carefully and just make sure that it's not doing anything else. So let's see if the format of this if statement is where the problem is. I want to load that back up here. Hello, hi. So there's a problem there. So for correct syntax of PHP, PHP is going to be C-like in that you'll see loops. You'll see if statements. You'll see all these friends that you've become familiar with over the course of this CS50 semester. But the best way to figure out how to do something in PHP is to Google it or to look at some examples of PHP code because you know the functionality. You know what you can do with the program. You can loop. You can loop as many times as you want. You can loop in all sorts of different ways. You can create functions. You can create functions that call other functions, functions that call themselves. And you have names for these concepts. You've got recursion, loops, if, other control flows. And so Google is your best friend. Even say, "PHP if statement" and there'll be tons of posts with answers to other people who've had similar questions to you, who are just starting out with PHP and are curious about a syntax thing. Because we have the luxury of being able to look at the code in P set 6, we actually pull it up and see that OK, here's something interesting. So this is what it actually looked like in P set 6. So if we go through this, we can see that we've got several of these little PHP-like question mark bits. And there aren't curly braces. There are colons. And there are curly braces in PHP, but this is a format and a way of doing PHP that works well with HTML because as you'll see, we're closing off these PHP bits-- the elses and the ifs and all of that-- and then we're interspersing HTML inside them while still following the control flow set out by PHP. So I'm just going to quick walk through this because it's a lot of the same concepts that we were doing before. We've got if not empty, parentheses, _GET_GET["name"]. This is all the same stuff. We're using the _GET dictionary that PHP sends upon request of forms, because it is the parameters of action, and the method is get. And then that ends that. The colon is a signifier to just do this if the if statement evaluates to true. It's like a curly brace. And in fact, it is a curly brace in other languages like Python, which you may encounter if you just do that for your final project. And then this line, hello. Then we've got this weird thing. We've got more brackets. There's no HTTP there-- or PHP, sorry. But there's an equal sign. And then we have a function, htmlspecialchars(_GEThtmlspecialchars(_GET["name"]). This is sort of like a more advanced version of echo. Like we had echo as a way to print things out in PHP. This is a function that's defined in PHP that will deal with some more nasty characters and byte values that you could pass it. It's always safest to use this. But echo will do the job just fine if we're not dealing with anything too nasty. And so this has the same effect of basically, this stuff in between the question marks is evaluated by PHP. htmlspecialchars returns a nice HTML printed value of _GET_GET["name"], i.e. whatever we typed in the form. And then it'll say hello, comma space, and then that. That whole thing between the angle brackets will be replaced by whatever htmlspecialchars puts out. So that's basically similar to what we're doing. And we have an else statement that's hello world, which makes sense. So now let's go back to our code and see exactly-- oh. I said exists, which is not a thing that we wanted to do. We wanted to say not empty. And so this should work a little bit better, not empty _GET_GET["name"]. And that curly brace matches that curly brace. We've got our curly braces here. echo hello _GET["name"]. Let's see if this works a little better. We're still running our server. Hello Jason. Hello Jason. And it worked this time. And so that's a proof that you can indeed use the curly braces that you know and love in PHP code in HTML. The PHP code provided to you in pset 6-- pset 6-- provides another way of doing that same thing. So now we have the power. We have the functionality to implement the PHP code that we saw in pset 6 by ourselves, basically. Before I move on, what are some of the questions that you have at this point? Yes [INAUDIBLE]. AUDIENCE: So in the version in pset6, when you run it, there's a space. And I can see where the space is after the comma. [INAUDIBLE] start the open bracket. How do you incorporate the space in the way you wrote your own codes? SPEAKER: That is a good question. And so let's figure that out. So that's a really good question and one that I didn't consider. But let's do it together. So first of all, what I'm doing with echo is when we just echo hello, it outputs hello. If we echo now this get on a separate line, let's examine what happens. So we click this. We keep saying, hi Jason. So again, we don't have this space. And that's because, in PHP, when we have echo, no matter how many spaces-- nope, not the V-- no matter how many spaces we put in here-- if we now load that up again, hi Jason. Yeah, see, all of those spaces got eaten up. And that's something that the echo function does. So to take care of that space, and this is one of the reasons why you don't use echo and you use htmlspecialchars instead. I'm curious what would happen if we did this where we enclosed a space in a string. I'm honestly not sure what will happen when I do this. So that's one way. That's one way to take care of it. If you wrap the space in a string, then the space will be output nicely by echo. The safest thing to do is to do htmlspecialchars. That's always the safe bet. But now we have a way to do it with echo if necessary. And in a similar way, we can echo new lines, all the sort of stuff you're familiar doing in PHP. Anyone else, what are any more questions that other people have at this point about PHP? If people showed up a little late, I'm happy to stay after a little bit and talk about some of the beginning. And it's also all livestreamed, and archived, which is crazy. Anyway, so now let's do some more advanced stuff with PHP. And one of the earliest things you were introduced to in C was for loops. And PHP has a more powerful for loop called the foreach loop. And it looks like this-- for each blank as blank, curly brackets, do the thing. So this is basically a shorthand. See, the for loop as a syntactical construction was devised in C and in assembly language and things like. Devised in C, precisely, as a shorthand for a lot of the types of loops that people would see. Like when you wrote a loop, there was often an initialization step executed right at the beginning, a condition where the loop would stop-- and that's the feature that's just in a while loop, or that a while has exactly just that feature-- and then an incrementation step at the end. And so you'd often find yourself writing code like the following. I'm going to erase some of this. But if we're iterating through characters in an array, for instance, like we've got an array of characters. Sorry to bring back C. I know, you thought you were done. But it's only for the purpose of learning PHP, I promise. So if you got a char str of length 8, and let's say it says Hellooo with a trailing null. Great, so that's our string. And then we had a for loop. We have int i equals 0. And we want to exit when str of i equals not equal to null, because we exit when it equals null. And then we do i++ at each point in the for loop. Doing something with str of i. So the basic formula was, we had this array that we wanted to treat as separate elements. But what we had to do is we had to basically create a separate integer variable that was counting up every time we went through the loop. And then we would have to then call strstr[i] when what we really wanted to do is just go character by character, right? We don't want to increment an integer and then use that integer to access each character individually. We really want character by character. And so for each intelligently calculates that for us. If we have an array, which we can declare in PHP as just-- if we have a variable called, let's call it array. The miracles of no typing, it's just like any other variable. It's just an array. And we have a little [INAUDIBLE] like 1, 2, 3, just a sort of initialized array. It's OK, it doesn't like my foreach. But if we do foreach-- actually I typed that a little wrong. There are two ways to do a foreach loop. There's the in syntax and the as syntax. And we're going to do in syntax first, not as. That's my mistake. So foreach num in array, echo num. And PHP is yelling at me for some reason. It's finding an unexpected in in something, which is a little bit of a bother. But we'll figure out why that is in a moment. So not like that. Let's try using the as. It prefers the as syntax is seems. So let's do foreach array as num. So a little explanation of what just happened is the as syntax is saying-- well first, let's look at what this prints out. So we open up our IDE. We go here. We say, Hello Jason. And it did 123, which were the contents of the array that we created up top. So diving into this foreach loop, we have a variable called array which is an array of three numbers. And then we are doing foreach array as num, echo num. And that's more intuitive than a for lop. We're saying, treating each of the things in the array as num, I want you to give me num. And that's exactly what it's doing. PHP is calculating that when you say foreach array, and you're dealing with an array, what you're going to want to iterate over is the characters in that array, is the ints in that array, is the elements in that array. And it's letting you store those variables as num, and then just output num right away rather than saying, I have a variable called i, and then I want to output strstr[i]. And so that allows us to do cool things. Like basically we don't have to create these variables like i's and do all this incrementation stuff at the end. PHP takes care of all of that for you. So now let's talk about foreach as it applies to our _GET dictionary. So we'll comment this out quickly. So we have our _GET array. We have this variable. And it's got some stuff in it. Right now, we only have one variable being passed to it, which is name. But if we press Enter, now we can have two variables. We can have name and age, for instance, if we want to get the age and also the name of a person, funnily enough. So now _GET is going to be a dictionary with two elements, with two key value pairs. And the first key-- I'm going to write this one up on the board too. We have our dictionary is _GET. Sorry, it's is a little hard to see. But inside our dictionary we have name, which is going to be something that we're given. And we'll have age, which is also going to be something that we're given. And this is the entirety of our dictionary. So it's got two elements in it. And so because foreach loops are smart, we might think, and correctly might think that foreach can iterate through this dictionary, printing out the values given by name and age. So let's in fact do just that. Let's construct a foreach loop. And we're going to do for _GET as. And we're going to do the following. So let's see what happens if we type just word, and then say echo word. We're also going to echo a new line just to make it a little clearer, what's going on. So let's see. It's not giving me any errors. And we'll close this. On our website, you're going to be doing a lot of that over the course of pset7. So we say my name is Sam. My age is 45. It's not. But it prints out, as expected, Sam 45. And so you'll notice that what foreach loop did-- here, let's go back to that so it's up on the board-- we get _GET as word. And there were four things in _GET. But it only printed out two things. foreach, being its intelligence self, assumed that what we really wanted was the values, not the keys. But there is a way that we could print out the keys as well, if we wanted to. If we wanted to also know what these variables were called, there's a way that we can access this as well. And the way to sort of do that, so we can say, lets really split it into key value pairs. So let's see what happens now. So we have key. We have value. We have another new line for readability. And let's see what happens when we do this now. I don't know how old Jason is. Jason's 15. So we have name Jason, age 15. So we were able to access the key and value pairs of this dictionary just by saying as key points to value. And that's a foreach syntactic sugar bit that allows you to access things in the dictionary. So hopefully this sort of emphasizes the power of the foreach loop. You can pretty much throw anything that seems iterable, like anything that has multiple elements like an array, like a dictionary-- those are two primary things you'll be working with both in life and in pset 7. So you can throw that stuff at it, and it will figure out what you want to do with it. It'll say, OK, I'm going to get these things from the data that was passed to me. And that's something that you're going to be using a lot of in pset 7. I'm going to quick scroll down just to see where I'm at. Do people have questions at this point? Questions at all? Yes? AUDIENCE: So with the key and value, you could name it anything else and it would still work? SPEAKER: Oops. Wow, I totally deleted the whole line. Great work. So a, a. Key and value is just a convention. It's helpful. You would get some design points, maybe some style points for doing that because it really conveys the intention. But we say a and yarp. AUDIENCE: You don't have to change anything in the HTML file in order to reflect that? SPEAKER: Not at all. AUDIENCE: And it just knows that because of the equals greater than-- SPEAKER: Yes. AUDIENCE: --that indicator that that's-- SPEAKER: Yes. That is a foreach syntax, but yes. AUDIENCE: There are not types. So what if you wanted age to only be a number? Is there a way to do that? SPEAKER: There are ways to check if variables conform to certain types. So PHP asks a little more from you because there are no types in. Some ways it asks less. In some ways it asks more. Because if you have just something in a variable, you have no idea what type it is. But if you are smart about the variables that you assign types to and make sure that functions only return-- you want functions to only return one type of value so that you can basically expect that the variable you get back from a function will be of the type that you think it will be, basically. But there are some methods by which you can check. I don't remember them off the top of my head. I'm waiting for it to turn blue. isint? isstr? There are methods built into PHP that can check the type of variables for you. But if you assign variables smartly, you should not have to do that too much in pset 7. But those methods do exist. And that's something that is in the language itself. And I don't remember the precise syntax. We could even look it up. But time is of the essence. have Does anyone else have any more questions? Yes. AUDIENCE: I have just one more. So you mentioned the GET method, but you didn't mention the POST method. Are we coming back to that? SPEAKER: Yes, we will be coming back to that. That's exactly what I was looking at my phone, which now fell asleep, but I'll find it. Just making sure we hit all of the PHP notes. Yep, there's no debugging version. Yes, we have a few more things that we want to do now at this point. So talking about POST, which you mentioned, the only difference between GET and POST is that remember when we looked at this URL and we saw, oh, name equals a and age equals yarp are right in the URL there for us. POST is a little more secretive with its passing of information. So if you didn't want a user to know, for instance, you didn't want the username and password of the person currently logged in to be displayed in the URL, which is a reasonable thing to not want in the URL, because someone can see it. If they link someone to a page, you don't want their URL plastered there, because that would allow people to login just with the pasting of a URL instead of actually filling out a form. POST is a little bit more secretive. And the only things that we'll have to change are this method, change from get to post. And then inside the HTTP, instead of accessing the array _GET, we're going to access the array _POST. And we'll notice that, if we open this back up again, Jason slowly declines in age. name Jason, age 14. The same stuff pops up. But we go to the URL and those variables aren't there. And the way that POST passes-- so remember how to look at the source of a page. We go to the network. We refresh. And this is another thing that POST will give you warnings about. You might have seen a box, a text box like this in your browser. Are you sure you want to send a form again? POST is what 's sending these forms. Because basically if you sent your credit card information to someone, that's not going to show up in the URL. That's going to be a POST request. So when you refresh the page, it's resending that post request. So now we do want to send the form again because it's not going to create any duplicate purchases. And we'll notice that down here, the method we're using is POST. And it did indeed transfer bytes. It transferred 401 of them. Program's pretty tiny. But there's nowhere that we can see the values that are being passed. The web pages themselves can see, but we as users are not able to see, unless you're a hacker. If you're a good hacker, you can look. If you know the basic format of the HTML, the values will make themselves known in the pages. You'll be able to see. The values will be there, they're just a little less obvious for you to access, basically. Do we have any more questions about GET, POST before-- what we're going to do next is actually look at some of the code that you're giving in pset 7, talk about how it uses some of these concepts, and talk about the things that you are going to have to do a little bit in pset 7. Any more questions before that? More questions you guys have? Great. All right, let's look a little bit at pset 7, no doubt what you are all most excited about. I mean, this is something that David goes through a little bit. But we'll have three directories at the top, as well as a configuration file. That's for databases, which we'll talk about in about five minutes. Includes, you never need to look in this directory if you don't want to but it's nice to know there are all sorts of helpers. Helpers is like helpful functions. And then we have config, which sets some stuff up. There are some functions that CS50 has written that are in helper and config. And some of the PHP that already exits in files will do a lot of the more sort of obtuse leg work for you. Like if we go into public login.php, which is what shows up right when you go into pset 7. We'll see that there's this require statement. And that sort of like a sharp include, hashtag include if you're of a newer generation. But this basically says that I need access to all the functions in config.php. And you could have a require for all sorts of other things. config actually requires helpers. So whenever you require config, you're also including or requiring helpers as well. So that gives you access to all the cool functions that we're going to use, things like render. I'm actually going to ease this down a little bit. So the function then we're going to walk through just before we move on to SQL a little bit is the login.php function, just because it uses some of the topics that we just talked about in PHP. You see the first thing is if $_SERVER. This is another global variable that you're going to be dealing with. It's like _GET and _POST, but what server contains is this can let you know if the request method was a GET or a POST. Like previously what we were doing is just in our code that we wrote, we were just changing it to be GET and POST depending on what the HTML has. But there are pages that can be accessed with both types of requests. And you might want to do different things depending on the type of request, just like login does. So you can check that request method through accessing keys, through using a key and getting the value of something in the dictionary _SERVER. So that's another global variable like _GET and _POST. If it's GET, we want to render the login form. Render is a function that basically just puts up the appropriate HTML and passes it some parameters. This title is a parameter that's used in displaying, oddly enough, the title of the page in question, the thing up here, say or hello in our previous example. Now we have a different thing. Else if it's POST, we do some other stuff. We're using that empty method. It's not exist, it's empty. And we saw before, PHP has a fair amount of built in methods that David will-- if there are methods that are useful to you, they will be alerted to you in the walk through that David gives at the beginning overview, and also Zamyla's helpful bits. She's back everyone. We can all rejoice. apologize is an aptly named function that just basically prints out some error messages, because CS50 is very polite. And now this, this is a tricky bit because this is where we're querying the database. Now we haven't talked about databases. And we're going to in the next five minutes or so, maximum. But this is a function that CS50 has written to get a table basically from a database that we're working with in pset 7. I'm really bad with my zero indexing today. But yes, it is 7. So query it's going to return an array, basically is the key bit. And because these things don't have typing, so rows is an array of arrays. Because when we're thinking about a table, what we're going to do is, as you learned in psets like the game of 15, anyway where you had to use a double array, we basically have array of other arrays makes a table. And you've got rows and columns. And then you can access them like [0] [1], you get the [0] [1]. Basic stuff like that. So what we're doing here in this function, we're asking the database if the user that's trying to login, that will be sent through the POST method. We'll see we're getting the username from _POST. They'll have sent, the user or you, will send a value through a form through POST because it's username and password stuff. We're checking the username to see, is this in the table? Because if a user is logging in, then their username should be stored in the table of users that exist for this site. So basically if the user is in the database, query is going to return that row, which is an array. But the tricky part is that if even if the double array is only of one row, even if it's a one row array-- like you've got basically-- if you've got a size one array that's holding another array, you're really dealing with one column. But it's still treated like a double array. And this is where it can sometimes get tricky, because we've got rows here. Our variable is rows. And then we're creating a new variable called row and setting it equal to the first row of rows. And you'll notice that comment says it's the first and only row. So this is the tricky part where now functions can return arrays very easily. There's not mallocs. You won't see mallocs. So you won't see seg faults. But functions will still be passing around arrays and data in groups. And you have to be wary of what exactly your functions will return. And even if it's one column like this, query is still going to return a double array. So to access that column-- or you can think of all of this as inverted since we're talking about rows. But to access that one row, you can't just say rows. Even though it is one row, you have to do rowsrows[0] to sort of eliminate this outer bit of the array and have just your one row. Do some other things. There's a function called password_verify that verifies the password that was POSTed. And then we see another global variable here, _SESSION. Basically session id is how you keep track of if someone is logged in or not. So right now with login.php, we're logging a user in. So what we want to do is we want to say the session id is equal to the row id, which just makes sense because each row will have a different id number as part of the table. We'll get into SQL in a second, so if any of this seems a little bit like blah, then all will be cleared up. But we're going to set the id equal to the proper thing, logging the user in. Apologize if anything goes wrong. And that is logins purpose in life as Professor Malan would say. So that was login.php. And a lot of the PHP code you write in pset 7, they'll be a little bit. Don't forget to chmod to the proper permissions. There will be a little bit about that in the beginning of the spec. But the PHP that you're writing is going to be doing stuff that's similar to this. You're going to be accessing some things that are given to you in the global variables of PHP that are dealing with the current logged in user, whether there have been requests sent to this page, different things like that. And it will also be potentially iterating through rows of this thing. In a different function, query does return this double array. And if there are more than one rows in it, if there are-- yes, if there are more than one rows in it, then it will be a table. And you might want to iterate through the rows of this array using the foreach loop that we described. So if you do foreach on a double array, what will the word-- here, I'll actually write it. I'll write it quick here. If we have a foreach of rows as row, what's the type of row? Does anyone know? You got it? So rows is a double array. So what is foreach going to infer that we want from this double array if we're iterating over it? We can basically assume that it's going to be either elements, or rows, or columns, basically. And so rows and columns we can treat as the same thing. Basically what the foreach loop is going to do is it's going to return rows. row is going to be of type row, whereas rows is a double array. So if you give foreach a double array, it's not going to iterate more than one level deep. Which is basically to say if there are eight cells in this table-- 1,2, 3 4, 5, 6, 7, 8-- the foreach loop is not going to go through each of these cells. What the foreach loop will do was it will go through this row, give you this whole row. And then it'll go through that row. So it only iterates one level deep. If you add a nested foreach loop, then you can treat each row returned from rows, you do foreach row as element, let's say. And then you could echo the element. So that's a brief little refresher on how you might be using foreach loops in the context of query. Are there any questions on PHP? Anything at all before we move on to talking about SQL and the fun of database? Feeling good? Feeling good. All right. Let's move on back to the PowerPoint, which you probably miss. SQL, yay. People who are in my section typically will know that subheadings of acronyms are always just the first words I think of that match that algorithm-- that acronym. It's not an algorithm. So SQL is a database. It's a language that works with databases. And all databases are is tables, at least in the way that SQL represents them. Another way to think about databases is databases are a set of keys and values basically. You can think about a database as a dictionary and also as a table. Basically it's a way to associate different data with other data, often through rows and columns. And that's the way that's SQL works best. So this is one example of a table. I've got a few examples of people in my section, which I didn't have time to change. But we've got things like ID, name, superpower, and hometown. I don't know where anyone's from in my section, so I'm just going to assume everyone's from New York City because I have a high statistical likelihood of being correct. SQL will automatically take care of the ID column for you. If you insert a new row into a SQL database, it will increment that ID number and just basically stick like five names, superpower, hometown, whoever onto the end of that table. So ID is a column you'll never have to worry about. But, like in the case of login.php, when we were getting the session ID from a table and just using ID, ID is a way to uniquely identify an element of a database. So if we had two Sams, both of which taught CS50, and both of who were from Milwaukee, those would still have distinct ID numbers and thus be distinct in the context of the table. So this is what SQL is dealing with, working with in the back end. Now these are the four commands that you'll need to work with SQL. And I threw them all up on one slide. But we're going to go through them all individually. The first command is UPDATE, which does what you might expect. Say you have some data in the table that's out of date. Like if you're keeping track of people's names and ages, if someone's age increases, then you're going to want to go in and update just that person's age. For an example that works with our first table-- don't worry about writing all of these commands at the same time. But if you've got update down, that'll be good for this part, because we're going to go back to the table. So if we go back to the table, let's say something that happened was there was an earthquake or a fault line that split directly through New York City. And we wanted to update everyone who lived in New York City. They all had to move to Pennsylvania. That's not a hometown. They all had to move to New Haven. There we go. So everyone in New York moves to New Haven. And so that's something that's editing three rows in this table. But in SQL, you can do that in just one statement. So we go back to UPDATE. Let me quick erase this board again. When we're talking about updating, there are a few parts of the syntax that are key. Well, all of the syntax is key. But the stuff in green is optional. The white are required, like predefined names. And the light blue are things that vary depending on the table. So that's what's going on with the color scheme here, up there. So if we want to update just those rows of the people who live in New York, so what we would do if we said UPDATE? So table is where we put the name of our table. Let's just say the name of our table is table one. So we want to UPDATE table one. And we want to set-- what do we want to set? Well we want to say, so column-- PHP treats rows as unique identifiers. And then columns are the different fields of those elements of the database. So the first element of the database has a name of Sam, superpower of CS50, and a hometown of Milwaukee. So if we said set, let's look at the parameters again that set takes. We have column equals value. So we want to say some column-- which remember is a field-- we want to see a field equal to something new. So if we just said update table 1, set name equal Elliot. Get some people from the new section in on this. But if we just did update table 1 set name equal Elliot, what would the table look like after that? People have any idea? Yeah. AUDIENCE: Everything in that row would become Elliot. SPEAKER: Everything in which row? AUDIENCE: In the first row. SPEAKER: In the first row? Why the first row? I don't mean to pick on you. AUDIENCE: Maybe everything in the whole table? SPEAKER: Everything in the whole table, yes. And that's exactly right because-- I was just helping you out a little bit there-- because we omitted the optional WHERE clause. If you don't have the WHERE clause, what this command will do is it'll work with every single row in the table. Everyone's name will become Elliott, basically, which Elliot is very happy about. Or Yanni, one of the two. But everyone's name will change. So the way we use the WHERE clause-- and this applies to all of the WHEREs that are in each of these different things. So you'll notice that SET has column equal value. And so does WHERE. But these are different types of statements. So the column equals value in SET is in assignment. Like we're saying we want to set name equal to Elliot. But in the WHERE clauses, these are equality statements. So let's say we only wanted to change the person's name to Elliot if their name was Ryan, let's say. So when we say WHERE name equals Ryan, that would successfully only change the name-- it would only change the name field in rows where the name field is equal to Ryan. So if we had multiple people named Ryan, all of their names would change to Elliot. This is similar to the example of if a fault line splits New York City and everyone has to move to New Haven, the way we can do that in one statement is UPDATE table1 SET hometown = New Haven where hometown equals New York City. This is the power of the UPDATE statement. We can select any number of rows through true statements about the fields in those rows. We can't say UPDATE table1 set name = Elliot WHERE row = 1, except that we can if we say ID = 1. So we're going to be working with equality of fields, equality of columns. But using the ID field is a way to select individual rows specifically, because the ID field is a unique identifier in a SQL database. So like updating row one, ID equals 1. Updating row two, just change that ID number. But the power of the WHERE statement is that we can update things based on what their current values of certain things are. Yes Elliot? AUDIENCE: And what if you want to-- again, this is another question. But my first question was, where is this happening? Where am I updating this? Is this in a PHP code? SPEAKER: Where you update, yes. We're going to talk about where all of this happens sort of once we go through all the commands. But what you need to know for now is basically that your SQL database exists as something to be accessed by the query function, which CS50 defines. So if you use the query function, you can access this table. So you will be sending these commands to your table in PHP files through the query function. You can also play around with your table directly. And that's the best way to test these sorts of commands. And we'll go through exactly how to do that in just a little bit. So that's UPDATE command. And the rest of the commands are going to be sort of similar, working on similar things. The INSERT INTO is probably the most different from UPDATE. I'm going to leave that up there for just a little bit and work over here. So INSERT INTO, you'll see that table is still the same. You want to INSERT INTO. The capitalization, SQL is case insensitive. So you don't have to capitalize these things. By convention, the words in white are capitalized. But I also color coded them. The only reason that you capitalize those when you're typing them is just to emphasize that those are constants. And so you can either look at the capitalization or the fact that I've colored them differently. So we've got INSERT INTO, let's do table1 again. This is all on one line. I'm just separating it by the different statements. So don't worry about the fact that table1 made it onto the second line. So we want to INSERT INTO table1 some values. And you'll notice the optional bit, which I'll get to in a second. So we've got VALUES. So let's say we want to add Andi to our table, because we miss Andi. Andi is sick. So let's add Andi to our table. Remember that the ID number is updated automatically. So the only fields we need to worry about are name, superpower, and hometown. And so the way that we do that, looking at our syntax, is we've just got a parentheses, with comma separated values, each of which is a value. So if we wanted to insert Andi into our table, all we have to do is right Andi. What's Andi's superpower, people in Andi's section? She like flight, or like speed, or something. What do we already have up there? We have CS50, flight, speed, and strength. AUDIENCE: Time travel. SPEAKER: Time travel, amazing. So we've got Andi, time travel, and her hometown. That's a really good question. New York City, unless someone knows. Everyone's from New York is the lesson to take away from today. So this statement would insert, as a fifth row, with the superpower time travel and a hometown of New York City. But the optional field is basically a way to specify exactly which columns you want to insert things in. The way that we're doing it now, Andi, time travel, New York City, is going in the exact order of our table-- name, superpower, hometown. And if you wanted to do something other than that, like say you didn't know someone's superpower, like how I didn't know Andi's superpower at the beginning. So all I knew was her name and her hometown. What I could do is I could do-- I'll erase this quick. I want to only update the columns. And this is where the optional column list comes into play. I only want to update name and hometown. And then I will say VALUES. I'll do Andi and New York City. If I had omitted the list of columns and just done these two things, where would New York City have gone? Which column would New York City have been placed in? People have any idea? Superpower, exactly. So this will just go in order. And once it reaches the end of the list, it'll just stop filling things in. And the values that it'll stick in all the columns will just be NULL. So because we specified name and hometown, we're going to have ID 5, name Andi, superpower NULL. So superpower is an uninitialized value. You won't necessarily get the same Valgrind errors if you try and access it. Everything will be nicely zeroed out, because NULL is a value in SQL. That is a constant. And then hometown will be New York City. So that's the INSERT INTO command. Before we move, there's two more commands. Do people have any questions about UPDATE, about INSERT INTO, about SQL generally before we move onto our final bits? People feel good, great. Love it. So let's talk about SELECT. Going ditch UPDATE over here. And SELECT is going to be very similar. The goal of SELECT, SELECT's purpose in life is to give you a bunch of columns that satisfy certain conditions. And when I say satisfy certain conditions, your mind might immediately go back to that WHERE clause that came up in UPDATE. And that clause is exactly there in SELECT. If we don't put the WHERE clause and we say SELECT name, hometown-- spelled that a little wrong-- name, hometown FROM table1. If we just say that, what SELECT is going to give us is it's going to give us a double-- a table, rather. A double array if we're thinking about in PHP senses. But it's just going to give us a double array of two columns-- name, and hometown. And it will ignore ID. And it will ignore superpower. And it'll just give us every single row of that table. So if we just inserted Andi, we'll have Andi. And we'll have the original four. If they've been updated, that will be reflected, et cetera, et cetera. So this is because we didn't use the WHERE clause. But we can use it in exactly the same way we used it in UPDATE. If we only want a table of the names and super powers of people living in New York, we can execute a statement like SELECT name, superpower-- I'm just going to leave that-- FROM table1 WHERE hometown = New York City. So this goes to show that you can get totally different columns, and then put columns that you're not even getting back in the WHERE clause. We don't even want the hometown of everyone. But we want the name and the superpower of people whose hometown is New York City. So that's something we can do with the WHERE clause is we can deal with columns that we don't necessarily want back. In the same way in UPDATE, we can deal with columns that we don't necessarily want to update. We can update the city of everyone who's name is Sam, for instance. We can update the city of everyone whose ID number is 2. So just update the city of the second row where we don't have to deal with necessary the common question. And DELETE is, as you'd expect, DELETE FROM table1. And then we've got another WHERE clause. So we can say WHERE ID = 1. Delete the first row. And DELETE will always delete a row, or it will delete some number of rows. DELETE FROM table WHERE hometown = New York City will delete everyone in New York City. That's if there was a sudden tragic plague and you just wanted to remove everyone from the table who lived in a certain city that was hit by the plague. May they rest in peace. These are the four SQL commands that you will need to use. You might not even need use them all. But these are the four that CS50 expects you to be comfortable with going into both quiz 1 and also pset7 and pset8. There's just that table again. In this one, Roy's superpower has been updated to laser beams, which is an example I did not use. I don't know which one Roy prefers, but strength. Roy has a superpower of strength. Katherine did not make it today. That's unfortunate. But she has super speed. Well that was PHP. Before we talk about MVC, does anyone have questions about PHP? Now SQL, or PHP if you suddenly have come up with a question about PHP? Great. All right, we're all set then. So talking a little bit about model view controllers, let's go back to some of the stuff in pset7. So what model view controller is-- I'm not going to save my changes to login because I totally butchered it. But basically we have two separate things going on. We have a public directory which contains the code that's going to be executed and the web pages that will be visited. And we also have this views directory. And views contains templates. This is what the function render-- we saw the render function in a bunch of the PHP code that CS50 has already written for you, that takes in certain parameters. What that code is doing is it's going into views, which are sets of like prewritten HTML code, and it's inserting values into certain places. This is how when you go into CS50 Finance, the same header is on every page. The same footer is on every page. This is because the way that render works is it'll automatically patch in that header and viewer which you can find in views. We actually can go into header, and look, it's an HTML file with a head. It's got some stylesheets. You don't need to look at CSS for pset7 if you don't want to. But you can modify them if you want, make your Finance look a little different. It's got some PHP in the header a bit to see if there's a different title it should put in this header. But just some other scripts, and links, and other things. Head ends, body starts, and oops, we have this weird little end bit. And there's a div, just like a formless kind of element that has an idea of middle. And then when we see footer, we have the end of a div. We have a bottom, which is where the footer text is. End of div, end of body, end of HTML. So what render is doing is render is sort of patching up header, a different PHP file that will contain the actual things that you'll view, like your table of stocks if you are buying or selling stocks. And then it'll add in the footer. And the model view controller idea is that we want to separate how things look from the code. It's we want to separate the frontend and the backend, where the frontend is the stuff that the user sees, the nice visuals-- HTML, CSS, things like that, images, et cetera. And the backend is PHP. This is code that you write. This is where the code that's doing actual operations. This is when you're adding a stock to your table, when you're buying and selling, that's backend. And we can, as you saw, including PHP directly in HTML. So what we could have done for this assignment is just had an HTML file for each page, like login. And then on that page, just had a huge block of PHP code, including all of the code that that page specifically would need. And then we could have done that for portfolio. We could have done all of the buying and selling within the individual pages. But because we're rendering separately from where we're writing the backend code, we can easily change how things look without changing every single file. We do things like just add a new div to the bottom of-- Hello I modified the footer. You can just do stuff like that. But also, you can change the entire visual layout without affecting what's going in the backend. And you can change the entire backend and still have it look just like it did before. This Is the idea of model view controller. And it's actually an imposed paradigm in some of the programming languages you might want to use for final projects. If you do iOS development, they have views, which is what you see on the iPhone, and then backend as like a separate thing. You can think about a little bit. There's a lot of binaries in computer science, which is funny, because everything's in binary. I didn't plan that. That was a pun unintended. Yes, pun not intended. But like .h files and .c files, there's a lot of separating of things that we might not need. So we can just edit the h files, or someone can just see a .h file and know exactly the functions that are in the .c file without necessarily knowing their implementation. This idea of separating components that depend on each other but can sort of access each other through different channels, passing of variables, just include statements, things like that, this principle helps to create applications that can be more easily edited by multiple people, can be more easily changed or modified on a big scale, and are easier to debug in a lot of ways. Really quick, I have a few tips for pset7, which I'll make full screen so you not just looking at the-- tip tip tippee. There aren't that many tips. But I mentioned PHP is hard to debug. Double and triple check it. If your code is just not showing up on the page, it's probably a PHP error, sorry. You never need to look at CSS if you don't want to. But once you're finished, it can be a nice little fun thing to just go in and mess with the CSS parameters. CSS and HTML are an example of a model view controller style thing too, right? You could have style tags inside of HTML elements. But if you sort of outsourcing them to CSS, they're easier to edit, and play around with, and have fun with. Treat CS50 helper functions as black boxes. You don't need to know exactly what render's doing, but trust it to always do the right thing depending on what you pass it, things like this. And I would recommend watching David's walkthrough, going through all the stuff, not just the todos, but you really can treat these as black boxes. Don't go into these functions looking for bugs. And welcome the return of our overlord Zamyla. Great. Are there any final questions before we sort of bounce for the day? Am I still live? Great. Hi livestream people. Great. Are there anymore questions? No? And then I think we're good to go for today. I'll stick around a little bit afterward if people had questions they were afraid to ask on the stream. But otherwise, have a good day.