PHP Basics00:00

  • Last time we left off with a new language, HTML, that we used to structure and make webpages.

  • We also used Cascading Style Sheets (CSS) to change the colors and positions of elements.

  • Today we’ll start to use a more powerful programming language for the web, PHP.

  • One feature that a language needs, in order to dynamically generate webpages, is simply a print function.

  • We’ve had this function in C and Scratch that can generate strings of text, but HTML is made up of manually written, static text.

  • To dynamically generate HTML, we’ll use PHP (and later JavaScript).

  • Remember that C is a compiled language, which means we need to assemble it into object code before we run it. PHP is an interpreted languages, meaning our source code is provided as input to some program (an interpreter) that understands it and runs it as-is.

  • Let’s open hello:

    #!/usr/bin/env php (1)
    <?php (2)
    
        printf("hello, world\n"); (4)
    
    ?> (6)
    • In line 1, we are telling the operating system to find the interpreter for PHP, wherever it is.

    • In line 2, we are writing a PHP start tag that means "this is the beginning of PHP code."

    • In line 4, we can write a printf statement that looks suspiciously like C.

    • And in line 6, we’re simply telling the interpreter, "this is the end of our PHP code."

    • When we save this file in gedit, it’s smart enough to realize that we’re writing a PHP file, based on that first line, and syntax-highlights (color-codes) the text accordingly:

      gedit color-codes PHP source code.
  • Remember that we saved this to our home directory, so in our Terminal window we can try to run it:

    jharvard@appliance (~): ./hello
    -bash: ./hello: Permission denied
    • We get this error, which we’ve gotten before, and know how to fix with chmod, that changes the mode of a file.

  • Let’s allow everyone to execute this file:

    jharvard@appliance (~): chmod a+x hello
    jharvard@appliance (~): ./hello
    hello, world

    And now it runs as we expected.

  • But notice that we skipped the step of compiling it!

  • Let’s open conditions-1:

    #!/usr/bin/env php
    <?php
    
        // ask user for an integer
        $n = readline("I'd like an integer please: "); (5)
    
        // analyze user's input
        if ($n > 0)
        {
            printf("You picked a positive number!\n");
        }
        else if ($n == 0)
        {
            printf("You picked zero!\n");
        }
        else
        {
            printf("You picked a negative number!\n");
        }
    
    ?>
    • Notice that we have a few comments, but this looks oddly familiar like a program we wrote in Week 1, conditions.c.

    • We ask the user for an integer, and tell them if it’s positive, negative, or zero.

    • There are two differences with C. One is the $ that is in front of all variables in PHP. The second is the readline function that we haven’t seen in C, but is basically the PHP version of GetString.

  • Let’s go into our source code directory where we have conditions-1 (which we saved in our ~/vhosts/ directory for convenience later):

    jharvard@appliance (~/vhosts/localhost/public/src8m): ./conditions-1
    -bash: ./conditions-1: Permission denied
    jharvard@appliance (~/vhosts/localhost/public/src8m): chmod a+x conditions-1
    jharvard@appliance (~/vhosts/localhost/public/src8m): ./conditions-1
    I'd like an integer please: 50
    You picked a positive number!
    • So first we had the same problem of not being able to run it, but we can fix that quickly with chmod, and now we see conditions-1 runs like we’d expect.

  • But notice that the top of the source code again had:

    #!/usr/bin/env php
    <?php
    ...

    which allows us to create what looks like a C program, but is executed not as compiled zeroes and ones. It’s passed in to an interpreter that happens to be called php, the same as the language.

  • We can open return:

    #!/usr/bin/env php
    <?php
    
        $x = 2;
        printf("x is now %d\n", $x);
        printf("Cubing...\n");
        $x = cube($x); (7)
        printf("Cubed!\n");
        printf("x is now %d\n", $x);
    
        /**
         * Cubes argument.
         */
        function cube($n) (14)
        {
            return $n * $n * $n;
        }
    
    ?>
    • Notice that we’ve defined cube, a function referenced in line 7, in line 14, with no prototype. PHP (and a lot of modern languages) has a smarter interpreter than C’s compiler in that it reads in the entire file that’s passed in as input, before deciding that a function doesn’t exist. So we can call a function and declare it later.

    • Another difference compared to C is that there’s no need to declare the types of variables, even though types do exist (as we’ll see later).

    • There’s also no need to include as many libraries, since PHP includes many more functions by default.

    • A final big difference is that there’s no main function, and we can just start writing code to be executed. This will come in useful shortly when we want many entry points into our code, spread among multiple URLs and files, not just a single main function.

Hash tables10:23

  • We glance through the source code of speller, which is too long to include here, but the takeaway is that the program is a porting, a manual conversion, or "translation," if you will, from C to PHP.

    • David’s taken care to convert line by line as similarly as possible, if you’re interested in opening both side-by-side and comparing them to notice differences. (For your convenience, here’s speller.c.)

  • But let’s see what we can do now that speller is in PHP. We can start a new file, dictionary.php, and save it to our Desktop folder for now:

    <?php
    
        function check($word)
        {
    
        }
    
        function load($dictionary)
        {
    
        }
    
        function size()
        {
    
        }
    
        function unload()
        {
    
        }
    
    ?>
    • These four functions were what we wrote in dictionary.c for Problem Set 5, but now we can rewrite them in PHP. Notice how we declare functions with function, and pass in variables not with a type but just the variable name with a $ in front.

  • We can declare a hash table in PHP by just adding this:

    <?php
    
        $size = 0; (3)
    
        $table = []; (5)
    
        function check($word)
        {
    ...
    • Notice that line 5 was all it took to declare a hash table. In line 3, we create a variable to store the size of the hash table, just like we would in C.

  • Now let’s look at what we can do with load:

    ...
        function load($dictionary)
        {
            global $size;
            gloabl $table;
    
            foreach(file($dictionary) as $word)
            {
                $table[$word] = true;
            }
        }
    ...
    • Notice that we have to start by mentioning the global variables we want to use in our function (which we didn’t have to in C).

    • Then we use a new foreach construct. file($dictionary) returns the dictionary file as an array of strings, which we can iterate over, and refer to each string as $word.

    • With each $word, we set the value in the hash table for that word to be true, signifying that it is a valid word.

  • Let’s add a few more features to our load function:

    ...
        function load($dictionary)
        {
            global $size;
            gloabl $table;
    
            foreach(file($dictionary) as $word)
            {
                $table[chop($word)] = true;
                $size++;
            }
    
            return true;
        }
    ...
    • chop removes the \n in each word (or trailing whitespace more generally), since each line that is passed in from $dictionary will have a \n that we don’t want to keep.

    • We’ll also keep track of the size, and then return true.

  • The size function is pretty straightforward:

    ...
        function size()
        {
            global $size;
            return size;
        }
    ...
    • All we have to do is refer to the global variable $size and return it.

  • How about check? We can do this:

    ...
        function check($word)
        {
            global $table;
            if (isset($table[strtolower($word)]))
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    ...
    • First, we want to have access to the global $table variable. Then, we return true if our hash table has a value set for $word (after we convert it to lowercase).

    • Notice that we can simplify this even more by returning the value of our condition, instead of returning true if our condition is true and false if our condition is false:

      ...
          function check($word)
          {
              global $table;
              return isset($table[strtolower($word)]);
          }
      ...
      • And this applies in C, too!

  • And unload is already done, since we didn’t allocate any memory ourselves! In C, we’ve had to malloc (and free) memory manually, but PHP manages it for us. One tradeoff here, however, is the speed of execution. David’s implementation of speller in C takes 0.38 seconds to run in total, but the PHP version takes 0.93 seconds. This difference would surely add up, even though the PHP version was faster to implement.

  • Another price of PHP is the amount of memory used. If we wanted the most performance, we’d probably want to avoid PHP. Lots of webservers are actually written in C (like the one we’ll make in Problem Set 6) in order to get the most performance and control over our server.

  • Moreover, the hash table in PHP (actually called an associative array) is meant to be a generic tool, since whoever wrote that doesn’t know what you might want to do with it, and thus probably has extra features to account for a wide range of situations.

  • The conclusion is that there are many tools to use, and the important thing is deciding on the correct one to use!

PHP for the Web19:48

  • So far, we’ve executed PHP files in the command line. But it’s much more common to use PHP as files ending in .php to generate web content.

Forms, sessions, and emails20:11

  • Back in the day, one of David’s first projects was helping improve the freshman intramurals program. Students had to fill out paper forms (gasp!) and drop them off with some proctor, who had to keep track manually. These days, we might just use a Google Form, but in the Olden Days when that didn’t exist, David and his roommate used a language called Perl to create online forms. And now, we have the glory of recreating that idea in PHP.

  • Expository story aside, let’s take a look at froshims-0.php:

    froshims-0.php in Chrome
  • Notice that it has a form that allows us to take input from the browser. Last time we submitted our query parameter to Google, but now we’ll do something else. First, let’s see what happens when we fill out the form:

    David fills out the form
    register-0.php in Chrome, after David filled out the form
    • Notice that the URL has changed to register-0.php, and even though the formatting isn’t very pretty, we see that the values were passed in.

    • The page has printed what looks like an Array in which these three values were stored.

    • But also notice that the URL doesn’t include the queries as strings, like we saw with Google and /search?q=cats.

  • Let’s investigate by opening the source code for froshims-0.php:

    <!DOCTYPE html>
    
    <html>
        <head>
            <title>Frosh IMs</title>
        </head>
        <body style="text-align: center;">
            <h1>Register for Frosh IMs</h1>
            <form action="register-0.php" method="post"> (9)
                Name: <input name="name" type="text"/>
                <br/>
                <input name="captain" type="checkbox"/> Captain?
                <br/>
                <input name="gender" type="radio" value="F"/> Female
                <input name="gender" type="radio" value="M"/> Male
                <br/>
                Dorm:
                <select name="dorm">
                    <option value=""></option>
                    <option value="Apley Court">Apley Court</option>
                    <option value="Canaday">Canaday</option>
                    <option value="Grays">Grays</option>
                    <option value="Greenough">Greenough</option>
                    <option value="Hollis">Hollis</option>
                    <option value="Holworthy">Holworthy</option>
                    <option value="Hurlbut">Hurlbut</option>
                    <option value="Lionel">Lionel</option>
                    <option value="Matthews">Matthews</option>
                    <option value="Mower">Mower</option>
                    <option value="Pennypacker">Pennypacker</option>
                    <option value="Stoughton">Stoughton</option>
                    <option value="Straus">Straus</option>
                    <option value="Thayer">Thayer</option>
                    <option value="Weld">Weld</option>
                    <option value="Wigglesworth">Wigglesworth</option>
                </select>
                <br/>
                <input type="submit" value="Register"/>
            </form>
        </body>
    </html>
  • This page is all HTML, with the most interesting part on line 9 that sends the form information to register-0.php, with the post method. get puts it in the URL, and post sends it another way. post, then, should be used for information we want to keep secure, like passwords or credit card information. Photos, too, should probably be sent with post since it’s not easy to put them in a URL.

  • So if we were to look now at register-0.php:

    <!DOCTYPE html>
    
    <html>
        <head>
            <title>Frosh IMs</title>
        </head>
        <body>
            <pre>
                <?php print_r($_POST); ?> (9)
            </pre>
        </body>
    </html>
    • all it does is print out the $_POST variable. We see that line 9 has a <?php tag, nested inside a <pre> HTML tag that means "preformatted text," or text we want monospaced like a typewriter.

    • print_r is the "print recursive" function that prints everything in its argument.

    • And inside, we pass in $_POST, which contains everything the browser passed in, stored for us by PHP.

  • Let’s open another example, froshims-1.php, which looks a little better but is otherwise the same:

    David fills out the form in froshims-1.php
    • which brings us to:

      register-1.php
  • Mysterious. Let’s investigate register-1.php:

    <?php
    
        // validate submission
        if (empty($_POST["name"]) || empty($_POST["gender"]) || empty($_POST["dorm"])) (4)
        {
            header("Location: http://localhost/src8m/froshims/froshims-1.php"); (6)
            exit;
        }
    
    ?>
    
    <!DOCTYPE html>
    
    <html>
        <head>
            <title>Frosh IMs</title>
        </head>
        <body>
            You are registered!  (Well, not really.)
        </body>
    </html>
    • So there’s more interesting code here, particularly lines 4-8. The comment says that this chunk of code is validating the submission.

      • Some variables, including $_POST, are superglobals, variables that are always accessible in your program.

      • In this case, we’re indexing into them with words (as though $_POST were a hash table), passing in a key, or lookup word, in the square bracket, and it’ll provide us with a value. In line 4, we first try to get the value of $_POST["name"], and empty is just a function in PHP that tells us if its argument is empty or not. The || means "or" just like in C, and so the line as a whole is just checking that the user gave a name, gender, and dorm. If any of those are empty, then we send them to froshims-1.php with line 6.

      • If that if condition didn’t evaluate to true (every field has a value), then we leave PHP mode and return to basic HTML. And this is an important feature of PHP, where we can open and close the PHP tag to put PHP code anywhere. After we close the tag, the server will just return whatever text is there, so we get this ability to comingle code and markup language (for better or worse).

  • Let’s check out froshims-3.php:

    froshims-3.php
    • The form looks the same, but when we submit it, we see this:

      register-3.php
  • And when we check John Harvard’s email, we see this:

    John Harvard's registration email
    • The real frosh IMs program would just email the proctor in charge the form information, but here we’ve programmed it to email jharvard@cs50.harvard.edu so we can see what happens.

  • Let’s look at the source for register-3.php:

    <?php
    
        // require PHPMailer
        require("libphp-phpmailer/class.phpmailer.php"); (4)
    
        // validate submission
        if (!empty($_POST["name"]) && !empty($_POST["gender"]) && !empty($_POST["dorm"])) (7)
        {
            // instantiate mailer (9)
            $mail = new PHPMailer();
    
            // use SMTP
            $mail->IsSMTP(); (13)
            $mail->Host = "smtp.fas.harvard.edu"; (14)
            $mail->Port = 587; (15)
            $mail->SMTPSecure = "tls"; (16)
    
            // set From:
            $mail->SetFrom("jharvard@cs50.harvard.edu"); (19)
    
            // set To:
            $mail->AddAddress("jharvard@cs50.harvard.edu"); (22)
    
            // set Subject:
            $mail->Subject = "registration";
    
            // set body
            $mail->Body =
                "This person just registered:\n\n" .
                "Name: " . $_POST["name"] . "\n" .
                "Captain: " . $_POST["captain"] . "\n" .
                "Gender: " . $_POST["gender"] . "\n" .
                "Dorm: " . $_POST["dorm"];
    
            // send mail
            if ($mail->Send() == false) (36)
            {
                die($mail->ErrInfo); (38)
            }
        }
        else
        {
            header("Location: http://localhost/src8m/froshims/froshims-3.php"); (43)
            exit;
        }
    ?>
    
    <!DOCTYPE html>
    
    <html>
        <head>
            <title>Frosh IMs</title>
        </head>
        <body>
            You are registered!  (Really.) (55)
        </body>
    </html>
    • We start by opening the <?php tag, and then requiring a special library called phpmailer in line 4, like how we might include one in C.

    • Then we validate the submission, and if none of the fields are empty, we "instantiate mailer" in line 9, which is just asking for a new PHPMailer, which is an object, that we put into $mail.

    • In lines 13-16, we set the protocol for sending our email to SMTP, the host to Harvard’s servers, the port to 587, and adding security with TLS, a protocol for securing communication with those servers. (We figured all this out by asking HUIT’s help desk.)

    • But then in line 19, it looks like we can send email from anyone to anyone, followed by a subject and a body of the email.

    • In PHP, the dot (.) operator allows us to concatenate strings (put strings together), as we do in lines 29-33, since we’re mixing variables with text.

    • Finally, in line 36, we try to send the email by calling the send function with $mail->Send(), and, if that doesn’t work for some reason, die with an error (no, seriously) in line 38.

    • Otherwise, if we didn’t meet the condition that all input was not empty (looking back up to line 7), then we send the user back to froshims-3.php in line 43, which is our original registration form.

    • If everything went successfully, though, we’d get to line 55, "You are registered! (Really.)", which is what we saw at the beginning of this example.

  • This would be how, with real websites or final projects, you might email users with password reminders or new messages.

  • And we see that this allows us to forge emails fairly easily, but at the same time those emails can still be traced back to us.

  • In PHP, there are many superglobal variables, including:

    • $_COOKIE

    • $_GET

    • $_POST

    • $_SERVER

    • $_SESSION

    • …​

  • We’ve seen one, $_POST, and similarly $_GET is where the stuff from the URL is stored for us.

  • Let’s look at $_SESSION, which is interesting because we can save the state of our browsing session. So far, we’ve accessed webpages and clicked around, but HTTP is stateless in that once that we finish loading the page, the connection closes. Other applications, like Skype, FaceTime, and Gchat maintain a constant connection, and we’ll see how we can do that too eventually.

  • Let’s look at counter.php:

    counter.php displaying 0
  • If we click refresh, we get:

    counter.php displaying 1
  • And we can keep going:

    …​